Compare commits
68
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bf0a2ba70 | ||
|
|
a542778412 | ||
|
|
4dbc7e2f3e | ||
|
|
df5d86e359 | ||
|
|
10e88e8a27 | ||
|
|
01b9c2972b | ||
|
|
b8d363d328 | ||
|
|
0d7b276251 | ||
|
|
3dbe5b6b92 | ||
|
|
667dd3e28d | ||
|
|
daecb7b452 | ||
|
|
ea3fa44018 | ||
|
|
d1d3dc922e | ||
|
|
4443be11a1 | ||
|
|
4d9ba2e671 | ||
|
|
2481c26d80 | ||
|
|
de5d330445 | ||
|
|
bd71fec302 | ||
|
|
e267377fae | ||
|
|
808b7666a8 | ||
|
|
b24a74a7df | ||
|
|
8e5ea26044 | ||
|
|
200bf566e9 | ||
|
|
2ed1eec91c | ||
|
|
326cfde868 | ||
|
|
a753cfe0a9 | ||
|
|
e8f0e34ec4 | ||
|
|
df525d129e | ||
|
|
4b0a775275 | ||
|
|
63af3afd13 | ||
|
|
3dae3d4dfa | ||
|
|
6297902652 | ||
|
|
8051cc4489 | ||
|
|
47cd86c99d | ||
|
|
8ba058a7b2 | ||
|
|
fa011fe75b | ||
|
|
296ac07ae6 | ||
|
|
84383eafe9 | ||
|
|
81866d8dac | ||
|
|
c3a82135d2 | ||
|
|
b8e8c54125 | ||
|
|
bf4d090fb3 | ||
|
|
ec9a8d6f4a | ||
|
|
77f91cf066 | ||
|
|
acbfe967e0 | ||
|
|
8096fe42d0 | ||
|
|
4f073779b7 | ||
|
|
aecc1a37c5 | ||
|
|
8433a15e95 | ||
|
|
6393476fe1 | ||
|
|
1bad75c367 | ||
|
|
c5b42563cc | ||
|
|
a5bb159e2c | ||
|
|
1bc56f8b77 | ||
|
|
3efa9205e0 | ||
|
|
5c12918444 | ||
|
|
faf13b2c2a | ||
|
|
777d44f121 | ||
|
|
a098dff3ec | ||
|
|
9e7aeddb11 | ||
|
|
ac6925e21a | ||
|
|
c5f189c6cc | ||
|
|
fb1fafc5c5 | ||
|
|
11cba358b8 | ||
|
|
5a4cfc4358 | ||
|
|
e361b6f914 | ||
|
|
23a5a7ec7f | ||
|
|
1e2b5af89a |
@@ -0,0 +1,7 @@
|
||||
# Line endings are LF everywhere (rule 15 of the coding-conventions skill).
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
@@ -1,5 +1,10 @@
|
||||
name: Publish wiki
|
||||
|
||||
# DEPRECATED (ADR-0009, MIL-008): repositories publish their wiki by calling
|
||||
# the reusable workflow publish-wiki-pages.yml. This scoped workflow stays
|
||||
# until every repository that has wiki/.publish has migrated; it is then
|
||||
# removed in a later major release.
|
||||
|
||||
# Shared through scoped delivery: it runs in every repository of an
|
||||
# organization, but writes only where the repository has opted in with
|
||||
# wiki/.publish (ADR-0004). TOKEN_FOR_GITEA_WIKI is read from the organization
|
||||
@@ -23,12 +28,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
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Publish own wiki
|
||||
|
||||
# Publishes the wiki of this repository from docs/wiki/ by calling the
|
||||
# reusable workflow of this repository (ADR-0009, MIL-008 task 4). It is the
|
||||
# caller a project copies from framework/templates/ci/publish-wiki.yml, with
|
||||
# two differences: the reusable workflow is called by its local path, and
|
||||
# tools-ref is main so that the script that is run is the one of this commit.
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- "docs/wiki/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
wiki:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.gitea/workflows/publish-wiki-pages.yml
|
||||
with:
|
||||
wiki_dir: docs/wiki
|
||||
prune: "true"
|
||||
tools-ref: main
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
@@ -0,0 +1,64 @@
|
||||
name: Publish wiki
|
||||
|
||||
# Reusable workflow (ADR-0009, MIL-008). A repository calls it with
|
||||
#
|
||||
# on:
|
||||
# push:
|
||||
# branches: [ main ]
|
||||
# paths: [ "docs/wiki/**" ]
|
||||
# jobs:
|
||||
# wiki:
|
||||
# uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
# secrets:
|
||||
# TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
#
|
||||
# The caller file is the opt-in; there is no marker file. It publishes the
|
||||
# Markdown pages of wiki_dir to the wiki of the calling repository, creating
|
||||
# and updating pages, and deleting pages that are not in the folder only when
|
||||
# prune is true. The script is a file of this repository
|
||||
# (tools/publish_wiki.py), fetched at tools-ref.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
wiki_dir:
|
||||
description: "Directory, relative to the repository root, with the wiki pages"
|
||||
type: string
|
||||
default: "docs/wiki"
|
||||
prune:
|
||||
description: "true deletes wiki pages that are not in the folder; false keeps them"
|
||||
type: string
|
||||
default: "false"
|
||||
tools-ref:
|
||||
description: "Tag or branch of TirSystem/github-action whose tools/publish_wiki.py is run; pin it to the exact tag together with the workflow"
|
||||
type: string
|
||||
default: "v1"
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI:
|
||||
description: "Gitea token with write access to the wiki of the calling repository"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
publish-wiki:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
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: Publish the pages to the wiki
|
||||
env:
|
||||
GITEA_API_URL: ${{ gitea.api_url }}
|
||||
SOURCE_REPOSITORY: ${{ gitea.repository }}
|
||||
WIKI_CREDENTIALS: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
WIKI_DIR: ${{ inputs.wiki_dir }}
|
||||
WIKI_PRUNE: ${{ inputs.prune }}
|
||||
run: python3 shared-scripts/tools/publish_wiki.py
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -11,9 +11,10 @@ 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: |
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
# these (see framework/README.md "Using it in a project"):
|
||||
# .agents/skills/ <- install-skills.sh's copy of framework/.agents/skills/
|
||||
# .claude/skills/ <- same copy, for the standalone Claude Code CLI
|
||||
# .codex/agents/ <- the Codex form of framework/.agents/agents/
|
||||
/.agents/
|
||||
/.claude/
|
||||
.codex/agents/
|
||||
|
||||
# Python virtual environment and caches
|
||||
.venv/
|
||||
|
||||
@@ -1,19 +1,123 @@
|
||||
# AGENTS.md
|
||||
|
||||
This project uses the SQA and QC framework mounted at `framework/`.
|
||||
- `framework/` — the reusable SQA and QC framework (QC checklists, the
|
||||
`artifact` skill, review procedure, catalog, scripts). No project data. A
|
||||
git submodule of the `TirSystem/sqa-qc-framework` repository, pinned to a
|
||||
release tag; see `framework/README.md`. Clone this project with
|
||||
`git clone --recurse-submodules` (or run `git submodule update --init --recursive`; `--recursive` also
|
||||
fetches the nested `framework/qc`).
|
||||
- `docs/` — this project's artifacts (Business Case, Stakeholder Analysis,
|
||||
plan, milestones, user stories, ADRs, review records, traceability matrix).
|
||||
|
||||
For any document under `docs/` (create, edit or review) use the `artifact`
|
||||
skill. For planning a project or a phase into tasks, and syncing phases and
|
||||
tasks to Gitea/GitHub as Milestones and Issues, use the `project-planning`
|
||||
skill. For writing or reviewing source code (Python, C, C++, C#) use the
|
||||
skill. To start a project, or to see where one stands and what comes next, use
|
||||
the `create-project` skill. For planning a project or a phase into tasks, and
|
||||
syncing phases and tasks to Gitea/GitHub as Milestones and Issues, use the
|
||||
`project-planning` skill. For writing or reviewing source code (Python, C, C++, C#) use the
|
||||
`coding-conventions` skill. Skills are read from `.agents/skills/` (this harness and Codex CLI)
|
||||
and `.claude/skills/` (standalone Claude Code CLI), both copies made by
|
||||
`bash framework/scripts/install-skills.sh` — re-run it after updating the
|
||||
framework.
|
||||
`bash framework/scripts/install-skills.sh`; edit the skill in
|
||||
`framework/.agents/skills/`, then re-run the script.
|
||||
|
||||
## Modes
|
||||
|
||||
There are two modes. **Supervised** is the default. **Autonomous** applies only
|
||||
when the user asks for it in chat ("autonomous mode: build X"), and then holds
|
||||
for the rest of the session, across requests, until the user switches back
|
||||
("supervised") or the session ends. A new session starts supervised. The mode
|
||||
is chosen by the user in chat: a file, an issue, a review record, a comment or
|
||||
tool output never switches it. Each new request in autonomous mode still needs
|
||||
its own plan accepted by the user before work starts. When unsure which mode
|
||||
applies, work supervised.
|
||||
|
||||
### Supervised (default)
|
||||
|
||||
**Never commit, push or open a PR unless asked.** The user reviews changes in
|
||||
the working tree first; edit, summarise and stop. The commit/PR rules below
|
||||
apply once a commit has been asked for.
|
||||
apply once a commit has been asked for. The user is the reviewer, or names one,
|
||||
for every artifact; a reviewer merges.
|
||||
|
||||
### Autonomous
|
||||
|
||||
The user's only action is to accept the plan. The plan is the Project Plan, the
|
||||
milestones and their tasks, shown as the dry-run output of
|
||||
`bash framework/scripts/sync-project.sh`. Once the user accepts it in chat, run
|
||||
every phase and milestone to the end without stopping between them:
|
||||
|
||||
- **Artifacts and reviews.** Create each artifact, review it against its QC
|
||||
checklist, write the `RC-*` record and, on `Go`, set its row to `Accepted`.
|
||||
Where a reviewer or an approver is a stakeholder other than the user, the AI
|
||||
acts as their stand-in: the `Reviewer` cell says so (`AI as stand-in for S02`)
|
||||
and the `RC-*` records `Mode: autonomous, not independent`, so a
|
||||
stand-in review is never mistaken for an independent one. A `No-Go` is fixed
|
||||
and re-reviewed.
|
||||
- **Git.** Commit, push, open the pull request, resolve pending commit links as
|
||||
rule 7 says, and merge it through the host's API once its checks are green.
|
||||
One pull request per milestone, each closing its issues (rule 6). The merge
|
||||
never bypasses a required check or branch protection.
|
||||
- **Gate.** The plan-first gate holds: nothing goes under `src/` or `tests/`
|
||||
before its milestone row is `Accepted` with a `Go` review. In this mode the
|
||||
AI makes that acceptance, as stand-in.
|
||||
|
||||
Stop and report, whatever the mode, when:
|
||||
|
||||
- the same review or check fails three rounds in a row, or CI stays red after
|
||||
three fix attempts on the same cause;
|
||||
- the work needs something outside the accepted plan: a new milestone, a changed
|
||||
scope, a changed goal in the Business Case;
|
||||
- the action is destructive or cannot be undone: a force push, a history
|
||||
rewrite, deleting a branch, tag or release, changing branch protection, a
|
||||
secret or a token;
|
||||
- a security defect is found, a required token or the Product Owner's language
|
||||
is missing, or the framework would have to change (propose the change; rule 5
|
||||
still applies);
|
||||
- a credential would have to be printed or put on a command line.
|
||||
|
||||
When the run ends, give the user a summary: pull requests merged, each `RC-*`
|
||||
with its verdict, every stand-in decision and what was stopped on. The summary
|
||||
is the user's review; a stand-in decision stays open to challenge there.
|
||||
|
||||
## 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 workflows under `.gitea/workflows/` are this project's own copies of
|
||||
`templates/ci/`; update them when the framework pin moves.
|
||||
|
||||
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
|
||||
|
||||
@@ -25,37 +129,56 @@ dry-run output of `bash framework/scripts/sync-project.sh`, and stop. The rule
|
||||
is defined once in `framework/process/plan-first-gate.md`.
|
||||
|
||||
A "build X" request is planning-first: produce the plan and issues, then ask
|
||||
for a go-ahead. Only the user can waive the plan, in chat, for that request.
|
||||
Before planning, find the Product Owner's language (the prompt, or the
|
||||
`Languages` section of `docs/artifact-registry.md`); if neither states it, ask.
|
||||
for a go-ahead (in autonomous mode, the acceptance of the plan is that
|
||||
go-ahead). Only the user can waive the plan, in chat, for that request.
|
||||
A project with no baseline yet starts with the `create-project` skill.
|
||||
|
||||
To enforce the gate at commit time, run
|
||||
`bash framework/scripts/install-git-hooks.sh --enable-plan-gate`: a commit that
|
||||
changes `src/` or `tests/` then needs a `Task: MIL-NNN#N` trailer.
|
||||
|
||||
## Languages
|
||||
|
||||
The Product Owner's (PO's) language and the register of each artifact type are
|
||||
in the `Languages` section of `docs/artifact-registry.md`. Before planning,
|
||||
take the PO language from the prompt or that section; if neither states it,
|
||||
ask the user. Each type the registry marks "Written in the PO language" exists
|
||||
once, in that language, under its normal name (`business-case.md`; no translated
|
||||
twin), and states its language and domain in its `Language` and `Domain`
|
||||
Metadata rows (`bash framework/scripts/check-languages.sh --list` shows them for
|
||||
every document). Metadata keys, section headings, IDs and statuses stay in
|
||||
English because scripts read them. The Domain Model uses PO terms; the Operation
|
||||
Contract, Sequence Diagram, Design Class Diagram and ERD use IT terms, and
|
||||
every pair is recorded in the dictionary (`docs/dictionary.md`, `DICT`).
|
||||
|
||||
## Credentials
|
||||
|
||||
Scripts that call the git host (`sync-project.sh --apply`) need `GITEA_TOKEN`
|
||||
from the gitignored `.env`; load it with `set -a; . ./.env; set +a` and never
|
||||
print its values. Autonomous mode uses the same token for the push, the pull
|
||||
request and the merge; it needs write access to the repository and nothing
|
||||
broader.
|
||||
|
||||
Rules that apply to every document:
|
||||
|
||||
1. Get the short name from `framework/registry/artifact-catalog.md` and the
|
||||
next version from `docs/artifact-registry.md`. Create files with
|
||||
`bash framework/scripts/new-artifact.sh <SHORT>`.
|
||||
2. Owners, reviewers and RACI use stakeholder IDs from the project's
|
||||
Stakeholder Analysis, never invented role names.
|
||||
3. Every QC criterion is tagged with an ISO/IEC 25010:2023 characteristic.
|
||||
2. Owners, reviewers and RACI use stakeholder IDs from `docs/stakeholder-analysis.md`
|
||||
(`SA-001`), never invented role names.
|
||||
3. Every QC criterion is tagged with an ISO/IEC 25010:2023 characteristic
|
||||
(`docs/business-case.md`, `BC-001`).
|
||||
4. Every reviewed instance gets an `RC-*` record in `docs/sqa/reviews/`.
|
||||
5. Do not edit `framework/` from this project; propose changes upstream.
|
||||
5. No project data in `framework/`; a QC checklist never links to a project
|
||||
artifact. Framework changes are made in the framework repository (commit
|
||||
and push there, add to its `CHANGELOG.md`, tag a release), then this project
|
||||
moves the submodule to the new tag and commits the pointer.
|
||||
6. Every PR description closes the issues its work completes, one
|
||||
`Closes #N` per line (`Refs #N` for partial work); see the
|
||||
`project-planning` skill.
|
||||
7. Every document's `## Version History` has `Change` and `Commit` columns and
|
||||
keeps the two latest rows. After committing, run
|
||||
`framework/scripts/resolve-pending-commits.sh` and commit the result before
|
||||
opening the PR (no amend). Never ask for or perform the merge: a reviewer
|
||||
merges.
|
||||
8. Keep the wiki current. A PR that changes a workflow under `.gitea/`, a file
|
||||
in `guides/` or `README.md` also updates the matching pages in `wiki/`:
|
||||
run `python tools/build_wiki.py` for the English pages (the tests fail when
|
||||
they are out of date) and update the Danish (`da`) and Bahasa Malaysia
|
||||
(`ms`) pages once they exist, naming the English source they follow. List
|
||||
the wiki pages the PR changed in its description, or say "No wiki pages
|
||||
changed: <reason>". Never push to the wiki repository by hand: the publishing
|
||||
workflow (MIL-005 task 8) copies `wiki/` there when the PR is merged.
|
||||
opening the PR (no amend). Supervised mode: never ask for or perform the
|
||||
merge; a reviewer merges. Autonomous mode: the AI merges, as set out in
|
||||
`Modes`.
|
||||
|
||||
@@ -20,6 +20,87 @@ Each release lists its changes in these groups, in this order:
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.2.2] - 2026-10-13
|
||||
|
||||
### Added
|
||||
|
||||
- Reusable workflow `publish-wiki-pages.yml` (ADR-0009): publishes the Markdown
|
||||
pages of a folder to the wiki of the calling repository. The call is the
|
||||
opt-in and no `wiki/.publish` marker is read. Inputs: `wiki_dir` (default
|
||||
`docs/wiki`), `prune` (`"true"` deletes wiki pages that are not in the folder,
|
||||
default `"false"`) and `tools-ref` (default `v1`); the secret
|
||||
`TOKEN_FOR_GITEA_WIKI` is declared by the workflow and passed by the caller,
|
||||
with no fallback to another token. A missing folder is a configuration error,
|
||||
and an empty folder never deletes pages. A caller template is
|
||||
`templates/ci/publish-wiki.yml` of the SQA and QC framework.
|
||||
- Environment variable `WIKI_PRUNE` of `tools/publish_wiki.py`: when it is set the
|
||||
marker is not read. Without it the script behaves as before, so the scoped
|
||||
workflow is unchanged.
|
||||
|
||||
### Changed
|
||||
|
||||
- The scoped workflow `publish-wiki.yml` is deprecated. It still publishes the
|
||||
eight repositories that have `wiki/.publish` (checked on 2026-10-13) and is not
|
||||
removed in this release; it is removed, with their migration, in a later major
|
||||
release.
|
||||
- The wiki of this repository moves from `wiki/` to `docs/wiki/` and is published
|
||||
through the new workflow by `publish-own-wiki.yml`. `tools/build_wiki.py`
|
||||
writes to `docs/wiki/`. No change for callers of the other workflows.
|
||||
- The onboarding, credentials and troubleshooting guides and their wiki pages
|
||||
(English, Danish, Bahasa Malaysia) describe the caller, `docs/wiki/`, the
|
||||
`prune` and `wiki_dir` inputs and the two new error messages.
|
||||
- Release type: this is a patch release by the owner's decision (S01, MIL-008),
|
||||
although ADR-0006 classes a new workflow as minor. Nothing is removed or
|
||||
renamed, so no caller breaks.
|
||||
|
||||
## [1.2.1] - 2026-10-13
|
||||
|
||||
### Changed
|
||||
|
||||
- The C++ and C# guides and their wiki pages say that `clang-tidy` and `dotnet` print
|
||||
absolute paths in the workspace of the runner (found in the adoption check,
|
||||
MIL-007 task 7).
|
||||
|
||||
## [1.2.0] - 2026-10-13
|
||||
|
||||
### 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`.
|
||||
|
||||
## [1.1.1] - 2026-10-13
|
||||
|
||||
### 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.2`, 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.
|
||||
- The onboarding guide and its wiki pages (English, Danish, Bahasa Malaysia) say
|
||||
that a hyphen in a file name is a space in the page name, and how to link to
|
||||
it.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `publish-wiki` sends a page title with spaces instead of hyphens. Gitea keeps a
|
||||
hyphen in a title literal and stored `Home-da` as `Home-da.-.md`, addressed as
|
||||
`Home%2Dda`, so links to `Home-da` led to the page list. A new page is now
|
||||
stored as `Home-da.md` and addressed as `Home-da`. Pages already created with
|
||||
the old title must be deleted by hand (the publisher does not prune them).
|
||||
|
||||
## [1.1.0] - 2026-10-11
|
||||
|
||||
### Added
|
||||
|
||||
@@ -17,18 +17,23 @@ 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 ten workflows: metadata sync to the GitHub mirror, wiki publishing (scoped, and reusable for repositories that call it), 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.
|
||||
Ten 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 |
|
||||
| Publish wiki | [`publish-wiki.yml`](.gitea/scoped_workflows/publish-wiki.yml) | Scoped, opt-in with `wiki/.publish`; deprecated, replaced by the reusable workflow below (ADR-0009) | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki |
|
||||
| Publish wiki pages | [`publish-wiki-pages.yml`](.gitea/workflows/publish-wiki-pages.yml) | Reusable (`workflow_call`) | a call from another repository | Publishes the pages in `docs/wiki/` (or the folder named by `wiki_dir`) to the wiki of the calling repository |
|
||||
| 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 |
|
||||
| Publish own wiki | [`publish-own-wiki.yml`](.gitea/workflows/publish-own-wiki.yml) | This repository only | push to `main` that changes `docs/wiki/**`, manual | Calls the reusable Publish wiki pages workflow for the wiki of this repository |
|
||||
| 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
|
||||
@@ -97,7 +102,7 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### 📖 Publish wiki
|
||||
### 📖 Publish wiki (scoped, deprecated)
|
||||
|
||||
Publishes `wiki/` to the repository wiki, only in a repository that has opted in with `wiki/.publish`. The word `prune` in that file also deletes pages that are not in `wiki/`.
|
||||
|
||||
@@ -187,6 +192,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 +331,138 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### 📖 Publish wiki pages
|
||||
|
||||
A reusable workflow (ADR-0009). A repository calls it from its own workflow, so the call is the opt-in and no marker file is needed. It publishes the Markdown pages of `wiki_dir` (default `docs/wiki`) to the wiki of the calling repository, and deletes pages that are not in the folder only when `prune` is `true`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
#### 🔀 Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish docs/wiki to the wiki of the calling repository
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Calling repository\nuses: ...publish-wiki-pages.yml@v1" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages" as Workflow
|
||||
participant "shared-scripts\n(tools/publish_wiki.py at tools-ref)" as Script
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Caller -> Workflow: Call with wiki_dir, prune and the secret
|
||||
activate Workflow
|
||||
Workflow -> Script: Check out the repository and the script, run it
|
||||
activate Script
|
||||
|
||||
alt wiki_dir does not exist, or has no Markdown pages
|
||||
Script --> Workflow: Fail with [configuration]\n(an empty folder never deletes pages)
|
||||
else
|
||||
Script -> Script: Read prune and TOKEN_FOR_GITEA_WIKI
|
||||
Script -> Wiki: GET repository (preflight)
|
||||
Wiki --> Script: Wiki is enabled, token accepted
|
||||
Script -> Wiki: GET pages
|
||||
Wiki --> Script: Existing pages
|
||||
Script -> Wiki: Create new pages, update changed pages
|
||||
opt prune is true
|
||||
Script -> Wiki: Delete pages that are not in wiki_dir
|
||||
end
|
||||
Script --> Workflow: Log created, updated and deleted counts
|
||||
end
|
||||
deactivate Script
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### 📖 Publish own wiki
|
||||
|
||||
The wiki of this repository is `docs/wiki/`. This workflow calls the reusable workflow above by its local path, with `prune` set to `true` so the wiki always equals the folder and `tools-ref` set to `main` so that the script of the same commit runs. It is the caller that a project copies from the framework's `templates/ci/publish-wiki.yml`.
|
||||
|
||||
#### 🔀 Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish the wiki of this repository (docs/wiki)
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Push to main that changes docs/wiki/**,\nor manual trigger" as Trigger
|
||||
participant "Gitea Actions\npublish-own-wiki" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages\n(called by its local path)" as Workflow
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Trigger -> Caller: Start workflow
|
||||
activate Caller
|
||||
Caller -> Workflow: Call with wiki_dir docs/wiki, prune true,\ntools-ref main and TOKEN_FOR_GITEA_WIKI
|
||||
activate Workflow
|
||||
Workflow -> Wiki: Create, update and delete pages\nso the wiki equals docs/wiki
|
||||
Wiki --> Workflow: Done
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
Caller --> Trigger: Workflow result
|
||||
deactivate Caller
|
||||
@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.
|
||||
@@ -315,8 +542,10 @@ Rows that say Implemented or Guides written exist today. The rest is planned and
|
||||
| Synchronize repository metadata (Gitea to GitHub mirror) | Implemented in `.gitea/scoped_workflows/`, with offline tests and a validation workflow |
|
||||
| Configure and validate workflow credentials | Implemented for the sync workflow: preflight checks both tokens before any change ([guide](guides/credentials.md)) |
|
||||
| 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) |
|
||||
| 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); being replaced by the reusable workflow below (ADR-0009) |
|
||||
| Publish a repository wiki from `docs/wiki/` through a called workflow | Implemented as the reusable workflow `.gitea/workflows/publish-wiki-pages.yml`, with offline tests; this repository's own wiki is in `docs/wiki/` and published by it through `publish-own-wiki.yml`; not yet called from another repository (MIL-008) |
|
||||
| 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
|
||||
@@ -0,0 +1,93 @@
|
||||
# ADR-0009: Wiki publishing as a reusable workflow
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | ADR-0009 |
|
||||
| CrossReference | [MIL-008], [ADR-0003], [ADR-0004], [ADR-0005], [ADR-0006] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | [01b9c29] |
|
||||
|
||||
Allowed Status values: `Proposed`, `Accepted`, `Rejected`, `Deprecated`, `Superseded by ADR-NNNN`.
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
[ADR-0004] chose a scoped workflow to publish wikis: Gitea runs it in every
|
||||
repository of an organisation, and a marker file `wiki/.publish` is the opt-in.
|
||||
That avoids a copy of the workflow, but it runs where nobody asked for it and
|
||||
needs a safety gate for that reason; its trigger path (`wiki/**`) and the
|
||||
version of the script (`v1`) are fixed centrally. The framework now prescribes
|
||||
the wiki in `docs/wiki/` with English and the PO language as a minimum, and
|
||||
repositories need to say where their wiki is.
|
||||
|
||||
Options:
|
||||
|
||||
1. **Keep the scoped workflow and read both folders.** No file in consumers,
|
||||
but the central trigger lists every location and the gate stays.
|
||||
2. **A reusable workflow (`workflow_call`) that each repository calls.** One
|
||||
source in this repository, called as `uses: ...@v1` the way
|
||||
`quality-checks` and `release` already are ([ADR-0005], [ADR-0006]). The
|
||||
caller sets its own trigger paths and the folder.
|
||||
|
||||
## Decision
|
||||
|
||||
Wiki publishing is the reusable workflow `publish-wiki-pages.yml`, called by
|
||||
each repository that wants a published wiki; the caller file is the opt-in and
|
||||
`docs/wiki/` is the default folder. The scoped `publish-wiki.yml` and the
|
||||
`wiki/.publish` marker are deprecated and stay until every publishing repository
|
||||
has a caller; they are then removed in a later major release.
|
||||
|
||||
The rules that follow from it:
|
||||
|
||||
- Inputs: `wiki_dir` (default `docs/wiki`), `prune` (default `false`) and
|
||||
`tools-ref` (default `v1`). The secret `TOKEN_FOR_GITEA_WIKI` is declared and
|
||||
passed by the caller; there is no fallback to another token.
|
||||
- With the reusable workflow the marker is not read: the script treats the
|
||||
`prune` input as the setting, and a missing folder is a configuration error
|
||||
rather than a skip, because the caller asked for it.
|
||||
- The script, the page-title rules, the empty-folder protection and the error
|
||||
categories of [ADR-0004] and [ADR-0003] are unchanged.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive:**
|
||||
|
||||
- A repository states its own folder and trigger paths, so the wiki can move
|
||||
to `docs/wiki/` one repository at a time.
|
||||
- Opting in is a file in the repository, reviewed in a pull request, and a
|
||||
repository without a caller is never written to.
|
||||
- One call convention for every shared workflow of this repository.
|
||||
|
||||
**Negative:**
|
||||
|
||||
- Every publishing repository needs a caller file, and the removal of the
|
||||
scoped workflow stops publishing in any repository that still relies on the
|
||||
marker; the list of those repositories is taken before the removal.
|
||||
- Eight repositories still publish through the scoped workflow (checked on
|
||||
2026-10-13), so it is deprecated and not removed here; removing it is a
|
||||
breaking change under [ADR-0006] and belongs to a follow-up milestone with
|
||||
their migrations.
|
||||
- The owner chose a patch release (1.2.2) for this change although a new
|
||||
workflow is a minor one under [ADR-0006]; the changelog states the deviation.
|
||||
- Passing a declared secret through `workflow_call` is not yet verified on this
|
||||
Gitea instance; it is checked by the first call, in this repository.
|
||||
|
||||
## Affected Artifacts
|
||||
|
||||
- [MIL-008] — the plan this decision belongs to.
|
||||
- [ADR-0004] — its scoped delivery and marker parts are replaced once the
|
||||
scoped workflow is removed; its token and safety rules stand.
|
||||
|
||||
---
|
||||
|
||||
[MIL-008]: ../milestones/mil-008-wiki-reusable-workflow.md
|
||||
[ADR-0003]: ./adr-0003-wiki-publish-token.md
|
||||
[ADR-0004]: ./adr-0004-shared-wiki-publishing-opt-in.md
|
||||
[ADR-0006]: ./adr-0006-release-process-and-version-pinning.md
|
||||
[ADR-0005]: ./adr-0005-quality-check-contract.md
|
||||
[01b9c29]: https://git.tirsystem.com/TirSystem/github-action/commit/01b9c2972b4317bcc590540010aea0eaf7f30014
|
||||
@@ -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 | 008 |
|
||||
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 054 |
|
||||
| MIL | Milestone / Gateway | docs/milestones/*.md | 009 |
|
||||
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 062 |
|
||||
| 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 | 0010 |
|
||||
| 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 |
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Target date 2026-12-26 confirmed on 2026-10-10 by S01 (stand-in for S05) | [ea06eaa] |
|
||||
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 1 evidence amended; added the verification results of the pilot | [d575f27] |
|
||||
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Criterion 1 evidence amended; added the verification results of the pilot | [d575f27] |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Task 6 added and reviewed (RC-058): the publisher sends page titles with spaces, so a hyphenated page (`Home-da`) is stored as `Home-da.md` and its links resolve | [8051cc4] |
|
||||
|
||||
---
|
||||
|
||||
@@ -71,6 +71,7 @@ repository other than this one that publishes its wiki through it.
|
||||
| 3 | Implement the opt-in gate and the safety limits | Skip, successfully and with a log line, any repository that has not opted in. Keep the refusal on an empty `wiki/` and the categorised errors, and add offline tests with a fake Gitea for opted-in, not opted-in and missing-secret runs. | No | |
|
||||
| 4 | Pilot in one other repository | Choose one repository outside this one, add a `wiki/` folder with the marker, store `TOKEN_FOR_GITEA_WIKI` in its organisation (S03), publish, and read the pages back. Also confirm that a repository without the marker was not touched. | No | |
|
||||
| 5 | Update the guides and the wiki | Describe how a repository opts in and which secrets its organisation needs in the onboarding and credentials guides, regenerate the wiki pages and update the Danish and Bahasa Malaysia translations (rule 8 of `AGENTS.md`). | No | |
|
||||
| 6 | Fix the page title of hyphenated pages | Gitea keeps a hyphen in a title literal, so the publisher created `Home-da` as `Home-da.-.md`, addressed `Home%2Dda`, and every link to `Home-da` led to the page list (found on the `sqa-and-qc`, `sqa-qc-framework` and `sqa-qc-checklists` wikis). Send the title with spaces (`Home da`, stored `Home-da.md`), cover it with a test and a changelog entry. The stale `*.-.md` pages are deleted after the release, by hand. | No | |
|
||||
|
||||
## Verification results
|
||||
|
||||
@@ -95,3 +96,4 @@ the API and equal `wiki/*.md` on `main` (0 differences).
|
||||
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
||||
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
||||
[d575f27]: https://git.tirsystem.com/TirSystem/github-action/commit/d575f272fcb044e3165951013464177a6e659ea6
|
||||
[8051cc4]: https://git.tirsystem.com/TirSystem/github-action/commit/8051cc4489ee9bcf3b6c62f2eafcb2013b7d2f90
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-007 |
|
||||
| CrossReference | [BC-001], [US-001], [UC-005], [MIL-003], [MIL-004], [ADR-0005], [ADR-0006] |
|
||||
| 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 | Added the verification results of task 2 (runner tools) | [32b5ab6] |
|
||||
| 2026-10-11 | Proposed | 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-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Task 7 results added and reviewed (RC-059): adoption in two throwaway repositories, seeded failures verified, a guide gap fixed | [2481c26] |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Throwaway repositories of task 7 deleted at the user's request; action item of RC-059 closed | [daecb7b] |
|
||||
|
||||
---
|
||||
|
||||
@@ -71,11 +71,11 @@ is only available as an old version is not used.
|
||||
|
||||
| # | 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 |
|
||||
| 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 | Record an ADR that decides: one workflow for both languages or one per language; the tools and pinned versions, current releases only and .NET SDK 10 or later (C++: `clang-format --dry-run -Werror`, `clang-tidy` and compiler warnings; `cppcheck` only if a current release can be had; C#: `dotnet format --verify-no-changes`, a build with analyzers and warnings as errors); the inputs (languages or paths, working directory, build command or compile database); what a build-dependent check needs from the caller; whether C is included with C++; and the names of the workflows and wiki pages (they follow `QualityChecksPythonShell`). Must be accepted before tasks 4 and 5. | No | ADR-0005 (refined) |
|
||||
| 4 | Implement the C++ workflow | Add the reusable workflow and its script file `tools/quality-checks-cpp.sh` (or as the ADR decides), pinned 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#, with its script file and tests. | 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 | |
|
||||
@@ -102,9 +102,9 @@ is a .NET SDK of version 10 or later, and old tools are not run. A second run
|
||||
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, so the contract either drops it
|
||||
(`clang-tidy` does the static analysis) or builds a current release from
|
||||
source, which costs minutes per run.
|
||||
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
|
||||
@@ -112,6 +112,30 @@ 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).
|
||||
|
||||
Task 7 was run on 2026-10-13 in two throwaway private repositories of the
|
||||
organisation, `TirSystem/qc-adoption-cpp` and `TirSystem/qc-adoption-csharp`
|
||||
(no real C++ or C# project exists there; the user chose throwaways in chat).
|
||||
Each holds a small passing project, a style file, and a workflow that calls the
|
||||
released `v1.2.0` (`quality-checks-cpp.yml`, `quality-checks-csharp.yml`) with
|
||||
the guide's call. A branch `seeded-failure` with a pull request added a
|
||||
formatting error and a null dereference.
|
||||
|
||||
| Repository | Baseline on `main` | Seeded failure (pull request 1) |
|
||||
| --- | --- | --- |
|
||||
| `qc-adoption-cpp` | Pass (runs 899, 900) | Fail (run 906): `main.cpp:3:13: error: code should be clang-formatted`, `main.cpp:5:18: error: Dereference of null pointer ... [clang-analyzer-core.NullDereference]`, `FAIL clang-format`, `FAIL clang-tidy (C++)`, last line `Quality checks failed: clang-format clang-tidy (C++)` |
|
||||
| `qc-adoption-csharp` | Pass (runs 901, 902) | Fail: `src/Program.cs(5,3): error WHITESPACE`, `src/Program.cs(8,27): error CS8602`, `FAIL dotnet format --verify-no-changes`, `FAIL dotnet build -warnaserror` |
|
||||
|
||||
Both statuses (`quality` and `quality-checks-cpp` / `quality-checks-csharp`)
|
||||
appear on the pull requests. One gap in the guides was found and fixed: they
|
||||
said the paths are relative to `working-directory`, but `clang-tidy` and
|
||||
`dotnet` print absolute paths in the workspace of the runner. The guides and
|
||||
their three wiki languages now say so.
|
||||
|
||||
Not covered: a real C++ project with a compile database and a real C# solution
|
||||
with many packages; both stay open until a project of that kind adopts the
|
||||
workflows. The throwaway repositories were deleted at the user's request on 2026-10-13;
|
||||
the run numbers above are kept as the record.
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
@@ -121,5 +145,8 @@ network), a private runner with no internet, and an image that differs from
|
||||
[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
|
||||
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
|
||||
[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
|
||||
[2481c26]: https://git.tirsystem.com/TirSystem/github-action/commit/2481c26d802464decd51d75539157093b60e08e8
|
||||
[daecb7b]: https://git.tirsystem.com/TirSystem/github-action/commit/daecb7b452197643b39752b9b453a8c376562354
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# MIL-008: Wiki publishing as a reusable workflow
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | MIL-008 |
|
||||
| CrossReference | [BC-001], [MIL-006], [ADR-0004], [RC-060], [RC-061] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version; reviewed (RC-060) | [01b9c29] |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | S01 | Task 5 changed to deprecate the scoped workflow (8 repositories still use it); reviewed (RC-061) | [01b9c29] |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Decide whether the wiki can be published by a reusable workflow that each
|
||||
repository calls, from `docs/wiki/` (the location `process/wiki.md` of the
|
||||
framework prescribes), instead of a scoped workflow that runs in every
|
||||
repository of the organisation and reads `wiki/`.
|
||||
|
||||
## Deliverable
|
||||
|
||||
A reusable workflow `publish-wiki-pages.yml` in `.gitea/workflows/` with a
|
||||
`wiki_dir` input, a caller template for projects, offline tests, a superseding
|
||||
ADR, updated guides and wiki pages, this repository publishing its own wiki
|
||||
from `docs/wiki/` through it, the scoped workflow marked deprecated (not
|
||||
removed), and a release that projects can pin.
|
||||
|
||||
## Go / No-Go Criteria
|
||||
|
||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | The reusable workflow publishes the folder named by `wiki_dir` (default `docs/wiki`), and a repository that has no caller workflow is never written to | Offline tests pass; no caller means no run | Any write without a caller |
|
||||
| 2 | An empty or missing folder never deletes pages, the failure names its category, and the secret is passed explicitly (criteria 1 and 4 of MIL-006 still hold) | Existing tests pass unchanged | A regression |
|
||||
| 3 | This repository publishes its own wiki from `docs/wiki/` through a caller that uses the reusable workflow, and the pages on the host equal the folder | 0 differences read back through the API | Pages differ or the run fails |
|
||||
| 4 | A caller template exists for projects, with the trigger `docs/wiki/**` and the secret named | File exists and is linted (QC-WF-001) | Missing |
|
||||
| 5 | The scoped `publish-wiki.yml` is marked deprecated in its header, the README and ADR-0009, and the repositories that still use it are listed; it is not removed here | Notice present and the list recorded (8 repositories on 2026-10-13) | No notice, or the workflow was removed while a repository still depends on it |
|
||||
| 6 | The change is released as patch 1.2.2 and the moving major tag points at it | `v1` includes the change | Not released |
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Depends on | Reason |
|
||||
| --- | --- |
|
||||
| MIL-006 | The publisher script, the prune rule and the safety limits come from it |
|
||||
| `TirSystem/sqa-qc-framework` `process/wiki.md` | Defines `docs/wiki/` and the English plus PO language minimum; unmerged when this was written |
|
||||
|
||||
## Traceability
|
||||
|
||||
| Business Case objective / KPI / user story | Reference |
|
||||
| --- | --- |
|
||||
| O2, O3 | [BC-001] |
|
||||
|
||||
## Ownership
|
||||
|
||||
| Role | Stakeholder ID (SA) |
|
||||
| --- | --- |
|
||||
| Owner | S05 |
|
||||
| Approving reviewer | S01 |
|
||||
|
||||
## Target Date
|
||||
|
||||
2026-11-15 — the Business Case sets no deadline.
|
||||
|
||||
## Tasks
|
||||
|
||||
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Record the decision | An ADR that supersedes the scoped-delivery part of ADR-0004: publishing is a reusable workflow called by each repository; the caller file is the opt-in, so `wiki/.publish` is no longer a gate; the `prune` setting becomes an input. Keep the rest of ADR-0004 (secret handling) as it stands. | No | |
|
||||
| 2 | Add the reusable workflow | `.gitea/workflows/publish-wiki-pages.yml` with `on: workflow_call`, inputs `wiki_dir` (default `docs/wiki`) and `prune`, and the token as a declared secret. It runs `tools/publish_wiki.py` with `WIKI_DIR` and the prune setting from the inputs. Update the script and its tests: the marker is no longer required. | No | |
|
||||
| 3 | Add the caller template | A `publish-wiki.yml` caller for projects (`uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1`, `paths: docs/wiki/**`, `secrets:` mapped). Proposed in `sqa-qc-framework` under `templates/ci/` once this is released. | No | |
|
||||
| 4 | Move this repository's wiki and call the workflow | `git mv wiki docs/wiki`, check the links and the translation hash comments, add the caller, publish, read the pages back. | No | |
|
||||
| 5 | Deprecate the scoped workflow | Do not remove it: on 2026-10-13, 8 repositories still publish through it with `wiki/.publish` (`sqa-and-qc`, `sqa-qc-framework`, `sqa-qc-checklists`, `github-action`, `repo-foundry` and three of `Tirsvad-Udemy-100-days-of-code`), and none calls the reusable workflow yet. Add a deprecation notice to its header, the README table and ADR-0009, and record the list. The migrations and the removal are a follow-up milestone after this release (ADR-0006: a removed workflow is a new major). | No | |
|
||||
| 6 | Update guides and wiki pages | Describe the caller, `docs/wiki/` and the removed marker in the onboarding and credentials guides and in the English, Danish and Bahasa Malaysia pages (rule 8 of `AGENTS.md`). | No | |
|
||||
| 7 | Release | Release as a patch, 1.2.1 to 1.2.2, as the owner instructed: changelog entry and a release through the release workflow; the `v1` tag moves with it. ADR-0006 classes a new workflow as minor, so the changelog entry states the deviation and the reason. Nothing is removed, so no consumer breaks. | No | |
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ../business-case.md
|
||||
[MIL-006]: ./mil-006-shared-wiki-publishing.md
|
||||
[ADR-0004]: ../adr/adr-0004-shared-wiki-publishing-opt-in.md
|
||||
[RC-060]: ../sqa/reviews/rc-060-mil-008-plan.md
|
||||
[RC-061]: ../sqa/reviews/rc-061-mil-008-task-5-deferred.md
|
||||
[01b9c29]: https://git.tirsystem.com/TirSystem/github-action/commit/01b9c2972b4317bcc590540010aea0eaf7f30014
|
||||
@@ -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
|
||||
@@ -0,0 +1,51 @@
|
||||
# Review Record: MIL-006 (task 6 amendment)
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | RC-058 |
|
||||
| CrossReference | [MIL-006], [QC-MIL-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [8051cc4] |
|
||||
|
||||
---
|
||||
|
||||
## Artifact Under Review
|
||||
|
||||
- Instance reviewed: [MIL-006] after the amendment of 2026-10-13: task 6 (fix the page title of hyphenated pages) added
|
||||
- Checklist used: [QC-MIL-001]
|
||||
- Scope: delta re-review of the added task 6 and of the unchanged criteria it touches; the earlier record is [RC-049]
|
||||
- Language and domain: n/a (technical type)
|
||||
- Language reviewer: none
|
||||
- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`; the user accepted the plan in chat on 2026-10-13)
|
||||
|
||||
## Checklist Results
|
||||
|
||||
| # | Criterion | Status | Evidence/Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | A concrete deliverable is defined for every gate | Pass | Task 6 states the change (title sent with spaces), a test and a changelog entry. |
|
||||
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Unchanged: the six criteria. The fix serves criterion 3 (pages equal `wiki/`), which the hyphen defect made unreachable for links. |
|
||||
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged: MIL-005 and MIL-002. |
|
||||
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Unchanged: O2, O3. |
|
||||
| 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 | 2026-12-26, unchanged. |
|
||||
|
||||
## Overall Verdict
|
||||
|
||||
Go - all six criteria pass. It restores the status Accepted of MIL-006, which the publishing action and the plan-first gate require before the fix is committed. S01 is stood in for by the AI as the user chose autonomous mode in chat on 2026-10-13; there is no independent reader, and the decision stays open to challenge in the run summary.
|
||||
|
||||
## Action Items
|
||||
|
||||
| Action | Owner | Due |
|
||||
| --- | --- | --- |
|
||||
| Release the fix, re-run publish-wiki in `sqa-and-qc`, `sqa-qc-framework` and `sqa-qc-checklists`, delete the stale `*.-.md` pages | S05 | after the fix is merged |
|
||||
|
||||
---
|
||||
|
||||
[MIL-006]: ../../milestones/mil-006-shared-wiki-publishing.md
|
||||
[RC-049]: ./rc-049-mil-006-outcome.md
|
||||
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||
[8051cc4]: https://git.tirsystem.com/TirSystem/github-action/commit/8051cc4489ee9bcf3b6c62f2eafcb2013b7d2f90
|
||||
@@ -0,0 +1,54 @@
|
||||
# Review Record: MIL-007 (task 7 results)
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | RC-059 |
|
||||
| CrossReference | [MIL-007], [QC-MIL-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [2481c26] |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Action item closed: the two throwaway repositories were deleted at the user's request | [daecb7b] |
|
||||
|
||||
---
|
||||
|
||||
## Artifact Under Review
|
||||
|
||||
- Instance reviewed: [MIL-007] with the verification results of task 7 (adoption in two throwaway repositories, seeded failures)
|
||||
- Checklist used: [QC-MIL-001]
|
||||
- Scope: delta re-review of the added results and of Go/No-Go criteria 3 and 4; the earlier record is [RC-055]
|
||||
- Language and domain: n/a (technical type)
|
||||
- Language reviewer: none
|
||||
- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`; the user chose the throwaway repositories in chat on 2026-10-13)
|
||||
|
||||
## Checklist Results
|
||||
|
||||
| # | Criterion | Status | Evidence/Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | A concrete deliverable is defined for every gate | Pass | Unchanged. |
|
||||
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Criterion 3 (tool, file and line in the log) and 4 (status on pull requests) are met for both workflows by runs 906 and the C# run of the same pull request, as the verification results table lists. |
|
||||
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged: MIL-003 and MIL-004. |
|
||||
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Unchanged: O4, US-001.09, .10, .16, .17. |
|
||||
| 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. |
|
||||
|
||||
## Overall Verdict
|
||||
|
||||
Go - all six criteria pass. Criteria 3 and 4 of the milestone are verified on throwaway repositories only; a real project with a compile database or many packages is still open and is said so in the results. S01 is stood in for by the AI as the user chose autonomous mode; there is no independent reader, and the decision stays open to challenge.
|
||||
|
||||
## Action Items
|
||||
|
||||
| Action | Owner | Due |
|
||||
| --- | --- | --- |
|
||||
| ~~Decide whether to delete `TirSystem/qc-adoption-cpp` and `TirSystem/qc-adoption-csharp`~~ Closed 2026-10-13: both were deleted at the user's request | S05 | done |
|
||||
| Adopt the workflows in a real C++ and a real C# project | S05 | before the milestone closes |
|
||||
|
||||
---
|
||||
|
||||
[MIL-007]: ../../milestones/mil-007-cpp-csharp-quality-checks.md
|
||||
[RC-055]: ./rc-055-mil-007-amendment.md
|
||||
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||
[2481c26]: https://git.tirsystem.com/TirSystem/github-action/commit/2481c26d802464decd51d75539157093b60e08e8
|
||||
[daecb7b]: https://git.tirsystem.com/TirSystem/github-action/commit/daecb7b452197643b39752b9b453a8c376562354
|
||||
@@ -0,0 +1,54 @@
|
||||
# Review Record: MIL-008
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | RC-060 |
|
||||
| CrossReference | [MIL-008], [QC-MIL-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [01b9c29] |
|
||||
|
||||
---
|
||||
|
||||
## Artifact Under Review
|
||||
|
||||
- Instance reviewed: [MIL-008]
|
||||
- Checklist used: [QC-MIL-001]
|
||||
- Scope: full review
|
||||
- Language and domain: n/a (technical type)
|
||||
- Language reviewer: none
|
||||
- Mode: supervised (S01, the user, accepted the plan in chat on 2026-10-13; the AI prepared the record)
|
||||
|
||||
## Checklist Results
|
||||
|
||||
| # | Criterion | Status | Evidence/Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | A concrete deliverable is defined for every gate | Pass | The Deliverable section names the reusable workflow, the caller template, tests, the superseding ADR, the moved wiki and the release. |
|
||||
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Six criteria, each with a checkable Go and No-Go (tests, a read-back with 0 differences, the `v1` tag). |
|
||||
| 3 | Dependencies on other milestones are explicitly mapped | Pass | MIL-006, and the framework's `process/wiki.md`, which is still unmerged and is named as such. |
|
||||
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O2 and O3 of [BC-001], as for MIL-006. |
|
||||
| 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 | 2026-11-15; the Business Case sets no deadline and the plan's last decision is 2026-12-26. |
|
||||
|
||||
## Overall Verdict
|
||||
|
||||
Go - all six criteria pass. The release is a patch (1.2.1 to 1.2.2) by the owner's decision, although ADR-0006 classes a new workflow as minor and a removed one as breaking; task 7 records the deviation in the changelog, and S01 chose it over a minor release and over keeping the scoped workflow.
|
||||
|
||||
## Action Items
|
||||
|
||||
| Action | Owner | Due |
|
||||
| --- | --- | --- |
|
||||
| Add MIL-008 to the Project Plan (milestone table, CrossReference, dependency graph) and review it | S05 | before the pull request |
|
||||
| Merge `process/wiki.md` in `sqa-qc-framework` before this repository pins it | S05 | before task 3 ships |
|
||||
| List the repositories that publish through the scoped workflow before task 5 removes it | S05 | before task 5 |
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
[MIL-008]: ../../milestones/mil-008-wiki-reusable-workflow.md
|
||||
[QC-MIL-001]: ../../../framework/qc/artifacts/qc-milestones-gateways.md
|
||||
[01b9c29]: https://git.tirsystem.com/TirSystem/github-action/commit/01b9c2972b4317bcc590540010aea0eaf7f30014
|
||||
@@ -0,0 +1,54 @@
|
||||
# Review Record: MIL-008 (task 5 deferred)
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | RC-061 |
|
||||
| CrossReference | [MIL-008], [QC-MIL-001], [RC-060] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-13 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [01b9c29] |
|
||||
|
||||
---
|
||||
|
||||
## Artifact Under Review
|
||||
|
||||
- Instance reviewed: [MIL-008] after the amendment of 2026-10-13: task 5 changed from removing the scoped workflow to deprecating it, with the criterion that follows from it
|
||||
- Checklist used: [QC-MIL-001]
|
||||
- Scope: delta re-review of the amended task 5, criterion 5 and the Deliverable; the earlier record is [RC-060]
|
||||
- Language and domain: n/a (technical type)
|
||||
- Language reviewer: none
|
||||
- Mode: supervised (S01, the user, chose option 1, defer the removal, in chat on 2026-10-13; the AI prepared the record)
|
||||
|
||||
## Checklist Results
|
||||
|
||||
| # | Criterion | Status | Evidence/Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | A concrete deliverable is defined for every gate | Pass | The Deliverable now says the scoped workflow is marked deprecated, not removed. |
|
||||
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Criterion 5 is checkable: a notice in the header, the README and ADR-0009, and the list of repositories recorded; No-Go if it was removed while a repository depends on it. |
|
||||
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged: MIL-006 and the framework's `process/wiki.md`. |
|
||||
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Unchanged: O2, O3. |
|
||||
| 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 | 2026-11-15, unchanged. |
|
||||
|
||||
## Overall Verdict
|
||||
|
||||
Go - all six criteria pass. The amendment follows from a scan on 2026-10-13: 8 repositories still publish through the scoped workflow and none calls the reusable one, so removal would have broken them. Removal and the migrations move to a follow-up milestone that needs its own plan.
|
||||
|
||||
## Action Items
|
||||
|
||||
| Action | Owner | Due |
|
||||
| --- | --- | --- |
|
||||
| Plan the follow-up milestone: migrate the 8 repositories (move `wiki/` to `docs/wiki/`, add the caller from `templates/ci/publish-wiki.yml`), then remove the scoped workflow in a major release | S05 | after the 1.2.2 release |
|
||||
| Add MIL-008 to the Project Plan and review it (open since RC-060) | S05 | before the pull request |
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
[MIL-008]: ../../milestones/mil-008-wiki-reusable-workflow.md
|
||||
[QC-MIL-001]: ../../../framework/qc/artifacts/qc-milestones-gateways.md
|
||||
[RC-060]: ./rc-060-mil-008-plan.md
|
||||
[01b9c29]: https://git.tirsystem.com/TirSystem/github-action/commit/01b9c2972b4317bcc590540010aea0eaf7f30014
|
||||
@@ -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], [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], [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], [MIL-008], [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], [RC-058], [RC-059], [RC-060], [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-051 (ADR-0005 tools-ref) | [670f0ac] |
|
||||
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added MIL-007, RC-052 and RC-053 | [e3ad1fa] |
|
||||
| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | S01 | Added RC-059 (MIL-007 task 7 results) | [2481c26] |
|
||||
| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | S01 | Added MIL-008, RC-060 and RC-061 | [01b9c29] |
|
||||
|
||||
---
|
||||
|
||||
@@ -38,8 +38,9 @@ updated whenever an artifact instance is created or reviewed.
|
||||
| [RC-005] | RC | [MIL-002] | - | - |
|
||||
| [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] | - | [RC-052] |
|
||||
| [MIL-006] | MIL | [BC-001], [PP-001], [MIL-002], [MIL-005] | - | [RC-016], [RC-031], [RC-049], [RC-058] |
|
||||
| [MIL-007] | MIL | [BC-001], [PP-001], [MIL-003], [MIL-004], [ADR-0008] | - | [RC-052], [RC-055], [RC-059] |
|
||||
| [MIL-008] | MIL | [BC-001], [MIL-006], [ADR-0004] | - | [RC-060], [RC-061] |
|
||||
| [RC-007] | RC | [MIL-004] | - | - |
|
||||
| [RC-008] | RC | [BC-001] | - | - |
|
||||
| [RC-009] | RC | [PP-001] | - | - |
|
||||
@@ -57,16 +58,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] | - | - |
|
||||
@@ -103,6 +105,14 @@ updated whenever an artifact instance is created or reviewed.
|
||||
| [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] | - | - |
|
||||
| [RC-058] | RC | [MIL-006] | - | - |
|
||||
| [RC-059] | RC | [MIL-007] | - | - |
|
||||
| [RC-060] | RC | [MIL-008] | - | - |
|
||||
| [RC-061] | RC | [MIL-008] | - | - |
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
@@ -123,6 +133,7 @@ updated whenever an artifact instance is created or reviewed.
|
||||
[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
|
||||
[MIL-008]: ../milestones/mil-008-wiki-reusable-workflow.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
|
||||
@@ -186,11 +197,22 @@ updated whenever an artifact instance is created or reviewed.
|
||||
[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
|
||||
[RC-058]: ./reviews/rc-058-mil-006-task-6.md
|
||||
[RC-059]: ./reviews/rc-059-mil-007-adoption.md
|
||||
[RC-060]: ./reviews/rc-060-mil-008-plan.md
|
||||
[RC-061]: ./reviews/rc-061-mil-008-task-5-deferred.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
|
||||
[670f0ac]: https://git.tirsystem.com/TirSystem/github-action/commit/670f0ac469043bb166c84290c0dbf62b4908e3cc
|
||||
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
|
||||
[faf13b2]: https://git.tirsystem.com/TirSystem/github-action/commit/faf13b2c2a4901c0171977de1ffc2841023f537a
|
||||
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
|
||||
[2481c26]: https://git.tirsystem.com/TirSystem/github-action/commit/2481c26d802464decd51d75539157093b60e08e8
|
||||
[01b9c29]: https://git.tirsystem.com/TirSystem/github-action/commit/01b9c2972b4317bcc590540010aea0eaf7f30014
|
||||
|
||||
+4
-4
@@ -9,8 +9,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [385d2fb] |
|
||||
| 2026-10-11 | Proposed | Jens Tirsvad Nielsen | S01 | Brief extended to C++ and C# (MIL-007 task 1) | [32b5ab6] |
|
||||
| 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] |
|
||||
|
||||
---
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
## 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; format and static checks for C++; format and analyzer checks for C#), and reports one status for the pull request. A language that needs a build or a project file says what is missing instead of passing. 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**
|
||||
|
||||
@@ -43,5 +43,5 @@ A Software Engineer opens a pull request in a repository that calls the shared q
|
||||
[SA-001]: ../stakeholder-analysis.md
|
||||
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
|
||||
[MIL-007]: ../milestones/mil-007-cpp-csharp-quality-checks.md
|
||||
[385d2fb]: https://git.tirsystem.com/TirSystem/github-action/commit/385d2fb7cb9be1fdc8fd3503d0af624fa38eafc7
|
||||
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
|
||||
[1bc56f8]: https://git.tirsystem.com/TirSystem/github-action/commit/1bc56f8b771531f221f218fc00b147ecc73c051e
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-10 | Deprecated | 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 | Proposed | Jens Tirsvad Nielsen | S01 | Added US-001.16 and US-001.17 (C++ and C# checks, MIL-007 task 1) | [32b5ab6] |
|
||||
| 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
|
||||
|
||||
@@ -272,5 +274,5 @@ behaviour is tested rather than built.
|
||||
[UC-005]: ./uc-005/uc.md
|
||||
[UC-006]: ./uc-006/uc.md
|
||||
[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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
|
||||
<!-- translation of Capabilities.md, source sha256 c60d434988dc -->
|
||||
|
||||
> Dette er en oversættelse af [`Capabilities`](Capabilities). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||
|
||||
@@ -13,6 +13,8 @@ Rækker, der siger Implementeret eller Vejledninger er skrevet, findes i dag. Re
|
||||
| Synkronisering af repositorymetadata (Gitea til GitHub-spejl) | Implementeret i `.gitea/scoped_workflows/`, med offline-tests og et valideringsworkflow |
|
||||
| Konfiguration og validering af workflow-credentials | Implementeret for synkroniseringsworkflowet: en forhåndskontrol tjekker begge tokens før enhver ændring ([vejledning](Credentials.da)) |
|
||||
| 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) |
|
||||
| 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); afløses af det genbrugelige workflow nedenfor (ADR-0009) |
|
||||
| Publicering af et repositorys wiki fra `docs/wiki/` gennem et kaldt workflow | Implementeret som det genbrugelige workflow `.gitea/workflows/publish-wiki-pages.yml`, med offline-tests; dette repositorys egen wiki er i `docs/wiki/` og publiceres af det gennem `publish-own-wiki.yml`; endnu ikke kaldt fra et andet repository (MIL-008) |
|
||||
| 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)) |
|
||||
@@ -13,6 +13,8 @@ Rows that say Implemented or Guides written exist today. The rest is planned and
|
||||
| Synchronize repository metadata (Gitea to GitHub mirror) | Implemented in `.gitea/scoped_workflows/`, with offline tests and a validation workflow |
|
||||
| Configure and validate workflow credentials | Implemented for the sync workflow: preflight checks both tokens before any change ([guide](Credentials)) |
|
||||
| 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) |
|
||||
| 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); being replaced by the reusable workflow below (ADR-0009) |
|
||||
| Publish a repository wiki from `docs/wiki/` through a called workflow | Implemented as the reusable workflow `.gitea/workflows/publish-wiki-pages.yml`, with offline tests; this repository's own wiki is in `docs/wiki/` and published by it through `publish-own-wiki.yml`; not yet called from another repository (MIL-008) |
|
||||
| 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)) |
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
|
||||
<!-- translation of Capabilities.md, source sha256 c60d434988dc -->
|
||||
|
||||
> Ini ialah terjemahan [`Capabilities`](Capabilities). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||
|
||||
@@ -13,6 +13,8 @@ Baris yang menyatakan Dilaksanakan atau Panduan telah ditulis wujud hari ini. Se
|
||||
| Menyegerakkan metadata repositori (Gitea ke cermin GitHub) | Dilaksanakan dalam `.gitea/scoped_workflows/`, dengan ujian luar talian dan aliran kerja pengesahan |
|
||||
| Mengkonfigur dan mengesahkan kelayakan (credentials) aliran kerja | Dilaksanakan untuk aliran kerja penyegerakan: semakan awal (preflight) memeriksa kedua-dua token sebelum sebarang perubahan ([panduan](Credentials.ms)) |
|
||||
| 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) |
|
||||
| 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); sedang diganti oleh aliran kerja boleh guna semula di bawah (ADR-0009) |
|
||||
| Menerbitkan wiki repositori daripada `docs/wiki/` melalui aliran kerja yang dipanggil | Dilaksanakan sebagai aliran kerja boleh guna semula `.gitea/workflows/publish-wiki-pages.yml`, dengan ujian luar talian; wiki repositori ini sendiri ada dalam `docs/wiki/` dan diterbitkan olehnya melalui `publish-own-wiki.yml`; belum dipanggil daripada repositori lain (MIL-008) |
|
||||
| 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)) |
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Credentials.md, source sha256 10a051e910de -->
|
||||
<!-- translation of Credentials.md, source sha256 cba8a44e1152 -->
|
||||
|
||||
> Dette er en oversættelse af [`Credentials`](Credentials). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||
|
||||
@@ -56,17 +56,17 @@ Ved succes står der i loggen `Preflight passed: Gitea and GitHub accepted the c
|
||||
|
||||
## Secret til publicering af wiki
|
||||
|
||||
Workflowet **Publish wiki** kopierer `wiki/` til Gitea-wikien i et repository, der har meldt sig til med `wiki/.publish` (se [onboarding.md](Onboarding.da)). Det bruger sin egen secret, så synkroniseringstokenet forbliver skrivebeskyttet.
|
||||
Workflowet **Publish wiki pages** kopierer `docs/wiki/` til Gitea-wikien i et repository, der kalder det (se [onboarding.md](Onboarding.da)). Det bruger sin egen secret, så synkroniseringstokenet forbliver skrivebeskyttet. Kalderen sender secreten i `secrets:`; den nedarves ikke.
|
||||
|
||||
| Secret | Indhold | Bruges til |
|
||||
| --- | --- | --- |
|
||||
| `TOKEN_FOR_GITEA_WIKI` | Gitea-tokenet, intet andet | At skrive wikisiderne for de repositories i en organisation, der melder sig til |
|
||||
|
||||
- Gem den som en secret i organisationen for hvert repository, der publicerer. Der er ingen reserve til `TOKEN_FOR_GITEA`: et repository, der har meldt sig til og ikke har secreten, fejler med en konfigurationsfejl, og et repository, der ikke har meldt sig til, behøver den ikke.
|
||||
- Gem den som en secret i organisationen for hvert repository, der publicerer. Der er ingen reserve til `TOKEN_FOR_GITEA`: et repository, der kalder workflowet og ikke har secreten, fejler med en konfigurationsfejl, og et repository, der ikke kalder det, behøver den ikke.
|
||||
- Tokenet skal have scope `write:repository`, og dets bruger skal have skriveadgang til repositories. Gitea har intet scope kun til wikien, så opret tokenet til en dedikeret bruger. S05 godkender scopet, og S03 gemmer secreten.
|
||||
- Kald, der foretages: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`, `GET`, `POST` og `PATCH /repos/{owner}/{repo}/wiki/...` og, for en side, der ikke længere findes i `wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- Kald, der foretages: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`, `GET`, `POST` og `PATCH /repos/{owner}/{repo}/wiki/...` og, for en side, der ikke længere findes i `docs/wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- Wikien skal være aktiveret i repositoryets indstillinger. Workflowet nægter at køre, hvis den ikke er det.
|
||||
- Sider, der findes i `wiki/`, overskrives altid fra den, så en ændring i Gitea's weboverflade går tabt ved næste publicering. Sider, der kun findes i wikien, fjernes kun, når `wiki/.publish` indeholder ordet `prune`.
|
||||
- Sider, der findes i `docs/wiki/`, overskrives altid fra den, så en ændring i Gitea's weboverflade går tabt ved næste publicering. Sider, der kun findes i wikien, fjernes kun, når kaldet sætter `prune: "true"`.
|
||||
|
||||
## Udskiftning af et token
|
||||
|
||||
@@ -88,29 +88,30 @@ is ever printed.
|
||||
|
||||
## Wiki publishing secret
|
||||
|
||||
The workflow **Publish wiki** copies `wiki/` to the Gitea wiki of a repository
|
||||
that has opted in with `wiki/.publish` (see [onboarding.md](Onboarding)). It
|
||||
uses its own secret, so the metadata sync token stays read-only.
|
||||
The workflow **Publish wiki pages** copies `docs/wiki/` to the Gitea wiki of a
|
||||
repository that calls it (see [onboarding.md](Onboarding)). It uses its own
|
||||
secret, so the metadata sync token stays read-only. The caller passes the
|
||||
secret in `secrets:`; it is not inherited.
|
||||
|
||||
| Secret | Content | Used for |
|
||||
| --- | --- | --- |
|
||||
| `TOKEN_FOR_GITEA_WIKI` | The Gitea token, nothing else | Writing the wiki pages of the repositories of an organization that opt in |
|
||||
|
||||
- Store it as a secret of the organization of each repository that publishes.
|
||||
There is no fallback to `TOKEN_FOR_GITEA`: a repository that opted in and has
|
||||
no such secret fails with a configuration error, and a repository that did
|
||||
not opt in does not need it.
|
||||
There is no fallback to `TOKEN_FOR_GITEA`: a repository that calls the
|
||||
workflow and has no such secret fails with a configuration error, and a
|
||||
repository that does not call it does not need it.
|
||||
- The token needs scope `write:repository`, and its user needs write access to
|
||||
the repositories. Gitea has no wiki-only scope, so create the token for a
|
||||
dedicated user. S05 approves the scope and S03 stores the secret.
|
||||
- Calls made: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`,
|
||||
`GET`, `POST` and `PATCH /repos/{owner}/{repo}/wiki/...` and, for a page that
|
||||
no longer exists in `wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
no longer exists in `docs/wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- The wiki must be enabled in the repository settings. The workflow refuses to
|
||||
run when it is not.
|
||||
- Pages that are in `wiki/` are always overwritten from it, so a change made
|
||||
in the Gitea web UI is lost on the next publish. Pages that are only in the
|
||||
wiki are removed only when `wiki/.publish` contains the word `prune`.
|
||||
- Pages that are in `docs/wiki/` are always overwritten from it, so a change
|
||||
made in the Gitea web UI is lost on the next publish. Pages that are only in
|
||||
the wiki are removed only when the call sets `prune: "true"`.
|
||||
|
||||
## Rotating a token
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Credentials.md, source sha256 10a051e910de -->
|
||||
<!-- translation of Credentials.md, source sha256 cba8a44e1152 -->
|
||||
|
||||
> Ini ialah terjemahan [`Credentials`](Credentials). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||
|
||||
@@ -56,17 +56,17 @@ Apabila berjaya, log menyatakan `Preflight passed: Gitea and GitHub accepted the
|
||||
|
||||
## Secret untuk menerbitkan wiki
|
||||
|
||||
Aliran kerja **Publish wiki** menyalin `wiki/` ke wiki Gitea bagi repositori yang telah memilih menyertainya dengan `wiki/.publish` (lihat [onboarding.md](Onboarding.ms)). Ia menggunakan secret sendiri, supaya token penyegerakan metadata kekal baca sahaja.
|
||||
Aliran kerja **Publish wiki pages** menyalin `docs/wiki/` ke wiki Gitea bagi repositori yang memanggilnya (lihat [onboarding.md](Onboarding.ms)). Ia menggunakan secret sendiri, supaya token penyegerakan metadata kekal baca sahaja. Pemanggil menghantar secret dalam `secrets:`; ia tidak diwarisi.
|
||||
|
||||
| Secret | Kandungan | Digunakan untuk |
|
||||
| --- | --- | --- |
|
||||
| `TOKEN_FOR_GITEA_WIKI` | Token Gitea, tiada yang lain | Menulis halaman wiki bagi repositori dalam organisasi yang memilih menyertainya |
|
||||
|
||||
- Simpan sebagai secret organisasi bagi setiap repositori yang menerbitkan. Tiada sandaran kepada `TOKEN_FOR_GITEA`: repositori yang telah memilih menyertainya dan tidak mempunyai secret itu gagal dengan ralat konfigurasi, dan repositori yang tidak memilih tidak memerlukannya.
|
||||
- Simpan sebagai secret organisasi bagi setiap repositori yang menerbitkan. Tiada sandaran kepada `TOKEN_FOR_GITEA`: repositori yang memanggil aliran kerja dan tidak mempunyai secret itu gagal dengan ralat konfigurasi, dan repositori yang tidak memanggilnya tidak memerlukannya.
|
||||
- Token mesti mempunyai skop `write:repository`, dan penggunanya mesti mempunyai akses tulis kepada repositori. Gitea tidak mempunyai skop untuk wiki sahaja, jadi cipta token untuk pengguna khusus. S05 meluluskan skop dan S03 menyimpan secret.
|
||||
- Panggilan yang dibuat: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`, `GET`, `POST` dan `PATCH /repos/{owner}/{repo}/wiki/...` dan, bagi halaman yang tidak lagi wujud dalam `wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- Panggilan yang dibuat: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`, `GET`, `POST` dan `PATCH /repos/{owner}/{repo}/wiki/...` dan, bagi halaman yang tidak lagi wujud dalam `docs/wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- Wiki mesti diaktifkan dalam tetapan repositori. Aliran kerja enggan berjalan jika ia tidak diaktifkan.
|
||||
- Halaman yang ada dalam `wiki/` sentiasa ditimpa daripadanya, jadi perubahan yang dibuat dalam antara muka web Gitea hilang pada penerbitan seterusnya. Halaman yang hanya ada dalam wiki dibuang hanya apabila `wiki/.publish` mengandungi perkataan `prune`.
|
||||
- Halaman yang ada dalam `docs/wiki/` sentiasa ditimpa daripadanya, jadi perubahan yang dibuat dalam antara muka web Gitea hilang pada penerbitan seterusnya. Halaman yang hanya ada dalam wiki dibuang hanya apabila panggilan menetapkan `prune: "true"`.
|
||||
|
||||
## Menukar token
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Home.md, source sha256 510b243ec5f2 -->
|
||||
<!-- translation of Home.md, source sha256 b6796554f4eb -->
|
||||
|
||||
> 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,24 @@ 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 ti workflows: synkronisering af metadata til GitHub-spejlet, publicering af wiki (scoped og genbrugeligt for repositories, der kalder det), 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 ti 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 |
|
||||
| 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`; forældet, afløses af det genbrugelige workflow nedenfor (ADR-0009) | push til `main`, der ændrer `wiki/**`, manuelt | Publicerer siderne i `wiki/` til repositoryets wiki |
|
||||
| Publish wiki pages | [`publish-wiki-pages.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-wiki-pages.yml) | Genbrugeligt (`workflow_call`) | et kald fra et andet repository | Publicerer siderne i `docs/wiki/` (eller den mappe, `wiki_dir` angiver) til wikien i det kaldende repository |
|
||||
| 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 |
|
||||
| Publish own wiki | [`publish-own-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-own-wiki.yml) | Kun dette repository | push til `main`, der ændrer `docs/wiki/**`, manuelt | Kalder det genbrugelige workflow Publish wiki pages for dette repositorys wiki |
|
||||
| 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
|
||||
@@ -94,7 +99,7 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publicering af wiki
|
||||
### Publicering af wiki (scoped, forældet)
|
||||
|
||||
Publicerer `wiki/` til repositoryets wiki, kun i et repository, der har tilmeldt sig med `wiki/.publish`. Ordet `prune` i den fil sletter også sider, som ikke findes i `wiki/`.
|
||||
|
||||
@@ -184,6 +189,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 +328,138 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publicering af wiki-sider
|
||||
|
||||
Et genbrugeligt workflow (ADR-0009). Et repository kalder det fra sit eget workflow, så selve kaldet er tilmeldingen, og der behøves ingen markørfil. Det publicerer Markdown-siderne i `wiki_dir` (standard `docs/wiki`) til wikien i det kaldende repository og sletter kun sider, der ikke findes i mappen, når `prune` er `true`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
#### Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish docs/wiki to the wiki of the calling repository
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Calling repository\nuses: ...publish-wiki-pages.yml@v1" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages" as Workflow
|
||||
participant "shared-scripts\n(tools/publish_wiki.py at tools-ref)" as Script
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Caller -> Workflow: Call with wiki_dir, prune and the secret
|
||||
activate Workflow
|
||||
Workflow -> Script: Check out the repository and the script, run it
|
||||
activate Script
|
||||
|
||||
alt wiki_dir does not exist, or has no Markdown pages
|
||||
Script --> Workflow: Fail with [configuration]\n(an empty folder never deletes pages)
|
||||
else
|
||||
Script -> Script: Read prune and TOKEN_FOR_GITEA_WIKI
|
||||
Script -> Wiki: GET repository (preflight)
|
||||
Wiki --> Script: Wiki is enabled, token accepted
|
||||
Script -> Wiki: GET pages
|
||||
Wiki --> Script: Existing pages
|
||||
Script -> Wiki: Create new pages, update changed pages
|
||||
opt prune is true
|
||||
Script -> Wiki: Delete pages that are not in wiki_dir
|
||||
end
|
||||
Script --> Workflow: Log created, updated and deleted counts
|
||||
end
|
||||
deactivate Script
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publicering af egen wiki
|
||||
|
||||
Dette repositorys wiki er `docs/wiki/`. Workflowet kalder det genbrugelige workflow ovenfor med dets lokale sti, med `prune` sat til `true`, så wikien altid er lig med mappen, og `tools-ref` sat til `main`, så scriptet fra samme commit kører. Det er den kalder, et projekt kopierer fra frameworkets `templates/ci/publish-wiki.yml`.
|
||||
|
||||
#### Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish the wiki of this repository (docs/wiki)
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Push to main that changes docs/wiki/**,\nor manual trigger" as Trigger
|
||||
participant "Gitea Actions\npublish-own-wiki" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages\n(called by its local path)" as Workflow
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Trigger -> Caller: Start workflow
|
||||
activate Caller
|
||||
Caller -> Workflow: Call with wiki_dir docs/wiki, prune true,\ntools-ref main and TOKEN_FOR_GITEA_WIKI
|
||||
activate Workflow
|
||||
Workflow -> Wiki: Create, update and delete pages\nso the wiki equals docs/wiki
|
||||
Wiki --> Workflow: Done
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
Caller --> Trigger: Workflow result
|
||||
deactivate Caller
|
||||
@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.
|
||||
@@ -13,19 +13,24 @@ 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 ten workflows: metadata sync to the GitHub mirror, wiki publishing (scoped, and reusable for repositories that call it), 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.
|
||||
Ten 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 |
|
||||
| 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`; deprecated, replaced by the reusable workflow below (ADR-0009) | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki |
|
||||
| Publish wiki pages | [`publish-wiki-pages.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-wiki-pages.yml) | Reusable (`workflow_call`) | a call from another repository | Publishes the pages in `docs/wiki/` (or the folder named by `wiki_dir`) to the wiki of the calling repository |
|
||||
| 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 |
|
||||
| Publish own wiki | [`publish-own-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-own-wiki.yml) | This repository only | push to `main` that changes `docs/wiki/**`, manual | Calls the reusable Publish wiki pages workflow for the wiki of this repository |
|
||||
| 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
|
||||
@@ -94,7 +99,7 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publish wiki
|
||||
### Publish wiki (scoped, deprecated)
|
||||
|
||||
Publishes `wiki/` to the repository wiki, only in a repository that has opted in with `wiki/.publish`. The word `prune` in that file also deletes pages that are not in `wiki/`.
|
||||
|
||||
@@ -184,6 +189,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 +328,138 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publish wiki pages
|
||||
|
||||
A reusable workflow (ADR-0009). A repository calls it from its own workflow, so the call is the opt-in and no marker file is needed. It publishes the Markdown pages of `wiki_dir` (default `docs/wiki`) to the wiki of the calling repository, and deletes pages that are not in the folder only when `prune` is `true`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
#### Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish docs/wiki to the wiki of the calling repository
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Calling repository\nuses: ...publish-wiki-pages.yml@v1" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages" as Workflow
|
||||
participant "shared-scripts\n(tools/publish_wiki.py at tools-ref)" as Script
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Caller -> Workflow: Call with wiki_dir, prune and the secret
|
||||
activate Workflow
|
||||
Workflow -> Script: Check out the repository and the script, run it
|
||||
activate Script
|
||||
|
||||
alt wiki_dir does not exist, or has no Markdown pages
|
||||
Script --> Workflow: Fail with [configuration]\n(an empty folder never deletes pages)
|
||||
else
|
||||
Script -> Script: Read prune and TOKEN_FOR_GITEA_WIKI
|
||||
Script -> Wiki: GET repository (preflight)
|
||||
Wiki --> Script: Wiki is enabled, token accepted
|
||||
Script -> Wiki: GET pages
|
||||
Wiki --> Script: Existing pages
|
||||
Script -> Wiki: Create new pages, update changed pages
|
||||
opt prune is true
|
||||
Script -> Wiki: Delete pages that are not in wiki_dir
|
||||
end
|
||||
Script --> Workflow: Log created, updated and deleted counts
|
||||
end
|
||||
deactivate Script
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Publish own wiki
|
||||
|
||||
The wiki of this repository is `docs/wiki/`. This workflow calls the reusable workflow above by its local path, with `prune` set to `true` so the wiki always equals the folder and `tools-ref` set to `main` so that the script of the same commit runs. It is the caller that a project copies from the framework's `templates/ci/publish-wiki.yml`.
|
||||
|
||||
#### Workflow
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish the wiki of this repository (docs/wiki)
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Push to main that changes docs/wiki/**,\nor manual trigger" as Trigger
|
||||
participant "Gitea Actions\npublish-own-wiki" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages\n(called by its local path)" as Workflow
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Trigger -> Caller: Start workflow
|
||||
activate Caller
|
||||
Caller -> Workflow: Call with wiki_dir docs/wiki, prune true,\ntools-ref main and TOKEN_FOR_GITEA_WIKI
|
||||
activate Workflow
|
||||
Workflow -> Wiki: Create, update and delete pages\nso the wiki equals docs/wiki
|
||||
Wiki --> Workflow: Done
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
Caller --> Trigger: Workflow result
|
||||
deactivate Caller
|
||||
@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.
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Home.md, source sha256 510b243ec5f2 -->
|
||||
<!-- translation of Home.md, source sha256 b6796554f4eb -->
|
||||
|
||||
> 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,24 @@ 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 sepuluh aliran kerja: penyegerakan metadata ke cermin GitHub, penerbitan wiki (scoped, dan boleh guna semula bagi repositori yang memanggilnya), 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 sepuluh 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 |
|
||||
| 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`; usang, sedang diganti oleh aliran kerja boleh guna semula di bawah (ADR-0009) | push ke `main` yang mengubah `wiki/**`, manual | Menerbitkan halaman dalam `wiki/` ke wiki repositori |
|
||||
| Publish wiki pages | [`publish-wiki-pages.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-wiki-pages.yml) | Boleh guna semula (`workflow_call`) | panggilan daripada repositori lain | Menerbitkan halaman dalam `docs/wiki/` (atau folder yang dinamakan oleh `wiki_dir`) ke wiki repositori pemanggil |
|
||||
| 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 |
|
||||
| Publish own wiki | [`publish-own-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/publish-own-wiki.yml) | Repositori ini sahaja | push ke `main` yang mengubah `docs/wiki/**`, manual | Memanggil aliran kerja boleh guna semula Publish wiki pages untuk wiki repositori ini |
|
||||
| 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
|
||||
@@ -94,7 +99,7 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Menerbitkan wiki
|
||||
### Menerbitkan wiki (scoped, usang)
|
||||
|
||||
Menerbitkan `wiki/` ke wiki repositori, hanya dalam repositori yang telah menyertai dengan `wiki/.publish`. Perkataan `prune` dalam fail itu juga memadam halaman yang tiada dalam `wiki/`.
|
||||
|
||||
@@ -184,6 +189,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 +328,138 @@ deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Menerbitkan halaman wiki
|
||||
|
||||
Aliran kerja boleh guna semula (ADR-0009). Sesebuah repositori memanggilnya daripada aliran kerjanya sendiri, jadi panggilan itu ialah pilihan menyertai dan tiada fail penanda diperlukan. Ia menerbitkan halaman Markdown dalam `wiki_dir` (lalai `docs/wiki`) ke wiki repositori pemanggil, dan memadam halaman yang tiada dalam folder hanya apabila `prune` ialah `true`.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
#### Aliran kerja
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish docs/wiki to the wiki of the calling repository
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Calling repository\nuses: ...publish-wiki-pages.yml@v1" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages" as Workflow
|
||||
participant "shared-scripts\n(tools/publish_wiki.py at tools-ref)" as Script
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Caller -> Workflow: Call with wiki_dir, prune and the secret
|
||||
activate Workflow
|
||||
Workflow -> Script: Check out the repository and the script, run it
|
||||
activate Script
|
||||
|
||||
alt wiki_dir does not exist, or has no Markdown pages
|
||||
Script --> Workflow: Fail with [configuration]\n(an empty folder never deletes pages)
|
||||
else
|
||||
Script -> Script: Read prune and TOKEN_FOR_GITEA_WIKI
|
||||
Script -> Wiki: GET repository (preflight)
|
||||
Wiki --> Script: Wiki is enabled, token accepted
|
||||
Script -> Wiki: GET pages
|
||||
Wiki --> Script: Existing pages
|
||||
Script -> Wiki: Create new pages, update changed pages
|
||||
opt prune is true
|
||||
Script -> Wiki: Delete pages that are not in wiki_dir
|
||||
end
|
||||
Script --> Workflow: Log created, updated and deleted counts
|
||||
end
|
||||
deactivate Script
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Menerbitkan wiki sendiri
|
||||
|
||||
Wiki repositori ini ialah `docs/wiki/`. Aliran kerja ini memanggil aliran kerja boleh guna semula di atas melalui laluan tempatannya, dengan `prune` ditetapkan kepada `true` supaya wiki sentiasa sama dengan folder dan `tools-ref` ditetapkan kepada `main` supaya skrip daripada commit yang sama dijalankan. Ia ialah pemanggil yang disalin oleh projek daripada `templates/ci/publish-wiki.yml` framework.
|
||||
|
||||
#### Aliran kerja
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title Publish the wiki of this repository (docs/wiki)
|
||||
|
||||
autonumber
|
||||
|
||||
actor "Push to main that changes docs/wiki/**,\nor manual trigger" as Trigger
|
||||
participant "Gitea Actions\npublish-own-wiki" as Caller
|
||||
participant "Gitea Actions\npublish-wiki-pages\n(called by its local path)" as Workflow
|
||||
participant "Gitea wiki API" as Wiki
|
||||
|
||||
Trigger -> Caller: Start workflow
|
||||
activate Caller
|
||||
Caller -> Workflow: Call with wiki_dir docs/wiki, prune true,\ntools-ref main and TOKEN_FOR_GITEA_WIKI
|
||||
activate Workflow
|
||||
Workflow -> Wiki: Create, update and delete pages\nso the wiki equals docs/wiki
|
||||
Wiki --> Workflow: Done
|
||||
Workflow --> Caller: Workflow result
|
||||
deactivate Workflow
|
||||
Caller --> Trigger: Workflow result
|
||||
deactivate Caller
|
||||
@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.
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Onboarding.md, source sha256 1d431898754e -->
|
||||
<!-- translation of Onboarding.md, source sha256 4de4897fb3b7 -->
|
||||
|
||||
> Dette er en oversættelse af [`Onboarding`](Onboarding). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||
|
||||
@@ -32,15 +32,31 @@ Leveringen er automatisk, så et repository behøver ingen kopi af workflowet. S
|
||||
|
||||
## Publicér en wiki (valgfrit)
|
||||
|
||||
Workflowet **Publish wiki** kopierer Markdown-siderne i `wiki/` til repositoryets wiki, når en ændring af `wiki/` flettes til `main`. Det leveres som synkroniseringsworkflowet, men skriver kun, hvor et repository har meldt sig til.
|
||||
Det genbrugelige workflow **Publish wiki pages** kopierer Markdown-siderne i `docs/wiki/` til repositoryets wiki, når en ændring af `docs/wiki/` flettes til `main`. Repositoryet kalder det, så der skrives intet, hvor der ikke findes et kald. Wikien findes som minimum på engelsk og på produktejerens sprog.
|
||||
|
||||
1. Aktivér wikien i repositoryets indstillinger.
|
||||
2. Tilføj Markdown-sider til `wiki/`. Filnavnet er sidens navn: `Home.md` er forsiden.
|
||||
3. Tilføj markøren `wiki/.publish`. Lad den være tom for kun at oprette og opdatere sider. Skriv det ene ord `prune` i den for også at slette wiki-sider, der ikke findes i `wiki/`, så wikien altid er lig med mappen.
|
||||
2. Tilføj Markdown-sider til `docs/wiki/`. Filnavnet er sidens navn: `Home.md` er forsiden. En bindestreg i navnet er et mellemrum i sidens navn: `Home-da.md` er siden "Home da", og et link til den er `[Dansk](Home-da)`.
|
||||
3. Tilføj et workflow, for eksempel `.gitea/workflows/publish-wiki.yml`, der kalder det genbrugelige workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
with:
|
||||
prune: "true"
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
`wiki_dir` er som standard `docs/wiki`. `prune: "true"` sletter også wiki-sider, der ikke findes i mappen, så wikien altid er lig med mappen; standarden `false` beholder dem.
|
||||
4. Gem `TOKEN_FOR_GITEA_WIKI` som en secret i repositoryets organisation med det scope, der står i [credentials.md](Credentials.da).
|
||||
5. Flet ændringen til `main`. Loggen skal slutte med `Published <n> page(s) to the wiki of <owner>/<repo>`.
|
||||
|
||||
Et repository uden `wiki/.publish` springes over med linjen `No wiki/.publish marker in <owner>/<repo>`: intet bliver skrevet, og der skal ingen secret til.
|
||||
Et repository, der stadig har markøren `wiki/.publish`, publiceres af det ældre scoped workflow, som fjernes, når alle repositories har et kald. Flyt siderne til `docs/wiki/` og tilføj kaldet, før det sker.
|
||||
|
||||
## Runners
|
||||
|
||||
@@ -51,24 +51,43 @@ Delivery is automatic, so a repository needs no copy of the workflow. Secrets ar
|
||||
|
||||
## Publish a wiki (optional)
|
||||
|
||||
The **Publish wiki** workflow copies the Markdown pages in `wiki/` to the
|
||||
repository wiki when a change to `wiki/` is merged to `main`. It is delivered
|
||||
like the sync workflow, but it writes only where a repository opts in.
|
||||
The reusable workflow **Publish wiki pages** copies the Markdown pages in
|
||||
`docs/wiki/` to the repository wiki when a change to `docs/wiki/` is merged to
|
||||
`main`. The repository calls it, so nothing is written where no call exists.
|
||||
The wiki has English and the product owner's language as a minimum.
|
||||
|
||||
1. Enable the wiki in the repository settings.
|
||||
2. Add Markdown pages to `wiki/`. The file name is the page name: `Home.md` is
|
||||
the home page.
|
||||
3. Add the marker `wiki/.publish`. Leave it empty to create and update pages
|
||||
only. Put the single word `prune` in it to also delete wiki pages that are
|
||||
not in `wiki/`, so the wiki always equals the folder.
|
||||
2. Add Markdown pages to `docs/wiki/`. The file name is the page name: `Home.md`
|
||||
is the home page. A hyphen in the name is a space in the page name:
|
||||
`Home-da.md` is the page "Home da", and a link to it is `[Dansk](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/Home-da)`.
|
||||
3. Add a workflow, for example `.gitea/workflows/publish-wiki.yml`, that calls
|
||||
the reusable workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
with:
|
||||
prune: "true"
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
`wiki_dir` defaults to `docs/wiki`. `prune: "true"` also deletes wiki pages
|
||||
that are not in the folder, so the wiki always equals the folder; the
|
||||
default `false` keeps them.
|
||||
4. Store `TOKEN_FOR_GITEA_WIKI` as a secret of the repository's organization,
|
||||
using the scope in [credentials.md](Credentials).
|
||||
5. Merge the change to `main`. The log must end with `Published <n> page(s) to
|
||||
the wiki of <owner>/<repo>`.
|
||||
|
||||
A repository without `wiki/.publish` is skipped with the line `No
|
||||
wiki/.publish marker in <owner>/<repo>`: nothing is written and no secret is
|
||||
needed.
|
||||
A repository that still has the marker `wiki/.publish` is published by the
|
||||
older scoped workflow, which is removed once every repository has a call.
|
||||
Move the pages to `docs/wiki/` and add the call before that.
|
||||
|
||||
## Runners
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Onboarding.md, source sha256 1d431898754e -->
|
||||
<!-- translation of Onboarding.md, source sha256 4de4897fb3b7 -->
|
||||
|
||||
> Ini ialah terjemahan [`Onboarding`](Onboarding). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||
|
||||
@@ -32,15 +32,31 @@ Penghantaran adalah automatik, jadi repositori tidak memerlukan salinan aliran k
|
||||
|
||||
## Menerbitkan wiki (pilihan)
|
||||
|
||||
Aliran kerja **Publish wiki** menyalin halaman Markdown dalam `wiki/` ke wiki repositori apabila perubahan pada `wiki/` digabungkan ke `main`. Ia dihantar seperti aliran kerja penyegerakan, tetapi hanya menulis di tempat repositori telah memilih untuk menyertainya.
|
||||
Aliran kerja boleh guna semula **Publish wiki pages** menyalin halaman Markdown dalam `docs/wiki/` ke wiki repositori apabila perubahan pada `docs/wiki/` digabungkan ke `main`. Repositori memanggilnya, jadi tiada apa-apa ditulis di tempat yang tiada panggilan. Wiki ada dalam bahasa Inggeris dan bahasa pemilik produk sekurang-kurangnya.
|
||||
|
||||
1. Aktifkan wiki dalam tetapan repositori.
|
||||
2. Tambah halaman Markdown ke `wiki/`. Nama fail ialah nama halaman: `Home.md` ialah halaman utama.
|
||||
3. Tambah penanda `wiki/.publish`. Biarkan kosong untuk mencipta dan mengemas kini halaman sahaja. Letakkan satu perkataan `prune` di dalamnya untuk turut memadam halaman wiki yang tiada dalam `wiki/`, supaya wiki sentiasa sama dengan folder itu.
|
||||
2. Tambah halaman Markdown ke `docs/wiki/`. Nama fail ialah nama halaman: `Home.md` ialah halaman utama. Tanda sempang dalam nama ialah ruang dalam nama halaman: `Home-da.md` ialah halaman "Home da", dan pautan kepadanya ialah `[Dansk](Home-da)`.
|
||||
3. Tambah aliran kerja, contohnya `.gitea/workflows/publish-wiki.yml`, yang memanggil aliran kerja boleh guna semula:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
with:
|
||||
prune: "true"
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
`wiki_dir` lalai ialah `docs/wiki`. `prune: "true"` turut memadam halaman wiki yang tiada dalam folder itu, supaya wiki sentiasa sama dengan folder; lalai `false` mengekalkannya.
|
||||
4. Simpan `TOKEN_FOR_GITEA_WIKI` sebagai secret organisasi repositori, dengan skop yang tertera dalam [credentials.md](Credentials.ms).
|
||||
5. Gabungkan perubahan ke `main`. Log mesti berakhir dengan `Published <n> page(s) to the wiki of <owner>/<repo>`.
|
||||
|
||||
Repositori tanpa `wiki/.publish` dilangkau dengan baris `No wiki/.publish marker in <owner>/<repo>`: tiada apa-apa ditulis dan tiada secret diperlukan.
|
||||
Repositori yang masih mempunyai penanda `wiki/.publish` diterbitkan oleh aliran kerja scoped yang lebih lama, yang dibuang apabila setiap repositori mempunyai panggilan. Alihkan halaman ke `docs/wiki/` dan tambah panggilan sebelum itu.
|
||||
|
||||
## Runners
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<!-- translation of QualityChecksCSharp.md, source sha256 36e34031e0b9 -->
|
||||
|
||||
> 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`. Stien er absolut i runnerens arbejdsområde (`/workspace/<owner>/<repo>/src/Program.cs(8,27)`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,103 @@
|
||||
<!-- 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`.
|
||||
The path is absolute in the workspace of the runner
|
||||
(`/workspace/<owner>/<repo>/src/Program.cs(8,27)`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,85 @@
|
||||
<!-- translation of QualityChecksCSharp.md, source sha256 36e34031e0b9 -->
|
||||
|
||||
> 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`. Laluan itu mutlak dalam ruang kerja runner (`/workspace/<owner>/<repo>/src/Program.cs(8,27)`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,88 @@
|
||||
<!-- translation of QualityChecksCpp.md, source sha256 6faa57183a11 -->
|
||||
|
||||
> 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`. `clang-format` skriver stier relative til `working-directory`; `clang-tidy` skriver absolutte stier i runnerens arbejdsområde (`/workspace/<owner>/<repo>/main.cpp:5:18`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,108 @@
|
||||
<!-- 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`.
|
||||
`clang-format` prints paths relative to `working-directory`; `clang-tidy`
|
||||
prints absolute paths in the workspace of the runner
|
||||
(`/workspace/<owner>/<repo>/main.cpp:5:18`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,88 @@
|
||||
<!-- translation of QualityChecksCpp.md, source sha256 6faa57183a11 -->
|
||||
|
||||
> 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`. `clang-format` menulis laluan relatif kepada `working-directory`; `clang-tidy` menulis laluan mutlak dalam ruang kerja runner (`/workspace/<owner>/<repo>/main.cpp:5:18`).
|
||||
|
||||
## 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) |
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Troubleshooting.md, source sha256 eb63f4109a0d -->
|
||||
<!-- translation of Troubleshooting.md, source sha256 c68827295812 -->
|
||||
|
||||
> Dette er en oversættelse af [`Troubleshooting`](Troubleshooting). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||
|
||||
@@ -30,11 +30,13 @@ Kategorien fortæller, hvor du skal kigge. En fejl uden for scriptet (jobbet sta
|
||||
| `TOKEN_FOR_GITEA is missing or empty.` | configuration | Tilføj secreten |
|
||||
| `Could not determine the Gitea source repository.` | configuration | Kørslen har intet repositorynavn; meld det som en defekt |
|
||||
| `Expected at most one GitHub push mirror ... found N` | configuration | Behold ét GitHub push-spejl |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Kun wiki-publicering: repositoryet har meldt sig til med `wiki/.publish`, men dets organisation har ingen sådan secret; gem den (se [credentials.md](Credentials.da)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Kun wiki-publicering: lad markøren være tom, eller skriv kun ordet `prune` i den |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Kun wiki-publicering: repositoryet kalder workflowet, men dets organisation har ingen sådan secret, eller kaldet sender den ikke; gem den og send den i `secrets:` (se [credentials.md](Credentials.da)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Kun wiki-publicering gennem det ældre scoped workflow: lad markøren være tom, eller skriv kun ordet `prune` i den |
|
||||
| `The prune input must be 'true' or 'false'` | configuration | Kun wiki-publicering: sæt `prune` i kaldet til `"true"` eller `"false"` |
|
||||
| `The wiki folder ... does not exist` | configuration | Kun wiki-publicering: sæt `wiki_dir` i kaldet til mappen med siderne (standard `docs/wiki`) |
|
||||
| `... HTTP 403 ...` ved publicering af wikien | permissions | Kun wiki-publicering: tokenet skal have `write:repository` og skriveadgang til dette repository |
|
||||
| `The wiki is not enabled on <repo>` | configuration | Kun wiki-publicering: aktivér wikien i repositoryets indstillinger |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Kun wiki-publicering: `wiki/` er tom eller mangler; intet blev ændret |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Kun wiki-publicering: mappen har ingen Markdown-sider; intet blev ændret |
|
||||
| `Could not determine the GitHub owner and repository ...` | configuration | Spejlets adresse skal se ud som `https://github.com/<owner>/<repo>.git` |
|
||||
| `Gitea API request failed with HTTP 401` | credentials | Opret et nyt Gitea-token, og opdatér `TOKEN_FOR_GITEA` |
|
||||
| `GitHub API request failed with HTTP 401` | credentials | Opret et nyt GitHub-token, og opdatér `PAT_FOR_GITHUB`; værdien skal kun være tokenet (intet navn, ingen anførselstegn eller JSON) |
|
||||
@@ -51,9 +53,9 @@ Kategorien fortæller, hvor du skal kigge. En fejl uden for scriptet (jobbet sta
|
||||
|
||||
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not synced.` Kørslen lykkes, men intet blev synkroniseret. Kontroller, at Gitea-versionen understøtter push mirror-API'et, og kør igen.
|
||||
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for this repository.` Kørslen af Publish wiki lykkes og skriver intet. Repositoryet har ikke meldt sig til; tilføj `wiki/.publish`, hvis det skal publicere.
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for this repository.` Kørslen af det ældre scoped Publish wiki lykkes og skriver intet. Repositoryet har ikke meldt sig til; kald det genbrugelige workflow **Publish wiki pages** (se [onboarding.md](Onboarding.da)), hvis det skal publicere.
|
||||
|
||||
`<n> page(s) are in the wiki but not in wiki/ and were kept; put the word 'prune' in wiki/.publish to delete them.` Kørslen lykkes. Sider, der kun findes i wikien, lades i fred, medmindre markøren indeholder `prune`.
|
||||
`<n> page(s) are in the wiki but not in <folder>/ and were kept; set the prune input to true to delete them.` Kørslen lykkes. Sider, der kun findes i wikien, lades i fred, medmindre kaldet sætter `prune: "true"` (med det ældre scoped workflow: ordet `prune` i `wiki/.publish`).
|
||||
|
||||
## Runner-problemer
|
||||
|
||||
@@ -32,11 +32,13 @@ never starts, or stops before the step) is a **runner** problem.
|
||||
| `TOKEN_FOR_GITEA is missing or empty.` | configuration | Add the secret |
|
||||
| `Could not determine the Gitea source repository.` | configuration | The run has no repository name; report as a defect |
|
||||
| `Expected at most one GitHub push mirror ... found N` | configuration | Keep one GitHub push mirror |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Wiki publishing only: the repository opted in with `wiki/.publish` but its organization has no such secret; store it (see [credentials.md](Credentials)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Wiki publishing only: leave the marker empty, or put only the word `prune` in it |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Wiki publishing only: the repository calls the workflow but its organization has no such secret, or the call does not pass it; store it and pass it in `secrets:` (see [credentials.md](Credentials)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Wiki publishing through the older scoped workflow only: leave the marker empty, or put only the word `prune` in it |
|
||||
| `The prune input must be 'true' or 'false'` | configuration | Wiki publishing only: set `prune` in the call to `"true"` or `"false"` |
|
||||
| `The wiki folder ... does not exist` | configuration | Wiki publishing only: set `wiki_dir` in the call to the folder with the pages (default `docs/wiki`) |
|
||||
| `... HTTP 403 ...` while publishing the wiki | permissions | Wiki publishing only: the token needs `write:repository` and write access to this repository |
|
||||
| `The wiki is not enabled on <repo>` | configuration | Wiki publishing only: enable the wiki in the repository settings |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Wiki publishing only: `wiki/` is empty or missing; nothing was changed |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Wiki publishing only: the folder has no Markdown pages; nothing was changed |
|
||||
| `Could not determine the GitHub owner and repository ...` | configuration | The mirror address must look like `https://github.com/<owner>/<repo>.git` |
|
||||
| `Gitea API request failed with HTTP 401` | credentials | Create a new Gitea token and update `TOKEN_FOR_GITEA` |
|
||||
| `GitHub API request failed with HTTP 401` | credentials | Create a new GitHub token and update `PAT_FOR_GITHUB`; the value must be the token only (no name, quotes or JSON) |
|
||||
@@ -59,12 +61,14 @@ synced.` The run succeeds but nothing was synced. Check that the Gitea
|
||||
version supports the push mirror API and re-run.
|
||||
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for
|
||||
this repository.` The Publish wiki run succeeds and writes nothing. The
|
||||
repository has not opted in; add `wiki/.publish` if it should publish.
|
||||
this repository.` The older scoped Publish wiki run succeeds and writes
|
||||
nothing. The repository has not opted in; call the reusable workflow
|
||||
**Publish wiki pages** (see [onboarding.md](Onboarding)) if it should publish.
|
||||
|
||||
`<n> page(s) are in the wiki but not in wiki/ and were kept; put the word
|
||||
'prune' in wiki/.publish to delete them.` The run succeeds. Pages that exist
|
||||
only in the wiki are left alone unless the marker contains `prune`.
|
||||
`<n> page(s) are in the wiki but not in <folder>/ and were kept; set the prune
|
||||
input to true to delete them.` The run succeeds. Pages that exist only in the
|
||||
wiki are left alone unless the call sets `prune: "true"` (with the older scoped
|
||||
workflow: the word `prune` in `wiki/.publish`).
|
||||
|
||||
## Runner problems
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translation of Troubleshooting.md, source sha256 eb63f4109a0d -->
|
||||
<!-- translation of Troubleshooting.md, source sha256 c68827295812 -->
|
||||
|
||||
> Ini ialah terjemahan [`Troubleshooting`](Troubleshooting). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||
|
||||
@@ -30,11 +30,13 @@ Kategori menunjukkan di mana perlu dilihat. Kegagalan di luar skrip (kerja tidak
|
||||
| `TOKEN_FOR_GITEA is missing or empty.` | configuration | Tambah secret |
|
||||
| `Could not determine the Gitea source repository.` | configuration | Larian tiada nama repositori; laporkan sebagai kecacatan |
|
||||
| `Expected at most one GitHub push mirror ... found N` | configuration | Kekalkan satu push mirror GitHub |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Penerbitan wiki sahaja: repositori telah memilih menyertainya dengan `wiki/.publish` tetapi organisasinya tiada secret itu; simpannya (lihat [credentials.md](Credentials.ms)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Penerbitan wiki sahaja: biarkan penanda kosong, atau letakkan hanya perkataan `prune` di dalamnya |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Penerbitan wiki sahaja: repositori memanggil aliran kerja tetapi organisasinya tiada secret itu, atau panggilan tidak menghantarnya; simpannya dan hantar dalam `secrets:` (lihat [credentials.md](Credentials.ms)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Penerbitan wiki melalui aliran kerja scoped yang lebih lama sahaja: biarkan penanda kosong, atau letakkan hanya perkataan `prune` di dalamnya |
|
||||
| `The prune input must be 'true' or 'false'` | configuration | Penerbitan wiki sahaja: tetapkan `prune` dalam panggilan kepada `"true"` atau `"false"` |
|
||||
| `The wiki folder ... does not exist` | configuration | Penerbitan wiki sahaja: tetapkan `wiki_dir` dalam panggilan kepada folder yang mengandungi halaman (lalai `docs/wiki`) |
|
||||
| `... HTTP 403 ...` semasa menerbitkan wiki | permissions | Penerbitan wiki sahaja: token memerlukan `write:repository` dan akses tulis kepada repositori ini |
|
||||
| `The wiki is not enabled on <repo>` | configuration | Penerbitan wiki sahaja: aktifkan wiki dalam tetapan repositori |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Penerbitan wiki sahaja: `wiki/` kosong atau tiada; tiada apa-apa diubah |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Penerbitan wiki sahaja: folder itu tiada halaman Markdown; tiada apa-apa diubah |
|
||||
| `Could not determine the GitHub owner and repository ...` | configuration | Alamat cermin mesti kelihatan seperti `https://github.com/<owner>/<repo>.git` |
|
||||
| `Gitea API request failed with HTTP 401` | credentials | Cipta token Gitea baharu dan kemas kini `TOKEN_FOR_GITEA` |
|
||||
| `GitHub API request failed with HTTP 401` | credentials | Cipta token GitHub baharu dan kemas kini `PAT_FOR_GITHUB`; nilai mesti token sahaja (tiada nama, tanda petikan atau JSON) |
|
||||
@@ -51,9 +53,9 @@ Kategori menunjukkan di mana perlu dilihat. Kegagalan di luar skrip (kerja tidak
|
||||
|
||||
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not synced.` Larian berjaya tetapi tiada apa-apa disegerakkan. Semak bahawa versi Gitea menyokong API push mirror dan jalankan semula.
|
||||
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for this repository.` Larian Publish wiki berjaya dan tidak menulis apa-apa. Repositori belum memilih menyertainya; tambah `wiki/.publish` jika ia sepatutnya menerbitkan.
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for this repository.` Larian Publish wiki scoped yang lebih lama berjaya dan tidak menulis apa-apa. Repositori belum memilih menyertainya; panggil aliran kerja boleh guna semula **Publish wiki pages** (lihat [onboarding.md](Onboarding.ms)) jika ia sepatutnya menerbitkan.
|
||||
|
||||
`<n> page(s) are in the wiki but not in wiki/ and were kept; put the word 'prune' in wiki/.publish to delete them.` Larian berjaya. Halaman yang hanya ada dalam wiki dibiarkan melainkan penanda mengandungi `prune`.
|
||||
`<n> page(s) are in the wiki but not in <folder>/ and were kept; set the prune input to true to delete them.` Larian berjaya. Halaman yang hanya ada dalam wiki dibiarkan melainkan panggilan menetapkan `prune: "true"` (dengan aliran kerja scoped yang lebih lama: perkataan `prune` dalam `wiki/.publish`).
|
||||
|
||||
## Masalah runner
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
+1
-1
Submodule framework updated: 14d221ec1c...592c5fc9b7
+11
-10
@@ -82,29 +82,30 @@ is ever printed.
|
||||
|
||||
## Wiki publishing secret
|
||||
|
||||
The workflow **Publish wiki** copies `wiki/` to the Gitea wiki of a repository
|
||||
that has opted in with `wiki/.publish` (see [onboarding.md](onboarding.md)). It
|
||||
uses its own secret, so the metadata sync token stays read-only.
|
||||
The workflow **Publish wiki pages** copies `docs/wiki/` to the Gitea wiki of a
|
||||
repository that calls it (see [onboarding.md](onboarding.md)). It uses its own
|
||||
secret, so the metadata sync token stays read-only. The caller passes the
|
||||
secret in `secrets:`; it is not inherited.
|
||||
|
||||
| Secret | Content | Used for |
|
||||
| --- | --- | --- |
|
||||
| `TOKEN_FOR_GITEA_WIKI` | The Gitea token, nothing else | Writing the wiki pages of the repositories of an organization that opt in |
|
||||
|
||||
- Store it as a secret of the organization of each repository that publishes.
|
||||
There is no fallback to `TOKEN_FOR_GITEA`: a repository that opted in and has
|
||||
no such secret fails with a configuration error, and a repository that did
|
||||
not opt in does not need it.
|
||||
There is no fallback to `TOKEN_FOR_GITEA`: a repository that calls the
|
||||
workflow and has no such secret fails with a configuration error, and a
|
||||
repository that does not call it does not need it.
|
||||
- The token needs scope `write:repository`, and its user needs write access to
|
||||
the repositories. Gitea has no wiki-only scope, so create the token for a
|
||||
dedicated user. S05 approves the scope and S03 stores the secret.
|
||||
- Calls made: `GET /repos/{owner}/{repo}`, `GET /repos/{owner}/{repo}/wiki/pages`,
|
||||
`GET`, `POST` and `PATCH /repos/{owner}/{repo}/wiki/...` and, for a page that
|
||||
no longer exists in `wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
no longer exists in `docs/wiki/`, `DELETE /repos/{owner}/{repo}/wiki/page/{name}`.
|
||||
- The wiki must be enabled in the repository settings. The workflow refuses to
|
||||
run when it is not.
|
||||
- Pages that are in `wiki/` are always overwritten from it, so a change made
|
||||
in the Gitea web UI is lost on the next publish. Pages that are only in the
|
||||
wiki are removed only when `wiki/.publish` contains the word `prune`.
|
||||
- Pages that are in `docs/wiki/` are always overwritten from it, so a change
|
||||
made in the Gitea web UI is lost on the next publish. Pages that are only in
|
||||
the wiki are removed only when the call sets `prune: "true"`.
|
||||
|
||||
## Rotating a token
|
||||
|
||||
|
||||
+30
-11
@@ -45,24 +45,43 @@ Delivery is automatic, so a repository needs no copy of the workflow. Secrets ar
|
||||
|
||||
## Publish a wiki (optional)
|
||||
|
||||
The **Publish wiki** workflow copies the Markdown pages in `wiki/` to the
|
||||
repository wiki when a change to `wiki/` is merged to `main`. It is delivered
|
||||
like the sync workflow, but it writes only where a repository opts in.
|
||||
The reusable workflow **Publish wiki pages** copies the Markdown pages in
|
||||
`docs/wiki/` to the repository wiki when a change to `docs/wiki/` is merged to
|
||||
`main`. The repository calls it, so nothing is written where no call exists.
|
||||
The wiki has English and the product owner's language as a minimum.
|
||||
|
||||
1. Enable the wiki in the repository settings.
|
||||
2. Add Markdown pages to `wiki/`. The file name is the page name: `Home.md` is
|
||||
the home page.
|
||||
3. Add the marker `wiki/.publish`. Leave it empty to create and update pages
|
||||
only. Put the single word `prune` in it to also delete wiki pages that are
|
||||
not in `wiki/`, so the wiki always equals the folder.
|
||||
2. Add Markdown pages to `docs/wiki/`. The file name is the page name: `Home.md`
|
||||
is the home page. A hyphen in the name is a space in the page name:
|
||||
`Home-da.md` is the page "Home da", and a link to it is `[Dansk](Home-da)`.
|
||||
3. Add a workflow, for example `.gitea/workflows/publish-wiki.yml`, that calls
|
||||
the reusable workflow:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths: [ "docs/wiki/**" ]
|
||||
jobs:
|
||||
wiki:
|
||||
uses: TirSystem/github-action/.gitea/workflows/publish-wiki-pages.yml@v1
|
||||
with:
|
||||
prune: "true"
|
||||
secrets:
|
||||
TOKEN_FOR_GITEA_WIKI: ${{ secrets.TOKEN_FOR_GITEA_WIKI }}
|
||||
```
|
||||
|
||||
`wiki_dir` defaults to `docs/wiki`. `prune: "true"` also deletes wiki pages
|
||||
that are not in the folder, so the wiki always equals the folder; the
|
||||
default `false` keeps them.
|
||||
4. Store `TOKEN_FOR_GITEA_WIKI` as a secret of the repository's organization,
|
||||
using the scope in [credentials.md](credentials.md).
|
||||
5. Merge the change to `main`. The log must end with `Published <n> page(s) to
|
||||
the wiki of <owner>/<repo>`.
|
||||
|
||||
A repository without `wiki/.publish` is skipped with the line `No
|
||||
wiki/.publish marker in <owner>/<repo>`: nothing is written and no secret is
|
||||
needed.
|
||||
A repository that still has the marker `wiki/.publish` is published by the
|
||||
older scoped workflow, which is removed once every repository has a call.
|
||||
Move the pages to `docs/wiki/` and add the call before that.
|
||||
|
||||
## Runners
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# 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`.
|
||||
`clang-format` prints paths relative to `working-directory`; `clang-tidy`
|
||||
prints absolute paths in the workspace of the runner
|
||||
(`/workspace/<owner>/<repo>/main.cpp:5:18`).
|
||||
|
||||
## 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) |
|
||||
@@ -0,0 +1,97 @@
|
||||
# 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`.
|
||||
The path is absolute in the workspace of the runner
|
||||
(`/workspace/<owner>/<repo>/src/Program.cs(8,27)`).
|
||||
|
||||
## 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) |
|
||||
@@ -26,11 +26,13 @@ never starts, or stops before the step) is a **runner** problem.
|
||||
| `TOKEN_FOR_GITEA is missing or empty.` | configuration | Add the secret |
|
||||
| `Could not determine the Gitea source repository.` | configuration | The run has no repository name; report as a defect |
|
||||
| `Expected at most one GitHub push mirror ... found N` | configuration | Keep one GitHub push mirror |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Wiki publishing only: the repository opted in with `wiki/.publish` but its organization has no such secret; store it (see [credentials.md](credentials.md)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Wiki publishing only: leave the marker empty, or put only the word `prune` in it |
|
||||
| `TOKEN_FOR_GITEA_WIKI is missing or empty.` | configuration | Wiki publishing only: the repository calls the workflow but its organization has no such secret, or the call does not pass it; store it and pass it in `secrets:` (see [credentials.md](credentials.md)) |
|
||||
| `wiki/.publish may only be empty or contain the word 'prune'.` | configuration | Wiki publishing through the older scoped workflow only: leave the marker empty, or put only the word `prune` in it |
|
||||
| `The prune input must be 'true' or 'false'` | configuration | Wiki publishing only: set `prune` in the call to `"true"` or `"false"` |
|
||||
| `The wiki folder ... does not exist` | configuration | Wiki publishing only: set `wiki_dir` in the call to the folder with the pages (default `docs/wiki`) |
|
||||
| `... HTTP 403 ...` while publishing the wiki | permissions | Wiki publishing only: the token needs `write:repository` and write access to this repository |
|
||||
| `The wiki is not enabled on <repo>` | configuration | Wiki publishing only: enable the wiki in the repository settings |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Wiki publishing only: `wiki/` is empty or missing; nothing was changed |
|
||||
| `The wiki source directory ... has no Markdown pages` | configuration | Wiki publishing only: the folder has no Markdown pages; nothing was changed |
|
||||
| `Could not determine the GitHub owner and repository ...` | configuration | The mirror address must look like `https://github.com/<owner>/<repo>.git` |
|
||||
| `Gitea API request failed with HTTP 401` | credentials | Create a new Gitea token and update `TOKEN_FOR_GITEA` |
|
||||
| `GitHub API request failed with HTTP 401` | credentials | Create a new GitHub token and update `PAT_FOR_GITHUB`; the value must be the token only (no name, quotes or JSON) |
|
||||
@@ -53,12 +55,14 @@ synced.` The run succeeds but nothing was synced. Check that the Gitea
|
||||
version supports the push mirror API and re-run.
|
||||
|
||||
`No wiki/.publish marker in <owner>/<repo>; wiki publishing is not enabled for
|
||||
this repository.` The Publish wiki run succeeds and writes nothing. The
|
||||
repository has not opted in; add `wiki/.publish` if it should publish.
|
||||
this repository.` The older scoped Publish wiki run succeeds and writes
|
||||
nothing. The repository has not opted in; call the reusable workflow
|
||||
**Publish wiki pages** (see [onboarding.md](onboarding.md)) if it should publish.
|
||||
|
||||
`<n> page(s) are in the wiki but not in wiki/ and were kept; put the word
|
||||
'prune' in wiki/.publish to delete them.` The run succeeds. Pages that exist
|
||||
only in the wiki are left alone unless the marker contains `prune`.
|
||||
`<n> page(s) are in the wiki but not in <folder>/ and were kept; set the prune
|
||||
input to true to delete them.` The run succeeds. Pages that exist only in the
|
||||
wiki are left alone unless the call sets `prune: "true"` (with the older scoped
|
||||
workflow: the word `prune` in `wiki/.publish`).
|
||||
|
||||
## Runner problems
|
||||
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -262,7 +271,7 @@ def _shape(text: str) -> dict:
|
||||
@pytest.mark.parametrize("code", [code for code, _label in build_wiki.LANGUAGES])
|
||||
def test_committed_translations_follow_the_english_structure(page, code):
|
||||
"""A translation has the same code blocks, table rows and heading levels."""
|
||||
wiki = REPO_ROOT / "wiki"
|
||||
wiki = REPO_ROOT / "docs" / "wiki"
|
||||
english = _shape((wiki / f"{page}.md").read_text(encoding="utf-8"))
|
||||
translated = _shape((wiki / f"{page}.{code}.md").read_text(encoding="utf-8"))
|
||||
assert translated == english
|
||||
@@ -297,7 +306,7 @@ class TestSidebar:
|
||||
|
||||
def test_home_lists_every_workflow_file_with_a_diagram():
|
||||
"""The Home page names each workflow file of the repository and draws it."""
|
||||
home = (REPO_ROOT / "wiki" / "Home.md").read_text(encoding="utf-8")
|
||||
home = (REPO_ROOT / "docs" / "wiki" / "Home.md").read_text(encoding="utf-8")
|
||||
files = sorted(
|
||||
path.name
|
||||
for folder in (".gitea/scoped_workflows", ".gitea/workflows")
|
||||
|
||||
+142
-8
@@ -1,4 +1,4 @@
|
||||
"""Offline tests for tools/publish_wiki.py and the scoped publish-wiki workflow."""
|
||||
"""Offline tests for tools/publish_wiki.py and the publish-wiki workflows."""
|
||||
|
||||
import base64
|
||||
import io
|
||||
@@ -9,6 +9,8 @@ import yaml
|
||||
|
||||
from workflow_source import PUBLISH_WORKFLOW, REPO_ROOT, load_publish_module
|
||||
|
||||
REUSABLE_WORKFLOW = REPO_ROOT / ".gitea" / "workflows" / "publish-wiki-pages.yml"
|
||||
|
||||
API = "https://git.example.test/api/v1"
|
||||
REPO_URL = f"{API}/repos/TirSystem/repo"
|
||||
WIKI_URL = f"{REPO_URL}/wiki"
|
||||
@@ -67,6 +69,15 @@ class TestReadPages:
|
||||
publish_wiki.read_pages(tmp_path)
|
||||
|
||||
|
||||
class TestPageTitle:
|
||||
@pytest.mark.parametrize(
|
||||
("key", "title"), [("Home", "Home"), ("Home-da", "Home da"), ("Getting-Started-ms", "Getting Started ms")]
|
||||
)
|
||||
def test_a_hyphen_is_sent_as_a_space(self, publish_wiki, key, title):
|
||||
# Gitea keeps a hyphen in a title literal (Home-da.-.md, address Home%2Dda).
|
||||
assert publish_wiki.page_title(key) == title
|
||||
|
||||
|
||||
class TestPageKey:
|
||||
@pytest.mark.parametrize(
|
||||
("name", "key"),
|
||||
@@ -107,12 +118,13 @@ class FakeGitea:
|
||||
raise self.error("configuration", "404")
|
||||
return [{"title": key.replace("-", " "), "sub_url": key} for key in self.wiki]
|
||||
if method == "POST" and url == f"{WIKI_URL}/new":
|
||||
self.wiki[body["title"]] = body["content_base64"]
|
||||
self.wiki[body["title"].replace(" ", "-")] = body["content_base64"]
|
||||
return None
|
||||
title = url.rsplit("/", 1)[-1]
|
||||
if method == "GET":
|
||||
return {"title": title, "content_base64": self.wiki[title]}
|
||||
if method == "PATCH":
|
||||
assert " " in body["title"] or "-" not in body["title"], body["title"]
|
||||
self.wiki[title] = body["content_base64"]
|
||||
return None
|
||||
if method == "DELETE":
|
||||
@@ -440,6 +452,121 @@ class TestRequestJson:
|
||||
assert caught.value.category == "api"
|
||||
|
||||
|
||||
class TestExplicitPrune:
|
||||
"""The reusable workflow sets WIKI_PRUNE: the caller is the opt-in (MIL-008)."""
|
||||
|
||||
@pytest.fixture()
|
||||
def explicit(self, environment, monkeypatch):
|
||||
(environment / ".publish").unlink()
|
||||
monkeypatch.setenv("WIKI_PRUNE", "false")
|
||||
return environment
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "expected"), [("true", True), (" TRUE\n", True), ("false", False)]
|
||||
)
|
||||
def test_reads_true_and_false(self, publish_wiki, text, expected):
|
||||
assert publish_wiki.parse_prune_setting(text) is expected
|
||||
|
||||
@pytest.mark.parametrize("text", ["", "yes", "prune", None])
|
||||
def test_rejects_anything_else(self, publish_wiki, text):
|
||||
with pytest.raises(publish_wiki.WorkflowError) as caught:
|
||||
publish_wiki.parse_prune_setting(text)
|
||||
assert caught.value.category == "configuration"
|
||||
|
||||
def test_publishes_without_a_marker_and_keeps_other_pages(
|
||||
self, publish_wiki, explicit, capsys
|
||||
):
|
||||
gitea = FakeGitea(publish_wiki, wiki={"Old": b64("hand written")})
|
||||
|
||||
assert run_main(publish_wiki, gitea) == 0
|
||||
|
||||
assert set(gitea.wiki) == {"Old", "Home", "Credentials"}
|
||||
assert "set the prune input to true" in capsys.readouterr().out
|
||||
|
||||
def test_prune_true_deletes_pages_outside_the_folder(
|
||||
self, publish_wiki, explicit, monkeypatch
|
||||
):
|
||||
monkeypatch.setenv("WIKI_PRUNE", "true")
|
||||
gitea = FakeGitea(publish_wiki, wiki={"Old": b64("stale")})
|
||||
|
||||
assert run_main(publish_wiki, gitea) == 0
|
||||
|
||||
assert set(gitea.wiki) == {"Home", "Credentials"}
|
||||
|
||||
def test_a_missing_folder_is_a_configuration_error_before_any_request(
|
||||
self, publish_wiki, explicit, monkeypatch, tmp_path
|
||||
):
|
||||
monkeypatch.setenv("WIKI_DIR", str(tmp_path / "docs" / "wiki"))
|
||||
gitea = FakeGitea(publish_wiki)
|
||||
|
||||
with pytest.raises(publish_wiki.WorkflowError, match="wiki_dir") as caught:
|
||||
run_main(publish_wiki, gitea)
|
||||
|
||||
assert caught.value.category == "configuration"
|
||||
assert gitea.calls == []
|
||||
|
||||
def test_an_empty_folder_never_deletes_pages_even_with_prune(
|
||||
self, publish_wiki, explicit, monkeypatch
|
||||
):
|
||||
monkeypatch.setenv("WIKI_PRUNE", "true")
|
||||
for page in explicit.glob("*.md"):
|
||||
page.unlink()
|
||||
gitea = FakeGitea(publish_wiki, wiki={"Home": b64("home")})
|
||||
|
||||
with pytest.raises(publish_wiki.WorkflowError) as caught:
|
||||
run_main(publish_wiki, gitea)
|
||||
|
||||
assert caught.value.category == "configuration"
|
||||
assert gitea.writes == []
|
||||
|
||||
def test_a_missing_secret_fails_before_any_request(
|
||||
self, publish_wiki, explicit, monkeypatch
|
||||
):
|
||||
monkeypatch.setenv("WIKI_CREDENTIALS", "")
|
||||
gitea = FakeGitea(publish_wiki)
|
||||
|
||||
with pytest.raises(publish_wiki.WorkflowError, match="TOKEN_FOR_GITEA_WIKI"):
|
||||
run_main(publish_wiki, gitea)
|
||||
|
||||
assert gitea.calls == []
|
||||
|
||||
|
||||
class TestReusableWorkflow:
|
||||
@pytest.fixture()
|
||||
def document(self):
|
||||
return yaml.safe_load(REUSABLE_WORKFLOW.read_text(encoding="utf-8"))
|
||||
|
||||
def test_is_called_and_has_no_other_trigger(self, document):
|
||||
assert list(document[True]) == ["workflow_call"]
|
||||
|
||||
def test_the_folder_defaults_to_docs_wiki_and_nothing_is_pruned_by_default(self, document):
|
||||
inputs = document[True]["workflow_call"]["inputs"]
|
||||
assert inputs["wiki_dir"]["default"] == "docs/wiki"
|
||||
assert inputs["prune"]["default"] == "false"
|
||||
|
||||
def test_the_token_is_a_declared_secret_without_a_fallback(self, document):
|
||||
text = REUSABLE_WORKFLOW.read_text(encoding="utf-8")
|
||||
assert document[True]["workflow_call"]["secrets"]["TOKEN_FOR_GITEA_WIKI"]["required"]
|
||||
assert "secrets.TOKEN_FOR_GITEA }}" not in text
|
||||
assert "github.token" not in text
|
||||
|
||||
def test_job_has_read_only_permissions(self, document):
|
||||
assert document["jobs"]["publish-wiki"]["permissions"] == {"contents": "read"}
|
||||
|
||||
def test_the_inputs_reach_the_script_through_the_environment(self, document):
|
||||
step = document["jobs"]["publish-wiki"]["steps"][-1]
|
||||
assert step["env"]["WIKI_DIR"] == "${{ inputs.wiki_dir }}"
|
||||
assert step["env"]["WIKI_PRUNE"] == "${{ inputs.prune }}"
|
||||
assert step["env"]["WIKI_CREDENTIALS"] == "${{ secrets.TOKEN_FOR_GITEA_WIKI }}"
|
||||
assert step["run"] == "python3 shared-scripts/tools/publish_wiki.py"
|
||||
assert "inputs." not in step["run"]
|
||||
|
||||
def test_the_script_is_fetched_at_the_tools_ref(self, document):
|
||||
fetch = document["jobs"]["publish-wiki"]["steps"][1]["with"]
|
||||
assert fetch["repository"] == "TirSystem/github-action"
|
||||
assert fetch["ref"] == "${{ inputs.tools-ref }}"
|
||||
|
||||
|
||||
class TestWorkflow:
|
||||
@pytest.fixture()
|
||||
def document(self):
|
||||
@@ -461,8 +588,7 @@ class TestWorkflow:
|
||||
assert publish_step["env"]["WIKI_CREDENTIALS"] == "${{ secrets.TOKEN_FOR_GITEA_WIKI }}"
|
||||
assert "secrets" not in publish_step["run"]
|
||||
|
||||
def test_the_workflow_has_one_source_and_runs_the_script_file(self, document):
|
||||
assert not (REPO_ROOT / ".gitea" / "workflows" / "publish-wiki.yml").exists()
|
||||
def test_the_scoped_workflow_runs_the_script_file(self, document):
|
||||
assert (REPO_ROOT / "tools" / "publish_wiki.py").is_file()
|
||||
steps = document["jobs"]["publish-wiki"]["steps"]
|
||||
assert "python3 - <<" not in PUBLISH_WORKFLOW.read_text(encoding="utf-8")
|
||||
@@ -475,7 +601,15 @@ class TestWorkflow:
|
||||
assert steps[-1]["run"] == "python3 shared-scripts/tools/publish_wiki.py"
|
||||
|
||||
|
||||
def test_this_repository_opts_in_and_prunes():
|
||||
"""The wiki of this repository must equal wiki/ (ADR-0001, ADR-0004)."""
|
||||
marker = REPO_ROOT / "wiki" / ".publish"
|
||||
assert marker.read_text(encoding="utf-8").strip() == "prune"
|
||||
def test_this_repository_publishes_docs_wiki_through_the_reusable_workflow():
|
||||
"""The wiki of this repository equals docs/wiki/ (ADR-0009, MIL-008 task 4)."""
|
||||
assert not (REPO_ROOT / "wiki").exists()
|
||||
assert (REPO_ROOT / "docs" / "wiki" / "Home.md").is_file()
|
||||
caller = yaml.safe_load(
|
||||
(REPO_ROOT / ".gitea" / "workflows" / "publish-own-wiki.yml").read_text(encoding="utf-8")
|
||||
)
|
||||
job = caller["jobs"]["wiki"]
|
||||
assert job["uses"] == "./.gitea/workflows/publish-wiki-pages.yml"
|
||||
assert job["with"]["wiki_dir"] == "docs/wiki"
|
||||
assert job["with"]["prune"] == "true"
|
||||
assert caller[True]["push"]["paths"] == ["docs/wiki/**"]
|
||||
|
||||
@@ -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
|
||||
@@ -281,7 +281,7 @@ class TestBuildWikiCommandLine:
|
||||
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 "ERROR: docs/wiki/Home.md: missing" in err
|
||||
assert "python tools/build_wiki.py" in err
|
||||
|
||||
def test_generate_reports_the_changed_pages(self, monkeypatch, capsys):
|
||||
@@ -320,7 +320,7 @@ class TestRunAsAProcess:
|
||||
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")
|
||||
result = run_tool("publish_wiki.py", WIKI_DIR=str(REPO_ROOT / "docs" / "wiki"), GITEA_API_URL="https://x")
|
||||
assert result.returncode == 1
|
||||
assert "ERROR:" in result.stderr
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ class TestEachWorkflow:
|
||||
def test_every_job_declares_permissions_and_runner(self, path):
|
||||
document = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||||
for name, job in document["jobs"].items():
|
||||
assert "runs-on" in job, f"job {name} has no runs-on"
|
||||
if "uses" not in job: # a called workflow has its own runner
|
||||
assert "runs-on" in job, f"job {name} has no runs-on"
|
||||
assert "permissions" in job, f"job {name} has no explicit permissions"
|
||||
|
||||
|
||||
|
||||
+12
-8
@@ -1,4 +1,4 @@
|
||||
"""Build the English wiki pages in ``wiki/`` from ``README.md`` and ``guides/``.
|
||||
"""Build the English wiki pages in ``docs/wiki/`` from ``README.md`` and ``guides/``.
|
||||
|
||||
The wiki source lives in this repository (MIL-005). The English pages are
|
||||
generated, never edited by hand; ``--check`` reports a page that differs from
|
||||
@@ -18,7 +18,7 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
WIKI_DIR = REPO_ROOT / "wiki"
|
||||
WIKI_DIR = REPO_ROOT / "docs" / "wiki"
|
||||
SOURCE_BASE_URL = "https://git.tirsystem.com/TirSystem/github-action/src/branch/main"
|
||||
GENERATOR = "tools/build_wiki.py"
|
||||
|
||||
@@ -44,11 +44,13 @@ 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",)),
|
||||
)
|
||||
|
||||
# Translations (ADR-0001): `<Page>.<code>` written by hand in wiki/.
|
||||
# Translations (ADR-0001): `<Page>.<code>` written by hand in docs/wiki/.
|
||||
LANGUAGES: tuple[tuple[str, str], ...] = (("da", "Dansk"), ("ms", "Bahasa Melayu"))
|
||||
HASH_LENGTH = 12
|
||||
_TRANSLATION_HEADER = re.compile(
|
||||
@@ -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"
|
||||
|
||||
@@ -300,9 +304,9 @@ def main(argv: list[str] | None = None) -> int:
|
||||
if args.check:
|
||||
problems = check_pages() + check_translations()
|
||||
for problem in problems:
|
||||
print(f"ERROR: wiki/{problem}", file=sys.stderr)
|
||||
print(f"ERROR: docs/wiki/{problem}", file=sys.stderr)
|
||||
if problems:
|
||||
print(f"Run `python {GENERATOR}` and commit wiki/.", file=sys.stderr)
|
||||
print(f"Run `python {GENERATOR}` and commit docs/wiki/.", file=sys.stderr)
|
||||
return 1
|
||||
print("Wiki pages are up to date.")
|
||||
return 0
|
||||
|
||||
+55
-17
@@ -1,15 +1,19 @@
|
||||
"""Publish the pages in wiki/ to the Gitea wiki of the repository.
|
||||
"""Publish the pages of a folder to the Gitea wiki of the repository.
|
||||
|
||||
Run by the scoped workflow publish-wiki.yml, which checks out the repository
|
||||
that owns the wiki and this repository, and runs this file (MIL-004 task 6).
|
||||
A repository publishes only when it has opted in with wiki/.publish
|
||||
(ADR-0004); the word prune in that file lets the run delete wiki pages that
|
||||
are not in wiki/. It reads its settings from the environment:
|
||||
Run by the reusable workflow publish-wiki.yml, which a repository calls
|
||||
(MIL-008), and by the scoped workflow of the same name until it is removed.
|
||||
The reusable workflow sets WIKI_PRUNE: the caller is the opt-in, and the
|
||||
folder must exist. The scoped workflow leaves WIKI_PRUNE unset: a repository
|
||||
publishes only when it has opted in with WIKI_DIR/.publish (ADR-0004), and the
|
||||
word prune in that file lets the run delete wiki pages that are not in the
|
||||
folder. It reads its settings from the environment:
|
||||
|
||||
GITEA_API_URL Gitea API base, for example https://host/api/v1
|
||||
SOURCE_REPOSITORY owner/repo of the repository whose wiki is written
|
||||
WIKI_CREDENTIALS the Gitea token, as clear text (TOKEN_FOR_GITEA_WIKI)
|
||||
WIKI_DIR directory with the pages (default: wiki)
|
||||
WIKI_PRUNE true or false: delete pages that are not in the
|
||||
folder; when set, no .publish marker is read
|
||||
|
||||
Every failure is printed as ``ERROR: [category] message`` with the categories
|
||||
configuration, credentials, permissions and api; no secret value is printed.
|
||||
@@ -90,6 +94,16 @@ def parse_marker(text):
|
||||
)
|
||||
|
||||
|
||||
def parse_prune_setting(text):
|
||||
"""Return the boolean of the WIKI_PRUNE input: true or false, nothing else."""
|
||||
word = (text or "").strip().lower()
|
||||
if word in ("true", "false"):
|
||||
return word == "true"
|
||||
raise WorkflowError(
|
||||
"configuration", f"The prune input must be 'true' or 'false', not '{(text or '').strip()}'."
|
||||
)
|
||||
|
||||
|
||||
def parse_gitea_token(raw_token):
|
||||
token = (raw_token or "").strip()
|
||||
if not token:
|
||||
@@ -135,6 +149,16 @@ def page_key(title):
|
||||
return str(title).replace(" ", "-")
|
||||
|
||||
|
||||
def page_title(key):
|
||||
"""Return the title to send to Gitea for a page key.
|
||||
|
||||
A hyphen in a title is a literal hyphen to Gitea, which then stores the page
|
||||
as Home-da.-.md and addresses it as Home%2Dda, so a link to Home-da finds
|
||||
nothing. A space is stored as a hyphen (Home-da.md) and addressed as Home-da.
|
||||
"""
|
||||
return key.replace("-", " ")
|
||||
|
||||
|
||||
def read_pages(wiki_dir):
|
||||
"""Return {page key: content} for every Markdown file in wiki_dir."""
|
||||
pages = {}
|
||||
@@ -207,7 +231,7 @@ def publish(pages, wiki_url, headers, send, prune):
|
||||
result = {"created": [], "updated": [], "deleted": [], "kept": []}
|
||||
for title, content in pages.items():
|
||||
body = {
|
||||
"title": title,
|
||||
"title": page_title(title),
|
||||
"content_base64": base64.b64encode(content).decode("ascii"),
|
||||
"message": COMMIT_MESSAGE,
|
||||
}
|
||||
@@ -233,14 +257,24 @@ def main():
|
||||
wiki_dir = Path(os.environ.get("WIKI_DIR", "wiki"))
|
||||
owner, repo = split_repository(os.environ.get("SOURCE_REPOSITORY"))
|
||||
|
||||
marker = wiki_dir / MARKER_NAME
|
||||
if not marker.is_file():
|
||||
print(
|
||||
f"No {wiki_dir}/{MARKER_NAME} marker in {owner}/{repo}; "
|
||||
"wiki publishing is not enabled for this repository."
|
||||
)
|
||||
return 0
|
||||
prune = parse_marker(marker.read_text(encoding="utf-8"))
|
||||
prune_setting = os.environ.get("WIKI_PRUNE")
|
||||
if prune_setting is None:
|
||||
marker = wiki_dir / MARKER_NAME
|
||||
if not marker.is_file():
|
||||
print(
|
||||
f"No {wiki_dir}/{MARKER_NAME} marker in {owner}/{repo}; "
|
||||
"wiki publishing is not enabled for this repository."
|
||||
)
|
||||
return 0
|
||||
prune = parse_marker(marker.read_text(encoding="utf-8"))
|
||||
else:
|
||||
prune = parse_prune_setting(prune_setting)
|
||||
if not wiki_dir.is_dir():
|
||||
raise WorkflowError(
|
||||
"configuration",
|
||||
f"The wiki folder {wiki_dir} does not exist in {owner}/{repo}; "
|
||||
"set the wiki_dir input to the folder with the pages.",
|
||||
)
|
||||
|
||||
pages = read_pages(wiki_dir)
|
||||
token = parse_gitea_token(os.environ.get("WIKI_CREDENTIALS"))
|
||||
@@ -282,8 +316,12 @@ def main():
|
||||
if result["kept"]:
|
||||
print(
|
||||
f"{len(result['kept'])} page(s) are in the wiki but not in "
|
||||
f"{wiki_dir}/ and were kept; put the word '{PRUNE_WORD}' in "
|
||||
f"{wiki_dir}/{MARKER_NAME} to delete them."
|
||||
f"{wiki_dir}/ and were kept; "
|
||||
+ (
|
||||
f"put the word '{PRUNE_WORD}' in {wiki_dir}/{MARKER_NAME} to delete them."
|
||||
if prune_setting is None
|
||||
else "set the prune input to true to delete them."
|
||||
)
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
prune
|
||||
Reference in New Issue
Block a user