Author SHA1 Message Date
Tirsvad 84383eafe9 Make every clang-tidy finding an error
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (pull_request) Successful in 23s
Task: MIL-007#4
2026-10-11 16:36:48 +08:00
Tirsvad 81866d8dac Run clang-tidy with default checks when the project has none
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 22s
Task: MIL-007#4
2026-10-11 16:32:46 +08:00
Tirsvad bf4d090fb3 Merge pull request 'Add the guides and wiki pages for C++ and C# quality checks (MIL-007 task 6)' (#113) from mil-007-guides into mil-007-cpp-csharp-workflows
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 20s
Reviewed-on: #113
2026-10-11 10:26:29 +02:00
Tirsvad ec9a8d6f4a Add the guides and wiki pages for the C and C++ and C# quality checks
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 20s
Task: MIL-007#6
2026-10-11 16:24:22 +08:00
Tirsvad 77f91cf066 Give the C++ and C# workflows a timeout and an exact checkout tag
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 23s
Task: MIL-007#4

Task: MIL-007#5
2026-10-11 16:20:13 +08:00
Tirsvad acbfe967e0 Add the reusable quality-check workflows for C++ and C#
Task: MIL-007#4

Task: MIL-007#5
2026-10-11 16:19:45 +08:00
Tirsvad 8096fe42d0 Merge pull request 'Adopt framework v0.6.0 and call the shared script from the publish workflow' (#112) from adopt-framework-0.6.0 into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 21s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 7s
Reviewed-on: #112
2026-10-11 07:20:39 +02:00
Tirsvad 4f073779b7 Adopt framework v0.6.0 and call the shared script from the publish workflow
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 21s
- framework moves from v0.5.2 to v0.6.0 (QC-YML-001, QC-WF-001, the YAML
  convention, the qc/artifacts and qc/code folders, autonomous mode, the CI
  publish script).
- .gitea/workflows/sync-milestones.yml: the two run blocks of six lines call
  framework/scripts/ci-publish-milestones.sh (ensure-tools, publish); QC-WF-001
  criterion 20. Same behaviour.
- CHANGELOG.md, Unreleased, Changed.

Tests 305 passed; changelog check passes; the wiki build writes 0 pages.
2026-10-11 13:20:01 +08:00
Tirsvad aecc1a37c5 Merge pull request 'Add the related repositories to AGENTS.md' (#111) from related-repositories into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 18s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #111
2026-10-11 07:03:38 +02:00
Tirsvad 8433a15e95 Add the related repositories to AGENTS.md
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 17s
A short section naming the four repositories that change together (the
checklists, the framework, github-action and sqa-and-qc), what each owns,
where a thing lives, and the rules for a change that spans repositories:
one pull request per repository in dependency order, pins only to merged
commits or tags, releases as a separate step, and the related repository
named in the plan before an autonomous run works in it.
2026-10-11 12:59:04 +08:00
Tirsvad 6393476fe1 Merge pull request 'Add timeouts to every job and pin actions/checkout to an exact tag' (#109) from workflow-timeouts-and-pins into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 20s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #109
2026-10-11 06:53:52 +02:00
Tirsvad 1bad75c367 Add timeouts to every job and pin actions/checkout to an exact tag
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 18s
Findings of QC-WF-001 (criteria 8 and 14) applied to the workflows of this
repository and to the two scoped workflows:

- timeout-minutes on every job: quality-checks 15, release 15,
  validate-workflows 10, sync-milestones 15, publish-wiki 10,
  sync-github-metadata 5.
- actions/checkout@v4 becomes actions/checkout@v4.2.2.

No change to inputs, secrets or behaviour. The 6-line run blocks of
sync-milestones.yml move to a script in the framework in a separate change.
2026-10-11 12:49:24 +08:00
Tirsvad c5b42563cc Merge pull request 'Review and accept UC-005 and US-001.16 and US-001.17' (#108) from uc-005-us-001-cpp-csharp-accepted into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Publish accepted milestones / publish (push) Successful in 27s
Validate workflows / validate (push) Successful in 19s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #108
2026-10-11 06:49:14 +02:00
Tirsvad a5bb159e2c Resolve pending commit links in the UC-005 and US-001 acceptance
Validate workflows / validate (pull_request) Successful in 17s
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
2026-10-11 12:48:19 +08:00
Tirsvad 1bc56f8b77 Review and accept UC-005 and US-001.16 and US-001.17 2026-10-11 12:48:18 +08:00
Tirsvad 3efa9205e0 Merge pull request 'Review and accept the MIL-007 amendment' (#107) from mil-007-amendment-accepted into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Publish accepted milestones / publish (push) Successful in 29s
Validate workflows / validate (push) Successful in 19s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 6s
Reviewed-on: #107
2026-10-11 06:47:09 +02:00
Tirsvad 5c12918444 Resolve pending commit links in the MIL-007 amendment acceptance
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 19s
2026-10-11 12:46:30 +08:00
Tirsvad faf13b2c2a Review and accept the MIL-007 amendment 2026-10-11 12:46:29 +08:00
Tirsvad 777d44f121 Merge pull request 'Review and accept ADR-0008' (#106) from adr-0008-accepted into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Publish accepted milestones / publish (push) Successful in 30s
Validate workflows / validate (push) Successful in 19s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #106
2026-10-11 06:45:00 +02:00
Tirsvad a098dff3ec Resolve pending commit links in the ADR-0008 acceptance
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 19s
2026-10-11 12:43:42 +08:00
Tirsvad 9e7aeddb11 Review and accept ADR-0008 2026-10-11 12:43:40 +08:00
Tirsvad ac6925e21a Merge pull request 'Install the workflow that publishes accepted milestones' (#104) from sync-milestones-action into main
Validate workflows / validate (push) Successful in 18s
TirSystem/github-action: Publish wiki / publish-wiki (push) Successful in 8s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #104
2026-10-11 06:43:09 +02:00
Tirsvad c5f189c6cc Merge pull request 'Draft ADR-0008 for C++ and C# quality checks (MIL-007 task 3)' (#105) from mil-007-sdk-10-and-adr into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 19s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #105
2026-10-11 06:42:39 +02:00
Tirsvad fb1fafc5c5 Resolve pending commit links in ADR-0008
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 19s
2026-10-11 12:40:06 +08:00
Tirsvad 11cba358b8 Draft ADR-0008: quality-check contract for C++ and C# 2026-10-11 12:40:05 +08:00
Tirsvad 5a4cfc4358 Resolve the pending commit link in MIL-007 2026-10-11 12:39:28 +08:00
Tirsvad e361b6f914 Use current tool versions only for MIL-007: .NET SDK 10 or later 2026-10-11 12:39:28 +08:00
Tirsvad 23a5a7ec7f Install the workflow that publishes accepted milestones and bump the framework to v0.5.2
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 17s
Task: MIL-007#1
2026-10-11 12:39:06 +08:00
Tirsvad 1e2b5af89a Merge pull request 'MIL-007 tasks 1 and 2: use case, stories and runner tools' (#103) from mil-007-use-case-and-runner into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 20s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 7s
Reviewed-on: #103
2026-10-11 06:27:35 +02:00
Tirsvad 92c1795379 Resolve pending commit links in the MIL-007 use case documents
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 19s
2026-10-11 12:26:59 +08:00
Tirsvad 32b5ab62ab Extend UC-005 and US-001 to C++ and C#, and record the runner tools of MIL-007 2026-10-11 12:26:58 +08:00
Tirsvad 2172939527 Merge pull request 'Plan MIL-007: quality checks for C++ and C#' (#94) from plan-mil-007-cpp-csharp into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
Validate workflows / validate (push) Successful in 20s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
Reviewed-on: #94
2026-10-11 06:23:15 +02:00
Tirsvad 4c51435b16 Link the MIL-007 milestone in the project plan
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 17s
2026-10-11 12:22:06 +08:00
Tirsvad bdf89d38d9 Resolve pending commit links in the MIL-007 acceptance
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 19s
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
2026-10-11 12:21:35 +08:00
Tirsvad e3ad1fa7e7 Review and accept MIL-007 and the PP-001 amendment 2026-10-11 12:21:33 +08:00
Tirsvad 8ad19fca8d Resolve pending commit links in the MIL-007 plan
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 20s
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
2026-10-11 12:19:57 +08:00
Tirsvad b74ee0e5cf Plan MIL-007: quality checks for C++ and C# 2026-10-11 12:19:56 +08:00
Tirsvad 07a5f9b084 Merge pull request 'Record the verification of pinned consumers in MIL-004' (#93) from mil-004-pin-verified into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 6s
Validate workflows / validate (push) Successful in 21s
2026-10-11 06:18:37 +02:00
Tirsvad fd62602c40 Resolve pending commit links in the MIL-004 pin verification
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 21s
Task: MIL-004#1
2026-10-11 12:17:58 +08:00
Tirsvad 05b635c1b3 Record the verification of pinned consumers in MIL-004
Task: MIL-004#1
2026-10-11 12:17:57 +08:00
Tirsvad 9cd723fb48 Merge pull request 'Add a coverage gate to validate-workflows' (#92) from coverage-gate into main
TirSystem/github-action: Publish wiki / publish-wiki (push) Successful in 9s
Validate workflows / validate (push) Successful in 21s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-11 06:07:53 +02:00
Tirsvad 075fae2e45 Add a coverage gate to validate-workflows and stop tracking .coverage
Validate workflows / validate (pull_request) Successful in 22s
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Task: MIL-003#3
2026-10-11 12:05:47 +08:00
Tirsvad 80fb0cfa82 Merge pull request 'Test the HTTP and command-line paths of the tools' (#91) from test-tools-coverage into main
Validate workflows / validate (push) Successful in 15s
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s
2026-10-11 05:27:08 +02:00
Tirsvad eb3e1395db Test the HTTP and command-line paths of the tools
TirSystem/github-action: Publish wiki / publish-wiki (push) Skipped
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Skipped
Validate workflows / validate (pull_request) Successful in 17s
Task: MIL-003#3
2026-10-11 11:26:45 +08:00
56 changed files with 3746 additions and 83 deletions
+12
View File
@@ -0,0 +1,12 @@
# Coverage of the scripts in tools/ by the offline tests. validate-workflows.yml
# runs `coverage run -m pytest -q tests` and `coverage report`, which fails
# below fail_under. Measured at 97% on 2026-10-11; the gate leaves room for a
# few lines and fails when a tool grows without tests.
[run]
branch = True
source = tools
[report]
fail_under = 95
show_missing = True
skip_empty = True
+3 -2
View File
@@ -23,12 +23,13 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the repository
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
- name: Fetch the shared script
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
with:
repository: TirSystem/github-action
ref: v1
@@ -16,9 +16,10 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Fetch the shared script
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
with:
repository: TirSystem/github-action
ref: v1
+72
View File
@@ -0,0 +1,72 @@
name: Quality checks C++
# Reusable workflow (ADR-0008). A repository calls it with
#
# jobs:
# quality:
# uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1
#
# It checks the C and C++ files of the repository with clang-format and
# clang-tidy at exact versions, changes no file and needs no secret. The
# repository needs a .clang-format; a .clang-tidy and a compile database
# (compile-commands-dir) are optional.
on:
workflow_call:
inputs:
working-directory:
description: "Directory, relative to the repository root, whose files are checked"
type: string
default: "."
std:
description: "C++ standard for clang-tidy when no compile database is given, such as c++20"
type: string
default: "c++20"
compile-commands-dir:
description: "Directory with a compile_commands.json built by the caller before the call; empty uses the std input"
type: string
default: ""
clang-format-version:
description: "Exact version of the clang-format package"
type: string
default: "23.1.3"
clang-tidy-version:
description: "Exact version of the clang-tidy package"
type: string
default: "22.1.8"
tools-ref:
description: "Tag or branch of TirSystem/github-action whose tools/quality-checks-cpp.sh is run; pin it to the exact tag together with the workflow"
type: string
default: "v1"
jobs:
quality-checks-cpp:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 15
env:
WORKING_DIRECTORY: ${{ inputs.working-directory }}
STD: ${{ inputs.std }}
COMPILE_COMMANDS_DIR: ${{ inputs.compile-commands-dir }}
CLANG_FORMAT_VERSION: ${{ inputs.clang-format-version }}
CLANG_TIDY_VERSION: ${{ inputs.clang-tidy-version }}
QC_VENV: /tmp/quality-tools
steps:
- name: Check out the repository
uses: actions/checkout@v4.2.2
- name: Fetch the shared script
uses: actions/checkout@v4.2.2
with:
repository: TirSystem/github-action
ref: ${{ inputs.tools-ref }}
path: shared-scripts
- name: Validate the inputs
run: bash shared-scripts/tools/quality-checks-cpp.sh validate
- name: Install the tools
run: bash shared-scripts/tools/quality-checks-cpp.sh install
- name: Run the checks
run: bash shared-scripts/tools/quality-checks-cpp.sh run
@@ -0,0 +1,61 @@
name: Quality checks C#
# Reusable workflow (ADR-0008). A repository calls it with
#
# jobs:
# quality:
# uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1
#
# It checks the C# solution or project of the repository with `dotnet format`
# and `dotnet build` (warnings as errors) on an exact .NET SDK 10 or later,
# changes no file and needs no secret. The package restore needs the network.
on:
workflow_call:
inputs:
working-directory:
description: "Directory, relative to the repository root, whose files are checked"
type: string
default: "."
project:
description: "Solution or project file, relative to working-directory; empty uses the single .sln, .slnx or .csproj found"
type: string
default: ""
dotnet-sdk-version:
description: "Exact .NET SDK version, 10 or later (no channel, no range)"
type: string
default: "10.0.401"
tools-ref:
description: "Tag or branch of TirSystem/github-action whose tools/quality-checks-csharp.sh is run; pin it to the exact tag together with the workflow"
type: string
default: "v1"
jobs:
quality-checks-csharp:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 15
env:
WORKING_DIRECTORY: ${{ inputs.working-directory }}
PROJECT: ${{ inputs.project }}
DOTNET_SDK_VERSION: ${{ inputs.dotnet-sdk-version }}
DOTNET_ROOT: /tmp/dotnet
steps:
- name: Check out the repository
uses: actions/checkout@v4.2.2
- name: Fetch the shared script
uses: actions/checkout@v4.2.2
with:
repository: TirSystem/github-action
ref: ${{ inputs.tools-ref }}
path: shared-scripts
- name: Validate the inputs
run: bash shared-scripts/tools/quality-checks-csharp.sh validate
- name: Install the .NET SDK
run: bash shared-scripts/tools/quality-checks-csharp.sh install
- name: Run the checks
run: bash shared-scripts/tools/quality-checks-csharp.sh run
+3 -2
View File
@@ -45,6 +45,7 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 15
env:
LANGUAGES: ${{ inputs.languages }}
WORKING_DIRECTORY: ${{ inputs.working-directory }}
@@ -55,10 +56,10 @@ jobs:
QC_VENV: /tmp/quality-tools
steps:
- name: Check out the repository
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
- name: Fetch the shared script
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
with:
repository: TirSystem/github-action
ref: ${{ inputs.tools-ref }}
+2 -1
View File
@@ -26,9 +26,10 @@ jobs:
permissions:
contents: write
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out the repository
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
- name: Check and publish the release
env:
+78
View File
@@ -0,0 +1,78 @@
# Publish accepted milestones to the git host.
#
# On a push to main that changes docs/milestones/ or docs/sqa/reviews/, this
# workflow runs `sync-project.sh --accepted-only --apply`: every milestone whose
# latest Version History row is Accepted and whose latest review record is a Go
# is created or updated as a Milestone with its tasks as Issues. A Proposed
# milestone, or one without a Go review, is skipped. Nothing is closed or
# deleted. Each run updates the issues of every accepted milestone (the sync is
# idempotent, but the host records the edit).
#
# INSTALLING THIS FILE IS THE STANDING AUTHORIZATION TO PUBLISH. This project
# installed it on 2026-10-11 at the request of S01.
#
# Secret: TOKEN_FOR_GITEA, the bare Gitea token of the organization (no JSON).
# It needs read and write on issues and milestones, and read on the framework
# repository, which is checked out as a submodule. Gitea does not accept secret
# names that start with GITEA_ or GITHUB_.
#
# Run it once by hand from the Actions page with dry_run left on: it prints
# the plan and creates nothing. Turn dry_run off only for a real run.
# A runner must be registered for the repository (or its organisation).
name: Publish accepted milestones
on:
push:
branches: [main]
paths:
- "docs/milestones/**"
- "docs/sqa/reviews/**"
workflow_dispatch:
inputs:
dry_run:
description: "Preview only: print the plan and create nothing"
type: boolean
default: true
# Two merges in a row queue instead of racing.
concurrency:
group: publish-accepted-milestones
cancel-in-progress: false
jobs:
publish:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out the project
uses: actions/checkout@v4.2.2
with:
token: ${{ secrets.TOKEN_FOR_GITEA }}
# .gitmodules uses ssh:// URLs and the runner has no SSH key, so the
# submodules (framework, and framework/qc inside it) are fetched over HTTPS
# with the same token. The token goes through the environment, not a
# command line.
- name: Check out the framework submodules over HTTPS
env:
GIT_CONFIG_COUNT: "2"
GIT_CONFIG_KEY_0: "url.https://git.tirsystem.com/.insteadOf"
GIT_CONFIG_VALUE_0: "ssh://git@git.tirsystem.com:10022/"
GIT_CONFIG_KEY_1: "http.extraheader"
GIT_CONFIG_VALUE_1: "Authorization: token ${{ secrets.TOKEN_FOR_GITEA }}"
run: |
set -euo pipefail
git submodule update --init --recursive --depth=1
- name: Make sure curl and jq are available
run: bash framework/scripts/ci-publish-milestones.sh ensure-tools
- name: Publish accepted milestones
env:
GITEA_TOKEN: ${{ secrets.TOKEN_FOR_GITEA }}
# Empty on a push (a real run); "true" or "false" on a manual run.
DRY_RUN: ${{ inputs.dry_run }}
run: bash framework/scripts/ci-publish-milestones.sh publish
+7 -3
View File
@@ -11,14 +11,18 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the repository
uses: actions/checkout@v4
uses: actions/checkout@v4.2.2
- name: Create a virtual environment and install test dependencies
run: |
python3 -m venv .venv
.venv/bin/python -m pip install --quiet -r tests/requirements.txt
- name: Validate workflow files and run the offline tests
run: .venv/bin/python -m pytest -q tests
- name: Validate workflow files and run the offline tests under coverage
run: .venv/bin/python -m coverage run -m pytest -q tests
- name: Check the coverage of the tools
run: .venv/bin/python -m coverage report
+3
View File
@@ -14,3 +14,6 @@
.venv/
__pycache__/
.pytest_cache/
# Local coverage data (python -m coverage run)
.coverage
+43
View File
@@ -15,6 +15,49 @@ framework.
the working tree first; edit, summarise and stop. The commit/PR rules below
apply once a commit has been asked for.
## Related repositories
This project is one of four repositories that change together. Each has one
job; a change goes to the repository that owns it, not to the one that happens
to be open.
| Repository | Owns | Consumed by | Pinned or released as |
| --- | --- | --- | --- |
| `TirSystem/SQA-QC-Checklists` | the QC checklists (`qc/artifacts/`, `qc/code/`) | `sqa-qc-framework` | a commit, pinned as the `qc/` submodule |
| `TirSystem/sqa-qc-framework` | the skills, process documents, catalog, templates (`templates/ci/`) and scripts | every project, as the `framework/` submodule | a release tag (`v0.5.2`, ...) |
| `TirSystem/github-action` | the shared workflows (`quality-checks`, `release`), the scoped workflows (`publish-wiki`, `sync-github-metadata`) and the scripts they call (`tools/`) | every repository of the organisation, by `uses:` and `ref:` | a release tag and a moving major tag (`v1`), made by its release workflow |
| `TirSystem/sqa-and-qc` | the SQA and AI project management: project artifacts, review records, the traceability matrix | itself | the pull request that merges it |
Where a thing lives:
- A QC checklist, a convention or a template is changed in its owner above and
reaches this project by moving the pin. The review record of a checklist is
written in the project that reviews it (`docs/sqa/reviews/`), not in the
checklist repository.
- A workflow that other repositories call is changed in `github-action` and
released there. A workflow a project copies from `templates/ci/` is changed
in the framework; the project updates its copy after the pin moves.
- A script a workflow needs is a file (`tools/` of `github-action`, or
`scripts/` of the framework for the templates), never a long `run:` block
(`QC-WF-001` criterion 20).
- The `framework/` pin here is independent of the one in `sqa-and-qc`; the two
may differ, and neither is moved to follow the other without a reason in
the pull request.
A change that spans repositories:
1. One pull request per repository, in dependency order: checklists, then
framework, then `github-action` and the projects. A pull request names the
ones it depends on in its description.
2. A downstream repository moves a pin only to a merged commit or tag of the
upstream, never to an unmerged branch.
3. Nothing is released or tagged until its dependencies are merged; a release
is a separate, deliberate step (the release workflow defaults to a dry run).
4. A related repository is added to the session as a working directory only
when the task needs it. In autonomous mode work in a related repository is
inside the accepted plan only if the plan names it; otherwise the run stops
and reports.
## Workflow order
Business Case, Stakeholder Analysis, Project Plan, milestones, tasks synced as
+25
View File
@@ -20,6 +20,31 @@ Each release lists its changes in these groups, in this order:
## [Unreleased]
### Added
- Reusable workflow `quality-checks-cpp.yml` (ADR-0008): `clang-format --dry-run
-Werror` and `clang-tidy` on the tracked C and C++ files, at exact versions
(inputs `clang-format-version`, `clang-tidy-version`), with the inputs
`working-directory`, `std`, `compile-commands-dir` and `tools-ref`. The
repository needs a `.clang-format`; without a `.clang-tidy` the checks
`clang-diagnostic-*` and `clang-analyzer-*` run, and every clang-tidy finding
is an error (`--warnings-as-errors=*`).
- Reusable workflow `quality-checks-csharp.yml` (ADR-0008): `dotnet format
--verify-no-changes` and `dotnet build -warnaserror` on an exact .NET SDK 10
or later (input `dotnet-sdk-version`, default `10.0.401`), with the inputs
`working-directory`, `project` and `tools-ref`.
### Changed
- Every job has a `timeout-minutes` (5 to 15), so a hung step no longer holds a
runner for the host's default limit.
- `actions/checkout` is referenced by the exact tag `v4.2.2` instead of the
moving tag `v4`. No change for callers.
- The framework pin moves from `v0.5.2` to `v0.6.0`, and the two long `run:`
blocks of this repository's own `sync-milestones.yml` call
`framework/scripts/ci-publish-milestones.sh`. No change for callers of the
shared workflows.
## [1.1.0] - 2026-10-11
### Added
+148 -5
View File
@@ -17,18 +17,21 @@ A collection of reusable Gitea Actions workflows for DevOps professionals and so
This repository is the central collection of reusable automation for TirSystem repositories. The primary repository lives at `git.tirsystem.com` (Gitea) and is push-mirrored to GitHub.
It contains five workflows: metadata sync to the GitHub mirror, wiki publishing, shared quality checks, a release workflow and the repository's own validation. They are listed with their purpose and a diagram under [Workflows](#-workflows).
It contains eight workflows: metadata sync to the GitHub mirror, wiki publishing, shared quality checks for Python and shell, for C and C++ and for C#, a release workflow, the publishing of accepted milestones and the repository's own validation. They are listed with their purpose and a diagram under [Workflows](#-workflows).
## 🔧 Workflows
Five workflows live in this repository. A **scoped** workflow is delivered by the instance to every repository of the TirSystem organizations and needs nothing in the repository; a **reusable** workflow is called by a repository with `uses:`; the others run only here. The diagrams are PlantUML source.
Eight workflows live in this repository. A **scoped** workflow is delivered by the instance to every repository of the TirSystem organizations and needs nothing in the repository; a **reusable** workflow is called by a repository with `uses:`; the others run only here. The diagrams are PlantUML source.
| Workflow | File | Kind | Starts on | Purpose |
| --- | --- | --- | --- | --- |
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push to `main`, manual, daily 03:17 UTC | Copies the description and topics of a Gitea repository to its GitHub push mirror |
| Publish wiki | [`publish-wiki.yml`](.gitea/scoped_workflows/publish-wiki.yml) | Scoped, opt-in with `wiki/.publish` | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki |
| Quality checks | [`quality-checks.yml`](.gitea/workflows/quality-checks.yml) | Reusable (`workflow_call`) | a call from another repository | Runs ruff, mypy, shellcheck and shfmt on the tracked files and changes nothing |
| Quality checks C++ | [`quality-checks-cpp.yml`](.gitea/workflows/quality-checks-cpp.yml) | Reusable (`workflow_call`) | a call from another repository | Runs clang-format and clang-tidy at exact versions on the tracked C and C++ files and changes nothing |
| Quality checks C# | [`quality-checks-csharp.yml`](.gitea/workflows/quality-checks-csharp.yml) | Reusable (`workflow_call`) | a call from another repository | Runs `dotnet format` and `dotnet build` on an exact .NET SDK 10 or later and changes nothing |
| Release | [`release.yml`](.gitea/workflows/release.yml) | This repository only | manual | Creates the version tag, the release page and the major tag after the checks |
| Publish accepted milestones | [`sync-milestones.yml`](.gitea/workflows/sync-milestones.yml) | This repository only | push to `main` that changes `docs/milestones/**` or `docs/sqa/reviews/**`, manual (dry run by default) | Creates or updates the Gitea milestone and issues of every milestone that is Accepted with a Go review |
| Validate workflows | [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml) | This repository only | pull request, push to `main`, manual | Parses every workflow and runs the offline tests |
### 🔄 Sync GitHub metadata
@@ -187,6 +190,96 @@ deactivate Workflow
@enduml
```
### 🧱 Quality checks C++
A reusable workflow for C and C++, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1` (ADR-0008). The repository needs a `.clang-format`; a `.clang-tidy` and a compile database are optional.
#### 🔀 Workflow
```plantuml
@startuml
title Shared quality checks for C and C++ (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-cpp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-cpp" as Workflow
participant "PyPI" as PyPI
Caller -> Workflow: workflow_call with working-directory, std,\ncompile-commands-dir and tool versions
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or a version is not exact
Workflow --> Caller: Fail with [configuration]
end
Workflow -> PyPI: Install clang-format and clang-tidy at the exact versions
PyPI --> Workflow: Tools installed
alt no C or C++ file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no .clang-format, or compile-commands-dir\nwithout compile_commands.json
Workflow --> Caller: Fail with [configuration]
else
Workflow -> Workflow: clang-format --dry-run -Werror on all files
Workflow -> Workflow: clang-tidy on the C++ files (-std=std)\nand on the C files (or with the compile database)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### 🟣 Quality checks C#
A reusable workflow for C#, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1` (ADR-0008). It installs the exact .NET SDK given by `dotnet-sdk-version` (10 or later) and needs the network for the package restore.
#### 🔀 Workflow
```plantuml
@startuml
title Shared quality checks for C# (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-csharp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-csharp" as Workflow
participant "dot.net\n(dotnet-install.sh)" as DotNet
Caller -> Workflow: workflow_call with working-directory,\nproject and dotnet-sdk-version
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or the SDK is not an exact\nstable version 10 or later
Workflow --> Caller: Fail with [configuration]
end
Workflow -> DotNet: Install the exact .NET SDK version
DotNet --> Workflow: SDK installed
alt no C# file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no solution or project, or several without the project input
Workflow --> Caller: Fail with [configuration] that names them
else
Workflow -> Workflow: dotnet format --verify-no-changes
Workflow -> Workflow: dotnet build -warnaserror\n(package restore needs the network)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### 🏷️ Release
Started by hand by a maintainer; with `dry_run` `true` (the default) it only checks (see the [release process](guides/release-process.md)).
@@ -236,6 +329,54 @@ deactivate Workflow
@enduml
```
### 📌 Publish accepted milestones
Standing authorization to publish: on a push to `main` that changes the milestones or their reviews, every milestone whose latest Version History row is Accepted and whose latest review is a Go is created or updated on Gitea with its tasks as issues. Nothing is closed or deleted. A manual run is a dry run unless `dry_run` is switched off. It uses the secret `TOKEN_FOR_GITEA` and the `--accepted-only` rule of the mounted framework (v0.5.0 or later).
#### 🔀 Workflow
```plantuml
@startuml
title Publish accepted milestones (this repository)
autonumber
actor "Push to main that changes\ndocs/milestones/** or docs/sqa/reviews/**,\nor manual trigger" as Trigger
participant "Gitea Actions\nsync-milestones" as Workflow
participant "framework/scripts/\nsync-project.sh" as Script
participant "Gitea REST API" as Gitea
Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the project and the framework\nsubmodules over HTTPS with TOKEN_FOR_GITEA
Workflow -> Script: --accepted-only (dry run)\nor --accepted-only --apply
activate Script
loop for each docs/milestones/mil-*.md
alt latest Version History row is not Accepted,\nor the latest review record is not a Go
Script -> Script: Skip with the reason on stderr
else
alt dry run
Script -> Script: Print the plan, no network call
else
Script -> Gitea: Create or update the Milestone\nand one Issue per task row
Gitea --> Script: Milestone and issue numbers
end
end
end
note right of Script
Nothing is closed or deleted.
Each real run edits the issues
of every accepted milestone.
end note
Script --> Workflow: Done, or "nothing to publish"
deactivate Script
Workflow --> Trigger: Workflow result
deactivate Workflow
@enduml
```
### 🧪 Validate workflows
The repository's own validation: the offline tests that gate every pull request.
@@ -255,7 +396,7 @@ Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the repository
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
Workflow -> Workflow: Run pytest on tests/ (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
alt a test fails
Workflow --> Trigger: Workflow fails (the pull request is not ready)
@@ -298,10 +439,11 @@ The workflow files and the scripts in `tools/` are validated by offline tests th
python3 -m venv .venv
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -r tests/requirements.txt
python -m pytest -q tests
python -m coverage run -m pytest -q tests
python -m coverage report
```
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API.
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API. The run fails when the line and branch coverage of `tools/` falls below 95% (`.coveragerc`).
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
@@ -316,6 +458,7 @@ Rows that say Implemented or Guides written exist today. The rest is planned and
| Onboard a repository, manage runners, diagnose failures | Guides written ([onboarding](guides/onboarding.md), [troubleshooting](guides/troubleshooting.md)); scoped delivery to the repositories of all four organizations verified (MIL-002) |
| Publish a repository wiki from `wiki/` (opt-in, delivered to every organization) | Implemented in `.gitea/scoped_workflows/publish-wiki.yml`, with offline tests; a pilot in a second repository publishes its wiki (MIL-006) |
| Shared quality checks (Python and shell) | Implemented as the reusable workflow `.gitea/workflows/quality-checks.yml`, with offline tests and a trial in a second organization; adopted in RepoFoundry ([guide](guides/quality-checks.md)) |
| Shared quality checks (C and C++, C#) | Implemented as the reusable workflows `.gitea/workflows/quality-checks-cpp.yml` and `.gitea/workflows/quality-checks-csharp.yml` with exact tool versions and offline tests; not yet used in another repository (MIL-007) ([C and C++ guide](guides/quality-checks-cpp.md), [C# guide](guides/quality-checks-csharp.md)) |
| Versioned release and publishing | Release process, changelog and upgrade guide defined; the release workflow exists and `v1.0.0` is released (MIL-004) ([guide](guides/upgrading.md)) |
## 📄 License
@@ -0,0 +1,145 @@
# ADR-0008: Quality-check contract for C++ and C#
## Metadata
| Key | Value |
| --- | --- |
| ID | ADR-0008 |
| CrossReference | [MIL-007], [UC-005], [US-001], [ADR-0005], [ADR-0006] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [11cba35] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Reviewed (RC-054): abbreviations expanded at first use and the security impact of downloading tools named | [9e7aedd] |
Allowed Status values: `Proposed`, `Accepted`, `Rejected`, `Deprecated`, `Superseded by ADR-NNNN`.
---
## Context
ADR-0005 defines the contract of the shared quality-check workflow for Python
and shell: inputs with working defaults, a pinned version per tool, every tool
runs, a failure names tool, file and line, and a language without files
passes with a notice. MIL-007 adds C++ and C#. Two requirements came from S01
on 2026-10-11 and bound the decision:
- C++ and C# are separate workflows, not an extension of `quality-checks.yml`.
- Old tools are not run: the .NET SDK is version 10 or later, and a tool that
is only available as an old version is not used.
Facts (MIL-007 task 2, runs 692 and 699 on `ubuntu-latest`, Ubuntu 24.04,
root, `gcc`/`g++` 13.3 present):
- `clang-format` 23.1.3 and `clang-tidy` 22.1.8 install from the Python Package
Index (PyPI) in a few seconds with an exact version.
- `cppcheck` is only available as an old version (apt 2.13.0; the latest
release is 2.22.0; the PyPI package of that name is another project).
- The .NET software development kit (SDK) 10.0.401 installs with the official
`dotnet-install.sh` in about 20 s with an exact `--version`; apt gives an older band (10.0.112).
- A `clang-tidy` run needs flags or a compile database, and a C# format check
and build need the project's package restore, which needs the network.
Options:
1. **One combined workflow for C++ and C#.** One page and one place to call,
but two unrelated toolchains in one job, and an input set that mixes both.
2. **One workflow per language** (`quality-checks-cpp.yml`,
`quality-checks-csharp.yml`), each with its own inputs and tools.
3. **Extend `quality-checks.yml`** with two more values of `languages`.
Rejected by S01 (separate workflows) and it would make the contract of
ADR-0005 grow with every language.
For `cppcheck`: (a) keep the apt version, (b) build a current release from
source in every run, (c) drop it. For the SDK: (a) a channel such as `10.0`,
(b) an exact version.
## Decision
C++ and C# are checked by two separate reusable workflows,
`quality-checks-cpp.yml` and `quality-checks-csharp.yml`, each running a script
file of this repository (`tools/quality-checks-cpp.sh`,
`tools/quality-checks-csharp.sh`) that it fetches at its input `tools-ref`
(default `v1`), with the contract of ADR-0005 for pass, fail, logs and
skipped languages; `cppcheck` is not used, and the .NET SDK is installed at an
exact version of 10 or later.
The rules that follow from it:
- **C++ (and C):** `clang-format --dry-run -Werror` and `clang-tidy` on the
tracked `*.c`, `*.cc`, `*.cpp`, `*.cxx`, `*.h`, `*.hh`, `*.hpp` files under
`working-directory`, both from PyPI at the exact versions of the inputs
`clang-format-version` (default `23.1.3`) and `clang-tidy-version` (default
`22.1.8`). Inputs: `working-directory` (default `.`), `std` (default
`c++20`), `compile-commands-dir` (default empty: the flags `-std=<std>` are
used; set it to the directory of a `compile_commands.json` the caller built
before the call), `tools-ref`. A `.clang-format` and a `.clang-tidy` of the
project configure the tools; a missing `.clang-format` is a
`[configuration]` failure.
- **C#:** `dotnet format --verify-no-changes` and `dotnet build
-warnaserror` with the analyzers the project enables in `.editorconfig`,
on the solution or project found under `working-directory`. Inputs:
`working-directory` (default `.`), `project` (default empty: the single
`*.sln`, `*.slnx` or `*.csproj` found; none or several is a
`[configuration]` failure that names them), `dotnet-sdk-version` (default
an exact `10.0.x`, installed with `dotnet-install.sh --version`),
`tools-ref`.
- **No `cppcheck`:** `clang-tidy` does the static analysis with a current
release; a future version of the contract may add a static analyzer when a
current release is a package.
- **Exact pins:** every tool input is an exact version, never a channel or a
range; raising a default is a breaking change under ADR-0006.
- **Names:** the wiki pages are `QualityChecksCpp` and `QualityChecksCSharp`
with the usual `.da` and `.ms` translations; the guides are
`guides/quality-checks-cpp.md` and `guides/quality-checks-csharp.md`.
- **C is included with C++:** the same tools check both and the files are
told apart by extension; `QC-CL-001` and `QC-CPP-001` stay the review
checklists of the code itself.
## Consequences
**Positive:**
- Each workflow has inputs that fit its language, and a consumer of one never
sees the inputs of the other.
- Only current tools run; a run is reproducible because every version is exact.
- The scripts are files that are linted and tested with stub tools, as for
`quality-checks.yml`.
**Negative:**
- Two workflows, two guides and two wiki pages to keep; a repository with both
languages calls both.
- Without `cppcheck` the C++ checks are `clang-tidy` and the compiler only; a
defect class that `cppcheck` finds may go unchecked.
- A C# check needs the network for the package restore, and a C++ check needs
the caller to build a compile database for precise results; both are the
caller's responsibility and are said in the guides.
- Raising the exact default of a tool, including the SDK, is a breaking
change and costs a major version (ADR-0006).
- A caller pinned to an exact tag is pinned completely only when `tools-ref`
names the same tag (as for `quality-checks.yml`).
- Security: each run downloads and executes code from outside the repository
(wheels from PyPI and the `dotnet-install.sh` script from `dot.net`, and for
C# the NuGet packages of the project). Exact versions limit what can change
but are not verified against a hash, so a compromised package index or
download host would reach the run. The jobs get `contents: read` and no
secret, which limits what such code can do.
## Affected Artifacts
- [MIL-007] — decides its criterion 2 and unlocks tasks 4 and 5.
- [UC-005] — the use case these workflows serve.
- [US-001] — US-001.16 and US-001.17 state their acceptance criteria.
- [ADR-0005] — the contract that this decision extends, unchanged.
- [ADR-0006] — raising a default tool version is breaking.
---
[MIL-007]: ../milestones/mil-007-cpp-csharp-quality-checks.md
[UC-005]: ../uc-005/uc.md
[US-001]: ../user-stories.md
[ADR-0005]: ./adr-0005-quality-check-contract.md
[ADR-0006]: ./adr-0006-release-process-and-version-pinning.md
[11cba35]: https://git.tirsystem.com/TirSystem/github-action/commit/11cba358b83cb7b6624f6b0956ae7b0c112d3692
[9e7aedd]: https://git.tirsystem.com/TirSystem/github-action/commit/9e7aeddb11c2b41ac893d9f7893d663a53fbe470
+3 -3
View File
@@ -10,10 +10,10 @@ each document lives in *this* project and the next version to use.
| BC | Business Case | docs/business-case.md | 002 |
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
| PP | Project Plan | docs/project-plan.md | 002 |
| MIL | Milestone / Gateway | docs/milestones/*.md | 007 |
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 052 |
| MIL | Milestone / Gateway | docs/milestones/*.md | 008 |
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 058 |
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
| ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0008 |
| ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0009 |
| UCD | Use Case Diagram | docs/use-case-diagram.md | 002 |
| US | User Story | docs/user-stories.md | 002 |
| UC | Use Case | docs/uc-NNN/uc.md | 008 |
+4 -4
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Added task 6 (embedded scripts to files) and Go/No-Go criterion 5; traceability adds O2 (RC-034) | [616c5d2] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added the verification results of the first release (v1.0.0) | [6933e91] |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added the verification results of the first release (v1.0.0) | [6933e91] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 3 verified with pinned consumers after v1.0.1 and v1.1.0 (RC-048) | [05b635c] |
---
@@ -81,7 +81,7 @@ and the release page were created, and the job token was enough (ADR-0007).
| --- | --- | --- |
| 1 | A release is validated before a tag is created | Go: `tools/release.py` refuses unless the status `Validate workflows / validate (push)` of the tip of `main` is success; tested for failed and missing runs |
| 2 | Version tag and changelog entry that marks breaking changes | Go: `v1.0.0` and `CHANGELOG.md` `[1.0.0]`; `tools/changelog.py` checks the convention |
| 3 | A consumer pinned to the previous version keeps working | Go: tags are never moved or deleted; the upgrade guide describes the way back; the first release has no previous version, so this is by construction until `v1.0.1` |
| 3 | A consumer pinned to the previous version keeps working | Go, verified on 2026-10-11 after `v1.0.1`: a caller in `TirSystem-BashScript/RepoFoundry` at `@v1.0.0` and one at `@v1` both passed (run 660); after `v1.1.0` a caller at `@v1.1.0` with `tools-ref: v1.1.0` and one at `@v1` passed (run 672). `v1.0.0` still points to `97ffa49` |
| 4 | Publish destination decided, token scope documented | Go: ADR-0007 |
| 5 | No embedded Python in the scoped workflows | Go: both run files of this repository, with offline tests that exercise the files (MIL-004 task 6) |
@@ -92,5 +92,5 @@ After the release the two scoped workflows fetch their scripts at `ref: v1`
[BC-001]: ../business-case.md
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
[616c5d2]: https://git.tirsystem.com/TirSystem/github-action/commit/616c5d2e48f0d76399a6f78923891fc7f50c8e22
[6933e91]: https://git.tirsystem.com/TirSystem/github-action/commit/6933e91c83075fb39b2dfbe41683cb2a0a0bce28
[05b635c]: https://git.tirsystem.com/TirSystem/github-action/commit/05b635c1b3d79390c794e62e781595fbe5f1a4ea
@@ -0,0 +1,126 @@
# MIL-007: Quality checks for C++ and C#
## Metadata
| Key | Value |
| --- | --- |
| ID | MIL-007 |
| CrossReference | [BC-001], [US-001], [UC-005], [MIL-003], [MIL-004], [ADR-0005], [ADR-0006], [ADR-0008] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Current tool versions only, .NET SDK 10 or later: results of run 699 replace the SDK 8 result; tasks 3 and criterion 1 amended | [7bcc67a] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Amendment reviewed (RC-055) and accepted: current tool versions, .NET SDK 10 or later, results of run 699, the contract of ADR-0008 in task 3 | [faf13b2] |
---
## Purpose
Decide whether a C++ or C# project can run the same kind of quality checks
as a Python or shell project, through a shared workflow of this repository,
and whether the runners of the instance can run them.
## Deliverable
Reusable quality-check workflows for C++ and for C#, each with a documented
set of inputs and pinned tool versions, a guide for reading its results on the
wiki in English, Danish and Bahasa Malaysia, a use of each in at least one
other repository, and a release that makes them available at the major tag.
The existing workflow `quality-checks.yml` for Python and shell keeps its
name and contract. The workflows run current tools only: a .NET SDK of version
10 or later, and the latest stable release of each clang tool; a tool that
is only available as an old version is not used.
## Go / No-Go Criteria
| # | Criterion (objectively checkable) | Go | No-Go |
| --- | --- | --- | --- |
| 1 | The runner of the instance can run the tools of each language (installed in the run or provided by the image), verified and recorded | Verified for both, at current versions (.NET SDK 10 or later) | A tool cannot be had without changing the runner, or only as an old version |
| 2 | The contract (tools, versions, inputs, what a pass and a fail mean) is decided in an ADR, and a language that cannot be checked without a build system says what it needs | ADR accepted | Open |
| 3 | A failing check shows the tool, file and line in the log, verified with a seeded failure for each workflow | Verified | Cause not visible |
| 4 | One other repository runs each workflow and its status appears on pull requests | Appears for both | Does not run |
| 5 | The workflows embed no script: each runs a file of this repository, and the offline tests exercise the file | Count of embedded scripts is 0 | Embedded script remains |
| 6 | A release (a minor version) makes both available, and the changelog and the wiki name them | Released | Unreleased |
## Dependencies
| Depends on | Reason |
| --- | --- |
| MIL-003 | The contract, the reusable workflow mechanism and the guide for reading results |
| MIL-004 | The release process and the release workflow publish the result |
## Traceability
| Business Case objective / KPI / user story | Reference |
| --- | --- |
| O4 | [BC-001] |
| US-001.09, US-001.10 (extended to C++ and C#) | [US-001] |
## Ownership
| Role | Stakeholder ID (SA) |
| --- | --- |
| Owner | S05 |
| Approving reviewer | S01 |
## Target Date
2027-01-16 — confirmed on 2026-10-11 by S01, standing in for S05 (ADR-0002); it follows the last decision of the plan, 2026-12-26, with two weeks from 2027-01-04. The Business Case sets no deadline.
## Tasks
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
| --- | --- | --- | --- | --- |
| 1 | Write the use case and stories for C++ and C# checks | Extend UC-005 (Run Project Quality Checks) so that its Brief names C++ and C#, and add stories to US-001 for a C++ project and a C# project, each with a pass and a fail acceptance criterion. Review them with the checklists of the `artifact` skill. | Yes | UC-005, US-001.09, US-001.10, US-001.16, US-001.17 |
| 2 | Verify what the runner provides | On a throwaway branch, run a job on `ubuntu-latest` that prints which of `clang-format`, `clang-tidy`, `cppcheck` and the .NET SDK (`dotnet --version`) exist, and whether each can be installed in the run (for example from PyPI, apt or the dotnet install script) and how long that takes. Record the result in the milestone like MIL-003 task 1. | No | |
| 3 | Decide the contract | Decided in ADR-0008 (accepted on 2026-10-11, RC-054): two separate reusable workflows, `quality-checks-cpp.yml` for C and C++ and `quality-checks-csharp.yml`, each running a script file fetched at `tools-ref`; C++: `clang-format --dry-run -Werror` and `clang-tidy` at exact current versions, no `cppcheck`; C#: `dotnet format --verify-no-changes` and a build with analyzers and warnings as errors, with the .NET SDK installed at an exact `10.0.x`; the inputs, the names of the workflows, guides and wiki pages and the consequences are in the ADR. | No | ADR-0008 |
| 4 | Implement the C++ workflow | Add the reusable workflow `quality-checks-cpp.yml` and its script file `tools/quality-checks-cpp.sh` as ADR-0008 decides, exact tool versions, least-privilege permissions and offline tests with stub tools, as `quality-checks.yml` does. | No | |
| 5 | Implement the C# workflow | The same for C#: `quality-checks-csharp.yml`, `tools/quality-checks-csharp.sh` and tests, as ADR-0008 decides. | No | |
| 6 | Write the guides and the wiki pages | One guide per workflow in `guides/` for reading its results, the wiki pages in English, Danish and Bahasa Malaysia, the Home workflow list and diagrams (a test requires every workflow to be listed), and an update of the upgrade guide. | No | |
| 7 | Adopt each workflow in one other repository | Onboard a real C++ project and a real C# project, or a throwaway repository when none exists, and fix the gaps in the guides that appear. Verify a seeded failure. | No | |
| 8 | Release | Add the changelog entry (a new workflow is a minor change, ADR-0006) and run the Release workflow; record the results in this milestone and review it. | No | |
## Verification results
Task 2 was run on 2026-10-11 with a throwaway branch, `verify-runner-tools`,
in `TirSystem/github-action` (run 692, deleted afterwards). One job on
`ubuntu-latest` printed what the image has and tried each way of installing a
tool.
| Fact | Result |
| --- | --- |
| Image | Ubuntu 24.04, `x86_64`, the job runs as root, `sudo`, `curl`, `python3` 3.12 and `pip` present |
| Present in the image | `gcc` and `g++` 13.3, `make`; missing: `clang-format`, `clang-tidy`, `cppcheck`, `cmake`, `dotnet` |
| `clang-format` | from PyPI in 2 s (23.1.3); from apt in 9 s |
| `clang-tidy` | from PyPI in 5 s (22.1.8); from apt in 25 s |
| `cppcheck` | apt gives 2.13.0 in 6 s, which is old (the latest release is 2.22.0); the PyPI package named `cppcheck` is a different project (1.5.3) and is not used; a current release needs a build from source |
| .NET SDK | the official script `dot.net/v1/dotnet-install.sh` with `--channel 10.0` gives 10.0.401 in 20 s; apt `dotnet-sdk-10.0` gives 10.0.112 in 23 s, an older feature band; the same script also offers 11.0 as a release candidate, which is not used |
A first run (run 692) looked at .NET SDK 8, which is not used: the requirement
is a .NET SDK of version 10 or later, and old tools are not run. A second run
(run 699, also deleted afterwards) checked current versions. The current
clang tools come from PyPI in a few seconds with an exact version, as
`quality-checks.yml` already does for its tools, and the .NET SDK 10 comes from
the official script in 20 s, with no change to the runner. `cppcheck` is the
exception: only an old version is a package. ADR-0008 drops it, because
`clang-tidy` does the static analysis and a current `cppcheck` would have to
be built from source, which costs minutes per run.
Not covered by this task: running a tool against a real C++ project (a
`clang-tidy` run needs a compile database or flags) or a real C# solution
(`dotnet format` and a build need the project's restore of packages from the
network), a private runner with no internet, and an image that differs from
`ubuntu-latest`. Those belong to the contract (task 3) and to the adoption
(task 7).
---
[BC-001]: ../business-case.md
[US-001]: ../user-stories.md
[UC-005]: ../uc-005/uc.md
[MIL-003]: ./mil-003-quality-checks.md
[MIL-004]: ./mil-004-versioned-release.md
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
[ADR-0006]: ../adr/adr-0006-release-process-and-version-pinning.md
[ADR-0008]: ../adr/adr-0008-cpp-csharp-quality-check-contract.md
[7bcc67a]: https://git.tirsystem.com/TirSystem/github-action/commit/7bcc67a065ac5f67b4e13ebf243a4bbbe2af47d9
[faf13b2]: https://git.tirsystem.com/TirSystem/github-action/commit/faf13b2c2a4901c0171977de1ffc2841023f537a
+15 -6
View File
@@ -4,25 +4,25 @@
| Key | Value |
| --- | --- |
| ID | PP-001 |
| CrossReference | [BC-001], [SA-001], [ADR-0002], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] |
| CrossReference | [BC-001], [SA-001], [ADR-0002], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | P1 use cases written and accepted (UCD-001, US-001, UC-001 to UC-004): Open Issues updated | [a2bf2d4] |
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Dates confirmed by S01 (stand-in for S05); the confirmation item is removed from Open Issues | [ea06eaa] |
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Dates confirmed by S01 (stand-in for S05); the confirmation item is removed from Open Issues | [ea06eaa] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added MIL-007 (quality checks for C++ and C#); reviewed (RC-053) | [e3ad1fa] |
---
## Purpose
This plan schedules six milestones that move the repository from one
This plan schedules seven milestones that move the repository from one
workflow with known defects to a documented, versioned collection of shared
workflows. The Business Case sets no deadline, so the dates are the plan's own; they were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
## Planning Assumptions
- Week 1 starts 2026-10-05; phases are two weeks long; the last decision is 2026-12-26.
- Week 1 starts 2026-10-05; phases are two weeks long; the last decision is 2026-12-26; MIL-007 follows in January 2027 (2027-01-04 to 2027-01-16, confirmed on 2026-10-11 by S01).
- Work on a milestone starts only after its `MIL-*` document is `Accepted`.
- Dates were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
@@ -36,6 +36,7 @@ workflows. The Business Case sets no deadline, so the dates are the plan's own;
| Versioned release and publishing | [MIL-004] | 2026-11-16 to 2026-11-28 | 2026-11-28 | S05 | None yet | Release process and reusable release workflow | [Milestone MIL-004] |
| Wiki and translations | [MIL-005] | 2026-11-30 to 2026-12-12 | 2026-12-12 | S05 | None yet | Wiki pages in English, Danish and Bahasa Malaysia, kept current by every pull request | [Milestone MIL-005] |
| Shared wiki publishing | [MIL-006] | 2026-12-14 to 2026-12-26 | 2026-12-26 | S05 | None yet | Scoped publish-wiki workflow with opt-in, piloted in one other repository | [Milestone MIL-006] |
| Quality checks for C++ and C# | [MIL-007] | 2027-01-04 to 2027-01-16 | 2027-01-16 | S05 | US-001.09, US-001.10 (to extend) | Reusable quality-check workflows for C++ and C#, released | [Milestone MIL-007] |
```plantuml
@startgantt
@@ -52,6 +53,8 @@ Project starts 2026-10-05
[MIL-005 Go/No-Go] happens 2026-12-12
[MIL-006 Shared wiki] starts 2026-12-14 and ends 2026-12-26
[MIL-006 Go/No-Go] happens 2026-12-26
[MIL-007 C++ and C#] starts 2027-01-04 and ends 2027-01-16
[MIL-007 Go/No-Go] happens 2027-01-16
@endgantt
```
@@ -65,12 +68,14 @@ Project starts 2026-10-05
| Gitea Actions workflows for software engineers (release and publishing) | [MIL-004] |
| Wiki pages in English, Danish and Bahasa Malaysia | [MIL-005] |
| The wiki publisher shared with other repositories through scoped delivery | [MIL-006] |
| Gitea Actions workflows for software engineers (quality checks for C++ and C#) | [MIL-007] |
## Dependencies
```
MIL-001 → MIL-002 → MIL-003 → MIL-004
MIL-002 → MIL-005 → MIL-006
MIL-003 + MIL-004 → MIL-007
```
A No-Go moves every later window by the rework time of the failed milestone.
@@ -79,6 +84,7 @@ A No-Go moves every later window by the rework time of the failed milestone.
| Risk | Impact | Mitigation |
| --- | --- | --- |
| The runner cannot provide the C++ or C# tools (MIL-007) | The workflows need a custom runner image or a longer install | MIL-007 task 2 verifies it first; the ADR of task 3 says what a build-dependent check needs from the caller. |
| Reusable workflow support is missing on the instance | MIL-003 and MIL-004 change shape | Verify first in each milestone (MIL-002 task 2, MIL-003 task 1); fall back to copied templates. |
| Security review by S05 is a bottleneck | Milestone decisions slip | Keep milestones small and plan review time before each decision date. |
@@ -251,11 +257,14 @@ no tests, no release process.
[MIL-004]: ./milestones/mil-004-versioned-release.md
[MIL-005]: ./milestones/mil-005-wiki-and-translations.md
[MIL-006]: ./milestones/mil-006-shared-wiki-publishing.md
[MIL-007]: ./milestones/mil-007-cpp-csharp-quality-checks.md
[Milestone MIL-001]: https://git.tirsystem.com/TirSystem/github-action/milestone/18
[Milestone MIL-002]: https://git.tirsystem.com/TirSystem/github-action/milestone/19
[Milestone MIL-003]: https://git.tirsystem.com/TirSystem/github-action/milestone/20
[Milestone MIL-004]: https://git.tirsystem.com/TirSystem/github-action/milestone/21
[Milestone MIL-005]: https://git.tirsystem.com/TirSystem/github-action/milestone/93
[Milestone MIL-006]: https://git.tirsystem.com/TirSystem/github-action/milestone/94
[a2bf2d4]: https://git.tirsystem.com/TirSystem/github-action/commit/a2bf2d420416f7aff2badc6fe32a7690e2e523fd
[Milestone MIL-007]: https://git.tirsystem.com/TirSystem/github-action/milestone/95
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
[b74ee0e]: https://git.tirsystem.com/TirSystem/github-action/commit/b74ee0e5cfd04f25ba5f2c1addc80699147c479a
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
+5 -3
View File
@@ -9,7 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [6933e91] |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [6933e91] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 3 verified; the action item is closed | [05b635c] |
---
@@ -31,16 +32,17 @@
## Overall Verdict
Go - all six criteria pass, and the five Go/No-Go criteria of MIL-004 are met. One limit is stated, not hidden: criterion 3 (a consumer pinned to the previous version keeps working) is met by construction until a second release exists, because tags are never moved. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
Go - all six criteria pass, and the five Go/No-Go criteria of MIL-004 are met. Criterion 3 (a consumer pinned to the previous version keeps working) was met by construction at the first release and verified on 2026-10-11 with pinned consumers after `v1.0.1` and `v1.1.0` (see the Verification results of MIL-004). S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Verify criterion 3 with a real consumer when `v1.0.1` or `v1.1.0` is released | S05 | next release |
| Done 2026-10-11: criterion 3 verified with pinned consumers after `v1.0.1` (run 660) and `v1.1.0` (run 672) | S05 | done |
---
[MIL-004]: ../../milestones/mil-004-versioned-release.md
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
[6933e91]: https://git.tirsystem.com/TirSystem/github-action/commit/6933e91c83075fb39b2dfbe41683cb2a0a0bce28
[05b635c]: https://git.tirsystem.com/TirSystem/github-action/commit/05b635c1b3d79390c794e62e781595fbe5f1a4ea
+47
View File
@@ -0,0 +1,47 @@
# Review Record: MIL-007
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-052 |
| CrossReference | [MIL-007], [QC-MIL-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [e3ad1fa] |
---
## Artifact Under Review
- Instance reviewed: [MIL-007]
- Checklist used: [QC-MIL-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | A concrete deliverable is defined for every gate | Pass | Two reusable workflows with pinned tools, guides and wiki pages in three languages, a use in another repository and a release. |
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Six criteria, each with a Go and a No-Go: runner verified, ADR accepted, seeded failure visible, a run in another repository, no embedded script, released. |
| 3 | Dependencies on other milestones are explicitly mapped | Pass | MIL-003 for the contract and mechanism, MIL-004 for the release; both are closed. |
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O4, and US-001.09 and US-001.10 which the milestone extends. |
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01. |
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2027-01-16, after the last decision of the plan; the Business Case sets no deadline. |
## Overall Verdict
Go - all six criteria pass; no findings. The plan-first order holds inside the milestone: the use case and stories (task 1), the runner check (task 2) and the contract ADR (task 3) come before any workflow (tasks 4 and 5). The decision between one workflow and one per language is left to the ADR and is not made here. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Run `sync-project.sh --apply` so that the milestone and its issues exist | S05 | 2026-10-11 |
| Decide in the ADR (task 3) one workflow or one per language, and whether C is included | S01 | before tasks 4 and 5 |
---
[MIL-007]: ../../milestones/mil-007-cpp-csharp-quality-checks.md
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
+47
View File
@@ -0,0 +1,47 @@
# Review Record: PP-001 Project Plan (MIL-007)
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-053 |
| CrossReference | [PP-001], [BC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [e3ad1fa] |
---
## Artifact Under Review
- Instance reviewed: [PP-001]
- Checklist used: none: the Project Plan has no QC checklist. Validated against the Business Case [BC-001] and the Go / No-Go criteria of each listed milestone, as `PP.md` prescribes.
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Every milestone in the plan has a `MIL-*` document and the plan's dates equal that document's target date | Pass | MIL-001 to MIL-007 exist; the MIL-007 decision date 2027-01-16 equals its Target Date. |
| 2 | Every Business Case scope item is covered by a gateway | Pass | Quality checks for C++ and C# are mapped to MIL-007 in Scope Coverage under the quality-check scope item (O4). |
| 3 | The schedule respects the Business Case constraints | Pass | The Business Case sets no deadline; the dates are the plan's own and say so. |
| 4 | Dependencies between milestones are stated | Pass | The Dependencies diagram shows MIL-003 and MIL-004 to MIL-007, and MIL-007 lists them in its own document. |
| 5 | Every gateway has an owner who is a stakeholder ID | Pass | MIL-007 is owned by S05. |
| 6 | Plan content is internally consistent | Pass | "Seven milestones", the Planning Assumptions, the Gantt entries, the Gateway Schedule and the Scope Coverage agree. |
| 7 | Open Issues are current | Pass | Unchanged items remain open; a plan risk was added for the runner's tools. |
## Overall Verdict
Go - all seven criteria pass; no findings. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Add the link to the Gitea milestone of MIL-007 to the Gateway Schedule after `--apply` | S05 | 2026-10-11 |
---
[PP-001]: ../../project-plan.md
[BC-001]: ../../business-case.md
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
+52
View File
@@ -0,0 +1,52 @@
# Review Record: ADR-0008
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-054 |
| CrossReference | [ADR-0008], [QC-ADR-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [9e7aedd] |
---
## Artifact Under Review
- Instance reviewed: [ADR-0008]
- Checklist used: [QC-ADR-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | The ID (`ADR-NNNN`, 4-digit) matches the filename number and is unique and sequential | Pass | ADR-0008 in `adr-0008-cpp-csharp-quality-check-contract.md`, after ADR-0007. |
| 2 | Context states the problem, the forces (cost, risk, constraints) and the options evaluated | Pass | States the two requirements from S01, the facts from runs 692 and 699, and the options. |
| 3 | At least two options were considered, or the absence of alternatives is justified | Pass | Three options for the workflows, three for `cppcheck`, two for the SDK pin. |
| 4 | Decision is stated in one or two unhedged sentences and matches one of the evaluated options | Pass | One sentence naming option 2, dropping `cppcheck` (c) and an exact SDK version (b). |
| 5 | Consequences list both Positive and Negative outcomes | Pass | Three positive and six negative (after the fix of criterion 6). |
| 6 | Quality-attribute impacts (performance, security, portability, etc.) are named where the decision affects them | Pass | Finding fixed during this review: the security impact of downloading and running tools and packages in every run was not named (ADR-0005 names it for PyPI); it is now a negative consequence, with the limit that the jobs have `contents: read` and no secret. |
| 7 | Affected Artifacts are listed as links, and each is also in CrossReference | Pass | MIL-007, UC-005, US-001, ADR-0005 and ADR-0006 are linked and cited. |
| 8 | Status changes are recorded as new Version History rows with a Change summary and Commit link; retained rows are never rewritten | Pass | The Proposed row keeps its status as Deprecated and the Accepted row is added. |
| 9 | A superseded or deprecated ADR names its successor, and the successor links back | N-A | Nothing is superseded; ADR-0005 is extended and unchanged. |
| 10 | Written in business or technical language of the domain, with no unexplained abbreviations | Pass | Finding fixed during this review: PyPI and SDK were used without being expanded; both are introduced at first use. |
| 11 | Status is one of `Proposed`, `Accepted`, `Rejected`, `Deprecated` or `Superseded by ADR-NNNN`, and every Version History row uses only these | Pass | Deprecated and Accepted. |
## Overall Verdict
Go - all applicable criteria pass; the two findings (criteria 6 and 10) were fixed during the review. It unlocks tasks 4 and 5 of MIL-007 (#98 and #99) under the plan-first gate, once MIL-007 itself is Accepted again (its amendment after RC-052 is still Proposed). S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Review and accept the amendment of MIL-007 (current tool versions, .NET SDK 10 or later, results of run 699) so that its latest row is Accepted | S01 | before #98 and #99 |
| Choose the exact default of `dotnet-sdk-version` (an `10.0.x` band) when the C# workflow is built, and check it is still the current stable release | S05 | task 5 |
---
[ADR-0008]: ../../adr/adr-0008-cpp-csharp-quality-check-contract.md
[QC-ADR-001]: ../../../framework/qc/qc-adr.md
[9e7aedd]: https://git.tirsystem.com/TirSystem/github-action/commit/9e7aeddb11c2b41ac893d9f7893d663a53fbe470
@@ -0,0 +1,46 @@
# Review Record: MIL-007 (amendment)
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-055 |
| CrossReference | [MIL-007], [QC-MIL-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [faf13b2] |
---
## Artifact Under Review
- Instance reviewed: [MIL-007] after the amendments since RC-052: current tool versions only (.NET SDK 10 or later), the results of runs 692 and 699, and the contract of ADR-0008
- Checklist used: [QC-MIL-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | A concrete deliverable is defined for every gate | Pass | Unchanged, and the deliverable now states the version requirement: current tools only, .NET SDK 10 or later. |
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Finding fixed during this review: criterion 1 was amended but task 3 still carried the options of the draft (`cppcheck` conditional, one workflow or two). Task 3 now states the decided contract and points to ADR-0008, so criterion 2 is checkable as it stands: the ADR is accepted. |
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged: MIL-003 and MIL-004, both closed. |
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O4, US-001.09 and .10, and now the stories US-001.16 and .17 of task 1; ADR-0008 is in CrossReference. |
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01. |
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2027-01-16, unchanged and confirmed on 2026-10-11. |
## Overall Verdict
Go - all six criteria pass; the one finding (criterion 2) was fixed during the review, together with two stale phrases (the verification results still offered a build of `cppcheck`, and tasks 4 and 5 said "as the ADR decides"). It restores the status Accepted of MIL-007, which the publishing action and the plan-first gate require, and it does not accept UC-005 and US-001.16 and .17 (task 1, #95), which still need their own review. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Review and accept the extension of UC-005 and the stories US-001.16 and US-001.17 (#95) | S01 | before #98 and #99 |
---
[MIL-007]: ../../milestones/mil-007-cpp-csharp-quality-checks.md
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
[faf13b2]: https://git.tirsystem.com/TirSystem/github-action/commit/faf13b2c2a4901c0171977de1ffc2841023f537a
@@ -0,0 +1,52 @@
# Review Record: UC-005 (C++ and C#)
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-056 |
| CrossReference | [UC-005], [QC-UC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [1bc56f8] |
---
## Artifact Under Review
- Instance reviewed: [UC-005] after the extension of its Brief to C++ and C# (MIL-007 task 1)
- Checklist used: [QC-UC-001] (Brief format)
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Consists of a single, concise paragraph summarizing only the primary success scenario | Pass | Finding fixed during this review: the extension had added a sentence about a language that needs a build or a project file and says what is missing, which is a failure flow. It is removed from the Brief; the stories US-001.16 and .17 carry it as an acceptance criterion. |
| 2 | Written as an informal multi-paragraph narrative; may mention some alternate flows without formal structure | N-A | Format is Brief. |
| 3 | All standard sections are present: actors, preconditions, postconditions, main success scenario, alternative/exception flows | N-A | Format is Brief; actor, stakeholders, pre- and postconditions and the paragraph are present. |
| 4 | Preconditions and postconditions are explicitly defined | Pass | The precondition now lists the four languages (Python, shell, C++, C#); the postcondition is unchanged. |
| 5 | Primary actor is explicitly stated | Pass | Software Engineer. |
| 6 | Stakeholders and their interests are stated | Pass | S02 and S05, unchanged. |
| 7 | Main success scenario is written as clear, numbered steps | N-A | Format is Brief. |
| 8 | Alternative/exception flows correctly reference `<<include>>`/`<<extend>>` use cases where relevant, per UML 2.5.1 | N-A | None in a Brief. |
| 9 | Explicit business rules are captured per step where applicable, rather than embedded loosely in narrative text | N-A | No steps in a Brief. |
| 10 | Naming of actors and use case title is consistent with the corresponding Use Case Diagram and User Stories | Pass | Title and actor equal UCD-001; the Stories line lists US-001.09, .10, .16 and .17, which exist. |
| 11 | Scope/level (e.g. summary, user-goal, subfunction) is explicitly stated | Pass | Scope and user-goal level, unchanged. |
| 12 | Use case is written from the actor's goal perspective, free of UI or implementation detail | Pass | Goal wording; the tool names are not in the Brief for C++ and C#. |
## Overall Verdict
Go - all applicable criteria pass; the one finding (criterion 1) was fixed during the review. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| Update the description of this use case in the Use Case Diagram table of UCD-001 ("Lint, format and type checks run on every change ...") to cover C++ and C# at its next review | S01 | next review of UCD-001 |
---
[UC-005]: ../../uc-005/uc.md
[QC-UC-001]: ../../../framework/qc/qc-use-case.md
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
@@ -0,0 +1,47 @@
# Review Record: US-001 (US-001.16 and US-001.17)
## Metadata
| Key | Value |
| --- | --- |
| ID | RC-057 |
| CrossReference | [US-001], [QC-US-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [1bc56f8] |
---
## Artifact Under Review
- Instance reviewed: [US-001], the new stories US-001.16 (a C++ project gets the same checks) and US-001.17 (a C# project gets the same checks) and the document's Purpose and Scope
- Checklist used: [QC-US-001]
## Checklist Results
| # | Criterion | Status | Evidence/Notes |
| --- | --- | --- | --- |
| 1 | Follows INVEST criteria (Independent, Negotiable, Valuable, Estimable, Small, Testable) | Pass | The two stories are independent of each other and of US-001.09 and .10, each states one goal, and the INVEST check names all seventeen stories. |
| 2 | Written in "As a / I want / So that" form | Pass | Both. |
| 3 | Clear, testable acceptance criteria are included | Pass | Three Given/When/Then criteria each: a pass or fail status, a finding with tool and `path:line`, and a `[configuration]` failure that names what is missing instead of passing; each is checked with a run. |
| 4 | Traceable to a use case or epic | Pass | [UC-005] and [MIL-007], and the Stories line of UC-005 lists both. |
| 5 | Story is sized to fit within a single iteration | Pass | One language each. |
| 6 | Story statement avoids technical implementation detail | Pass | No tool is named in the statements. The acceptance criteria name the category `[configuration]`, as US-001.07 does. |
| 7 | Role named in the story matches an actor defined in the Use Case Diagram | Pass | Software Engineer. |
## Overall Verdict
Go - all seven criteria pass. One stale sentence in the Purpose and Scope (it said that stories for quality checks and releases were not written yet) was corrected during the review, as it is false since US-001.09. With RC-056 this completes task 1 of MIL-007 (#95) and, with ADR-0008 and the accepted amendment of MIL-007, meets the plan-first gate for tasks 4 and 5 (#98 and #99). S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
## Action Items
| Action | Owner | Due |
| --- | --- | --- |
| None | - | - |
---
[US-001]: ../../user-stories.md
[QC-US-001]: ../../../framework/qc/qc-user-story.md
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
+24 -8
View File
@@ -4,13 +4,13 @@
| Key | Value |
| --- | --- |
| ID | TM-001 |
| CrossReference | [BC-001], [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [RC-001], [RC-002], [RC-003], [RC-004], [RC-005], [RC-006], [RC-007], [RC-008], [RC-009], [RC-010], [RC-011], [RC-012], [RC-013], [RC-014], [RC-015], [RC-016], [RC-017], [RC-018], [RC-019], [RC-020], [RC-021], [RC-022], [RC-023], [RC-024], [RC-025], [RC-026], [RC-027], [RC-028], [RC-029], [RC-030], [RC-031], [RC-032], [RC-033], [RC-034], [RC-035], [RC-036], [RC-037], [RC-038], [RC-039], [RC-040], [RC-041], [RC-042], [RC-043], [RC-044], [RC-045], [RC-046], [RC-047], [RC-048], [RC-049], [RC-050], [RC-051], [ADR-0007], [UC-007], [UC-006], [ADR-0006], [UC-005], [ADR-0005], [UCD-001], [US-001], [UC-001], [UC-002], [UC-003], [UC-004], [ADR-0001], [ADR-0002], [ADR-0003], [ADR-0004] |
| CrossReference | [BC-001], [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007], [RC-001], [RC-002], [RC-003], [RC-004], [RC-005], [RC-006], [RC-007], [RC-008], [RC-009], [RC-010], [RC-011], [RC-012], [RC-013], [RC-014], [RC-015], [RC-016], [RC-017], [RC-018], [RC-019], [RC-020], [RC-021], [RC-022], [RC-023], [RC-024], [RC-025], [RC-026], [RC-027], [RC-028], [RC-029], [RC-030], [RC-031], [RC-032], [RC-033], [RC-034], [RC-035], [RC-036], [RC-037], [RC-038], [RC-039], [RC-040], [RC-041], [RC-042], [RC-043], [RC-044], [RC-045], [RC-046], [RC-047], [RC-048], [RC-049], [RC-050], [RC-051], [RC-052], [RC-053], [RC-054], [RC-055], [RC-056], [RC-057], [ADR-0007], [ADR-0008], [UC-007], [UC-006], [ADR-0006], [UC-005], [ADR-0005], [UCD-001], [US-001], [UC-001], [UC-002], [UC-003], [UC-004], [ADR-0001], [ADR-0002], [ADR-0003], [ADR-0004] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added RC-050 (MIL-005 translations accepted) | [ead3d98] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added RC-051 (ADR-0005 tools-ref) | [670f0ac] |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added RC-055 (MIL-007 amendment) | [faf13b2] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added RC-056 and RC-057 (UC-005 and US-001 for C++ and C#) | [1bc56f8] |
---
@@ -26,7 +26,7 @@ updated whenever an artifact instance is created or reviewed.
| --- | --- | --- | --- | --- |
| [SA-001] | SA | - | [BC-001], [UCD-001] | [RC-004] |
| [BC-001] | BC | [SA-001] | [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] | [RC-001], [RC-008] |
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [US-001] | [RC-002], [RC-009], [RC-015], [RC-017], [RC-025], [RC-032] |
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007], [US-001] | [RC-002], [RC-009], [RC-015], [RC-017], [RC-025], [RC-032], [RC-053] |
| [MIL-001] | MIL | [BC-001], [PP-001] | [MIL-002] | [RC-003], [RC-026] |
| [MIL-002] | MIL | [BC-001], [PP-001], [MIL-001] | [MIL-003], [MIL-005] | [RC-005], [RC-027] |
| [MIL-003] | MIL | [BC-001], [PP-001], [MIL-002] | [MIL-004] | [RC-006], [RC-028], [RC-033], [RC-039] |
@@ -39,6 +39,7 @@ updated whenever an artifact instance is created or reviewed.
| [RC-006] | RC | [MIL-003] | - | - |
| [MIL-005] | MIL | [BC-001], [PP-001], [MIL-002] | [MIL-006] | [RC-010], [RC-011], [RC-030], [RC-050] |
| [MIL-006] | MIL | [BC-001], [PP-001], [MIL-002], [MIL-005] | - | [RC-016], [RC-031], [RC-049] |
| [MIL-007] | MIL | [BC-001], [PP-001], [MIL-003], [MIL-004], [ADR-0008] | - | [RC-052], [RC-055] |
| [RC-007] | RC | [MIL-004] | - | - |
| [RC-008] | RC | [BC-001] | - | - |
| [RC-009] | RC | [PP-001] | - | - |
@@ -56,16 +57,17 @@ updated whenever an artifact instance is created or reviewed.
| [RC-017] | RC | [PP-001] | - | - |
| [RC-018] | RC | [ADR-0004] | - | - |
| [UCD-001] | UCD | [SA-001], [BC-001] | [US-001], [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007] | [RC-019], [RC-035], [RC-040], [RC-045] |
| [US-001] | US | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004] | [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007] | [RC-020], [RC-036], [RC-041], [RC-046] |
| [US-001] | US | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-007] | [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007] | [RC-020], [RC-036], [RC-041], [RC-046], [RC-057] |
| [UC-001] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-021] |
| [UC-002] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-022] |
| [UC-003] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-023] |
| [UC-004] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-024] |
| [UC-005] | UC | [UCD-001], [US-001], [SA-001] | [ADR-0005] | [RC-037] |
| [UC-005] | UC | [UCD-001], [US-001], [SA-001] | [ADR-0005] | [RC-037], [RC-056] |
| [ADR-0005] | ADR | [MIL-003], [UC-005], [US-001], [ADR-0004] | - | [RC-038], [RC-051] |
| [UC-006] | UC | [UCD-001], [US-001], [SA-001] | [ADR-0006] | [RC-042] |
| [ADR-0006] | ADR | [MIL-004], [UC-006], [US-001], [ADR-0004], [ADR-0005] | - | [RC-043] |
| [ADR-0007] | ADR | [MIL-004], [UC-006], [ADR-0006] | - | [RC-047] |
| [ADR-0008] | ADR | [MIL-007], [UC-005], [US-001], [ADR-0005], [ADR-0006] | - | [RC-054] |
| [UC-007] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-044] |
| [RC-019] | RC | [UCD-001] | - | - |
| [RC-020] | RC | [US-001] | - | - |
@@ -100,6 +102,12 @@ updated whenever an artifact instance is created or reviewed.
| [RC-049] | RC | [MIL-006] | - | - |
| [RC-050] | RC | [MIL-005] | - | - |
| [RC-051] | RC | [ADR-0005] | - | - |
| [RC-052] | RC | [MIL-007] | - | - |
| [RC-053] | RC | [PP-001] | - | - |
| [RC-054] | RC | [ADR-0008] | - | - |
| [RC-055] | RC | [MIL-007] | - | - |
| [RC-056] | RC | [UC-005] | - | - |
| [RC-057] | RC | [US-001] | - | - |
## Coverage Notes
@@ -119,6 +127,7 @@ updated whenever an artifact instance is created or reviewed.
[MIL-004]: ../milestones/mil-004-versioned-release.md
[MIL-005]: ../milestones/mil-005-wiki-and-translations.md
[MIL-006]: ../milestones/mil-006-shared-wiki-publishing.md
[MIL-007]: ../milestones/mil-007-cpp-csharp-quality-checks.md
[RC-001]: ./reviews/rc-001-business-case.md
[RC-002]: ./reviews/rc-002-project-plan.md
[RC-003]: ./reviews/rc-003-mil-001.md
@@ -180,11 +189,18 @@ updated whenever an artifact instance is created or reviewed.
[RC-049]: ./reviews/rc-049-mil-006-outcome.md
[RC-050]: ./reviews/rc-050-mil-005-outcome.md
[RC-051]: ./reviews/rc-051-adr-0005-tools-ref.md
[RC-052]: ./reviews/rc-052-mil-007.md
[RC-053]: ./reviews/rc-053-pp-001-mil-007.md
[RC-054]: ./reviews/rc-054-adr-0008.md
[RC-055]: ./reviews/rc-055-mil-007-amendment.md
[RC-056]: ./reviews/rc-056-uc-005-cpp-csharp.md
[RC-057]: ./reviews/rc-057-us-001-cpp-csharp.md
[ADR-0008]: ../adr/adr-0008-cpp-csharp-quality-check-contract.md
[ADR-0007]: ../adr/adr-0007-release-publish-destination.md
[UC-007]: ../uc-007/uc.md
[UC-006]: ../uc-006/uc.md
[ADR-0006]: ../adr/adr-0006-release-process-and-version-pinning.md
[UC-005]: ../uc-005/uc.md
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
[ead3d98]: https://git.tirsystem.com/TirSystem/github-action/commit/ead3d98d73fcab95fd57b0eb005a02aff9983256
[670f0ac]: https://git.tirsystem.com/TirSystem/github-action/commit/670f0ac469043bb166c84290c0dbf62b4908e3cc
[faf13b2]: https://git.tirsystem.com/TirSystem/github-action/commit/faf13b2c2a4901c0171977de1ffc2841023f537a
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
+9 -6
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | UC-005 |
| CrossReference | [UCD-001], [US-001], [SA-001], [ADR-0005] |
| CrossReference | [UCD-001], [US-001], [SA-001], [ADR-0005], [MIL-007] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [385d2fb] |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Brief extended to C++ and C# (MIL-007 task 1) | [32b5ab6] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Brief extended to C++ and C# reviewed (RC-056) and accepted; the failure sentence is left to the stories | [1bc56f8] |
---
@@ -20,18 +21,18 @@
**Level:** user-goal
**Primary Actor:** Software Engineer
**Stakeholders:** S02, S05 (interests below)
**Stories:** US-001.09, US-001.10
**Stories:** US-001.09, US-001.10, US-001.16, US-001.17
## Brief
A Software Engineer opens a pull request in a repository that calls the shared quality-check workflow. The workflow installs the pinned tools, runs the checks for each selected language on the files of the repository (lint, format and types for Python; lint and format for shell), and reports one status for the pull request. When every selected tool passes, the status is green.
A Software Engineer opens a pull request in a repository that calls the shared quality-check workflow. The workflow installs the pinned tools, runs the checks for each selected language on the files of the repository (lint, format and types for Python; lint and format for shell; format and static checks for C++; format and analyzer checks for C#), and reports one status for the pull request. When every selected tool passes, the status is green.
**Stakeholder interests**
- S02 — checks run the same way in every project without writing a pipeline, and a failure says what to fix
- S05 — the checks and their tool versions are defined once and change through a reviewed release
**Preconditions:** The repository is onboarded, the shared workflow is available through reusable workflow delivery, and the repository has files of at least one supported language.
**Preconditions:** The repository is onboarded, the shared workflow is available through reusable workflow delivery, and the repository has files of at least one supported language (Python, shell, C++ or C#).
**Postconditions (success guarantee):** The pull request has a pass or fail status that comes from every selected tool, and no file of the repository was changed.
@@ -41,4 +42,6 @@ A Software Engineer opens a pull request in a repository that calls the shared q
[US-001]: ../user-stories.md
[SA-001]: ../stakeholder-analysis.md
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
[385d2fb]: https://git.tirsystem.com/TirSystem/github-action/commit/385d2fb7cb9be1fdc8fd3503d0af624fa38eafc7
[MIL-007]: ../milestones/mil-007-cpp-csharp-quality-checks.md
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
+38 -7
View File
@@ -4,13 +4,13 @@
| Key | Value |
| --- | --- |
| ID | US-001 |
| CrossReference | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007] |
| CrossReference | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007], [MIL-007] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Added US-001.11 to US-001.13 (releases, UC-006); US-001.13 traced to the epic (RC-041) | [044d8ba] |
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Added US-001.14 and US-001.15 (UC-007); US-001.13 traced to UC-007 (RC-046) | [4cf52af] |
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added US-001.16 and US-001.17 (C++ and C# checks, MIL-007 task 1) | [32b5ab6] |
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | US-001.16 and US-001.17 reviewed (RC-057) and accepted; the Purpose and Scope names the later stories | [1bc56f8] |
---
@@ -19,7 +19,9 @@
These stories cover the P1 use cases of the Project Plan that MIL-002 delivers
(O1 to O3 of [BC-001]): keeping the mirror metadata correct, configuring
credentials, onboarding a repository and diagnosing a failed run. Roles are the
actors of [UCD-001]. Stories for quality checks and releases (MIL-004) and for the wiki (MIL-005, MIL-006) are not written yet.
actors of [UCD-001]. Later stories cover quality checks (US-001.09, US-001.10 and, for
C++ and C#, US-001.16 and US-001.17), releases and updates (US-001.11 to
US-001.15). Stories for the wiki (MIL-005, MIL-006) are not written yet.
## Story List
@@ -218,9 +220,37 @@ actors of [UCD-001]. Stories for quality checks and releases (MIL-004) and for t
| --- | --- | --- |
| [UC-007], [MIL-004] | fits one iteration | none |
### US-001.16 — A C++ project gets the same checks
**As a** Software Engineer, **I want** a pull request in a C++ repository to run format and static checks, **so that** a defect is found before review without me writing a pipeline.
**Acceptance Criteria**
- Given a repository that calls the shared C++ quality-check workflow and has C++ files, when a pull request is opened, then the format and static checks run and the status is pass or fail.
- Given a file with a finding, when the check runs, then the job fails and the log shows the tool name with `path:line` and the tool's message.
- Given a repository that lacks what a check needs, when the check runs, then it fails with a `[configuration]` message that names what is missing instead of passing.
| Traces to | Size | INVEST exceptions |
| --- | --- | --- |
| [UC-005], [MIL-007] | fits one iteration | none |
### US-001.17 — A C# project gets the same checks
**As a** Software Engineer, **I want** a pull request in a C# repository to run format and analyzer checks, **so that** a defect is found before review without me writing a pipeline.
**Acceptance Criteria**
- Given a repository that calls the shared C# quality-check workflow and has a project or solution, when a pull request is opened, then the format and analyzer checks run and the status is pass or fail.
- Given a file with a finding, when the check runs, then the job fails and the log shows the tool name with `path:line` and the tool's message.
- Given a repository without a project or solution, when the check runs, then it fails with a `[configuration]` message that names what is missing instead of passing.
| Traces to | Size | INVEST exceptions |
| --- | --- | --- |
| [UC-005], [MIL-007] | fits one iteration | none |
## INVEST Check
All fifteen stories are independent of each other except that US-001.05 and
All seventeen stories are independent of each other except that US-001.05 and
US-001.06 build on US-001.04 (the secrets must exist before a repository can
run the workflow). Each states one goal and can be negotiated, delivers value
to the named role, is small enough for one iteration, and has acceptance
@@ -236,12 +266,13 @@ behaviour is tested rather than built.
[MIL-002]: ./milestones/mil-002-onboarding-and-operations.md
[MIL-003]: ./milestones/mil-003-quality-checks.md
[MIL-004]: ./milestones/mil-004-versioned-release.md
[MIL-007]: ./milestones/mil-007-cpp-csharp-quality-checks.md
[UC-001]: ./uc-001/uc.md
[UC-002]: ./uc-002/uc.md
[UC-003]: ./uc-003/uc.md
[UC-004]: ./uc-004/uc.md
[UC-005]: ./uc-005/uc.md
[UC-006]: ./uc-006/uc.md
[044d8ba]: https://git.tirsystem.com/TirSystem/github-action/commit/044d8ba21f96f4aceb807d62addc35cdcbb56051
[UC-007]: ./uc-007/uc.md
[4cf52af]: https://git.tirsystem.com/TirSystem/github-action/commit/4cf52afe00f546c6b20424fb8dfc12796ffd9296
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
+100
View File
@@ -0,0 +1,100 @@
# Reading C and C++ quality-check results
How a software engineer calls the shared C and C++ quality checks, reads a
failed run and makes it pass. The workflow format-checks and statically checks
the C and C++ files of a repository with clang tools at exact versions, changes
no file and needs no secret. Its contract is ADR-0008 in this repository.
## Calling the workflow
```yaml
name: Quality C++
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1
with:
std: c++20
```
| Input | Default | Meaning |
| --- | --- | --- |
| `working-directory` | `.` | Directory, relative to the repository root, whose files are checked |
| `std` | `c++20` | C++ standard given to clang-tidy when there is no compile database, such as `c++17` or `gnu++20` |
| `compile-commands-dir` | empty | Directory, relative to the repository root, with a `compile_commands.json` that your pipeline built before the call; when set, clang-tidy uses it and ignores `std` |
| `clang-format-version` | `23.1.3` | Exact version of the clang-format package |
| `clang-tidy-version` | `22.1.8` | Exact version of the clang-tidy package |
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks-cpp.sh` is fetched |
Reference the workflow at the major tag (`@v1`) or at an exact tag, never at
`main`. A call at an exact tag is pinned completely only when `tools-ref` names
the same tag. See the upgrade guide. The tool versions are exact: a newer
version of a tool is a new release of this repository, not a silent change.
## What the repository needs
- A `.clang-format` in the working directory or in a directory above it, up to
the top of the repository. Without one the run fails with `[configuration]`
and no tool runs.
- Optionally a `.clang-tidy` with the checks of the project (for example the
C++ Core Guidelines). Without one the workflow runs the compiler diagnostics
and the static analyzer (`clang-diagnostic-*` and `clang-analyzer-*`),
because clang-tidy itself enables no check when there is no configuration.
- For precise static checks, a compile database: build it first (for example
`cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`) and pass
`compile-commands-dir: build`. The workflow does not build your project.
## What is checked
| Files | Tool | What it reports |
| --- | --- | --- |
| tracked `*.c`, `*.cc`, `*.cpp`, `*.cxx`, `*.h`, `*.hh`, `*.hpp`, `*.hxx` | `clang-format --dry-run -Werror` | formatting that differs from `.clang-format` |
| the same files | `clang-tidy` | findings of the checks of `.clang-tidy` (or of `clang-diagnostic-*` and `clang-analyzer-*` without one); `*.c` files are checked as C17, the other files as the C++ standard of `std`; every finding is an error (`--warnings-as-errors=*`), so a warning fails the run |
Untracked files are not checked. A repository without these files passes with a
notice. There is no `cppcheck`: only an old version of it is available as a
package, and old tools are not run (ADR-0008).
## Reading a run
1. Open the status check on the pull request, then the job `quality-checks-cpp`.
2. Each tool has its own log group. Every tool runs even when an earlier one
failed, so one run shows all findings.
3. A tool ends with `PASS <tool>` or `FAIL <tool>`; the last line of a failed
run names them: `Quality checks failed: clang-format`.
4. A finding is written by the tool itself as `path:line:column: message`.
Paths are relative to `working-directory`.
## Typical failures and fixes
| Tool | What the log shows | Fix |
| --- | --- | --- |
| `clang-format` | `code should be clang-formatted [-Wclang-format-violations]` | Run `clang-format -i <file>` with the same version and commit |
| `clang-tidy` | `warning: ... [modernize-use-nullptr]` | Fix the code, or switch the check off in `.clang-tidy` with a reason |
| `clang-tidy` | `error: 'x.h' file not found` | Build the compile database and set `compile-commands-dir`, or add the include path to it |
To reproduce a run on your machine, install the same versions:
```bash
python3 -m venv .qc
.qc/bin/pip install clang-format==23.1.3 clang-tidy==22.1.8
git ls-files '*.cpp' '*.hpp' | xargs .qc/bin/clang-format --dry-run -Werror
```
## When the workflow itself fails
| Message | Cause | Fix |
| --- | --- | --- |
| `[configuration] std '<x>' is not a C++ standard` | `std` is not like `c++20` or `gnu++20` | Correct the input |
| `[configuration] ... is not an exact version` | A tool version is a range, a channel or empty | Give an exact version such as `23.1.3` |
| `[configuration] working-directory must be a relative path inside the repository.` | An absolute path or `..` | Use a path inside the repository |
| `[configuration] No .clang-format found` | The project has no style file | Add a `.clang-format` |
| `[configuration] compile-commands-dir '<x>' has no compile_commands.json` | The database was not built before the call | Build it in an earlier step of the job or in a job it depends on |
| The install step fails | PyPI or the runner network is unreachable | Re-run the job; see [troubleshooting.md](troubleshooting.md) |
+95
View File
@@ -0,0 +1,95 @@
# Reading C# quality-check results
How a software engineer calls the shared C# quality checks, reads a failed run
and makes it pass. The workflow checks the formatting and builds a solution or
project with warnings as errors, on an exact .NET SDK of version 10 or later,
changes no file and needs no secret. Its contract is ADR-0008 in this
repository.
## Calling the workflow
```yaml
name: Quality C#
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1
with:
project: src/App.sln
```
| Input | Default | Meaning |
| --- | --- | --- |
| `working-directory` | `.` | Directory, relative to the repository root, whose files are checked |
| `project` | empty | Solution or project file, relative to `working-directory`; empty uses the single `*.sln` or `*.slnx`, else the single `*.csproj`, that is tracked there |
| `dotnet-sdk-version` | `10.0.401` | Exact version of the .NET SDK, 10 or later; a channel such as `10.0`, a range and a version below 10 are refused |
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks-csharp.sh` is fetched |
Reference the workflow at the major tag (`@v1`) or at an exact tag, never at
`main`. A call at an exact tag is pinned completely only when `tools-ref` names
the same tag. See the upgrade guide. The SDK version is exact: raising the
default is a new release of this repository, not a silent change.
## What the repository needs
- A solution or project that builds with the SDK. Several candidates need the
`project` input; C# files with no solution or project fail with
`[configuration]`.
- The network: `dotnet format` and `dotnet build` restore the NuGet packages of
the project in the run.
- Rules in `.editorconfig` (and the analyzers the project enables, for example
with `AnalysisLevel` and `EnforceCodeStyleInBuild`) decide what a finding is.
## What is checked
| Files | Tool | What it reports |
| --- | --- | --- |
| the solution or project | `dotnet format --verify-no-changes` | formatting and style that differ from `.editorconfig` |
| the same | `dotnet build -warnaserror` | compiler and analyzer warnings, which fail the build |
Untracked files are not checked. A repository without `*.cs` files passes with
a notice. Project tests are not run.
## Reading a run
1. Open the status check on the pull request, then the job
`quality-checks-csharp`.
2. Each tool has its own log group. Both run even when the first failed, so one
run shows all findings.
3. A tool ends with `PASS <tool>` or `FAIL <tool>`; the last line of a failed
run names them:
`Quality checks failed: dotnet format --verify-no-changes`.
4. A finding is written by the tool itself as `path(line,column): CODE message`.
## Typical failures and fixes
| Tool | What the log shows | Fix |
| --- | --- | --- |
| `dotnet format --verify-no-changes` | `Program.cs(12,5): error WHITESPACE: Fix whitespace formatting` | Run `dotnet format <project>` and commit |
| `dotnet build -warnaserror` | `CS8602: Dereference of a possibly null reference` | Fix the code (null check), do not suppress the warning without a reason |
| `dotnet build -warnaserror` | `IDE0005: Using directive is unnecessary` | Remove the directive |
To reproduce a run on your machine, use the same SDK:
```bash
dotnet --version # 10.0.401
dotnet format src/App.sln --verify-no-changes
dotnet build src/App.sln -warnaserror
```
## When the workflow itself fails
| Message | Cause | Fix |
| --- | --- | --- |
| `[configuration] dotnet-sdk-version '<x>' is not an exact stable version 10 or later` | A channel, a range, a preview or a version below 10 | Give an exact version such as `10.0.401` |
| `[configuration] working-directory must be a relative path inside the repository.` | An absolute path or `..` | Use a path inside the repository |
| `[configuration] C# files exist but no solution or project was found` | The repository has `*.cs` files and no `*.sln`, `*.slnx` or `*.csproj` in the working directory | Add one, or set `working-directory` |
| `[configuration] Several solutions or projects were found` | More than one candidate | Set the input `project` |
| The install step fails | `dot.net` or the runner network is unreachable | Re-run the job; see [troubleshooting.md](troubleshooting.md) |
+3 -2
View File
@@ -16,8 +16,9 @@ repository, tags `vMAJOR.MINOR.PATCH` and a moving major tag `vMAJOR`.
A breaking release gets a new major version (`v2`), so a pipeline on `@v1`
never receives it until you change the line yourself.
The quality-checks workflow fetches its script at its input `tools-ref`, which
defaults to `v1`. To pin it completely, call it at an exact tag and set
The quality-checks workflows (`quality-checks.yml`, `quality-checks-cpp.yml` and
`quality-checks-csharp.yml`) fetch their script at their input `tools-ref`, which
defaults to `v1`. To pin one completely, call it at an exact tag and set
`tools-ref` to the same tag; otherwise the script follows the major tag.
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
+1
View File
@@ -1,2 +1,3 @@
pytest>=8,<10
PyYAML>=6,<7
coverage>=7,<8
+10 -1
View File
@@ -98,7 +98,16 @@ def _write_sources(root: Path) -> None:
"## 📄 License\nMIT.\n",
encoding="utf-8",
)
for name in ("onboarding", "credentials", "troubleshooting", "quality-checks", "upgrading"):
guide_names = (
"onboarding",
"credentials",
"troubleshooting",
"quality-checks",
"quality-checks-cpp",
"quality-checks-csharp",
"upgrading",
)
for name in guide_names:
(root / "guides" / f"{name}.md").write_text(
f"# {name.title()}\nBody.\n", encoding="utf-8"
)
+722
View File
@@ -0,0 +1,722 @@
"""Offline tests for the reusable C++ and C# quality-check workflows (ADR-0008).
The shell steps run with stub tools in a throwaway git repository, so no
network, no clang and no .NET SDK are needed.
"""
import os
import re
import shutil
import subprocess
from pathlib import Path
from typing import Any
import pytest
import yaml
from workflow_source import REPO_ROOT
CPP_WORKFLOW = REPO_ROOT / ".gitea" / "workflows" / "quality-checks-cpp.yml"
CSHARP_WORKFLOW = REPO_ROOT / ".gitea" / "workflows" / "quality-checks-csharp.yml"
CPP_SCRIPT = REPO_ROOT / "tools" / "quality-checks-cpp.sh"
CSHARP_SCRIPT = REPO_ROOT / "tools" / "quality-checks-csharp.sh"
BASH = shutil.which("bash")
pytestmark = pytest.mark.skipif(BASH is None, reason="bash is needed to run the workflow steps")
# A script run: the finished process and the tool calls the stubs logged.
Run = tuple[subprocess.CompletedProcess[str], list[str]]
def load(path: Path) -> dict[str, Any]: # parsed YAML has no fixed shape
return yaml.safe_load(path.read_text(encoding="utf-8"))
def inputs_of(path: Path) -> dict[str, Any]:
return load(path)[True]["workflow_call"]["inputs"] # PyYAML reads `on` as True
@pytest.mark.parametrize(
"workflow, script, job",
[
(CPP_WORKFLOW, "quality-checks-cpp.sh", "quality-checks-cpp"),
(CSHARP_WORKFLOW, "quality-checks-csharp.sh", "quality-checks-csharp"),
],
ids=["cpp", "csharp"],
)
class TestDefinition:
def test_has_least_privilege_and_needs_no_secret(self, workflow: Path, script: str, job: str) -> None:
document = load(workflow)
assert document["jobs"][job]["permissions"] == {"contents": "read"}
assert "secrets" not in workflow.read_text(encoding="utf-8").replace("needs no secret", "")
def test_embeds_no_script_and_runs_the_file_in_three_steps(
self,
workflow: Path,
script: str,
job: str,
) -> None:
steps = load(workflow)["jobs"][job]["steps"]
commands = [step["run"] for step in steps if "run" in step]
assert commands == [f"bash shared-scripts/tools/{script} {c}" for c in ("validate", "install", "run")]
def test_fetches_the_script_at_the_tools_ref_input(self, workflow: Path, script: str, job: str) -> None:
steps = load(workflow)["jobs"][job]["steps"]
fetch = next(step for step in steps if step.get("name") == "Fetch the shared script")
assert fetch["with"] == {
"repository": "TirSystem/github-action",
"ref": "${{ inputs.tools-ref }}",
"path": "shared-scripts",
}
assert inputs_of(workflow)["tools-ref"]["default"] == "v1"
def test_inputs_reach_the_script_only_through_the_environment(
self,
workflow: Path,
script: str,
job: str,
) -> None:
for step in load(workflow)["jobs"][job]["steps"]:
assert "${{" not in step.get("run", "")
def test_script_is_a_file_that_parses(self, workflow: Path, script: str, job: str) -> None:
result = subprocess.run(
[BASH, "-n", str(REPO_ROOT / "tools" / script)], text=True, capture_output=True
)
assert result.returncode == 0, result.stderr
def test_unknown_command_is_refused(self, workflow: Path, script: str, job: str) -> None:
result = subprocess.run(
[BASH, str(REPO_ROOT / "tools" / script), "bogus"], text=True, capture_output=True
)
assert result.returncode == 2
def test_cpp_inputs_and_exact_defaults() -> None:
inputs = inputs_of(CPP_WORKFLOW)
assert set(inputs) == {
"working-directory",
"std",
"compile-commands-dir",
"clang-format-version",
"clang-tidy-version",
"tools-ref",
}
assert inputs["std"]["default"] == "c++20"
assert inputs["compile-commands-dir"]["default"] == ""
assert inputs["clang-format-version"]["default"] == "23.1.3"
assert inputs["clang-tidy-version"]["default"] == "22.1.8"
def test_csharp_inputs_and_exact_sdk_default() -> None:
inputs = inputs_of(CSHARP_WORKFLOW)
assert set(inputs) == {"working-directory", "project", "dotnet-sdk-version", "tools-ref"}
assert inputs["dotnet-sdk-version"]["default"] == "10.0.401"
def test_cpp_script_and_workflow_do_not_mention_cppcheck() -> None:
for path in (CPP_SCRIPT, CPP_WORKFLOW):
assert "cppcheck" not in path.read_text(encoding="utf-8").lower(), path.name
# ----------------------------------------------------------------- helpers
def make_repo(tmp_path: Path) -> Path:
root = tmp_path / "repo"
root.mkdir()
subprocess.run(["git", "init", "-q"], cwd=root, check=True)
return root
def add_files(root: Path, *relative: str) -> None:
for name in relative:
path = root / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("x\n", encoding="utf-8", newline="\n")
subprocess.run(["git", "add", "-A"], cwd=root, check=True)
def stub(directory: Path, name: str) -> Path:
path = directory / name
path.write_text(
"#!/usr/bin/env bash\n"
'name="$(basename "$0")"\n'
'[ "$name" = dotnet ] && name="dotnet $1"\n'
'echo "$name :: $*" >> "$STUB_LOG"\n'
'case ",${STUB_FAIL}," in\n'
' *",$name,"*) echo "src/a.cpp:3:1: stub finding from $name"; exit 1 ;;\n'
"esac\n"
"exit 0\n",
encoding="utf-8",
newline="\n",
)
path.chmod(0o755)
return path
def run_script(script: Path, command: str, cwd: Path, tmp_path: Path, **env: str) -> Run:
log = tmp_path / "tools.log"
environment = dict(os.environ)
environment.update({"STUB_LOG": log.as_posix(), "STUB_FAIL": ""})
environment.update(env)
result = subprocess.run(
[BASH, str(script), command], cwd=cwd, env=environment, text=True, capture_output=True
)
calls = log.read_text(encoding="utf-8").splitlines() if log.exists() else []
return result, calls
# --------------------------------------------------------------------- C++
@pytest.fixture
def cpp_bin(tmp_path: Path) -> Path:
directory = tmp_path / "bin"
directory.mkdir()
for tool in ("clang-format", "clang-tidy"):
stub(directory, tool)
return directory
def cpp_env(cpp_bin: Path, **extra: str) -> dict[str, str]:
values = {
"WORKING_DIRECTORY": ".",
"STD": "c++20",
"COMPILE_COMMANDS_DIR": "",
"CLANG_FORMAT_VERSION": "23.1.3",
"CLANG_TIDY_VERSION": "22.1.8",
"QC_VENV": "/nonexistent",
"QC_BIN": cpp_bin.as_posix(),
}
values.update(extra)
return values
class TestCppValidate:
def run(self, tmp_path: Path, cpp_bin: Path, **extra: str) -> Run:
return run_script(CPP_SCRIPT, "validate", tmp_path, tmp_path, **cpp_env(cpp_bin, **extra))
def test_accepts_the_defaults(self, tmp_path: Path, cpp_bin: Path) -> None:
result, _ = self.run(tmp_path, cpp_bin)
assert result.returncode == 0, result.stdout
@pytest.mark.parametrize("std", ["c++17", "c++23", "gnu++20"])
def test_accepts_a_cpp_standard(self, tmp_path: Path, cpp_bin: Path, std: str) -> None:
assert self.run(tmp_path, cpp_bin, STD=std)[0].returncode == 0
@pytest.mark.parametrize("std", ["", "c17", "c++", "latest", "c++20; rm"])
def test_rejects_a_value_that_is_not_a_cpp_standard(
self,
tmp_path: Path,
cpp_bin: Path,
std: str,
) -> None:
result, _ = self.run(tmp_path, cpp_bin, STD=std)
assert result.returncode == 1 and "[configuration]" in result.stdout
@pytest.mark.parametrize("directory", ["/etc", "..", "../x", "a/../..", ""])
def test_rejects_a_working_directory_outside_the_repository(
self,
tmp_path: Path,
cpp_bin: Path,
directory: str,
) -> None:
result, _ = self.run(tmp_path, cpp_bin, WORKING_DIRECTORY=directory)
assert result.returncode == 1 and "working-directory" in result.stdout
@pytest.mark.parametrize("directory", ["/tmp/build", "../build"])
def test_rejects_a_compile_commands_dir_outside_the_repository(
self,
tmp_path: Path,
cpp_bin: Path,
directory: str,
) -> None:
result, _ = self.run(tmp_path, cpp_bin, COMPILE_COMMANDS_DIR=directory)
assert result.returncode == 1 and "compile-commands-dir" in result.stdout
@pytest.mark.parametrize("name", ["CLANG_FORMAT_VERSION", "CLANG_TIDY_VERSION"])
@pytest.mark.parametrize("version", ["", "latest", "23", ">=23", "23.1.3 --pre"])
def test_rejects_a_version_that_is_not_exact(
self,
tmp_path: Path,
cpp_bin: Path,
name: str,
version: str,
) -> None:
result, _ = self.run(tmp_path, cpp_bin, **{name: version})
assert result.returncode == 1 and "exact version" in result.stdout
class TestCppRun:
@pytest.fixture
def repo(self, tmp_path: Path) -> Path:
root = make_repo(tmp_path)
add_files(root, ".clang-format")
return root
def run(self, repo: Path, tmp_path: Path, cpp_bin: Path, **extra: str) -> Run:
return run_script(CPP_SCRIPT, "run", repo, tmp_path, **cpp_env(cpp_bin, **extra))
def test_runs_clang_format_once_and_clang_tidy_per_language(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "src/a.cpp", "src/a.hpp", "lib/c.c")
result, calls = self.run(repo, tmp_path, cpp_bin)
assert result.returncode == 0, result.stdout + result.stderr
assert [c.split(" :: ")[0] for c in calls] == ["clang-format", "clang-tidy", "clang-tidy"]
assert "--dry-run -Werror" in calls[0]
assert "src/a.cpp" in calls[0] and "lib/c.c" in calls[0]
assert "-- -std=c++20" in calls[1] and "lib/c.c" not in calls[1]
assert "-- -std=c17" in calls[2] and "lib/c.c" in calls[2]
assert "All selected checks passed." in result.stdout
def test_the_std_input_reaches_clang_tidy(self, repo: Path, tmp_path: Path, cpp_bin: Path) -> None:
add_files(repo, "a.cpp")
_, calls = self.run(repo, tmp_path, cpp_bin, STD="c++17")
assert "-- -std=c++17" in calls[1]
def test_a_compile_database_is_used_instead_of_a_standard(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "a.cpp", "build/compile_commands.json")
result, calls = self.run(repo, tmp_path, cpp_bin, COMPILE_COMMANDS_DIR="build")
assert result.returncode == 0, result.stdout
assert len(calls) == 2
database = re.search(r"-p (\S+)", calls[1])
assert database is not None and database.group(1).endswith(f"/{repo.name}/build")
assert "-std=" not in calls[1]
def test_clang_tidy_gets_default_checks_without_a_clang_tidy_file(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "a.cpp")
_, calls = self.run(repo, tmp_path, cpp_bin)
assert "--checks=clang-diagnostic-*,clang-analyzer-*" in calls[1]
assert "--checks=" not in calls[0]
def test_no_default_checks_when_a_clang_tidy_file_is_in_the_repository_root(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "a.cpp", ".clang-tidy")
_, calls = self.run(repo, tmp_path, cpp_bin)
assert len(calls) == 2
assert not any("--checks=" in call for call in calls)
@pytest.mark.parametrize(
("files", "extra", "tidy_calls"),
[
(("a.cpp", "lib/c.c"), {}, 2),
(("a.cpp", ".clang-tidy"), {}, 1),
(("a.cpp", "build/compile_commands.json"), {"COMPILE_COMMANDS_DIR": "build"}, 1),
],
ids=["no-clang-tidy-file", "clang-tidy-file", "compile-database"],
)
def test_every_clang_tidy_call_treats_warnings_as_errors(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
files: tuple[str, ...],
extra: dict[str, str],
tidy_calls: int,
) -> None:
add_files(repo, *files)
_, calls = self.run(repo, tmp_path, cpp_bin, **extra)
tidy = [c for c in calls if c.startswith("clang-tidy")]
assert len(tidy) == tidy_calls
assert all("--warnings-as-errors=*" in call for call in tidy)
assert "--warnings-as-errors" not in calls[0] and calls[0].startswith("clang-format")
def test_no_default_checks_when_a_clang_tidy_file_is_above_the_working_directory(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "service/a.cpp", ".clang-tidy")
_, calls = self.run(repo, tmp_path, cpp_bin, WORKING_DIRECTORY="service")
assert len(calls) == 2
assert not any("--checks=" in call for call in calls)
def test_a_compile_database_is_resolved_from_the_repository_root(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "service/a.cpp", "build/compile_commands.json")
result, calls = self.run(
repo, tmp_path, cpp_bin, WORKING_DIRECTORY="service", COMPILE_COMMANDS_DIR="build"
)
assert result.returncode == 0, result.stdout
database = re.search(r"-p (\S+)", calls[1])
assert database is not None and database.group(1).endswith(f"/{repo.name}/build")
def test_a_compile_database_only_inside_the_working_directory_is_not_found(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "service/a.cpp", "service/build/compile_commands.json")
result, calls = self.run(
repo, tmp_path, cpp_bin, WORKING_DIRECTORY="service", COMPILE_COMMANDS_DIR="build"
)
assert result.returncode == 1 and "[configuration]" in result.stdout
assert calls == []
def test_a_missing_compile_database_is_a_configuration_error(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "a.cpp")
result, calls = self.run(repo, tmp_path, cpp_bin, COMPILE_COMMANDS_DIR="build")
assert result.returncode == 1 and "compile_commands.json" in result.stdout
assert calls == []
def test_a_missing_clang_format_file_is_a_configuration_error(
self,
tmp_path: Path,
cpp_bin: Path,
) -> None:
repo = make_repo(tmp_path)
add_files(repo, "a.cpp")
result, calls = self.run(repo, tmp_path, cpp_bin)
assert result.returncode == 1
assert "[configuration]" in result.stdout and ".clang-format" in result.stdout
assert calls == []
def test_a_clang_format_file_above_the_working_directory_is_found(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "service/a.cpp")
result, _ = run_script(
CPP_SCRIPT,
"run",
repo,
tmp_path,
**cpp_env(cpp_bin, WORKING_DIRECTORY="service"),
)
assert result.returncode == 0, result.stdout
def test_a_failing_tool_fails_the_job_and_the_other_still_runs(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "src/a.cpp")
result, calls = self.run(repo, tmp_path, cpp_bin, STUB_FAIL="clang-format")
assert result.returncode == 1
assert len(calls) == 2, "clang-tidy runs after clang-format failed"
assert "::group::clang-format" in result.stdout
assert "src/a.cpp:3:1: stub finding from clang-format" in result.stdout
assert "FAIL clang-format" in result.stdout and "PASS clang-tidy (C++)" in result.stdout
assert "Quality checks failed: clang-format" in result.stdout
def test_a_repository_without_c_or_cpp_files_passes_with_a_notice(
self,
tmp_path: Path,
cpp_bin: Path,
) -> None:
repo = make_repo(tmp_path)
add_files(repo, "README.md")
result, calls = self.run(repo, tmp_path, cpp_bin)
assert result.returncode == 0 and calls == []
assert "No C or C++ files" in result.stdout
def test_only_tracked_files_under_the_working_directory_are_checked(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
add_files(repo, "top.cpp", "service/api.cpp")
(repo / "service" / "untracked.cpp").write_text("x\n", encoding="utf-8")
_, calls = self.run(repo, tmp_path, cpp_bin, WORKING_DIRECTORY="service")
text = "\n".join(calls)
assert "api.cpp" in text and "top.cpp" not in text and "untracked" not in text
def test_no_file_is_changed(self, repo: Path, tmp_path: Path, cpp_bin: Path) -> None:
add_files(repo, "a.cpp")
def snapshot() -> dict[str, bytes]:
return {p.name: p.read_bytes() for p in repo.iterdir() if p.is_file()}
before = snapshot()
self.run(repo, tmp_path, cpp_bin, STUB_FAIL="clang-tidy (C++)")
assert snapshot() == before
def test_a_missing_working_directory_is_a_configuration_error(
self,
repo: Path,
tmp_path: Path,
cpp_bin: Path,
) -> None:
result, _ = self.run(repo, tmp_path, cpp_bin, WORKING_DIRECTORY="nope")
assert result.returncode == 1 and "[configuration]" in result.stdout
def test_cpp_install_pins_both_tools_to_the_exact_versions(tmp_path: Path) -> None:
"""`install` creates the venv and installs `==` versions; checked with a fake pip."""
venv = tmp_path / "venv"
fake_python = tmp_path / "bin"
fake_python.mkdir()
log = tmp_path / "pip.log"
python3 = fake_python / "python3"
python3.write_text(
"#!/usr/bin/env bash\n"
'mkdir -p "$3/bin"\n'
"printf '#!/usr/bin/env bash\\necho \"$*\" >> \"%s\"\\n' > \"$3/bin/pip\"\n" % log.as_posix()
+ 'chmod +x "$3/bin/pip"\n',
encoding="utf-8",
newline="\n",
)
python3.chmod(0o755)
environment = dict(os.environ)
environment["PATH"] = f"{fake_python.as_posix()}:{environment['PATH']}"
environment.update(
{
"QC_VENV": venv.as_posix(),
"CLANG_FORMAT_VERSION": "23.1.3",
"CLANG_TIDY_VERSION": "22.1.8",
}
)
result = subprocess.run(
[BASH, str(CPP_SCRIPT), "install"], env=environment, text=True, capture_output=True
)
assert result.returncode == 0, result.stdout + result.stderr
installed = log.read_text(encoding="utf-8")
assert "clang-format==23.1.3" in installed
assert "clang-tidy==22.1.8" in installed
# --------------------------------------------------------------------- C#
@pytest.fixture
def dotnet_stub(tmp_path: Path) -> Path:
directory = tmp_path / "dotnet-bin"
directory.mkdir()
return stub(directory, "dotnet")
def csharp_env(dotnet_stub: Path, tmp_path: Path, **extra: str) -> dict[str, str]:
values = {
"WORKING_DIRECTORY": ".",
"PROJECT": "",
"DOTNET_SDK_VERSION": "10.0.401",
"DOTNET_ROOT": (tmp_path / "dotnet-root").as_posix(),
"QC_DOTNET": dotnet_stub.as_posix(),
}
values.update(extra)
return values
class TestCsharpValidate:
def run(self, tmp_path: Path, dotnet_stub: Path, **extra: str) -> Run:
return run_script(
CSHARP_SCRIPT, "validate", tmp_path, tmp_path, **csharp_env(dotnet_stub, tmp_path, **extra)
)
@pytest.mark.parametrize("version", ["10.0.401", "10.0.100", "11.0.100", "100.1.2"])
def test_accepts_an_exact_sdk_of_version_10_or_later(
self,
tmp_path: Path,
dotnet_stub: Path,
version: str,
) -> None:
assert self.run(tmp_path, dotnet_stub, DOTNET_SDK_VERSION=version)[0].returncode == 0
@pytest.mark.parametrize(
"version",
["", "8.0.425", "9.0.100", "10.0", "10", "10.0.x", "latest", "10.0.401-rc.1", "10.0.401 --verbose"],
)
def test_rejects_an_old_or_inexact_sdk(self, tmp_path: Path, dotnet_stub: Path, version: str) -> None:
result, _ = self.run(tmp_path, dotnet_stub, DOTNET_SDK_VERSION=version)
assert result.returncode == 1
assert "[configuration]" in result.stdout and "dotnet-sdk-version" in result.stdout
@pytest.mark.parametrize("directory", ["/etc", "..", "../x", ""])
def test_rejects_a_working_directory_outside_the_repository(
self,
tmp_path: Path,
dotnet_stub: Path,
directory: str,
) -> None:
result, _ = self.run(tmp_path, dotnet_stub, WORKING_DIRECTORY=directory)
assert result.returncode == 1 and "working-directory" in result.stdout
@pytest.mark.parametrize("project", ["/etc/x.sln", "../x.sln"])
def test_rejects_a_project_outside_the_working_directory(
self,
tmp_path: Path,
dotnet_stub: Path,
project: str,
) -> None:
result, _ = self.run(tmp_path, dotnet_stub, PROJECT=project)
assert result.returncode == 1 and "project" in result.stdout
class TestCsharpInstall:
def test_installs_the_exact_version_with_the_official_script(
self,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
root = tmp_path / "dotnet-root"
installer = tmp_path / "dotnet-install.sh"
installer.write_text(
"#!/usr/bin/env bash\n"
'echo "$*" >> "$STUB_LOG"\n'
'dir=""\n'
'while [ "$#" -gt 0 ]; do [ "$1" = --install-dir ] && dir="$2"; shift; done\n'
'mkdir -p "$dir"\n'
"printf '#!/usr/bin/env bash\\necho 10.0.401\\n' > \"$dir/dotnet\"\n"
'chmod +x "$dir/dotnet"\n',
encoding="utf-8",
newline="\n",
)
result, calls = run_script(
CSHARP_SCRIPT,
"install",
tmp_path,
tmp_path,
**csharp_env(dotnet_stub, tmp_path, QC_DOTNET_INSTALL_SCRIPT=installer.as_posix()),
)
assert result.returncode == 0, result.stdout + result.stderr
assert calls and "--version 10.0.401" in calls[0]
assert f"--install-dir {root.as_posix()}" in calls[0]
assert "10.0.401" in result.stdout
class TestCsharpRun:
@pytest.fixture
def repo(self, tmp_path: Path) -> Path:
return make_repo(tmp_path)
def run(self, repo: Path, tmp_path: Path, dotnet_stub: Path, **extra: str) -> Run:
return run_script(
CSHARP_SCRIPT, "run", repo, tmp_path, **csharp_env(dotnet_stub, tmp_path, **extra)
)
def test_runs_format_and_build_on_the_single_solution(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "App.sln", "src/App.csproj", "src/Program.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub)
assert result.returncode == 0, result.stdout + result.stderr
assert [c.split(" :: ")[0] for c in calls] == ["dotnet format", "dotnet build"]
assert "App.sln" in calls[0] and "--verify-no-changes" in calls[0]
assert "App.sln" in calls[1] and "-warnaserror" in calls[1]
assert "All selected checks passed." in result.stdout
def test_uses_the_single_project_when_there_is_no_solution(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "src/App.csproj", "src/Program.cs")
_, calls = self.run(repo, tmp_path, dotnet_stub)
assert "src/App.csproj" in calls[0]
def test_several_projects_without_a_solution_need_the_project_input(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "a/A.csproj", "b/B.csproj", "a/P.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub)
assert result.returncode == 1 and calls == []
assert "[configuration]" in result.stdout
assert "a/A.csproj" in result.stdout and "b/B.csproj" in result.stdout
def test_the_project_input_picks_one(self, repo: Path, tmp_path: Path, dotnet_stub: Path) -> None:
add_files(repo, "a/A.csproj", "b/B.csproj", "a/P.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub, PROJECT="b/B.csproj")
assert result.returncode == 0 and "b/B.csproj" in calls[0]
def test_a_missing_project_file_is_a_configuration_error(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "a/P.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub, PROJECT="nope.csproj")
assert result.returncode == 1 and "does not exist" in result.stdout and calls == []
def test_csharp_files_without_a_project_are_a_configuration_error(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "Program.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub)
assert result.returncode == 1 and calls == []
assert "[configuration]" in result.stdout and "no solution or project" in result.stdout
def test_a_repository_without_csharp_files_passes_with_a_notice(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "README.md")
result, calls = self.run(repo, tmp_path, dotnet_stub)
assert result.returncode == 0 and calls == []
assert "No C# files" in result.stdout
def test_a_failing_tool_fails_the_job_and_the_other_still_runs(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "App.sln", "Program.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub, STUB_FAIL="dotnet format")
assert result.returncode == 1 and len(calls) == 2
assert "::group::dotnet format --verify-no-changes" in result.stdout
assert "FAIL dotnet format --verify-no-changes" in result.stdout
assert "PASS dotnet build -warnaserror" in result.stdout
assert "Quality checks failed: dotnet format --verify-no-changes" in result.stdout
def test_only_files_under_the_working_directory_are_considered(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
add_files(repo, "Top.sln", "svc/Svc.csproj", "svc/P.cs", "Top.cs")
result, calls = self.run(repo, tmp_path, dotnet_stub, WORKING_DIRECTORY="svc")
assert result.returncode == 0
assert "Svc.csproj" in calls[0] and "Top.sln" not in calls[0]
def test_a_missing_working_directory_is_a_configuration_error(
self,
repo: Path,
tmp_path: Path,
dotnet_stub: Path,
) -> None:
result, _ = self.run(repo, tmp_path, dotnet_stub, WORKING_DIRECTORY="nope")
assert result.returncode == 1 and "[configuration]" in result.stdout
+371
View File
@@ -0,0 +1,371 @@
"""Offline tests for the parts of tools/ that the flow tests do not reach.
The flow tests of each tool replace its HTTP function with a fake, so the real
`request_json` of the three API tools and the command-line entry point of each
tool are tested here: the reply that is parsed, the HTTP error that is named by
category, and the exit code and message of a run as a process.
"""
import io
import json
import subprocess
import sys
import urllib.error
import pytest
from workflow_source import REPO_ROOT, load_script
TOOLS = REPO_ROOT / "tools"
changelog = load_script(TOOLS / "changelog.py", "changelog_entry")
build_wiki = load_script(TOOLS / "build_wiki.py", "build_wiki_entry")
release = load_script(TOOLS / "release.py", "release_entry")
publish = load_script(TOOLS / "publish_wiki.py", "publish_wiki_entry")
sync = load_script(TOOLS / "sync_github_metadata.py", "sync_entry")
API_TOOLS = pytest.mark.parametrize(
"tool", [release, publish, sync], ids=["release", "publish_wiki", "sync_github_metadata"]
)
class FakeResponse:
def __init__(self, body: bytes) -> None:
self._body = body
def __enter__(self):
return self
def __exit__(self, *exc):
return False
def read(self) -> bytes:
return self._body
def http_error(code: int) -> urllib.error.HTTPError:
return urllib.error.HTTPError("https://git.example/api", code, "reason", {}, io.BytesIO(b""))
@pytest.fixture()
def urlopen(monkeypatch):
"""Replace urllib.request.urlopen; set `.reply` to a body or an exception."""
class Opener:
reply: object = b"{}"
requests: list = []
def __call__(self, request, timeout=None):
self.requests.append(request)
if isinstance(self.reply, BaseException):
raise self.reply
return FakeResponse(self.reply)
opener = Opener()
opener.requests = []
monkeypatch.setattr("urllib.request.urlopen", opener)
return opener
class TestRequestJson:
@API_TOOLS
def test_parses_a_json_reply(self, tool, urlopen):
urlopen.reply = b'{"name": "x"}'
assert tool["request_json"]("https://git.example/api", headers={"A": "b"}) == {"name": "x"}
@API_TOOLS
def test_an_empty_reply_is_none(self, tool, urlopen):
urlopen.reply = b""
assert tool["request_json"]("https://git.example/api", method="DELETE") is None
@API_TOOLS
def test_a_body_is_sent_as_json(self, tool, urlopen):
urlopen.reply = b"{}"
tool["request_json"]("https://git.example/api", method="POST", body={"k": 1})
assert json.loads(urlopen.requests[0].data) == {"k": 1}
assert urlopen.requests[0].get_method() == "POST"
@API_TOOLS
@pytest.mark.parametrize(
"code, category",
[(401, "credentials"), (403, "permissions"), (500, "api")],
)
def test_an_http_error_is_named_by_category(self, tool, urlopen, code, category):
urlopen.reply = http_error(code)
with pytest.raises(tool["WorkflowError"]) as error:
tool["request_json"]("https://git.example/api")
assert error.value.category == category
assert str(code) in str(error.value)
@pytest.mark.parametrize("tool", [publish, sync], ids=["publish_wiki", "sync_github_metadata"])
def test_a_missing_repository_is_a_configuration_error(self, tool, urlopen):
urlopen.reply = http_error(404)
with pytest.raises(tool["WorkflowError"]) as error:
tool["request_json"]("https://git.example/api")
assert error.value.category == "configuration"
@API_TOOLS
def test_an_unreachable_host_is_an_api_error(self, tool, urlopen):
urlopen.reply = urllib.error.URLError("no route")
with pytest.raises(tool["WorkflowError"]) as error:
tool["request_json"]("https://git.example/api")
assert error.value.category == "api"
assert "unreachable" in str(error.value)
def test_the_sync_tool_names_the_service_in_its_message(self, urlopen):
urlopen.reply = http_error(500)
with pytest.raises(sync["WorkflowError"]) as github:
sync["request_json"]("https://api.github.com/repos/o/r")
assert "GitHub API" in str(github.value)
with pytest.raises(sync["WorkflowError"]) as gitea:
sync["request_json"]("https://git.example/api/v1/repos/o/r")
assert "Gitea API" in str(gitea.value)
class TestPagination:
def test_release_reads_every_page_of_tags(self):
pages = {1: [{"name": f"v{n}"} for n in range(50)], 2: [{"name": "v50"}], 3: []}
def request(url, headers=None):
page = int(url.split("page=")[1])
return pages[page]
names = release["list_tag_names"]("https://git.example/api", {}, request)
assert len(names) == 51 and names[-1] == "v50"
def test_release_stops_on_an_empty_first_page(self):
assert release["list_tag_names"]("https://git.example/api", {}, lambda *a, **k: []) == []
def test_publish_reads_every_page_of_wiki_titles(self):
full = [{"sub_url": f"Page-{n}"} for n in range(publish["PAGE_LIMIT"])]
calls = []
def send(url, headers=None):
calls.append(url)
return full if "page=1&" in url else [{"sub_url": "Last"}]
titles = publish["list_wiki_titles"]("https://git.example/wiki", {}, send)
assert len(calls) == 2
assert "Last" in titles and "Page-0" in titles
def test_publish_refuses_a_list_that_is_not_a_list(self):
with pytest.raises(publish["WorkflowError"]) as error:
publish["list_wiki_titles"](
"https://git.example/wiki", {}, lambda *a, **k: {"message": "x"}
)
assert error.value.category == "api"
class TestReleaseInputs:
@pytest.fixture()
def env(self, tmp_path, monkeypatch):
changelog_file = tmp_path / "CHANGELOG.md"
changelog_file.write_text(
"## [Unreleased]\n\n## [1.0.0] - 2026-10-10\n\n### Added\n\n- First.\n",
encoding="utf-8",
)
for key, value in {
"GITEA_API_URL": "https://git.example/api/v1",
"SOURCE_REPOSITORY": "o/r",
"RELEASE_CREDENTIALS": "t" * 40,
"RELEASE_VERSION": "1.0.0",
"RELEASE_SHA": "a" * 40,
"RELEASE_DRY_RUN": "true",
"CHANGELOG_FILE": str(changelog_file),
}.items():
monkeypatch.setenv(key, value)
return monkeypatch
@pytest.mark.parametrize("repository", ["", "owner", "/repo", "owner/"])
def test_a_malformed_repository_is_refused(self, env, repository):
env.setenv("SOURCE_REPOSITORY", repository)
with pytest.raises(release["WorkflowError"]) as error:
release["main"](request=lambda *a, **k: None)
assert error.value.category == "configuration"
@pytest.mark.parametrize("sha", ["", "abc", "g" * 40])
def test_a_malformed_commit_is_refused(self, env, sha):
env.setenv("RELEASE_SHA", sha)
with pytest.raises(release["WorkflowError"]) as error:
release["main"](request=lambda *a, **k: None)
assert "RELEASE_SHA" in str(error.value)
def test_an_unreadable_changelog_is_a_configuration_error(self, env, tmp_path):
env.setenv("CHANGELOG_FILE", str(tmp_path / "missing.md"))
with pytest.raises(release["WorkflowError"]) as error:
release["main"](request=lambda *a, **k: None)
assert error.value.category == "configuration"
def test_a_changelog_that_breaks_its_convention_is_a_validation_error(self, env, tmp_path):
bad = tmp_path / "bad.md"
bad.write_text("## [1.0.0] - 2026-10-10\n\n### Added\n\n- X.\n", encoding="utf-8")
env.setenv("CHANGELOG_FILE", str(bad))
with pytest.raises(release["WorkflowError"]) as error:
release["main"](request=lambda *a, **k: None)
assert error.value.category == "validation"
assert "Unreleased" in str(error.value)
class TestChangelogCommandLine:
@pytest.fixture()
def good(self, tmp_path):
path = tmp_path / "CHANGELOG.md"
path.write_text(
"## [Unreleased]\n\n## [1.1.0] - 2026-10-11\n\n### Added\n\n- A.\n\n"
"## [1.0.0] - 2026-10-10\n\n### Fixed\n\n- B.\n",
encoding="utf-8",
)
return path
def test_check_passes_a_good_file(self, good, capsys):
assert changelog["main"](["check", "--file", str(good)]) == 0
assert "follows the convention" in capsys.readouterr().out
def test_check_names_a_missing_version(self, good, capsys):
assert changelog["main"](["check", "--file", str(good), "--version", "2.0.0"]) == 1
assert "no changelog entry with changes for version 2.0.0" in capsys.readouterr().err
def test_check_reports_each_problem(self, tmp_path, capsys):
path = tmp_path / "CHANGELOG.md"
path.write_text("## [1.0.0]\n\n### Odd\n\n", encoding="utf-8")
assert changelog["main"](["check", "--file", str(path)]) == 1
err = capsys.readouterr().err
assert "first section must be `## [Unreleased]`" in err
assert "not one of Breaking, Added, Changed, Fixed" in err
assert "needs a date" in err
def test_notes_prints_the_release_page(self, good, capsys):
assert changelog["main"](["notes", "1.1.0", "--file", str(good)]) == 0
out = capsys.readouterr().out
assert out.startswith("## 1.1.0 - 2026-10-11") and "- A." in out
def test_notes_needs_a_version(self, good, capsys):
assert changelog["main"](["notes", "--file", str(good)]) == 1
assert "needs a version" in capsys.readouterr().err
def test_notes_names_an_unknown_version(self, good, capsys):
assert changelog["main"](["notes", "9.9.9", "--file", str(good)]) == 1
assert "no changelog entry" in capsys.readouterr().err
def test_a_group_without_an_item_and_a_release_without_a_group_are_problems(self):
text = "## [Unreleased]\n\n### Added\n\n## [1.0.0] - 2026-10-10\n"
problems = changelog["validate"](text)
assert any("has no item" in p for p in problems)
assert any("has no change group" in p for p in problems)
def test_an_unreleased_section_has_no_date_and_versions_descend(self):
text = (
"## [Unreleased] - 2026-10-10\n\n## [1.0.0] - 2026-10-10\n\n### Added\n\n- A.\n\n"
"## [1.1.0] - 2026-10-11\n\n### Added\n\n- B.\n"
)
problems = changelog["validate"](text)
assert any("has no date" in p for p in problems)
assert any("must be lower than the version above it" in p for p in problems)
class TestBuildWikiCommandLine:
def test_hash_prints_twelve_hex_digits_for_a_page(self, capsys):
assert build_wiki["main"](["--hash", "Home"]) == 0
assert len(capsys.readouterr().out.strip()) == build_wiki["HASH_LENGTH"]
def test_hash_of_an_unknown_page_fails(self, capsys):
assert build_wiki["main"](["--hash", "Nope"]) == 1
assert "unknown page" in capsys.readouterr().err
def test_check_passes_on_the_committed_wiki(self, capsys):
assert build_wiki["main"](["--check"]) == 0
assert "up to date" in capsys.readouterr().out
def test_check_lists_every_problem_and_the_command_that_fixes_it(self, monkeypatch, capsys):
monkeypatch.setattr(build_wiki._module, "check_pages", lambda: ["Home.md: missing"])
monkeypatch.setattr(build_wiki._module, "check_translations", lambda: [])
assert build_wiki["main"](["--check"]) == 1
err = capsys.readouterr().err
assert "ERROR: wiki/Home.md: missing" in err
assert "python tools/build_wiki.py" in err
def test_generate_reports_the_changed_pages(self, monkeypatch, capsys):
monkeypatch.setattr(build_wiki._module, "write_pages", lambda: ["Home.md"])
assert build_wiki["main"]([]) == 0
assert "Wrote 1 page(s): Home.md" in capsys.readouterr().out
def test_generate_reports_a_build_error(self, monkeypatch, capsys):
def broken():
raise build_wiki["WikiBuildError"]("README.md is missing")
monkeypatch.setattr(build_wiki._module, "write_pages", broken)
assert build_wiki["main"]([]) == 1
assert "ERROR: README.md is missing" in capsys.readouterr().err
def run_tool(name: str, **env: str) -> subprocess.CompletedProcess:
"""Run a tool as `python tools/<name>` with only the given environment."""
environment = {"PATH": "", "SYSTEMROOT": "", **env}
environment = {k: v for k, v in environment.items() if v != "" or k in env}
return subprocess.run(
[sys.executable, str(TOOLS / name)],
env=environment,
capture_output=True,
text=True,
cwd=REPO_ROOT,
)
class TestRunAsAProcess:
"""The `if __name__ == "__main__"` block: exit code 1 and ERROR: on stderr."""
def test_release_without_a_version_exits_1(self):
result = run_tool("release.py")
assert result.returncode == 1
assert result.stderr.startswith("ERROR: [configuration]")
def test_publish_wiki_without_a_repository_exits_1(self):
result = run_tool("publish_wiki.py", WIKI_DIR=str(REPO_ROOT / "wiki"), GITEA_API_URL="https://x")
assert result.returncode == 1
assert "ERROR:" in result.stderr
def test_sync_without_a_token_exits_1(self):
result = run_tool("sync_github_metadata.py", GITEA_API_URL="https://x", SOURCE_REPOSITORY="o/r")
assert result.returncode == 1
assert "ERROR:" in result.stderr and "TOKEN_FOR_GITEA" in result.stderr
def test_changelog_checks_the_committed_file(self):
result = run_tool("changelog.py", **{})
assert result.returncode != 0 # the command is required
result = subprocess.run(
[sys.executable, str(TOOLS / "changelog.py"), "check"],
capture_output=True,
text=True,
cwd=REPO_ROOT,
)
assert result.returncode == 0, result.stderr
class TestRemainingBranches:
def test_notes_of_a_release_without_changes_is_not_a_page(self):
text = "## [Unreleased]\n\n## [1.0.0] - 2026-10-10\n"
with pytest.raises(LookupError):
changelog["notes"](text, "1.0.0")
@pytest.mark.parametrize("repository", [None, "", "owner", "/repo", "owner/"])
def test_publish_refuses_a_malformed_repository(self, repository):
with pytest.raises(publish["WorkflowError"]) as error:
publish["split_repository"](repository)
assert error.value.category == "configuration"
def test_publish_treats_a_wiki_without_pages_as_empty(self):
def send(url, headers=None):
raise publish["WorkflowError"]("configuration", "not found")
assert publish["list_wiki_titles"]("https://git.example/wiki", {}, send) == set()
def test_publish_does_not_hide_a_failure_on_a_later_page(self):
full = [{"sub_url": f"P-{n}"} for n in range(publish["PAGE_LIMIT"])]
def send(url, headers=None):
if "page=1&" in url:
return full
raise publish["WorkflowError"]("configuration", "gone")
with pytest.raises(publish["WorkflowError"]):
publish["list_wiki_titles"]("https://git.example/wiki", {}, send)
+16
View File
@@ -73,3 +73,19 @@ def test_no_workflow_copy_outside_the_workflow_directories():
if path.name == SYNC_WORKFLOW.name
]
assert not stray, f"duplicate workflow copies: {stray}"
def test_validation_runs_the_tests_under_a_coverage_gate():
"""validate-workflows.yml measures tools/ and fails below the .coveragerc limit."""
text = (REPO_ROOT / ".gitea" / "workflows" / "validate-workflows.yml").read_text(
encoding="utf-8"
)
assert "-m coverage run -m pytest -q tests" in text
assert "-m coverage report" in text
config = (REPO_ROOT / ".coveragerc").read_text(encoding="utf-8")
assert "source = tools" in config and "branch = True" in config
assert any(
line.replace(" ", "") == "fail_under=95" for line in config.splitlines()
), "the gate is 95 percent"
requirements = (REPO_ROOT / "tests" / "requirements.txt").read_text(encoding="utf-8")
assert "coverage" in requirements
+7 -3
View File
@@ -44,6 +44,8 @@ PAGES: tuple[Page, ...] = (
Page("Credentials", "guides/credentials.md"),
Page("Troubleshooting", "guides/troubleshooting.md"),
Page("QualityChecksPythonShell", "guides/quality-checks.md"),
Page("QualityChecksCpp", "guides/quality-checks-cpp.md"),
Page("QualityChecksCSharp", "guides/quality-checks-csharp.md"),
Page("Upgrading", "guides/upgrading.md"),
Page("Capabilities", "README.md", ("Capabilities",)),
)
@@ -62,6 +64,8 @@ _PAGE_FOR_SOURCE = {
"guides/credentials.md": "Credentials",
"guides/troubleshooting.md": "Troubleshooting",
"guides/quality-checks.md": "QualityChecksPythonShell",
"guides/quality-checks-cpp.md": "QualityChecksCpp",
"guides/quality-checks-csharp.md": "QualityChecksCSharp",
"guides/upgrading.md": "Upgrading",
}
@@ -187,9 +191,9 @@ def render_page(page: Page, repo_root: Path = REPO_ROOT) -> str:
# Link text of the sidebar: English, then one list per translation code.
SIDEBAR_TITLE = "TirSystem GitHub Actions"
SIDEBAR_LABELS: dict[str, tuple[str, ...]] = {
"en": ("Home", "Onboarding", "Credentials", "Troubleshooting", "Quality checks (Python, shell)", "Upgrading", "Capabilities"),
"da": ("Hjem", "Tilslutning", "Credentials", "Fejlfinding", "Kvalitetskontrol (Python, shell)", "Opgradering", "Kapabiliteter"),
"ms": ("Utama", "Menyertakan", "Kelayakan", "Diagnosis", "Semakan kualiti (Python, shell)", "Menaik taraf", "Keupayaan"),
"en": ("Home", "Onboarding", "Credentials", "Troubleshooting", "Quality checks (Python, shell)", "Quality checks (C and C++)", "Quality checks (C#)", "Upgrading", "Capabilities"),
"da": ("Hjem", "Tilslutning", "Credentials", "Fejlfinding", "Kvalitetskontrol (Python, shell)", "Kvalitetskontrol (C og C++)", "Kvalitetskontrol (C#)", "Opgradering", "Kapabiliteter"),
"ms": ("Utama", "Menyertakan", "Kelayakan", "Diagnosis", "Semakan kualiti (Python, shell)", "Semakan kualiti (C dan C++)", "Semakan kualiti (C#)", "Menaik taraf", "Keupayaan"),
}
SIDEBAR_NAME = "_Sidebar.md"
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env bash
# Steps of the reusable workflow .gitea/workflows/quality-checks-cpp.yml
# (ADR-0008). The workflow checks out the calling repository, fetches this file
# into shared-scripts/ and runs one command per step:
#
# quality-checks-cpp.sh validate check the inputs, before anything is installed
# quality-checks-cpp.sh install install the exact clang tool versions into a venv
# quality-checks-cpp.sh run run clang-format and clang-tidy on the tracked files
#
# Settings come from the environment, never from interpolated expressions:
# WORKING_DIRECTORY, STD, COMPILE_COMMANDS_DIR, CLANG_FORMAT_VERSION,
# CLANG_TIDY_VERSION, QC_VENV (and QC_BIN for tests).
# Every failure is printed as ::error::[category] message.
C_STANDARD="${C_STANDARD:-c17}"
DEFAULT_TIDY_CHECKS="clang-diagnostic-*,clang-analyzer-*"
validate_inputs() {
set -u
case "$WORKING_DIRECTORY" in
"" | /* | .. | ../* | */.. | */../*)
echo "::error::[configuration] working-directory must be a relative path inside the repository."
exit 1
;;
esac
if ! [[ "$STD" =~ ^(c\+\+|gnu\+\+)[0-9]{2}$ ]]; then
echo "::error::[configuration] std '$STD' is not a C++ standard such as c++20 or gnu++20."
exit 1
fi
case "$COMPILE_COMMANDS_DIR" in
/* | .. | ../* | */.. | */../*)
echo "::error::[configuration] compile-commands-dir must be a relative path inside the repository."
exit 1
;;
esac
local name version
for name in CLANG_FORMAT_VERSION CLANG_TIDY_VERSION; do
version="${!name}"
if ! [[ "$version" =~ ^[0-9]+(\.[0-9]+){1,3}$ ]]; then
echo "::error::[configuration] ${name,,} '$version' is not an exact version such as 23.1.3."
exit 1
fi
done
echo "Checking C and C++ in ${WORKING_DIRECTORY} with std ${STD}"
}
install_tools() {
set -eu
python3 -m venv "$QC_VENV"
"$QC_VENV/bin/pip" install --quiet \
"clang-format==${CLANG_FORMAT_VERSION}" "clang-tidy==${CLANG_TIDY_VERSION}"
}
# Succeeds when one of the named files exists in the working directory or above
# it, up to the top of the repository: clang-format and clang-tidy find their
# configuration the same way.
find_config_upwards() {
local top dir parent name
top="$(cd "$(git rev-parse --show-toplevel)" && pwd -P)"
dir="$(pwd -P)"
while true; do
for name in "$@"; do
if [ -f "$dir/$name" ]; then
return 0
fi
done
parent="$(dirname "$dir")"
# stop at the top of the repository, or at the file system root
if [ "$dir" = "$top" ] || [ "$parent" = "$dir" ]; then
return 1
fi
dir="$parent"
done
}
run_checks() {
set -u
QC_BIN="${QC_BIN:-$QC_VENV/bin}"
if [ ! -d "$WORKING_DIRECTORY" ]; then
echo "::error::[configuration] working-directory '$WORKING_DIRECTORY' does not exist."
exit 1
fi
# compile-commands-dir is relative to the repository root, not to the working directory
local repo_top compile_db=""
repo_top="$(cd "$(git rev-parse --show-toplevel)" && pwd -P)"
if [ -n "$COMPILE_COMMANDS_DIR" ]; then
compile_db="$repo_top/$COMPILE_COMMANDS_DIR"
fi
cd "$WORKING_DIRECTORY"
local all_files cpp_files c_files
mapfile -t all_files < <(git ls-files -- '*.c' '*.cc' '*.cpp' '*.cxx' '*.h' '*.hh' '*.hpp' '*.hxx')
if [ "${#all_files[@]}" -eq 0 ]; then
echo "::notice::No C or C++ files in '$WORKING_DIRECTORY'; nothing was checked."
echo "All selected checks passed."
exit 0
fi
if ! find_config_upwards .clang-format _clang-format; then
echo "::error::[configuration] No .clang-format found in '$WORKING_DIRECTORY' or above it; add the style of the project."
exit 1
fi
if [ -n "$compile_db" ] && [ ! -f "$compile_db/compile_commands.json" ]; then
echo "::error::[configuration] compile-commands-dir '$COMPILE_COMMANDS_DIR' has no compile_commands.json; build it before the call."
exit 1
fi
# .c files are C; everything else (including headers) is checked as C++.
mapfile -t c_files < <(git ls-files -- '*.c')
mapfile -t cpp_files < <(git ls-files -- '*.cc' '*.cpp' '*.cxx' '*.h' '*.hh' '*.hpp' '*.hxx')
local failed=()
run_tool() {
local name="$1"
shift
echo "::group::$name"
if "$@"; then
echo "::endgroup::"
echo "PASS $name"
else
echo "::endgroup::"
echo "FAIL $name"
failed+=("$name")
fi
}
run_tool "clang-format" "$QC_BIN/clang-format" --dry-run -Werror "${all_files[@]}"
# Without a .clang-tidy, clang-tidy enables no check and refuses to run, so
# the project gets the compiler diagnostics and the static analyzer.
# clang-tidy exits 0 on a warning, so every finding is made an error: a
# finding must fail the check, as a failing tool does for the other languages.
local tidy_args=(--quiet "--warnings-as-errors=*")
if ! find_config_upwards .clang-tidy _clang-tidy; then
tidy_args+=("--checks=${DEFAULT_TIDY_CHECKS}")
fi
if [ -n "$compile_db" ]; then
run_tool "clang-tidy" "$QC_BIN/clang-tidy" "${tidy_args[@]}" -p "$compile_db" "${all_files[@]}"
else
if [ "${#cpp_files[@]}" -gt 0 ]; then
run_tool "clang-tidy (C++)" "$QC_BIN/clang-tidy" "${tidy_args[@]}" "${cpp_files[@]}" -- "-std=${STD}"
fi
if [ "${#c_files[@]}" -gt 0 ]; then
run_tool "clang-tidy (C)" "$QC_BIN/clang-tidy" "${tidy_args[@]}" "${c_files[@]}" -- "-std=${C_STANDARD}"
fi
fi
if [ "${#failed[@]}" -gt 0 ]; then
echo "::error::Quality checks failed: ${failed[*]}"
exit 1
fi
echo "All selected checks passed."
}
case "${1:-}" in
validate) validate_inputs ;;
install) install_tools ;;
run) run_checks ;;
*)
echo "::error::[configuration] usage: quality-checks-cpp.sh validate|install|run" >&2
exit 2
;;
esac
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
# Steps of the reusable workflow .gitea/workflows/quality-checks-csharp.yml
# (ADR-0008). The workflow checks out the calling repository, fetches this file
# into shared-scripts/ and runs one command per step:
#
# quality-checks-csharp.sh validate check the inputs, before anything is installed
# quality-checks-csharp.sh install install the exact .NET SDK version
# quality-checks-csharp.sh run run dotnet format and dotnet build on the project
#
# Settings come from the environment, never from interpolated expressions:
# WORKING_DIRECTORY, PROJECT, DOTNET_SDK_VERSION, DOTNET_ROOT (and
# QC_DOTNET_INSTALL_SCRIPT, QC_DOTNET for tests).
# Every failure is printed as ::error::[category] message.
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
validate_inputs() {
set -u
case "$WORKING_DIRECTORY" in
"" | /* | .. | ../* | */.. | */../*)
echo "::error::[configuration] working-directory must be a relative path inside the repository."
exit 1
;;
esac
case "$PROJECT" in
/* | .. | ../* | */.. | */../*)
echo "::error::[configuration] project must be a relative path inside the working directory."
exit 1
;;
esac
# An exact stable version of the .NET SDK, 10 or later (no channel, no range).
if ! [[ "$DOTNET_SDK_VERSION" =~ ^([1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]] || [ "${BASH_REMATCH[1]}" -lt 10 ]; then
echo "::error::[configuration] dotnet-sdk-version '$DOTNET_SDK_VERSION' is not an exact stable version 10 or later, such as 10.0.401."
exit 1
fi
echo "Checking C# in ${WORKING_DIRECTORY} with .NET SDK ${DOTNET_SDK_VERSION}"
}
install_sdk() {
set -eu
local script="${QC_DOTNET_INSTALL_SCRIPT:-}"
if [ -z "$script" ]; then
script="$(mktemp)"
curl -fsSL "$DOTNET_INSTALL_URL" -o "$script"
fi
bash "$script" --version "$DOTNET_SDK_VERSION" --install-dir "$DOTNET_ROOT" --no-path
"$DOTNET_ROOT/dotnet" --version
}
run_checks() {
set -u
if [ ! -d "$WORKING_DIRECTORY" ]; then
echo "::error::[configuration] working-directory '$WORKING_DIRECTORY' does not exist."
exit 1
fi
cd "$WORKING_DIRECTORY"
local dotnet="${QC_DOTNET:-$DOTNET_ROOT/dotnet}"
local sources
mapfile -t sources < <(git ls-files -- '*.cs')
if [ "${#sources[@]}" -eq 0 ]; then
echo "::notice::No C# files in '$WORKING_DIRECTORY'; nothing was checked."
echo "All selected checks passed."
exit 0
fi
local target="$PROJECT" candidates
if [ -z "$target" ]; then
mapfile -t candidates < <(git ls-files -- '*.sln' '*.slnx')
if [ "${#candidates[@]}" -eq 0 ]; then
mapfile -t candidates < <(git ls-files -- '*.csproj')
fi
case "${#candidates[@]}" in
0)
echo "::error::[configuration] C# files exist but no solution or project was found in '$WORKING_DIRECTORY'; add one or set the input project."
exit 1
;;
1) target="${candidates[0]}" ;;
*)
echo "::error::[configuration] Several solutions or projects were found (${candidates[*]}); set the input project."
exit 1
;;
esac
elif [ ! -f "$target" ]; then
echo "::error::[configuration] project '$target' does not exist in '$WORKING_DIRECTORY'."
exit 1
fi
echo "Checking $target"
export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1
local failed=()
run_tool() {
local name="$1"
shift
echo "::group::$name"
if "$@"; then
echo "::endgroup::"
echo "PASS $name"
else
echo "::endgroup::"
echo "FAIL $name"
failed+=("$name")
fi
}
run_tool "dotnet format --verify-no-changes" "$dotnet" format "$target" --verify-no-changes
run_tool "dotnet build -warnaserror" "$dotnet" build "$target" --nologo -warnaserror
if [ "${#failed[@]}" -gt 0 ]; then
echo "::error::Quality checks failed: ${failed[*]}"
exit 1
fi
echo "All selected checks passed."
}
case "${1:-}" in
validate) validate_inputs ;;
install) install_sdk ;;
run) run_checks ;;
*)
echo "::error::[configuration] usage: quality-checks-csharp.sh validate|install|run" >&2
exit 2
;;
esac
+2 -1
View File
@@ -1,4 +1,4 @@
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
<!-- translation of Capabilities.md, source sha256 1f12a6b27e5d -->
> Dette er en oversættelse af [`Capabilities`](Capabilities). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
@@ -15,4 +15,5 @@ Rækker, der siger Implementeret eller Vejledninger er skrevet, findes i dag. Re
| Tilslutning af et repository, administration af runners, fejlfinding | Vejledninger er skrevet ([tilslutning](Onboarding.da), [fejlfinding](Troubleshooting.da)); scoped levering til alle fire organisationers repositories er verificeret (MIL-002) |
| Publicering af et repositorys wiki fra `wiki/` (tilmelding, leveres til alle organisationer) | Implementeret i `.gitea/scoped_workflows/publish-wiki.yml`, med offline-tests; et pilotforsøg i et andet repository publicerer sin wiki (MIL-006) |
| Fælles kvalitetskontrol (Python og shell) | Implementeret som det genbrugelige workflow `.gitea/workflows/quality-checks.yml`, med offline-tests og et forsøg i en anden organisation; taget i brug i RepoFoundry ([vejledning](QualityChecksPythonShell.da)) |
| Fælles kvalitetskontrol (C og C++, C#) | Implementeret som de genbrugelige workflows `.gitea/workflows/quality-checks-cpp.yml` og `.gitea/workflows/quality-checks-csharp.yml` med præcise værktøjsversioner og offline-tests; endnu ikke brugt i et andet repository (MIL-007) ([vejledning til C og C++](QualityChecksCpp.da), [vejledning til C#](QualityChecksCSharp.da)) |
| Versioneret udgivelse og publicering | Udgivelsesproces, changelog og opgraderingsvejledning er defineret; udgivelsesworkflowet findes, og `v1.0.0` er udgivet (MIL-004) ([vejledning](Upgrading.da)) |
+1
View File
@@ -15,4 +15,5 @@ Rows that say Implemented or Guides written exist today. The rest is planned and
| Onboard a repository, manage runners, diagnose failures | Guides written ([onboarding](Onboarding), [troubleshooting](Troubleshooting)); scoped delivery to the repositories of all four organizations verified (MIL-002) |
| Publish a repository wiki from `wiki/` (opt-in, delivered to every organization) | Implemented in `.gitea/scoped_workflows/publish-wiki.yml`, with offline tests; a pilot in a second repository publishes its wiki (MIL-006) |
| Shared quality checks (Python and shell) | Implemented as the reusable workflow `.gitea/workflows/quality-checks.yml`, with offline tests and a trial in a second organization; adopted in RepoFoundry ([guide](QualityChecksPythonShell)) |
| Shared quality checks (C and C++, C#) | Implemented as the reusable workflows `.gitea/workflows/quality-checks-cpp.yml` and `.gitea/workflows/quality-checks-csharp.yml` with exact tool versions and offline tests; not yet used in another repository (MIL-007) ([C and C++ guide](QualityChecksCpp), [C# guide](QualityChecksCSharp)) |
| Versioned release and publishing | Release process, changelog and upgrade guide defined; the release workflow exists and `v1.0.0` is released (MIL-004) ([guide](Upgrading)) |
+2 -1
View File
@@ -1,4 +1,4 @@
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
<!-- translation of Capabilities.md, source sha256 1f12a6b27e5d -->
> Ini ialah terjemahan [`Capabilities`](Capabilities). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
@@ -15,4 +15,5 @@ Baris yang menyatakan Dilaksanakan atau Panduan telah ditulis wujud hari ini. Se
| Menyertakan repositori, mengurus runner, mendiagnosis kegagalan | Panduan telah ditulis ([menyertakan repositori](Onboarding.ms), [diagnosis](Troubleshooting.ms)); penghantaran scoped ke repositori keempat-empat organisasi telah disahkan (MIL-002) |
| Menerbitkan wiki repositori daripada `wiki/` (pilih menyertai, dihantar ke setiap organisasi) | Dilaksanakan dalam `.gitea/scoped_workflows/publish-wiki.yml`, dengan ujian luar talian; satu juruterbang dalam repositori kedua menerbitkan wikinya (MIL-006) |
| Semakan kualiti bersama (Python dan shell) | Dilaksanakan sebagai aliran kerja boleh guna semula `.gitea/workflows/quality-checks.yml`, dengan ujian luar talian dan percubaan dalam organisasi kedua; digunakan dalam RepoFoundry ([panduan](QualityChecksPythonShell.ms)) |
| Semakan kualiti bersama (C dan C++, C#) | Dilaksanakan sebagai aliran kerja boleh guna semula `.gitea/workflows/quality-checks-cpp.yml` dan `.gitea/workflows/quality-checks-csharp.yml` dengan versi alat yang tepat dan ujian luar talian; belum digunakan dalam repositori lain (MIL-007) ([panduan C dan C++](QualityChecksCpp.ms), [panduan C#](QualityChecksCSharp.ms)) |
| Keluaran berversi dan penerbitan | Proses keluaran, changelog dan panduan naik taraf telah ditakrifkan; aliran kerja keluaran sudah ada dan `v1.0.0` telah dikeluarkan (MIL-004) ([panduan](Upgrading.ms)) |
+148 -6
View File
@@ -1,4 +1,4 @@
<!-- translation of Home.md, source sha256 8d1f5ed6df38 -->
<!-- translation of Home.md, source sha256 5751829e99af -->
> Dette er en oversættelse af [`Home`](Home). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
@@ -13,19 +13,22 @@ En samling af genbrugelige Gitea Actions-workflows til DevOps-professionelle og
Dette repository er den centrale samling af genbrugelig automatisering til TirSystems repositories. Det primære repository ligger på `git.tirsystem.com` (Gitea) og spejles med push til GitHub.
Det indeholder fem workflows: synkronisering af metadata til GitHub-spejlet, publicering af wiki, fælles kvalitetskontrol, et udgivelsesworkflow og repositoryets egen validering. De er listet med formål og diagram under [Workflows](#workflows).
Det indeholder otte workflows: synkronisering af metadata til GitHub-spejlet, publicering af wiki, fælles kvalitetskontrol for Python og shell, for C og C++ og for C#, et udgivelsesworkflow, publicering af accepterede milepæle og repositoryets egen validering. De er listet med formål og diagram under [Workflows](#workflows).
## Workflows
Der er fem workflows i dette repository. Et **scoped** workflow leveres af instansen til alle repositories i TirSystem-organisationerne og kræver intet i repositoryet; et **genbrugeligt** workflow kaldes fra et repository med `uses:`; de øvrige kører kun her. Diagrammerne er PlantUML-kildekode og er på engelsk.
Der er otte workflows i dette repository. Et **scoped** workflow leveres af instansen til alle repositories i TirSystem-organisationerne og kræver intet i repositoryet; et **genbrugeligt** workflow kaldes fra et repository med `uses:`; de øvrige kører kun her. Diagrammerne er PlantUML-kildekode og er på engelsk.
| Workflow | Fil | Type | Starter ved | Formål |
| --- | --- | --- | --- | --- |
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push til `main`, manuelt, dagligt kl. 03:17 UTC | Kopierer beskrivelsen og emnerne for et Gitea-repository til dets GitHub push-spejl |
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, tilmelding med `wiki/.publish` | push til `main`, der ændrer `wiki/**`, manuelt | Publicerer siderne i `wiki/` til repositoryets wiki |
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Genbrugeligt (`workflow_call`) | et kald fra et andet repository | Kører ruff, mypy, shellcheck og shfmt på de sporede filer og ændrer intet |
| Quality checks C++ | [`quality-checks-cpp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-cpp.yml) | Genbrugeligt (`workflow_call`) | et kald fra et andet repository | Kører clang-format og clang-tidy i præcise versioner på de sporede C- og C++-filer og ændrer intet |
| Quality checks C# | [`quality-checks-csharp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-csharp.yml) | Genbrugeligt (`workflow_call`) | et kald fra et andet repository | Kører `dotnet format` og `dotnet build` på et præcist .NET SDK 10 eller nyere og ændrer intet |
| Release | [`release.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/release.yml) | Kun dette repository | manuelt | Opretter versionstagget, udgivelsessiden og major-tagget efter kontrollerne |
| Publicering af accepterede milepæle | [`sync-milestones.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/sync-milestones.yml) | Kun dette repository | push til `main`, der ændrer `docs/milestones/**` eller `docs/sqa/reviews/**`, manuelt (tørkørsel som standard) | Opretter eller opdaterer Gitea-milepælen og issues for hver milepæl, der er Accepted med en Go-gennemgang |
| Validate workflows | [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml) | Kun dette repository | pull request, push til `main`, manuelt | Læser hvert workflow som YAML og kører offline-testene |
### Synkronisering af GitHub-metadata
@@ -184,6 +187,96 @@ deactivate Workflow
@enduml
```
### Kvalitetskontrol C++
Et genbrugeligt workflow til C og C++, kaldt med `uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1` (ADR-0008). Repositoryet skal have en `.clang-format`; en `.clang-tidy` og en compile-database er valgfrie.
#### Workflow
```plantuml
@startuml
title Shared quality checks for C and C++ (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-cpp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-cpp" as Workflow
participant "PyPI" as PyPI
Caller -> Workflow: workflow_call with working-directory, std,\ncompile-commands-dir and tool versions
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or a version is not exact
Workflow --> Caller: Fail with [configuration]
end
Workflow -> PyPI: Install clang-format and clang-tidy at the exact versions
PyPI --> Workflow: Tools installed
alt no C or C++ file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no .clang-format, or compile-commands-dir\nwithout compile_commands.json
Workflow --> Caller: Fail with [configuration]
else
Workflow -> Workflow: clang-format --dry-run -Werror on all files
Workflow -> Workflow: clang-tidy on the C++ files (-std=std)\nand on the C files (or with the compile database)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Kvalitetskontrol C#
Et genbrugeligt workflow til C#, kaldt med `uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1` (ADR-0008). Det installerer det præcise .NET SDK, som `dotnet-sdk-version` angiver (10 eller nyere), og skal bruge netværket til pakkegendannelsen.
#### Workflow
```plantuml
@startuml
title Shared quality checks for C# (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-csharp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-csharp" as Workflow
participant "dot.net\n(dotnet-install.sh)" as DotNet
Caller -> Workflow: workflow_call with working-directory,\nproject and dotnet-sdk-version
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or the SDK is not an exact\nstable version 10 or later
Workflow --> Caller: Fail with [configuration]
end
Workflow -> DotNet: Install the exact .NET SDK version
DotNet --> Workflow: SDK installed
alt no C# file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no solution or project, or several without the project input
Workflow --> Caller: Fail with [configuration] that names them
else
Workflow -> Workflow: dotnet format --verify-no-changes
Workflow -> Workflow: dotnet build -warnaserror\n(package restore needs the network)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Udgivelse
Startes manuelt af en vedligeholder; med `dry_run` `true` (standard) kontrollerer det kun (se [udgivelsesprocessen](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/release-process.md)).
@@ -233,6 +326,54 @@ deactivate Workflow
@enduml
```
### Publicering af accepterede milepæle
Permanent tilladelse til at publicere: ved et push til `main`, der ændrer milepælene eller deres gennemgange, oprettes eller opdateres hver milepæl, hvis seneste række i Version History er Accepted, og hvis seneste gennemgang er en Go, på Gitea med sine opgaver som issues. Intet lukkes eller slettes. En manuel kørsel er en tørkørsel, medmindre `dry_run` slås fra. Det bruger secret'en `TOKEN_FOR_GITEA` og `--accepted-only`-reglen i det monterede framework (v0.5.0 eller nyere).
#### Workflow
```plantuml
@startuml
title Publish accepted milestones (this repository)
autonumber
actor "Push to main that changes\ndocs/milestones/** or docs/sqa/reviews/**,\nor manual trigger" as Trigger
participant "Gitea Actions\nsync-milestones" as Workflow
participant "framework/scripts/\nsync-project.sh" as Script
participant "Gitea REST API" as Gitea
Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the project and the framework\nsubmodules over HTTPS with TOKEN_FOR_GITEA
Workflow -> Script: --accepted-only (dry run)\nor --accepted-only --apply
activate Script
loop for each docs/milestones/mil-*.md
alt latest Version History row is not Accepted,\nor the latest review record is not a Go
Script -> Script: Skip with the reason on stderr
else
alt dry run
Script -> Script: Print the plan, no network call
else
Script -> Gitea: Create or update the Milestone\nand one Issue per task row
Gitea --> Script: Milestone and issue numbers
end
end
end
note right of Script
Nothing is closed or deleted.
Each real run edits the issues
of every accepted milestone.
end note
Script --> Workflow: Done, or "nothing to publish"
deactivate Script
Workflow --> Trigger: Workflow result
deactivate Workflow
@enduml
```
### Validering af workflows
Repositoryets egen validering: de offline-tests, der er en betingelse for hver pull request.
@@ -252,7 +393,7 @@ Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the repository
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
Workflow -> Workflow: Run pytest on tests/ (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
alt a test fails
Workflow --> Trigger: Workflow fails (the pull request is not ready)
@@ -299,9 +440,10 @@ Workflow-filerne og scripts i `tools/` valideres af offline-tests, som hverken k
python3 -m venv .venv
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -r tests/requirements.txt
python -m pytest -q tests
python -m coverage run -m pytest -q tests
python -m coverage report
```
De samme kontroller kører ved hver pull request og hvert push til `main` gennem [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). De parser alle workflows som YAML, kontrollerer at ingen indlejrer Python, kompilerer scripts i `tools/`, kræver eksplicitte jobtilladelser og tester parsing af credentials, parsing af push-spejlets adresse og synkroniserings- og publiceringsforløbene mod et falsk API.
De samme kontroller kører ved hver pull request og hvert push til `main` gennem [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). De parser alle workflows som YAML, kontrollerer at ingen indlejrer Python, kompilerer scripts i `tools/`, kræver eksplicitte jobtilladelser og tester parsing af credentials, parsing af push-spejlets adresse og synkroniserings- og publiceringsforløbene mod et falsk API. Kørslen fejler, når linje- og forgreningsdækningen af `tools/` er under 95 % (`.coveragerc`).
Efter en ændring af synkroniseringsworkflowet skal du også starte **Sync GitHub mirror metadata** manuelt i Gitea og sammenligne beskrivelsen og emnerne på GitHub-spejlet.
+147 -5
View File
@@ -13,19 +13,22 @@ A collection of reusable Gitea Actions workflows for DevOps professionals and so
This repository is the central collection of reusable automation for TirSystem repositories. The primary repository lives at `git.tirsystem.com` (Gitea) and is push-mirrored to GitHub.
It contains five workflows: metadata sync to the GitHub mirror, wiki publishing, shared quality checks, a release workflow and the repository's own validation. They are listed with their purpose and a diagram under [Workflows](#workflows).
It contains eight workflows: metadata sync to the GitHub mirror, wiki publishing, shared quality checks for Python and shell, for C and C++ and for C#, a release workflow, the publishing of accepted milestones and the repository's own validation. They are listed with their purpose and a diagram under [Workflows](#workflows).
## Workflows
Five workflows live in this repository. A **scoped** workflow is delivered by the instance to every repository of the TirSystem organizations and needs nothing in the repository; a **reusable** workflow is called by a repository with `uses:`; the others run only here. The diagrams are PlantUML source.
Eight workflows live in this repository. A **scoped** workflow is delivered by the instance to every repository of the TirSystem organizations and needs nothing in the repository; a **reusable** workflow is called by a repository with `uses:`; the others run only here. The diagrams are PlantUML source.
| Workflow | File | Kind | Starts on | Purpose |
| --- | --- | --- | --- | --- |
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push to `main`, manual, daily 03:17 UTC | Copies the description and topics of a Gitea repository to its GitHub push mirror |
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, opt-in with `wiki/.publish` | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki |
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Reusable (`workflow_call`) | a call from another repository | Runs ruff, mypy, shellcheck and shfmt on the tracked files and changes nothing |
| Quality checks C++ | [`quality-checks-cpp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-cpp.yml) | Reusable (`workflow_call`) | a call from another repository | Runs clang-format and clang-tidy at exact versions on the tracked C and C++ files and changes nothing |
| Quality checks C# | [`quality-checks-csharp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-csharp.yml) | Reusable (`workflow_call`) | a call from another repository | Runs `dotnet format` and `dotnet build` on an exact .NET SDK 10 or later and changes nothing |
| Release | [`release.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/release.yml) | This repository only | manual | Creates the version tag, the release page and the major tag after the checks |
| Publish accepted milestones | [`sync-milestones.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/sync-milestones.yml) | This repository only | push to `main` that changes `docs/milestones/**` or `docs/sqa/reviews/**`, manual (dry run by default) | Creates or updates the Gitea milestone and issues of every milestone that is Accepted with a Go review |
| Validate workflows | [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml) | This repository only | pull request, push to `main`, manual | Parses every workflow and runs the offline tests |
### Sync GitHub metadata
@@ -184,6 +187,96 @@ deactivate Workflow
@enduml
```
### Quality checks C++
A reusable workflow for C and C++, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1` (ADR-0008). The repository needs a `.clang-format`; a `.clang-tidy` and a compile database are optional.
#### Workflow
```plantuml
@startuml
title Shared quality checks for C and C++ (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-cpp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-cpp" as Workflow
participant "PyPI" as PyPI
Caller -> Workflow: workflow_call with working-directory, std,\ncompile-commands-dir and tool versions
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or a version is not exact
Workflow --> Caller: Fail with [configuration]
end
Workflow -> PyPI: Install clang-format and clang-tidy at the exact versions
PyPI --> Workflow: Tools installed
alt no C or C++ file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no .clang-format, or compile-commands-dir\nwithout compile_commands.json
Workflow --> Caller: Fail with [configuration]
else
Workflow -> Workflow: clang-format --dry-run -Werror on all files
Workflow -> Workflow: clang-tidy on the C++ files (-std=std)\nand on the C files (or with the compile database)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Quality checks C#
A reusable workflow for C#, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1` (ADR-0008). It installs the exact .NET SDK given by `dotnet-sdk-version` (10 or later) and needs the network for the package restore.
#### Workflow
```plantuml
@startuml
title Shared quality checks for C# (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-csharp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-csharp" as Workflow
participant "dot.net\n(dotnet-install.sh)" as DotNet
Caller -> Workflow: workflow_call with working-directory,\nproject and dotnet-sdk-version
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or the SDK is not an exact\nstable version 10 or later
Workflow --> Caller: Fail with [configuration]
end
Workflow -> DotNet: Install the exact .NET SDK version
DotNet --> Workflow: SDK installed
alt no C# file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no solution or project, or several without the project input
Workflow --> Caller: Fail with [configuration] that names them
else
Workflow -> Workflow: dotnet format --verify-no-changes
Workflow -> Workflow: dotnet build -warnaserror\n(package restore needs the network)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Release
Started by hand by a maintainer; with `dry_run` `true` (the default) it only checks (see the [release process](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/release-process.md)).
@@ -233,6 +326,54 @@ deactivate Workflow
@enduml
```
### Publish accepted milestones
Standing authorization to publish: on a push to `main` that changes the milestones or their reviews, every milestone whose latest Version History row is Accepted and whose latest review is a Go is created or updated on Gitea with its tasks as issues. Nothing is closed or deleted. A manual run is a dry run unless `dry_run` is switched off. It uses the secret `TOKEN_FOR_GITEA` and the `--accepted-only` rule of the mounted framework (v0.5.0 or later).
#### Workflow
```plantuml
@startuml
title Publish accepted milestones (this repository)
autonumber
actor "Push to main that changes\ndocs/milestones/** or docs/sqa/reviews/**,\nor manual trigger" as Trigger
participant "Gitea Actions\nsync-milestones" as Workflow
participant "framework/scripts/\nsync-project.sh" as Script
participant "Gitea REST API" as Gitea
Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the project and the framework\nsubmodules over HTTPS with TOKEN_FOR_GITEA
Workflow -> Script: --accepted-only (dry run)\nor --accepted-only --apply
activate Script
loop for each docs/milestones/mil-*.md
alt latest Version History row is not Accepted,\nor the latest review record is not a Go
Script -> Script: Skip with the reason on stderr
else
alt dry run
Script -> Script: Print the plan, no network call
else
Script -> Gitea: Create or update the Milestone\nand one Issue per task row
Gitea --> Script: Milestone and issue numbers
end
end
end
note right of Script
Nothing is closed or deleted.
Each real run edits the issues
of every accepted milestone.
end note
Script --> Workflow: Done, or "nothing to publish"
deactivate Script
Workflow --> Trigger: Workflow result
deactivate Workflow
@enduml
```
### Validate workflows
The repository's own validation: the offline tests that gate every pull request.
@@ -252,7 +393,7 @@ Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the repository
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
Workflow -> Workflow: Run pytest on tests/ (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
alt a test fails
Workflow --> Trigger: Workflow fails (the pull request is not ready)
@@ -299,9 +440,10 @@ The workflow files and the scripts in `tools/` are validated by offline tests th
python3 -m venv .venv
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -r tests/requirements.txt
python -m pytest -q tests
python -m coverage run -m pytest -q tests
python -m coverage report
```
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API.
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API. The run fails when the line and branch coverage of `tools/` falls below 95% (`.coveragerc`).
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
+148 -6
View File
@@ -1,4 +1,4 @@
<!-- translation of Home.md, source sha256 8d1f5ed6df38 -->
<!-- translation of Home.md, source sha256 5751829e99af -->
> Ini ialah terjemahan [`Home`](Home). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
@@ -13,19 +13,22 @@ Koleksi aliran kerja (workflow) Gitea Actions yang boleh digunakan semula untuk
Repositori ini ialah koleksi pusat bagi automasi yang boleh digunakan semula untuk repositori TirSystem. Repositori utama berada di `git.tirsystem.com` (Gitea) dan dicerminkan dengan push ke GitHub.
Ia mengandungi lima aliran kerja: penyegerakan metadata ke cermin GitHub, penerbitan wiki, semakan kualiti bersama, aliran kerja keluaran dan pengesahan repositori sendiri. Ia disenaraikan dengan tujuan dan rajah di bawah [Aliran kerja](#aliran-kerja).
Ia mengandungi lapan aliran kerja: penyegerakan metadata ke cermin GitHub, penerbitan wiki, semakan kualiti bersama untuk Python dan shell, untuk C dan C++ serta untuk C#, aliran kerja keluaran, penerbitan pencapaian (milestone) yang diterima dan pengesahan repositori sendiri. Ia disenaraikan dengan tujuan dan rajah di bawah [Aliran kerja](#aliran-kerja).
## Aliran kerja
Terdapat lima aliran kerja dalam repositori ini. Aliran kerja **scoped** dihantar oleh instans ke setiap repositori organisasi TirSystem dan tidak memerlukan apa-apa dalam repositori; aliran kerja **boleh guna semula** dipanggil oleh sebuah repositori dengan `uses:`; yang lain hanya berjalan di sini. Rajah ialah kod sumber PlantUML dan dalam bahasa Inggeris.
Terdapat lapan aliran kerja dalam repositori ini. Aliran kerja **scoped** dihantar oleh instans ke setiap repositori organisasi TirSystem dan tidak memerlukan apa-apa dalam repositori; aliran kerja **boleh guna semula** dipanggil oleh sebuah repositori dengan `uses:`; yang lain hanya berjalan di sini. Rajah ialah kod sumber PlantUML dan dalam bahasa Inggeris.
| Aliran kerja | Fail | Jenis | Bermula apabila | Tujuan |
| --- | --- | --- | --- | --- |
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push ke `main`, manual, setiap hari 03:17 UTC | Menyalin penerangan dan topik repositori Gitea ke push mirror GitHub-nya |
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, pilih menyertai dengan `wiki/.publish` | push ke `main` yang mengubah `wiki/**`, manual | Menerbitkan halaman dalam `wiki/` ke wiki repositori |
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Boleh guna semula (`workflow_call`) | panggilan daripada repositori lain | Menjalankan ruff, mypy, shellcheck dan shfmt pada fail yang dijejaki dan tidak mengubah apa-apa |
| Quality checks C++ | [`quality-checks-cpp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-cpp.yml) | Boleh guna semula (`workflow_call`) | panggilan daripada repositori lain | Menjalankan clang-format dan clang-tidy pada versi tepat pada fail C dan C++ yang dijejaki dan tidak mengubah apa-apa |
| Quality checks C# | [`quality-checks-csharp.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks-csharp.yml) | Boleh guna semula (`workflow_call`) | panggilan daripada repositori lain | Menjalankan `dotnet format` dan `dotnet build` pada .NET SDK 10 atau lebih baharu yang tepat dan tidak mengubah apa-apa |
| Release | [`release.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/release.yml) | Repositori ini sahaja | manual | Mencipta tag versi, halaman keluaran dan tag major selepas semakan |
| Menerbitkan milestone yang diterima | [`sync-milestones.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/sync-milestones.yml) | Repositori ini sahaja | push ke `main` yang mengubah `docs/milestones/**` atau `docs/sqa/reviews/**`, manual (larian percubaan secara lalai) | Mencipta atau mengemas kini milestone Gitea dan isu bagi setiap milestone yang Accepted dengan semakan Go |
| Validate workflows | [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml) | Repositori ini sahaja | pull request, push ke `main`, manual | Menghurai setiap aliran kerja sebagai YAML dan menjalankan ujian luar talian |
### Menyegerakkan metadata GitHub
@@ -184,6 +187,96 @@ deactivate Workflow
@enduml
```
### Semakan kualiti C++
Aliran kerja boleh guna semula untuk C dan C++, dipanggil dengan `uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1` (ADR-0008). Repositori mesti mempunyai `.clang-format`; `.clang-tidy` dan pangkalan data kompilasi adalah pilihan.
#### Aliran kerja
```plantuml
@startuml
title Shared quality checks for C and C++ (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-cpp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-cpp" as Workflow
participant "PyPI" as PyPI
Caller -> Workflow: workflow_call with working-directory, std,\ncompile-commands-dir and tool versions
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or a version is not exact
Workflow --> Caller: Fail with [configuration]
end
Workflow -> PyPI: Install clang-format and clang-tidy at the exact versions
PyPI --> Workflow: Tools installed
alt no C or C++ file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no .clang-format, or compile-commands-dir\nwithout compile_commands.json
Workflow --> Caller: Fail with [configuration]
else
Workflow -> Workflow: clang-format --dry-run -Werror on all files
Workflow -> Workflow: clang-tidy on the C++ files (-std=std)\nand on the C files (or with the compile database)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Semakan kualiti C#
Aliran kerja boleh guna semula untuk C#, dipanggil dengan `uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1` (ADR-0008). Ia memasang .NET SDK tepat yang diberikan oleh `dotnet-sdk-version` (10 atau lebih baharu) dan memerlukan rangkaian untuk pemulihan pakej.
#### Aliran kerja
```plantuml
@startuml
title Shared quality checks for C# (reusable workflow)
autonumber
actor "Calling repository\nuses: ...quality-checks-csharp.yml@v1" as Caller
participant "Gitea Actions\nquality-checks-csharp" as Workflow
participant "dot.net\n(dotnet-install.sh)" as DotNet
Caller -> Workflow: workflow_call with working-directory,\nproject and dotnet-sdk-version
activate Workflow
Workflow -> Workflow: Check out the caller and the shared script
Workflow -> Workflow: Validate the inputs
alt an input is invalid or the SDK is not an exact\nstable version 10 or later
Workflow --> Caller: Fail with [configuration]
end
Workflow -> DotNet: Install the exact .NET SDK version
DotNet --> Workflow: SDK installed
alt no C# file is tracked
Workflow --> Caller: Notice: nothing was checked, pass
else no solution or project, or several without the project input
Workflow --> Caller: Fail with [configuration] that names them
else
Workflow -> Workflow: dotnet format --verify-no-changes
Workflow -> Workflow: dotnet build -warnaserror\n(package restore needs the network)
alt any tool failed
Workflow --> Caller: Fail with tool, file and line in the log
else
Workflow --> Caller: All selected checks passed
end
end
deactivate Workflow
@enduml
```
### Keluaran
Dimulakan secara manual oleh penyelenggara; dengan `dry_run` `true` (lalai) ia hanya menyemak (lihat [proses keluaran](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/release-process.md)).
@@ -233,6 +326,54 @@ deactivate Workflow
@enduml
```
### Menerbitkan milestone yang diterima
Kebenaran tetap untuk menerbitkan: pada push ke `main` yang mengubah milestone atau semakannya, setiap milestone yang baris terkini Version History-nya Accepted dan semakan terkininya Go dicipta atau dikemas kini di Gitea dengan tugasnya sebagai isu. Tiada apa-apa ditutup atau dipadam. Larian manual ialah larian percubaan kecuali `dry_run` dimatikan. Ia menggunakan secret `TOKEN_FOR_GITEA` dan peraturan `--accepted-only` framework yang dipasang (v0.5.0 atau lebih baharu).
#### Aliran kerja
```plantuml
@startuml
title Publish accepted milestones (this repository)
autonumber
actor "Push to main that changes\ndocs/milestones/** or docs/sqa/reviews/**,\nor manual trigger" as Trigger
participant "Gitea Actions\nsync-milestones" as Workflow
participant "framework/scripts/\nsync-project.sh" as Script
participant "Gitea REST API" as Gitea
Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the project and the framework\nsubmodules over HTTPS with TOKEN_FOR_GITEA
Workflow -> Script: --accepted-only (dry run)\nor --accepted-only --apply
activate Script
loop for each docs/milestones/mil-*.md
alt latest Version History row is not Accepted,\nor the latest review record is not a Go
Script -> Script: Skip with the reason on stderr
else
alt dry run
Script -> Script: Print the plan, no network call
else
Script -> Gitea: Create or update the Milestone\nand one Issue per task row
Gitea --> Script: Milestone and issue numbers
end
end
end
note right of Script
Nothing is closed or deleted.
Each real run edits the issues
of every accepted milestone.
end note
Script --> Workflow: Done, or "nothing to publish"
deactivate Script
Workflow --> Trigger: Workflow result
deactivate Workflow
@enduml
```
### Mengesahkan aliran kerja
Pengesahan repositori sendiri: ujian luar talian yang menjadi syarat bagi setiap pull request.
@@ -252,7 +393,7 @@ Trigger -> Workflow: Start workflow
activate Workflow
Workflow -> Workflow: Check out the repository
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
Workflow -> Workflow: Run pytest on tests/ (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
alt a test fails
Workflow --> Trigger: Workflow fails (the pull request is not ready)
@@ -299,9 +440,10 @@ Fail aliran kerja dan skrip dalam `tools/` disahkan oleh ujian luar talian yang
python3 -m venv .venv
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -r tests/requirements.txt
python -m pytest -q tests
python -m coverage run -m pytest -q tests
python -m coverage report
```
Semakan yang sama dijalankan pada setiap pull request dan setiap push ke `main` melalui [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). Semakan itu menghurai setiap aliran kerja sebagai YAML, memastikan tiada yang menanam Python, mengkompil skrip dalam `tools/`, memerlukan kebenaran kerja yang jelas, dan menguji penghuraian kelayakan (credentials), penghuraian alamat push mirror serta aliran penyegerakan dan penerbitan terhadap API palsu.
Semakan yang sama dijalankan pada setiap pull request dan setiap push ke `main` melalui [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). Semakan itu menghurai setiap aliran kerja sebagai YAML, memastikan tiada yang menanam Python, mengkompil skrip dalam `tools/`, memerlukan kebenaran kerja yang jelas, dan menguji penghuraian kelayakan (credentials), penghuraian alamat push mirror serta aliran penyegerakan dan penerbitan terhadap API palsu. Larian gagal apabila liputan baris dan cabang `tools/` di bawah 95% (`.coveragerc`).
Selepas perubahan pada aliran kerja penyegerakan, cetuskan juga **Sync GitHub mirror metadata** secara manual dalam Gitea dan bandingkan penerangan dan topik pada cermin GitHub.
+85
View File
@@ -0,0 +1,85 @@
<!-- translation of QualityChecksCSharp.md, source sha256 2baa0d48f712 -->
> Dette er en oversættelse af [`QualityChecksCSharp`](QualityChecksCSharp). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
[English](QualityChecksCSharp) | Dansk | [Bahasa Melayu](QualityChecksCSharp.ms)
# Aflæsning af resultater fra kvalitetskontrol af C#
Sådan kalder en softwareudvikler den fælles kvalitetskontrol af C#, aflæser en mislykket kørsel og får den til at bestå. Workflowet kontrollerer formateringen og bygger en solution eller et projekt med advarsler som fejl, på et præcist .NET SDK i version 10 eller nyere, ændrer ingen fil og kræver ingen secret. Dets kontrakt er ADR-0008 i dette repository.
## Kald af workflowet
```yaml
name: Quality C#
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1
with:
project: src/App.sln
```
| Input | Standard | Betydning |
| --- | --- | --- |
| `working-directory` | `.` | Mappe, relativt til repositoryets rod, hvis filer kontrolleres |
| `project` | tom | Solution- eller projektfil, relativt til `working-directory`; tom bruger den eneste sporede `*.sln` eller `*.slnx`, ellers den eneste `*.csproj`, der er sporet dér |
| `dotnet-sdk-version` | `10.0.401` | Præcis version af .NET SDK, 10 eller nyere; en kanal som `10.0`, et interval og en version under 10 afvises |
| `tools-ref` | `v1` | Tag eller gren i `TirSystem/github-action`, hvorfra scriptet `tools/quality-checks-csharp.sh` hentes |
Henvis til workflowet ved major-tagget (`@v1`) eller et præcist tag, aldrig ved `main`. Et kald ved et præcist tag er kun fuldt fastlåst, når `tools-ref` angiver samme tag. Se opgraderingsvejledningen. SDK-versionen er præcis: at hæve standardværdien er en ny udgivelse af dette repository, ikke en stille ændring.
## Hvad repositoryet skal have
- En solution eller et projekt, der bygger med SDK'et. Flere kandidater kræver inputtet `project`; C#-filer uden solution eller projekt fejler med `[configuration]`.
- Netværk: `dotnet format` og `dotnet build` gendanner projektets NuGet-pakker i kørslen.
- Regler i `.editorconfig` (og de analysatorer, projektet slår til, for eksempel med `AnalysisLevel` og `EnforceCodeStyleInBuild`) afgør, hvad et fund er.
## Hvad der kontrolleres
| Filer | Værktøj | Hvad det melder |
| --- | --- | --- |
| solutionen eller projektet | `dotnet format --verify-no-changes` | formatering og stil, der afviger fra `.editorconfig` |
| det samme | `dotnet build -warnaserror` | compiler- og analysatoradvarsler, som får bygningen til at fejle |
Usporede filer kontrolleres ikke. Et repository uden `*.cs`-filer består med en bemærkning. Projektets tests køres ikke.
## Aflæsning af en kørsel
1. Åbn statuskontrollen på pull requesten og derefter jobbet `quality-checks-csharp`.
2. Hvert værktøj har sin egen logggruppe. Begge kører, selv om det første fejlede, så én kørsel viser alle fund.
3. Et værktøj ender med `PASS <værktøj>` eller `FAIL <værktøj>`; sidste linje i en mislykket kørsel nævner dem: `Quality checks failed: dotnet format --verify-no-changes`.
4. Et fund skrives af værktøjet selv som `path(line,column): CODE message`.
## Typiske fejl og rettelser
| Værktøj | Hvad loggen viser | Rettelse |
| --- | --- | --- |
| `dotnet format --verify-no-changes` | `Program.cs(12,5): error WHITESPACE: Fix whitespace formatting` | Kør `dotnet format <projekt>`, og commit |
| `dotnet build -warnaserror` | `CS8602: Dereference of a possibly null reference` | Ret koden (null-kontrol); undertryk ikke advarslen uden en begrundelse |
| `dotnet build -warnaserror` | `IDE0005: Using directive is unnecessary` | Fjern direktivet |
For at gentage en kørsel på din egen maskine skal du bruge samme SDK:
```bash
dotnet --version # 10.0.401
dotnet format src/App.sln --verify-no-changes
dotnet build src/App.sln -warnaserror
```
## Når workflowet selv fejler
| Meddelelse | Årsag | Rettelse |
| --- | --- | --- |
| `[configuration] dotnet-sdk-version '<x>' is not an exact stable version 10 or later` | En kanal, et interval, en preview eller en version under 10 | Angiv en præcis version som `10.0.401` |
| `[configuration] working-directory must be a relative path inside the repository.` | En absolut sti eller `..` | Brug en sti inde i repositoryet |
| `[configuration] C# files exist but no solution or project was found` | Repositoryet har `*.cs`-filer og ingen `*.sln`, `*.slnx` eller `*.csproj` i arbejdsmappen | Tilføj en, eller sæt `working-directory` |
| `[configuration] Several solutions or projects were found` | Mere end én kandidat | Sæt inputtet `project` |
| Installationstrinnet fejler | `dot.net` eller runnerens netværk kan ikke nås | Kør jobbet igen; se [troubleshooting.md](troubleshooting.md) |
+101
View File
@@ -0,0 +1,101 @@
<!-- Generated from guides/quality-checks-csharp.md by tools/build_wiki.py. Edit the source, not this page. -->
> This page is generated from [`guides/quality-checks-csharp.md`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/quality-checks-csharp.md). Changes made here are overwritten the next time the wiki is published.
English | [Dansk](QualityChecksCSharp.da) | [Bahasa Melayu](QualityChecksCSharp.ms)
# Reading C# quality-check results
How a software engineer calls the shared C# quality checks, reads a failed run
and makes it pass. The workflow checks the formatting and builds a solution or
project with warnings as errors, on an exact .NET SDK of version 10 or later,
changes no file and needs no secret. Its contract is ADR-0008 in this
repository.
## Calling the workflow
```yaml
name: Quality C#
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1
with:
project: src/App.sln
```
| Input | Default | Meaning |
| --- | --- | --- |
| `working-directory` | `.` | Directory, relative to the repository root, whose files are checked |
| `project` | empty | Solution or project file, relative to `working-directory`; empty uses the single `*.sln` or `*.slnx`, else the single `*.csproj`, that is tracked there |
| `dotnet-sdk-version` | `10.0.401` | Exact version of the .NET SDK, 10 or later; a channel such as `10.0`, a range and a version below 10 are refused |
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks-csharp.sh` is fetched |
Reference the workflow at the major tag (`@v1`) or at an exact tag, never at
`main`. A call at an exact tag is pinned completely only when `tools-ref` names
the same tag. See the upgrade guide. The SDK version is exact: raising the
default is a new release of this repository, not a silent change.
## What the repository needs
- A solution or project that builds with the SDK. Several candidates need the
`project` input; C# files with no solution or project fail with
`[configuration]`.
- The network: `dotnet format` and `dotnet build` restore the NuGet packages of
the project in the run.
- Rules in `.editorconfig` (and the analyzers the project enables, for example
with `AnalysisLevel` and `EnforceCodeStyleInBuild`) decide what a finding is.
## What is checked
| Files | Tool | What it reports |
| --- | --- | --- |
| the solution or project | `dotnet format --verify-no-changes` | formatting and style that differ from `.editorconfig` |
| the same | `dotnet build -warnaserror` | compiler and analyzer warnings, which fail the build |
Untracked files are not checked. A repository without `*.cs` files passes with
a notice. Project tests are not run.
## Reading a run
1. Open the status check on the pull request, then the job
`quality-checks-csharp`.
2. Each tool has its own log group. Both run even when the first failed, so one
run shows all findings.
3. A tool ends with `PASS <tool>` or `FAIL <tool>`; the last line of a failed
run names them:
`Quality checks failed: dotnet format --verify-no-changes`.
4. A finding is written by the tool itself as `path(line,column): CODE message`.
## Typical failures and fixes
| Tool | What the log shows | Fix |
| --- | --- | --- |
| `dotnet format --verify-no-changes` | `Program.cs(12,5): error WHITESPACE: Fix whitespace formatting` | Run `dotnet format <project>` and commit |
| `dotnet build -warnaserror` | `CS8602: Dereference of a possibly null reference` | Fix the code (null check), do not suppress the warning without a reason |
| `dotnet build -warnaserror` | `IDE0005: Using directive is unnecessary` | Remove the directive |
To reproduce a run on your machine, use the same SDK:
```bash
dotnet --version # 10.0.401
dotnet format src/App.sln --verify-no-changes
dotnet build src/App.sln -warnaserror
```
## When the workflow itself fails
| Message | Cause | Fix |
| --- | --- | --- |
| `[configuration] dotnet-sdk-version '<x>' is not an exact stable version 10 or later` | A channel, a range, a preview or a version below 10 | Give an exact version such as `10.0.401` |
| `[configuration] working-directory must be a relative path inside the repository.` | An absolute path or `..` | Use a path inside the repository |
| `[configuration] C# files exist but no solution or project was found` | The repository has `*.cs` files and no `*.sln`, `*.slnx` or `*.csproj` in the working directory | Add one, or set `working-directory` |
| `[configuration] Several solutions or projects were found` | More than one candidate | Set the input `project` |
| The install step fails | `dot.net` or the runner network is unreachable | Re-run the job; see [troubleshooting.md](Troubleshooting) |
+85
View File
@@ -0,0 +1,85 @@
<!-- translation of QualityChecksCSharp.md, source sha256 2baa0d48f712 -->
> Ini ialah terjemahan [`QualityChecksCSharp`](QualityChecksCSharp). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
[English](QualityChecksCSharp) | [Dansk](QualityChecksCSharp.da) | Bahasa Melayu
# Membaca keputusan semakan kualiti C#
Cara seorang jurutera perisian memanggil semakan kualiti bersama untuk C#, membaca larian yang gagal dan menjadikannya lulus. Aliran kerja ini menyemak pemformatan dan membina solution atau projek dengan amaran sebagai ralat, pada .NET SDK versi 10 atau lebih baharu yang tepat, tidak mengubah sebarang fail dan tidak memerlukan secret. Kontraknya ialah ADR-0008 dalam repositori ini.
## Memanggil aliran kerja
```yaml
name: Quality C#
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-csharp.yml@v1
with:
project: src/App.sln
```
| Input | Lalai | Maksud |
| --- | --- | --- |
| `working-directory` | `.` | Direktori, relatif kepada akar repositori, yang failnya disemak |
| `project` | kosong | Fail solution atau projek, relatif kepada `working-directory`; kosong menggunakan satu-satunya `*.sln` atau `*.slnx` yang dijejaki, jika tiada maka satu-satunya `*.csproj` yang dijejaki di situ |
| `dotnet-sdk-version` | `10.0.401` | Versi tepat .NET SDK, 10 atau lebih baharu; saluran seperti `10.0`, julat dan versi di bawah 10 ditolak |
| `tools-ref` | `v1` | Tag atau cabang `TirSystem/github-action` tempat skrip `tools/quality-checks-csharp.sh` diambil |
Rujuk aliran kerja pada tag major (`@v1`) atau pada tag tepat, jangan sekali-kali pada `main`. Panggilan pada tag tepat hanya disematkan sepenuhnya apabila `tools-ref` menamakan tag yang sama. Lihat panduan naik taraf. Versi SDK adalah tepat: menaikkan nilai lalai ialah keluaran baharu repositori ini, bukan perubahan senyap.
## Apa yang diperlukan oleh repositori
- Satu solution atau projek yang boleh dibina dengan SDK. Beberapa calon memerlukan input `project`; fail C# tanpa solution atau projek gagal dengan `[configuration]`.
- Rangkaian: `dotnet format` dan `dotnet build` memulihkan pakej NuGet projek dalam larian.
- Peraturan dalam `.editorconfig` (dan penganalisis yang diaktifkan projek, contohnya dengan `AnalysisLevel` dan `EnforceCodeStyleInBuild`) menentukan apa yang dikira sebagai dapatan.
## Apa yang disemak
| Fail | Alat | Apa yang dilaporkan |
| --- | --- | --- |
| solution atau projek | `dotnet format --verify-no-changes` | pemformatan dan gaya yang berbeza daripada `.editorconfig` |
| yang sama | `dotnet build -warnaserror` | amaran pengkompil dan penganalisis, yang menggagalkan binaan |
Fail yang tidak dijejaki tidak disemak. Repositori tanpa fail `*.cs` lulus dengan satu notis. Ujian projek tidak dijalankan.
## Membaca satu larian
1. Buka semakan status pada pull request, kemudian kerja `quality-checks-csharp`.
2. Setiap alat mempunyai kumpulan lognya sendiri. Kedua-duanya dijalankan walaupun yang pertama gagal, jadi satu larian menunjukkan semua dapatan.
3. Satu alat berakhir dengan `PASS <alat>` atau `FAIL <alat>`; baris terakhir larian yang gagal menamakannya: `Quality checks failed: dotnet format --verify-no-changes`.
4. Satu dapatan ditulis oleh alat itu sendiri sebagai `path(line,column): CODE message`.
## Kegagalan biasa dan pembetulan
| Alat | Apa yang ditunjukkan log | Pembetulan |
| --- | --- | --- |
| `dotnet format --verify-no-changes` | `Program.cs(12,5): error WHITESPACE: Fix whitespace formatting` | Jalankan `dotnet format <projek>` dan commit |
| `dotnet build -warnaserror` | `CS8602: Dereference of a possibly null reference` | Betulkan kod (semakan null); jangan tindas amaran tanpa sebab |
| `dotnet build -warnaserror` | `IDE0005: Using directive is unnecessary` | Buang arahan itu |
Untuk mengulangi satu larian pada mesin anda, gunakan SDK yang sama:
```bash
dotnet --version # 10.0.401
dotnet format src/App.sln --verify-no-changes
dotnet build src/App.sln -warnaserror
```
## Apabila aliran kerja itu sendiri gagal
| Mesej | Punca | Pembetulan |
| --- | --- | --- |
| `[configuration] dotnet-sdk-version '<x>' is not an exact stable version 10 or later` | Saluran, julat, pratonton atau versi di bawah 10 | Berikan versi tepat seperti `10.0.401` |
| `[configuration] working-directory must be a relative path inside the repository.` | Laluan mutlak atau `..` | Gunakan laluan di dalam repositori |
| `[configuration] C# files exist but no solution or project was found` | Repositori mempunyai fail `*.cs` tetapi tiada `*.sln`, `*.slnx` atau `*.csproj` dalam direktori kerja | Tambah satu, atau tetapkan `working-directory` |
| `[configuration] Several solutions or projects were found` | Lebih daripada satu calon | Tetapkan input `project` |
| Langkah pemasangan gagal | `dot.net` atau rangkaian runner tidak dapat dicapai | Jalankan semula kerja; lihat [troubleshooting.md](troubleshooting.md) |
+88
View File
@@ -0,0 +1,88 @@
<!-- translation of QualityChecksCpp.md, source sha256 baf659e82523 -->
> Dette er en oversættelse af [`QualityChecksCpp`](QualityChecksCpp). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
[English](QualityChecksCpp) | Dansk | [Bahasa Melayu](QualityChecksCpp.ms)
# Aflæsning af resultater fra kvalitetskontrol af C og C++
Sådan kalder en softwareudvikler den fælles kvalitetskontrol af C og C++, aflæser en mislykket kørsel og får den til at bestå. Workflowet formatkontrollerer og analyserer statisk repositoryets C- og C++-filer med clang-værktøjer i præcise versioner, ændrer ingen fil og kræver ingen secret. Dets kontrakt er ADR-0008 i dette repository.
## Kald af workflowet
```yaml
name: Quality C++
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1
with:
std: c++20
```
| Input | Standard | Betydning |
| --- | --- | --- |
| `working-directory` | `.` | Mappe, relativt til repositoryets rod, hvis filer kontrolleres |
| `std` | `c++20` | C++-standard, som clang-tidy får, når der ikke er en compile-database, for eksempel `c++17` eller `gnu++20` |
| `compile-commands-dir` | tom | Mappe, relativt til repositoryets rod, med en `compile_commands.json`, som din pipeline har bygget før kaldet; når den er sat, bruger clang-tidy den og ignorerer `std` |
| `clang-format-version` | `23.1.3` | Præcis version af pakken clang-format |
| `clang-tidy-version` | `22.1.8` | Præcis version af pakken clang-tidy |
| `tools-ref` | `v1` | Tag eller gren i `TirSystem/github-action`, hvorfra scriptet `tools/quality-checks-cpp.sh` hentes |
Henvis til workflowet ved major-tagget (`@v1`) eller et præcist tag, aldrig ved `main`. Et kald ved et præcist tag er kun fuldt fastlåst, når `tools-ref` angiver samme tag. Se opgraderingsvejledningen. Værktøjsversionerne er præcise: en nyere version af et værktøj er en ny udgivelse af dette repository, ikke en stille ændring.
## Hvad repositoryet skal have
- En `.clang-format` i arbejdsmappen eller i en mappe over den, op til repositoryets rod. Uden en fejler kørslen med `[configuration]`, og intet værktøj kører.
- Eventuelt en `.clang-tidy` med projektets kontroller (for eksempel C++ Core Guidelines). Uden en kører workflowet compilerdiagnostik og den statiske analysator (`clang-diagnostic-*` og `clang-analyzer-*`), fordi clang-tidy selv ikke aktiverer nogen kontrol uden konfiguration.
- For præcise statiske kontroller en compile-database: byg den først (for eksempel `cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`) og angiv `compile-commands-dir: build`. Workflowet bygger ikke dit projekt.
## Hvad der kontrolleres
| Filer | Værktøj | Hvad det melder |
| --- | --- | --- |
| sporede `*.c`, `*.cc`, `*.cpp`, `*.cxx`, `*.h`, `*.hh`, `*.hpp`, `*.hxx` | `clang-format --dry-run -Werror` | formatering, der afviger fra `.clang-format` |
| de samme filer | `clang-tidy` | fund fra kontrollerne i `.clang-tidy` (eller fra `clang-diagnostic-*` og `clang-analyzer-*` uden en); `*.c`-filer kontrolleres som C17, de øvrige filer som C++-standarden i `std`; hvert fund er en fejl (`--warnings-as-errors=*`), så en advarsel får kørslen til at fejle |
Usporede filer kontrolleres ikke. Et repository uden disse filer består med en bemærkning. Der er ingen `cppcheck`: kun en gammel version findes som pakke, og gamle værktøjer køres ikke (ADR-0008).
## Aflæsning af en kørsel
1. Åbn statuskontrollen på pull requesten og derefter jobbet `quality-checks-cpp`.
2. Hvert værktøj har sin egen logggruppe. Alle værktøjer kører, selv om et tidligere fejlede, så én kørsel viser alle fund.
3. Et værktøj ender med `PASS <værktøj>` eller `FAIL <værktøj>`; sidste linje i en mislykket kørsel nævner dem: `Quality checks failed: clang-format`.
4. Et fund skrives af værktøjet selv som `path:line:column: message`. Stier er relative til `working-directory`.
## Typiske fejl og rettelser
| Værktøj | Hvad loggen viser | Rettelse |
| --- | --- | --- |
| `clang-format` | `code should be clang-formatted [-Wclang-format-violations]` | Kør `clang-format -i <fil>` med samme version, og commit |
| `clang-tidy` | `warning: ... [modernize-use-nullptr]` | Ret koden, eller slå kontrollen fra i `.clang-tidy` med en begrundelse |
| `clang-tidy` | `error: 'x.h' file not found` | Byg compile-databasen og sæt `compile-commands-dir`, eller tilføj include-stien til den |
For at gentage en kørsel på din egen maskine skal du installere de samme versioner:
```bash
python3 -m venv .qc
.qc/bin/pip install clang-format==23.1.3 clang-tidy==22.1.8
git ls-files '*.cpp' '*.hpp' | xargs .qc/bin/clang-format --dry-run -Werror
```
## Når workflowet selv fejler
| Meddelelse | Årsag | Rettelse |
| --- | --- | --- |
| `[configuration] std '<x>' is not a C++ standard` | `std` er ikke som `c++20` eller `gnu++20` | Ret inputtet |
| `[configuration] ... is not an exact version` | En værktøjsversion er et interval, en kanal eller tom | Angiv en præcis version som `23.1.3` |
| `[configuration] working-directory must be a relative path inside the repository.` | En absolut sti eller `..` | Brug en sti inde i repositoryet |
| `[configuration] No .clang-format found` | Projektet har ingen stilfil | Tilføj en `.clang-format` |
| `[configuration] compile-commands-dir '<x>' has no compile_commands.json` | Databasen blev ikke bygget før kaldet | Byg den i et tidligere trin i jobbet eller i et job, det afhænger af |
| Installationstrinnet fejler | PyPI eller runnerens netværk kan ikke nås | Kør jobbet igen; se [troubleshooting.md](troubleshooting.md) |
+106
View File
@@ -0,0 +1,106 @@
<!-- Generated from guides/quality-checks-cpp.md by tools/build_wiki.py. Edit the source, not this page. -->
> This page is generated from [`guides/quality-checks-cpp.md`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/quality-checks-cpp.md). Changes made here are overwritten the next time the wiki is published.
English | [Dansk](QualityChecksCpp.da) | [Bahasa Melayu](QualityChecksCpp.ms)
# Reading C and C++ quality-check results
How a software engineer calls the shared C and C++ quality checks, reads a
failed run and makes it pass. The workflow format-checks and statically checks
the C and C++ files of a repository with clang tools at exact versions, changes
no file and needs no secret. Its contract is ADR-0008 in this repository.
## Calling the workflow
```yaml
name: Quality C++
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1
with:
std: c++20
```
| Input | Default | Meaning |
| --- | --- | --- |
| `working-directory` | `.` | Directory, relative to the repository root, whose files are checked |
| `std` | `c++20` | C++ standard given to clang-tidy when there is no compile database, such as `c++17` or `gnu++20` |
| `compile-commands-dir` | empty | Directory, relative to the repository root, with a `compile_commands.json` that your pipeline built before the call; when set, clang-tidy uses it and ignores `std` |
| `clang-format-version` | `23.1.3` | Exact version of the clang-format package |
| `clang-tidy-version` | `22.1.8` | Exact version of the clang-tidy package |
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks-cpp.sh` is fetched |
Reference the workflow at the major tag (`@v1`) or at an exact tag, never at
`main`. A call at an exact tag is pinned completely only when `tools-ref` names
the same tag. See the upgrade guide. The tool versions are exact: a newer
version of a tool is a new release of this repository, not a silent change.
## What the repository needs
- A `.clang-format` in the working directory or in a directory above it, up to
the top of the repository. Without one the run fails with `[configuration]`
and no tool runs.
- Optionally a `.clang-tidy` with the checks of the project (for example the
C++ Core Guidelines). Without one the workflow runs the compiler diagnostics
and the static analyzer (`clang-diagnostic-*` and `clang-analyzer-*`),
because clang-tidy itself enables no check when there is no configuration.
- For precise static checks, a compile database: build it first (for example
`cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`) and pass
`compile-commands-dir: build`. The workflow does not build your project.
## What is checked
| Files | Tool | What it reports |
| --- | --- | --- |
| tracked `*.c`, `*.cc`, `*.cpp`, `*.cxx`, `*.h`, `*.hh`, `*.hpp`, `*.hxx` | `clang-format --dry-run -Werror` | formatting that differs from `.clang-format` |
| the same files | `clang-tidy` | findings of the checks of `.clang-tidy` (or of `clang-diagnostic-*` and `clang-analyzer-*` without one); `*.c` files are checked as C17, the other files as the C++ standard of `std`; every finding is an error (`--warnings-as-errors=*`), so a warning fails the run |
Untracked files are not checked. A repository without these files passes with a
notice. There is no `cppcheck`: only an old version of it is available as a
package, and old tools are not run (ADR-0008).
## Reading a run
1. Open the status check on the pull request, then the job `quality-checks-cpp`.
2. Each tool has its own log group. Every tool runs even when an earlier one
failed, so one run shows all findings.
3. A tool ends with `PASS <tool>` or `FAIL <tool>`; the last line of a failed
run names them: `Quality checks failed: clang-format`.
4. A finding is written by the tool itself as `path:line:column: message`.
Paths are relative to `working-directory`.
## Typical failures and fixes
| Tool | What the log shows | Fix |
| --- | --- | --- |
| `clang-format` | `code should be clang-formatted [-Wclang-format-violations]` | Run `clang-format -i <file>` with the same version and commit |
| `clang-tidy` | `warning: ... [modernize-use-nullptr]` | Fix the code, or switch the check off in `.clang-tidy` with a reason |
| `clang-tidy` | `error: 'x.h' file not found` | Build the compile database and set `compile-commands-dir`, or add the include path to it |
To reproduce a run on your machine, install the same versions:
```bash
python3 -m venv .qc
.qc/bin/pip install clang-format==23.1.3 clang-tidy==22.1.8
git ls-files '*.cpp' '*.hpp' | xargs .qc/bin/clang-format --dry-run -Werror
```
## When the workflow itself fails
| Message | Cause | Fix |
| --- | --- | --- |
| `[configuration] std '<x>' is not a C++ standard` | `std` is not like `c++20` or `gnu++20` | Correct the input |
| `[configuration] ... is not an exact version` | A tool version is a range, a channel or empty | Give an exact version such as `23.1.3` |
| `[configuration] working-directory must be a relative path inside the repository.` | An absolute path or `..` | Use a path inside the repository |
| `[configuration] No .clang-format found` | The project has no style file | Add a `.clang-format` |
| `[configuration] compile-commands-dir '<x>' has no compile_commands.json` | The database was not built before the call | Build it in an earlier step of the job or in a job it depends on |
| The install step fails | PyPI or the runner network is unreachable | Re-run the job; see [troubleshooting.md](Troubleshooting) |
+88
View File
@@ -0,0 +1,88 @@
<!-- translation of QualityChecksCpp.md, source sha256 baf659e82523 -->
> Ini ialah terjemahan [`QualityChecksCpp`](QualityChecksCpp). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
[English](QualityChecksCpp) | [Dansk](QualityChecksCpp.da) | Bahasa Melayu
# Membaca keputusan semakan kualiti C dan C++
Cara seorang jurutera perisian memanggil semakan kualiti bersama untuk C dan C++, membaca larian yang gagal dan menjadikannya lulus. Aliran kerja ini menyemak format dan menganalisis secara statik fail C dan C++ sesebuah repositori dengan alat clang pada versi yang tepat, tidak mengubah sebarang fail dan tidak memerlukan secret. Kontraknya ialah ADR-0008 dalam repositori ini.
## Memanggil aliran kerja
```yaml
name: Quality C++
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks-cpp.yml@v1
with:
std: c++20
```
| Input | Lalai | Maksud |
| --- | --- | --- |
| `working-directory` | `.` | Direktori, relatif kepada akar repositori, yang failnya disemak |
| `std` | `c++20` | Piawaian C++ yang diberikan kepada clang-tidy apabila tiada pangkalan data kompilasi, seperti `c++17` atau `gnu++20` |
| `compile-commands-dir` | kosong | Direktori, relatif kepada akar repositori, dengan `compile_commands.json` yang dibina oleh saluran paip anda sebelum panggilan; apabila ditetapkan, clang-tidy menggunakannya dan mengabaikan `std` |
| `clang-format-version` | `23.1.3` | Versi tepat pakej clang-format |
| `clang-tidy-version` | `22.1.8` | Versi tepat pakej clang-tidy |
| `tools-ref` | `v1` | Tag atau cabang `TirSystem/github-action` tempat skrip `tools/quality-checks-cpp.sh` diambil |
Rujuk aliran kerja pada tag major (`@v1`) atau pada tag tepat, jangan sekali-kali pada `main`. Panggilan pada tag tepat hanya disematkan sepenuhnya apabila `tools-ref` menamakan tag yang sama. Lihat panduan naik taraf. Versi alat adalah tepat: versi alat yang lebih baharu ialah keluaran baharu repositori ini, bukan perubahan senyap.
## Apa yang diperlukan oleh repositori
- Satu `.clang-format` dalam direktori kerja atau dalam direktori di atasnya, sehingga akar repositori. Tanpanya larian gagal dengan `[configuration]` dan tiada alat dijalankan.
- Pilihan: satu `.clang-tidy` dengan semakan projek (contohnya C++ Core Guidelines). Tanpanya aliran kerja menjalankan diagnostik pengkompil dan penganalisis statik (`clang-diagnostic-*` dan `clang-analyzer-*`), kerana clang-tidy sendiri tidak mengaktifkan sebarang semakan tanpa konfigurasi.
- Untuk semakan statik yang tepat, satu pangkalan data kompilasi: bina dahulu (contohnya `cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`) dan berikan `compile-commands-dir: build`. Aliran kerja tidak membina projek anda.
## Apa yang disemak
| Fail | Alat | Apa yang dilaporkan |
| --- | --- | --- |
| `*.c`, `*.cc`, `*.cpp`, `*.cxx`, `*.h`, `*.hh`, `*.hpp`, `*.hxx` yang dijejaki | `clang-format --dry-run -Werror` | pemformatan yang berbeza daripada `.clang-format` |
| fail yang sama | `clang-tidy` | dapatan semakan dalam `.clang-tidy` (atau `clang-diagnostic-*` dan `clang-analyzer-*` tanpanya); fail `*.c` disemak sebagai C17, fail lain sebagai piawaian C++ dalam `std`; setiap dapatan ialah ralat (`--warnings-as-errors=*`), jadi amaran menggagalkan larian |
Fail yang tidak dijejaki tidak disemak. Repositori tanpa fail ini lulus dengan satu notis. Tiada `cppcheck`: hanya versi lama tersedia sebagai pakej, dan alat lama tidak dijalankan (ADR-0008).
## Membaca satu larian
1. Buka semakan status pada pull request, kemudian kerja `quality-checks-cpp`.
2. Setiap alat mempunyai kumpulan lognya sendiri. Setiap alat dijalankan walaupun yang terdahulu gagal, jadi satu larian menunjukkan semua dapatan.
3. Satu alat berakhir dengan `PASS <alat>` atau `FAIL <alat>`; baris terakhir larian yang gagal menamakannya: `Quality checks failed: clang-format`.
4. Satu dapatan ditulis oleh alat itu sendiri sebagai `path:line:column: message`. Laluan relatif kepada `working-directory`.
## Kegagalan biasa dan pembetulan
| Alat | Apa yang ditunjukkan log | Pembetulan |
| --- | --- | --- |
| `clang-format` | `code should be clang-formatted [-Wclang-format-violations]` | Jalankan `clang-format -i <fail>` dengan versi yang sama dan commit |
| `clang-tidy` | `warning: ... [modernize-use-nullptr]` | Betulkan kod, atau matikan semakan itu dalam `.clang-tidy` dengan sebab |
| `clang-tidy` | `error: 'x.h' file not found` | Bina pangkalan data kompilasi dan tetapkan `compile-commands-dir`, atau tambah laluan include kepadanya |
Untuk mengulangi satu larian pada mesin anda, pasang versi yang sama:
```bash
python3 -m venv .qc
.qc/bin/pip install clang-format==23.1.3 clang-tidy==22.1.8
git ls-files '*.cpp' '*.hpp' | xargs .qc/bin/clang-format --dry-run -Werror
```
## Apabila aliran kerja itu sendiri gagal
| Mesej | Punca | Pembetulan |
| --- | --- | --- |
| `[configuration] std '<x>' is not a C++ standard` | `std` bukan seperti `c++20` atau `gnu++20` | Betulkan input |
| `[configuration] ... is not an exact version` | Versi alat ialah julat, saluran atau kosong | Berikan versi tepat seperti `23.1.3` |
| `[configuration] working-directory must be a relative path inside the repository.` | Laluan mutlak atau `..` | Gunakan laluan di dalam repositori |
| `[configuration] No .clang-format found` | Projek tiada fail gaya | Tambah `.clang-format` |
| `[configuration] compile-commands-dir '<x>' has no compile_commands.json` | Pangkalan data tidak dibina sebelum panggilan | Bina dalam langkah terdahulu kerja itu atau dalam kerja yang menjadi tanggungannya |
| Langkah pemasangan gagal | PyPI atau rangkaian runner tidak dapat dicapai | Jalankan semula kerja; lihat [troubleshooting.md](troubleshooting.md) |
+2 -2
View File
@@ -1,4 +1,4 @@
<!-- translation of Upgrading.md, source sha256 3f119a1ab12d -->
<!-- translation of Upgrading.md, source sha256 7fba937279b1 -->
> Dette er en oversættelse af [`Upgrading`](Upgrading). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
@@ -18,7 +18,7 @@ Sådan tager en softwareudvikler en ny udgivelse af de fælles workflows i brug
En udgivelse, der bryder kompatibiliteten, får en ny major-version (`v2`), så en pipeline på `@v1` aldrig modtager den, før du selv ændrer linjen.
Kvalitetskontrol-workflowet henter sit script ved sit input `tools-ref`, som som standard er `v1`. For at fastlåse det helt skal du kalde det ved et præcist tag og sætte `tools-ref` til samme tag; ellers følger scriptet major-tagget.
Kvalitetskontrol-workflowene (`quality-checks.yml`, `quality-checks-cpp.yml` og `quality-checks-csharp.yml`) henter deres script ved deres input `tools-ref`, som som standard er `v1`. For at fastlåse et helt skal du kalde det ved et præcist tag og sætte `tools-ref` til samme tag; ellers følger scriptet major-tagget.
De to scoped workflows (**Sync GitHub mirror metadata** og **Publish wiki**) leveres af instansen og står ikke i dine `uses:`-linjer; du kan ikke fastlåse dem, men de henter deres scripts ved major-tagget.
+3 -2
View File
@@ -22,8 +22,9 @@ repository, tags `vMAJOR.MINOR.PATCH` and a moving major tag `vMAJOR`.
A breaking release gets a new major version (`v2`), so a pipeline on `@v1`
never receives it until you change the line yourself.
The quality-checks workflow fetches its script at its input `tools-ref`, which
defaults to `v1`. To pin it completely, call it at an exact tag and set
The quality-checks workflows (`quality-checks.yml`, `quality-checks-cpp.yml` and
`quality-checks-csharp.yml`) fetch their script at their input `tools-ref`, which
defaults to `v1`. To pin one completely, call it at an exact tag and set
`tools-ref` to the same tag; otherwise the script follows the major tag.
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
+2 -2
View File
@@ -1,4 +1,4 @@
<!-- translation of Upgrading.md, source sha256 3f119a1ab12d -->
<!-- translation of Upgrading.md, source sha256 7fba937279b1 -->
> Ini ialah terjemahan [`Upgrading`](Upgrading). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
@@ -18,7 +18,7 @@ Cara seorang jurutera perisian menerima keluaran baharu aliran kerja bersama den
Keluaran yang memecahkan keserasian mendapat versi major baharu (`v2`), jadi saluran paip pada `@v1` tidak menerimanya sehingga anda sendiri menukar baris itu.
Aliran kerja semakan kualiti mengambil skripnya pada inputnya `tools-ref`, yang lalai ialah `v1`. Untuk menyematkannya sepenuhnya, panggil pada tag tepat dan tetapkan `tools-ref` kepada tag yang sama; jika tidak, skrip mengikuti tag major.
Aliran kerja semakan kualiti (`quality-checks.yml`, `quality-checks-cpp.yml` dan `quality-checks-csharp.yml`) mengambil skripnya pada inputnya `tools-ref`, yang lalai ialah `v1`. Untuk menyematkan satu sepenuhnya, panggil pada tag tepat dan tetapkan `tools-ref` kepada tag yang sama; jika tidak, skrip mengikuti tag major.
Dua aliran kerja scoped (**Sync GitHub mirror metadata** dan **Publish wiki**) dihantar oleh instans dan tidak terdapat dalam baris `uses:` anda; anda tidak boleh menyematkannya, tetapi ia mengambil skripnya pada tag major.
+6
View File
@@ -9,6 +9,8 @@
- [Credentials](Credentials)
- [Troubleshooting](Troubleshooting)
- [Quality checks (Python, shell)](QualityChecksPythonShell)
- [Quality checks (C and C++)](QualityChecksCpp)
- [Quality checks (C#)](QualityChecksCSharp)
- [Upgrading](Upgrading)
- [Capabilities](Capabilities)
@@ -19,6 +21,8 @@
- [Credentials](Credentials.da)
- [Fejlfinding](Troubleshooting.da)
- [Kvalitetskontrol (Python, shell)](QualityChecksPythonShell.da)
- [Kvalitetskontrol (C og C++)](QualityChecksCpp.da)
- [Kvalitetskontrol (C#)](QualityChecksCSharp.da)
- [Opgradering](Upgrading.da)
- [Kapabiliteter](Capabilities.da)
@@ -29,5 +33,7 @@
- [Kelayakan](Credentials.ms)
- [Diagnosis](Troubleshooting.ms)
- [Semakan kualiti (Python, shell)](QualityChecksPythonShell.ms)
- [Semakan kualiti (C dan C++)](QualityChecksCpp.ms)
- [Semakan kualiti (C#)](QualityChecksCSharp.ms)
- [Menaik taraf](Upgrading.ms)
- [Keupayaan](Capabilities.ms)