mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
@@ -68,6 +68,38 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
// Dependabot cannot be pointed at dev. `target-branch` in dependabot.yml
|
||||
// applies to version updates only; security updates always open against
|
||||
// the default branch, and security updates are all this repository gets
|
||||
// (there is no dependabot.yml). Labelling them meant close-stale-wrong-branch
|
||||
// shut them 24 hours later, which is how 13 of them died. Retarget instead:
|
||||
// a bot cannot click "Edit" the way the comment below asks a human to.
|
||||
if (context.payload.pull_request.user.login === 'dependabot[bot]') {
|
||||
try {
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber,
|
||||
base: 'dev',
|
||||
});
|
||||
if (labels.includes('wrong-base-branch')) {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
name: 'wrong-base-branch',
|
||||
});
|
||||
}
|
||||
console.log('Retargeted the Dependabot PR onto dev.');
|
||||
return;
|
||||
} catch (err) {
|
||||
// Retargeting can fail when the branch was cut from main and dev has
|
||||
// moved on. Fall through to the normal path so a human sees it rather
|
||||
// than the check passing on a PR that is still aimed at main.
|
||||
console.log(`Could not retarget the Dependabot PR: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Base is main — check if this user is a maintainer
|
||||
let permission = 'none';
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,11 @@ name: Lint & Prettier
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -9,6 +9,10 @@ on:
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
scout:
|
||||
# Docker Hub secrets are not exposed to pull requests from forks, so the
|
||||
|
||||
+400
-52
@@ -1,18 +1,115 @@
|
||||
name: Tests
|
||||
name: Tests & SonarQube
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# The repo's test/quality CI and SonarQube Cloud analysis in one workflow, so
|
||||
# each test suite runs once per event instead of once for the old test.yml and
|
||||
# once more for Sonar's coverage. Pushes to dev and main produce branch
|
||||
# analysis; pull requests get PR analysis with decoration on the PR itself
|
||||
# (the scanner picks the context up from the Actions environment).
|
||||
#
|
||||
# Job layout — three tiers:
|
||||
# - Preflight: plugin-facts, i18n-parity and the quality jobs
|
||||
# (server-quality, client-quality, plugin-sdk-quality) hold the cheap
|
||||
# generated-code/typecheck/lint/smoke gates. Every test job `needs:` all
|
||||
# of them, so a gate failure stops the run before the expensive coverage
|
||||
# fan-out spends ~15 runner-minutes on a result the gates already sank.
|
||||
# - Tests: the *-coverage jobs run the suites and upload lcov; s3-contract
|
||||
# runs the MinIO contract suite. Coverage jobs run tests only — with the
|
||||
# gates cleared in preflight, they can only fail because tests failed.
|
||||
# - Scan `needs:` exactly the four coverage jobs. A coverage job failing
|
||||
# must stop the scan — a missing lcov file would make every line of that
|
||||
# package report as uncovered, and the dashboard would show a collapse
|
||||
# that did not happen. (The preflight gates stop it transitively.)
|
||||
# - Fork PRs don't receive secrets, so the two jobs that need them skip
|
||||
# themselves: s3-contract (MINIO_LICENSE_KEY) and scan (SONAR_TOKEN).
|
||||
# Everything else runs on fork PRs so outside contributors still get the
|
||||
# full test signal.
|
||||
#
|
||||
# Automatic Analysis must stay disabled on sonarcloud.io — it is mutually
|
||||
# exclusive with CI-based analysis, and it cannot import the lcov coverage
|
||||
# this workflow produces.
|
||||
# A push or PR that touches none of these paths can't change the tests or the
|
||||
# analysis, so don't spend the coverage fan-out on it. For a docs-only push
|
||||
# that means no run and no fresh branch analysis — harmless, since the last
|
||||
# analysis is still accurate for unchanged code. GitHub Actions doesn't
|
||||
# support YAML anchors, so the two lists are literal copies: keep them
|
||||
# identical when editing either one.
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- 'server/**'
|
||||
- 'client/**'
|
||||
- 'shared/**'
|
||||
- 'plugin-sdk/**'
|
||||
# npm workspaces hoist every dependency into the single root lockfile,
|
||||
# so a dependency bump touches none of the four directories above — and
|
||||
# a native binding like better-sqlite3 is exactly what needs the suite.
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'sonar-project.properties'
|
||||
- '.github/workflows/test.yml'
|
||||
# Docs inside the workspaces (CLAUDE.md, READMEs, PATTERN.md) affect
|
||||
# neither the tests nor the scan — no test reads checked-in markdown
|
||||
# and SonarCloud has no markdown analyzer. Negations must stay last.
|
||||
- '!**/*.md'
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- 'server/**'
|
||||
- 'client/**'
|
||||
- 'shared/**'
|
||||
- 'plugin-sdk/**'
|
||||
# npm workspaces hoist every dependency into the single root lockfile,
|
||||
# so a dependency bump touches none of the four directories above — and
|
||||
# a native binding like better-sqlite3 is exactly what needs the suite.
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'sonar-project.properties'
|
||||
- '.github/workflows/test.yml'
|
||||
# Docs inside the workspaces (CLAUDE.md, READMEs, PATTERN.md) affect
|
||||
# neither the tests nor the scan — no test reads checked-in markdown
|
||||
# and SonarCloud has no markdown analyzer. Negations must stay last.
|
||||
- '!**/*.md'
|
||||
workflow_dispatch:
|
||||
|
||||
# A newer push to the same branch/PR supersedes the running one — cancel it
|
||||
# rather than spending the coverage fan-out on a stale commit. Safe here
|
||||
# because the Sonar scan job runs last and only the latest commit matters.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
plugin-facts:
|
||||
name: Plugin Permission Facts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
# 22 matches the TREK server runtime (same choice as the plugin-sdk
|
||||
# jobs and publish-plugin-sdk.yml).
|
||||
node-version: 22
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --workspace server
|
||||
|
||||
# The plugin permission facts live once, in
|
||||
# server/src/nest/plugins/protocol/envelope.ts. Every other copy — the
|
||||
# SDK's generated/host-facts.ts and shared's plugin-permissions.ts — is
|
||||
# generated from it and checked in, because publish-plugin-sdk builds
|
||||
# from a standalone checkout with no server present. This fails the run
|
||||
# if a copy drifts, if a new permission has no admin.plugins.perm.*
|
||||
# translation, or if the CLI has no hint for it.
|
||||
- name: Check the generated plugin facts are in sync
|
||||
run: cd server && npm run check:plugin-facts
|
||||
|
||||
i18n-parity:
|
||||
name: i18n Key Parity
|
||||
runs-on: ubuntu-latest
|
||||
@@ -27,32 +124,9 @@ jobs:
|
||||
- name: Check i18n key parity
|
||||
run: node shared/scripts/i18n-parity.mjs --strict
|
||||
|
||||
shared-contracts:
|
||||
name: Shared Contracts (Zod)
|
||||
server-quality:
|
||||
name: Server Types & Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --workspace shared
|
||||
|
||||
- name: Typecheck
|
||||
run: cd shared && npm run typecheck
|
||||
|
||||
- name: Run tests
|
||||
run: cd shared && npm test
|
||||
|
||||
server-tests:
|
||||
name: Server Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
@@ -65,40 +139,40 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
||||
# The lockfile was generated on Windows and omits @swc/core's Linux
|
||||
# optional native binary, so npm ci/install skips it on the runner.
|
||||
# Install the matching version explicitly so the server's SWC transform
|
||||
# (server/vitest.config.ts) can load.
|
||||
run: |
|
||||
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
||||
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
||||
|
||||
- name: Build shared
|
||||
run: npm run build --workspace=shared
|
||||
|
||||
- name: Typecheck shared
|
||||
# Rides along here rather than in shared-coverage: this job already
|
||||
# pays the root install and shared build, and a coverage job may only
|
||||
# fail because tests failed (it gates the scan).
|
||||
run: cd shared && npm run typecheck
|
||||
|
||||
- name: Build server (tsc -> dist)
|
||||
run: cd server && npm run build
|
||||
|
||||
- name: Smoke production require chain
|
||||
# Vitest aliases the MCP SDK deep imports, so only this exercises what
|
||||
# production runs: the built dist resolving the MCP SDK's subpath
|
||||
# exports through the tsconfig-paths/register runtime hook.
|
||||
run: cd server && node --require tsconfig-paths/register -e "require('./dist/nest-mcp')"
|
||||
|
||||
- name: Typecheck
|
||||
run: cd server && npm run typecheck
|
||||
|
||||
- name: Typecheck tests
|
||||
# tests/ is outside the build tsconfig, so a service that grows a
|
||||
# constructor parameter does not break its hand-wired call sites at
|
||||
# compile time: the argument arrives as undefined and throws at
|
||||
# runtime, if anything reads it at all. This is the step that
|
||||
# catches it.
|
||||
run: cd server && npm run typecheck:tests
|
||||
|
||||
- name: Lint
|
||||
run: cd server && npm run lint:check
|
||||
|
||||
- name: Run tests
|
||||
run: cd server && npm run test:coverage
|
||||
|
||||
- name: Upload coverage
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: backend-coverage
|
||||
path: server/coverage/
|
||||
retention-days: 7
|
||||
|
||||
client-tests:
|
||||
name: Client Tests
|
||||
client-quality:
|
||||
name: Client Types & Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -125,13 +199,287 @@ jobs:
|
||||
- name: Page pattern check
|
||||
run: cd client && npm run lint:pages
|
||||
|
||||
- name: Run tests
|
||||
plugin-sdk-quality:
|
||||
name: Plugin SDK Types
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugin-sdk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
# plugin-sdk is standalone (own lockfile, not a root workspace), so it
|
||||
# installs from its own directory.
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Typecheck
|
||||
run: npm run typecheck
|
||||
|
||||
s3-contract:
|
||||
name: S3 Driver Contract (MinIO)
|
||||
runs-on: ubuntu-latest
|
||||
needs: [plugin-facts, i18n-parity, server-quality, client-quality, plugin-sdk-quality]
|
||||
# Fork PRs don't get repo secrets, so MINIO_LICENSE_KEY would be empty and
|
||||
# the AIStor container would fail to boot. Pushes and manual dispatches do
|
||||
# have secrets, so only fork PRs are filtered out. (The implicit success()
|
||||
# on this expression also keeps the job skipped when a preflight fails.)
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
||||
# The lockfile was generated on Windows and omits @swc/core's Linux
|
||||
# optional native binary, so npm ci/install skips it on the runner.
|
||||
# Install the matching version explicitly so the server's SWC transform
|
||||
# (server/vitest.config.ts) can load.
|
||||
run: |
|
||||
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
||||
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
||||
|
||||
- name: Build shared
|
||||
run: npm run build --workspace=shared
|
||||
|
||||
- name: Write MinIO license
|
||||
run: printf '%s' "${{ secrets.MINIO_LICENSE_KEY }}" > minio-licence.key
|
||||
|
||||
- name: Start MinIO
|
||||
# `services:` can't pass the `server /data --license ...` command to
|
||||
# the AIStor image, so it starts via docker run. 127.0.0.1 endpoint is
|
||||
# load-bearing: aws-lite picks path-style only for IP/localhost hosts,
|
||||
# which is all stock MinIO/AIStor speaks.
|
||||
run: |
|
||||
docker run -d --name minio -p 127.0.0.1:9000:9000 \
|
||||
-v "$PWD/minio-licence.key:/minio.license:ro" \
|
||||
-e MINIO_ROOT_USER=trekci -e MINIO_ROOT_PASSWORD=trekci-secret \
|
||||
quay.io/minio/aistor/minio:RELEASE.2026-08-07T18-34-35Z server /data --license /minio.license
|
||||
|
||||
- name: Wait for MinIO
|
||||
# curl was removed from the AIStor image — poll from the runner instead.
|
||||
# 60 x 2s gives a wider margin on cold runners than the 30 x 1s the
|
||||
# pre-6fbff835 job used.
|
||||
run: |
|
||||
for i in $(seq 1 60); do
|
||||
curl -sf http://127.0.0.1:9000/minio/health/live && exit 0
|
||||
sleep 2
|
||||
done
|
||||
echo "MinIO never became healthy" >&2
|
||||
docker logs minio >&2
|
||||
exit 1
|
||||
|
||||
- name: Run the S3 driver contract suite
|
||||
# No --coverage: the src/nest/storage/** 94/84/97/94 pin must keep
|
||||
# holding from hermetic tests alone. The suite's beforeAll creates
|
||||
# the trek-test bucket idempotently — no separate bucket-init step.
|
||||
env:
|
||||
TREK_TEST_S3_ENDPOINT: http://127.0.0.1:9000
|
||||
TREK_TEST_S3_BUCKET: trek-test
|
||||
TREK_TEST_S3_ACCESS_KEY_ID: trekci
|
||||
TREK_TEST_S3_SECRET_ACCESS_KEY: trekci-secret
|
||||
run: cd server && npx vitest run tests/unit/nest/storage/s3.driver.contract.test.ts
|
||||
|
||||
server-coverage:
|
||||
name: Server Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: [plugin-facts, i18n-parity, server-quality, client-quality, plugin-sdk-quality]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
||||
# The lockfile was generated on Windows and omits @swc/core's Linux
|
||||
# optional native binary, so npm ci/install skips it on the runner.
|
||||
# Install the matching version explicitly so the server's SWC transform
|
||||
# (server/vitest.config.ts) can load.
|
||||
run: |
|
||||
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
||||
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
||||
|
||||
- name: Build shared
|
||||
run: npm run build --workspace=shared
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: cd server && npm run test:coverage
|
||||
|
||||
- name: Upload coverage
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: sonar-server-coverage
|
||||
path: server/coverage/
|
||||
retention-days: 1
|
||||
|
||||
client-coverage:
|
||||
name: Client Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: [plugin-facts, i18n-parity, server-quality, client-quality, plugin-sdk-quality]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
# Only the shared and client workspaces — a full root npm ci is not
|
||||
# needed, and the scoped install keeps @testing-library/dom (a peer of
|
||||
# @testing-library/react) in the tree without the re-resolution dance
|
||||
# the folded coverage job used to need.
|
||||
- name: Install dependencies
|
||||
run: npm ci --workspace shared && npm ci --workspace client
|
||||
|
||||
- name: Build shared
|
||||
run: npm run build --workspace=shared
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: cd client && npm run test:coverage
|
||||
|
||||
- name: Upload coverage
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: frontend-coverage
|
||||
name: sonar-client-coverage
|
||||
path: client/coverage/
|
||||
retention-days: 7
|
||||
retention-days: 1
|
||||
|
||||
shared-coverage:
|
||||
name: Shared Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: [plugin-facts, i18n-parity, server-quality, client-quality, plugin-sdk-quality]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --workspace shared
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: cd shared && npm run test:coverage
|
||||
|
||||
- name: Upload coverage
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: sonar-shared-coverage
|
||||
path: shared/coverage/
|
||||
retention-days: 1
|
||||
|
||||
plugin-sdk-coverage:
|
||||
name: Plugin SDK Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: [plugin-facts, i18n-parity, server-quality, client-quality, plugin-sdk-quality]
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugin-sdk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
# 22 matches the TREK server runtime and has node:sqlite, which the
|
||||
# dev-server tests exercise (same choice as publish-plugin-sdk.yml).
|
||||
node-version: 22
|
||||
|
||||
# plugin-sdk is standalone (own lockfile, not a root workspace), so it
|
||||
# installs from its own directory.
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: npm run test:coverage
|
||||
|
||||
- name: Upload coverage
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: sonar-plugin-sdk-coverage
|
||||
path: plugin-sdk/coverage/
|
||||
retention-days: 1
|
||||
|
||||
scan:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
# Fork PRs don't receive SONAR_TOKEN — skip the scan rather than fail it.
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
# Coverage jobs failing must stop the scan: a missing lcov file would make
|
||||
# every line of that package report as uncovered, and the dashboard would
|
||||
# show a collapse that did not happen. The preflight gates already stop it
|
||||
# transitively through these four, so they aren't repeated here.
|
||||
needs: [server-coverage, client-coverage, shared-coverage, plugin-sdk-coverage]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
# Sonar reads git blame to date each issue and to decide what counts
|
||||
# as new code. A shallow clone leaves it blind to both.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download server coverage
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: sonar-server-coverage
|
||||
path: server/coverage/
|
||||
|
||||
- name: Download client coverage
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: sonar-client-coverage
|
||||
path: client/coverage/
|
||||
|
||||
- name: Download shared coverage
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: sonar-shared-coverage
|
||||
path: shared/coverage/
|
||||
|
||||
- name: Download plugin-sdk coverage
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: sonar-plugin-sdk-coverage
|
||||
path: plugin-sdk/coverage/
|
||||
|
||||
- name: Scan
|
||||
uses: SonarSource/sonarqube-scan-action@v8
|
||||
env:
|
||||
# SonarQube Cloud is the scan action's default host, so no
|
||||
# SONAR_HOST_URL — the token is a sonarcloud.io token for the
|
||||
# liketrek org.
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
with:
|
||||
# New Code is configured as "previous version", so this string is what
|
||||
# draws that line — changing it re-bases every "new code" metric.
|
||||
# Pinned rather than read from package.json on purpose: package.json is
|
||||
# still on 3.4.1 while the project has been analysed as 4.0.0 all along,
|
||||
# and taking the lower number would silently move the baseline. Bump it
|
||||
# here as part of the release, together with the version bump.
|
||||
#
|
||||
# Everything else — sources, tests, exclusions, the documented
|
||||
# false-positive list — lives in sonar-project.properties so it stays
|
||||
# reviewable in a PR rather than buried in workflow YAML.
|
||||
args: -Dsonar.projectVersion=4.0.0
|
||||
|
||||
Reference in New Issue
Block a user