Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb1b88b1d | ||
|
|
7bcc67a065 | ||
|
|
92c1795379 | ||
|
|
32b5ab62ab | ||
|
|
2172939527 | ||
|
|
4c51435b16 | ||
|
|
bdf89d38d9 | ||
|
|
e3ad1fa7e7 | ||
|
|
8ad19fca8d | ||
|
|
b74ee0e5cf | ||
|
|
07a5f9b084 | ||
|
|
fd62602c40 | ||
|
|
05b635c1b3 | ||
|
|
9cd723fb48 | ||
|
|
075fae2e45 | ||
|
|
80fb0cfa82 | ||
|
|
eb3e1395db | ||
|
|
2817ecdef5 | ||
|
|
0025c58e7b | ||
|
|
ae0360350a | ||
|
|
670f0ac469 | ||
|
|
6f01fd6828 | ||
|
|
b8d08f7d90 | ||
|
|
893890497a | ||
|
|
aa88ea6f8b | ||
|
|
532e9663cb | ||
|
|
4cb4689471 | ||
|
|
4b8d659e02 | ||
|
|
d8dc35e88f | ||
|
|
21b9b83e82 | ||
|
|
e6c855554c | ||
|
|
e375900d2a | ||
|
|
4210a7492e | ||
|
|
ead3d98d73 | ||
|
|
2f1aa4d26d | ||
|
|
b85947f076 | ||
|
|
d575f272fc | ||
|
|
81fd82a909 | ||
|
|
513ad69de2 | ||
|
|
6933e91c83 |
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Coverage of the scripts in tools/ by the offline tests. validate-workflows.yml
|
||||||
|
# runs `coverage run -m pytest -q tests` and `coverage report`, which fails
|
||||||
|
# below fail_under. Measured at 97% on 2026-10-11; the gate leaves room for a
|
||||||
|
# few lines and fails when a tool grows without tests.
|
||||||
|
[run]
|
||||||
|
branch = True
|
||||||
|
source = tools
|
||||||
|
|
||||||
|
[report]
|
||||||
|
fail_under = 95
|
||||||
|
show_missing = True
|
||||||
|
skip_empty = True
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: TirSystem/github-action
|
repository: TirSystem/github-action
|
||||||
ref: main
|
ref: v1
|
||||||
path: shared-scripts
|
path: shared-scripts
|
||||||
|
|
||||||
- name: Publish the pages to the wiki
|
- name: Publish the pages to the wiki
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: TirSystem/github-action
|
repository: TirSystem/github-action
|
||||||
ref: main
|
ref: v1
|
||||||
path: shared-scripts
|
path: shared-scripts
|
||||||
|
|
||||||
- name: Sync description and topics
|
- name: Sync description and topics
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ name: Quality checks
|
|||||||
#
|
#
|
||||||
# jobs:
|
# jobs:
|
||||||
# quality:
|
# quality:
|
||||||
# uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
|
# uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1
|
||||||
#
|
#
|
||||||
# It checks the Python and shell files of the repository with pinned tools,
|
# It checks the Python and shell files of the repository with pinned tools,
|
||||||
# changes no file and needs no secret.
|
# changes no file and needs no secret.
|
||||||
@@ -35,6 +35,10 @@ on:
|
|||||||
description: "Version of the shfmt-py package (shfmt 3.11.0)"
|
description: "Version of the shfmt-py package (shfmt 3.11.0)"
|
||||||
type: string
|
type: string
|
||||||
default: "3.11.0.2"
|
default: "3.11.0.2"
|
||||||
|
tools-ref:
|
||||||
|
description: "Tag or branch of TirSystem/github-action whose tools/quality-checks.sh is run; pin it to the exact tag together with the workflow"
|
||||||
|
type: string
|
||||||
|
default: "v1"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
quality-checks:
|
quality-checks:
|
||||||
@@ -50,104 +54,21 @@ jobs:
|
|||||||
SHFMT_PY_VERSION: ${{ inputs.shfmt-py-version }}
|
SHFMT_PY_VERSION: ${{ inputs.shfmt-py-version }}
|
||||||
QC_VENV: /tmp/quality-tools
|
QC_VENV: /tmp/quality-tools
|
||||||
steps:
|
steps:
|
||||||
- name: Validate the inputs
|
|
||||||
run: |
|
|
||||||
set -u
|
|
||||||
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
||||||
if [ "${#langs[@]}" -eq 0 ]; then
|
|
||||||
echo "::error::[configuration] languages is empty; use python, shell or both, comma separated."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
for lang in "${langs[@]}"; do
|
|
||||||
case "$lang" in
|
|
||||||
python | shell) ;;
|
|
||||||
*)
|
|
||||||
echo "::error::[configuration] Unknown language '$lang'; use python and shell, comma separated."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
case "$WORKING_DIRECTORY" in
|
|
||||||
"" | /* | .. | ../* | */.. | */../*)
|
|
||||||
echo "::error::[configuration] working-directory must be a relative path inside the repository."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo "Checking ${LANGUAGES} in ${WORKING_DIRECTORY}"
|
|
||||||
|
|
||||||
- name: Check out the repository
|
- name: Check out the repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Fetch the shared script
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: TirSystem/github-action
|
||||||
|
ref: ${{ inputs.tools-ref }}
|
||||||
|
path: shared-scripts
|
||||||
|
|
||||||
|
- name: Validate the inputs
|
||||||
|
run: bash shared-scripts/tools/quality-checks.sh validate
|
||||||
|
|
||||||
- name: Install the tools
|
- name: Install the tools
|
||||||
run: |
|
run: bash shared-scripts/tools/quality-checks.sh install
|
||||||
set -eu
|
|
||||||
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
||||||
packages=()
|
|
||||||
for lang in "${langs[@]}"; do
|
|
||||||
case "$lang" in
|
|
||||||
python) packages+=("ruff==${RUFF_VERSION}" "mypy==${MYPY_VERSION}") ;;
|
|
||||||
shell) packages+=("shellcheck-py==${SHELLCHECK_PY_VERSION}" "shfmt-py==${SHFMT_PY_VERSION}") ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
python3 -m venv "$QC_VENV"
|
|
||||||
"$QC_VENV/bin/pip" install --quiet "${packages[@]}"
|
|
||||||
|
|
||||||
- name: Run the checks
|
- name: Run the checks
|
||||||
run: |
|
run: bash shared-scripts/tools/quality-checks.sh run
|
||||||
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
|
|
||||||
cd "$WORKING_DIRECTORY"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
wanted() {
|
|
||||||
local lang
|
|
||||||
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
||||||
for lang in "${langs[@]}"; do
|
|
||||||
[ "$lang" = "$1" ] && return 0
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if wanted python; then
|
|
||||||
mapfile -t files < <(git ls-files -- '*.py')
|
|
||||||
if [ "${#files[@]}" -eq 0 ]; then
|
|
||||||
echo "::notice::No python files in '$WORKING_DIRECTORY'; nothing was checked."
|
|
||||||
else
|
|
||||||
run_tool "ruff check" "$QC_BIN/ruff" check "${files[@]}"
|
|
||||||
run_tool "ruff format --check" "$QC_BIN/ruff" format --check "${files[@]}"
|
|
||||||
run_tool "mypy --strict" "$QC_BIN/mypy" --strict "${files[@]}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if wanted shell; then
|
|
||||||
mapfile -t files < <(git ls-files -- '*.sh')
|
|
||||||
if [ "${#files[@]}" -eq 0 ]; then
|
|
||||||
echo "::notice::No shell files in '$WORKING_DIRECTORY'; nothing was checked."
|
|
||||||
else
|
|
||||||
run_tool "shellcheck" "$QC_BIN/shellcheck" "${files[@]}"
|
|
||||||
run_tool "shfmt -d" "$QC_BIN/shfmt" -d "${files[@]}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${#failed[@]}" -gt 0 ]; then
|
|
||||||
echo "::error::Quality checks failed: ${failed[*]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "All selected checks passed."
|
|
||||||
|
|||||||
@@ -20,5 +20,8 @@ jobs:
|
|||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
.venv/bin/python -m pip install --quiet -r tests/requirements.txt
|
.venv/bin/python -m pip install --quiet -r tests/requirements.txt
|
||||||
|
|
||||||
- name: Validate workflow files and run the offline tests
|
- name: Validate workflow files and run the offline tests under coverage
|
||||||
run: .venv/bin/python -m pytest -q tests
|
run: .venv/bin/python -m coverage run -m pytest -q tests
|
||||||
|
|
||||||
|
- name: Check the coverage of the tools
|
||||||
|
run: .venv/bin/python -m coverage report
|
||||||
|
|||||||
@@ -14,3 +14,6 @@
|
|||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Local coverage data (python -m coverage run)
|
||||||
|
.coverage
|
||||||
|
|||||||
@@ -20,6 +20,28 @@ Each release lists its changes in these groups, in this order:
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.1.0] - 2026-10-11
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Input `tools-ref` of `quality-checks.yml` (default `v1`): the tag or branch from
|
||||||
|
which the workflow fetches its script `tools/quality-checks.sh`.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `quality-checks.yml` runs the script file `tools/quality-checks.sh` instead of
|
||||||
|
embedding about 100 lines of shell; the checks, messages and results are the
|
||||||
|
same.
|
||||||
|
|
||||||
|
## [1.0.1] - 2026-10-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Sync GitHub mirror metadata: a repository without a GitHub push mirror still
|
||||||
|
succeeds, and the log now ends with the line `Skipped`.
|
||||||
|
- The scoped workflows fetch their scripts at the tag `v1` instead of `main`,
|
||||||
|
so a merge to `main` reaches consumers only when it is released.
|
||||||
|
|
||||||
## [1.0.0] - 2026-10-10
|
## [1.0.0] - 2026-10-10
|
||||||
|
|
||||||
First release. The reusable workflow can be pinned at `v1` or `v1.0.0`. The
|
First release. The reusable workflow can be pinned at `v1` or `v1.0.0`. The
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ A collection of reusable Gitea Actions workflows for DevOps professionals and so
|
|||||||
## 📚 Table of Contents
|
## 📚 Table of Contents
|
||||||
|
|
||||||
- [Overview](#-overview)
|
- [Overview](#-overview)
|
||||||
|
- [Workflows](#-workflows)
|
||||||
- [Requirements](#-requirements)
|
- [Requirements](#-requirements)
|
||||||
- [Setup](#-setup)
|
- [Setup](#-setup)
|
||||||
- [Run](#-run)
|
- [Run](#-run)
|
||||||
@@ -16,59 +17,19 @@ 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.
|
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 currently contains the Gitea workflow [`sync-github-metadata.yml`](.gitea/scoped_workflows/sync-github-metadata.yml), which copies the repository description and topics from Gitea to the GitHub mirror on every push to `main`, on manual dispatch, and daily at 03:17 UTC.
|
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).
|
||||||
|
|
||||||
## 📋 Requirements
|
## 🔧 Workflows
|
||||||
|
|
||||||
- A Gitea instance with Actions enabled and a runner providing `ubuntu-latest` with `python3`
|
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.
|
||||||
- A configured GitHub push mirror on the Gitea repository (at most one; repositories without a mirror are skipped successfully)
|
|
||||||
- Repository secrets:
|
|
||||||
- `TOKEN_FOR_GITEA`: Gitea API token (the token only, no JSON)
|
|
||||||
- `PAT_FOR_GITHUB`: a GitHub personal access token allowed to edit the mirror repository (the token only, no JSON)
|
|
||||||
- `TOKEN_FOR_GITEA_WIKI` (only for repositories that publish a wiki, see the [onboarding guide](guides/onboarding.md)): a Gitea token that can write the wiki, stored as a secret of the repository's organization; there is no fallback to `TOKEN_FOR_GITEA`
|
|
||||||
|
|
||||||
## 🛠️ Setup
|
| Workflow | File | Kind | Starts on | Purpose |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
No dependencies need to be installed; the workflow uses only the Python standard library.
|
| 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 |
|
||||||
1. Clone the 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 |
|
||||||
```bash
|
| 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 |
|
||||||
git clone ssh://git@git.tirsystem.com:10022/TirSystem/github-action.git
|
| 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 |
|
||||||
```
|
|
||||||
2. Add the secrets listed under [Requirements](#-requirements) to the repository settings in Gitea.
|
|
||||||
3. Configure the GitHub push mirror in the repository settings.
|
|
||||||
|
|
||||||
## ▶️ Run
|
|
||||||
|
|
||||||
Workflows run automatically on push to `main` and on the daily schedule. To run manually, trigger **Sync GitHub mirror metadata** via `workflow_dispatch` from the Actions tab in Gitea.
|
|
||||||
|
|
||||||
## 🧪 Tests
|
|
||||||
|
|
||||||
The workflow files and the scripts in `tools/` are validated by offline tests that need no network access and no secrets:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 -m venv .venv
|
|
||||||
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
|
||||||
python -m pip install -r tests/requirements.txt
|
|
||||||
python -m pytest -q tests
|
|
||||||
```
|
|
||||||
|
|
||||||
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API.
|
|
||||||
|
|
||||||
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
|
|
||||||
|
|
||||||
## 🟢 Capabilities
|
|
||||||
|
|
||||||
Rows that say Implemented or Guides written exist today. The rest is planned and tracked in the [Project Plan](docs/project-plan.md), which also describes each use case.
|
|
||||||
|
|
||||||
| Capability | Status |
|
|
||||||
| --- | --- |
|
|
||||||
| 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 other repositories not yet verified; brief use cases open (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; the pilot in a second repository is pending (MIL-006) |
|
|
||||||
| Shared quality checks (Python and shell) | Implemented as the reusable workflow `.gitea/workflows/quality-checks.yml`, with offline tests and a trial in a second organization; adoption in RepoFoundry is in review ([guide](guides/quality-checks.md)) |
|
|
||||||
| Versioned release and publishing | Release process, changelog and upgrade guide defined; the release workflow exists; the first release `v1.0.0` is pending (MIL-004) ([guide](guides/upgrading.md)) |
|
|
||||||
|
|
||||||
### 🔄 Sync GitHub metadata
|
### 🔄 Sync GitHub metadata
|
||||||
|
|
||||||
@@ -136,6 +97,228 @@ deactivate Workflow
|
|||||||
@enduml
|
@enduml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 📖 Publish wiki
|
||||||
|
|
||||||
|
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/`.
|
||||||
|
|
||||||
|
#### 🔀 Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Publish wiki/ to the repository wiki
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main that changes wiki/**,\nor manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\npublish-wiki" as Workflow
|
||||||
|
participant "shared-scripts\n(tools/publish_wiki.py at v1)" as Script
|
||||||
|
participant "Gitea wiki API" as Wiki
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Script: Check out the repository and the script, run it
|
||||||
|
activate Script
|
||||||
|
|
||||||
|
alt wiki/.publish does not exist
|
||||||
|
Script --> Workflow: Log that publishing is not enabled and succeed\n(nothing is written)
|
||||||
|
else wiki/ has no Markdown pages
|
||||||
|
Script --> Workflow: Fail with [configuration]\n(an empty wiki/ never deletes pages)
|
||||||
|
else
|
||||||
|
Script -> Script: Read the marker (empty, or the word prune)\nand 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 marker says prune
|
||||||
|
Script -> Wiki: Delete pages that are not in wiki/
|
||||||
|
end
|
||||||
|
Script --> Workflow: Log created, updated and deleted counts
|
||||||
|
end
|
||||||
|
deactivate Script
|
||||||
|
Workflow --> Trigger: Workflow result
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### ✅ Quality checks
|
||||||
|
|
||||||
|
A reusable workflow for Python and shell, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1` (see the [guide](guides/quality-checks.md)).
|
||||||
|
|
||||||
|
#### 🔀 Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Shared quality checks (reusable workflow)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Calling repository\nuses: ...quality-checks.yml@v1" as Caller
|
||||||
|
participant "Gitea Actions\nquality-checks" as Workflow
|
||||||
|
participant "PyPI" as PyPI
|
||||||
|
|
||||||
|
Caller -> Workflow: workflow_call with languages,\nworking-directory and tool versions
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Validate the inputs
|
||||||
|
alt languages or working-directory is invalid
|
||||||
|
Workflow --> Caller: Fail with [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check out the calling repository
|
||||||
|
Workflow -> PyPI: Install the pinned tools in a virtual environment\n(ruff, mypy, shellcheck-py, shfmt-py as selected)
|
||||||
|
PyPI --> Workflow: Tools installed
|
||||||
|
|
||||||
|
loop for each selected language
|
||||||
|
Workflow -> Workflow: List tracked files
|
||||||
|
alt no files of that language
|
||||||
|
Workflow -> Workflow: Notice: nothing was checked
|
||||||
|
else
|
||||||
|
Workflow -> Workflow: Run every tool and record PASS or FAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alt any tool failed
|
||||||
|
Workflow --> Caller: Fail and list the failed tools
|
||||||
|
else
|
||||||
|
Workflow --> Caller: All selected checks passed
|
||||||
|
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)).
|
||||||
|
|
||||||
|
#### 🔀 Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Release this repository
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Maintainer\n(workflow_dispatch: version, dry_run)" as Trigger
|
||||||
|
participant "Gitea Actions\nrelease" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start with version and dry_run
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check the version and read CHANGELOG.md
|
||||||
|
alt version malformed or no changelog entry
|
||||||
|
Workflow --> Trigger: Fail with [validation] or [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET branch main and status of the commit
|
||||||
|
Gitea --> Workflow: Tip of main and the validation run
|
||||||
|
alt commit is not the tip of main,\nor the validation run is not green
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(no tag is created)
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET tags
|
||||||
|
Gitea --> Workflow: Existing tags
|
||||||
|
alt tag vMAJOR.MINOR.PATCH exists
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(tags are never moved)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt dry_run is true (default)
|
||||||
|
Workflow --> Trigger: Log what would be created and stop
|
||||||
|
else
|
||||||
|
Workflow -> Gitea: POST release (creates the version tag,\nbody is the changelog entry)
|
||||||
|
opt this is the highest version of its major
|
||||||
|
Workflow -> Gitea: Delete and recreate the major tag vMAJOR
|
||||||
|
end
|
||||||
|
Workflow --> Trigger: Released
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🧪 Validate workflows
|
||||||
|
|
||||||
|
The repository's own validation: the offline tests that gate every pull request.
|
||||||
|
|
||||||
|
#### 🔀 Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Validate workflows (this repository's own checks)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Pull request,\npush to main, or manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\nvalidate-workflows" as Workflow
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Workflow: Check out the repository
|
||||||
|
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
|
||||||
|
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
|
||||||
|
|
||||||
|
alt a test fails
|
||||||
|
Workflow --> Trigger: Workflow fails (the pull request is not ready)
|
||||||
|
else
|
||||||
|
Workflow --> Trigger: Workflow succeeds
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 Requirements
|
||||||
|
|
||||||
|
- A Gitea instance with Actions enabled and a runner providing `ubuntu-latest` with `python3`
|
||||||
|
- A configured GitHub push mirror on the Gitea repository (at most one; repositories without a mirror are skipped successfully)
|
||||||
|
- Repository secrets:
|
||||||
|
- `TOKEN_FOR_GITEA`: Gitea API token (the token only, no JSON)
|
||||||
|
- `PAT_FOR_GITHUB`: a GitHub personal access token allowed to edit the mirror repository (the token only, no JSON)
|
||||||
|
- `TOKEN_FOR_GITEA_WIKI` (only for repositories that publish a wiki, see the [onboarding guide](guides/onboarding.md)): a Gitea token that can write the wiki, stored as a secret of the repository's organization; there is no fallback to `TOKEN_FOR_GITEA`
|
||||||
|
|
||||||
|
## 🛠️ Setup
|
||||||
|
|
||||||
|
No dependencies need to be installed; the workflow uses only the Python standard library.
|
||||||
|
|
||||||
|
1. Clone the repository:
|
||||||
|
```bash
|
||||||
|
git clone ssh://git@git.tirsystem.com:10022/TirSystem/github-action.git
|
||||||
|
```
|
||||||
|
2. Add the secrets listed under [Requirements](#-requirements) to the repository settings in Gitea.
|
||||||
|
3. Configure the GitHub push mirror in the repository settings.
|
||||||
|
|
||||||
|
## ▶️ Run
|
||||||
|
|
||||||
|
Workflows run automatically on push to `main` and on the daily schedule. To run manually, trigger **Sync GitHub mirror metadata** via `workflow_dispatch` from the Actions tab in Gitea.
|
||||||
|
|
||||||
|
## 🧪 Tests
|
||||||
|
|
||||||
|
The workflow files and the scripts in `tools/` are validated by offline tests that need no network access and no secrets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
||||||
|
python -m pip install -r tests/requirements.txt
|
||||||
|
python -m coverage run -m pytest -q tests
|
||||||
|
python -m coverage report
|
||||||
|
```
|
||||||
|
|
||||||
|
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API. The run fails when the line and branch coverage of `tools/` falls below 95% (`.coveragerc`).
|
||||||
|
|
||||||
|
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
|
||||||
|
|
||||||
|
## 🟢 Capabilities
|
||||||
|
|
||||||
|
Rows that say Implemented or Guides written exist today. The rest is planned and tracked in the [Project Plan](docs/project-plan.md), which also describes each use case.
|
||||||
|
|
||||||
|
| Capability | Status |
|
||||||
|
| --- | --- |
|
||||||
|
| 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) |
|
||||||
|
| 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)) |
|
||||||
|
| 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
|
## 📄 License
|
||||||
|
|
||||||
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See [LICENSE](LICENSE).
|
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See [LICENSE](LICENSE).
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [385d2fb] |
|
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Reviewed (RC-038): the security impact of installing the tools from PyPI named | [385d2fb] |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Reviewed (RC-038): the security impact of installing the tools from PyPI named | [385d2fb] |
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added the input tools-ref: the shell steps moved to a script file fetched at that ref (RC-051) | [670f0ac] |
|
||||||
|
|
||||||
Allowed Status values: `Proposed`, `Accepted`, `Rejected`, `Deprecated`, `Superseded by ADR-NNNN`.
|
Allowed Status values: `Proposed`, `Accepted`, `Rejected`, `Deprecated`, `Superseded by ADR-NNNN`.
|
||||||
|
|
||||||
@@ -55,9 +55,12 @@ Options for the shape of the workflow:
|
|||||||
|
|
||||||
The shared workflow `quality-checks.yml` is one reusable workflow with the
|
The shared workflow `quality-checks.yml` is one reusable workflow with the
|
||||||
inputs `languages` (a comma list of `python` and `shell`, default both),
|
inputs `languages` (a comma list of `python` and `shell`, default both),
|
||||||
`working-directory` (default `.`) and one version input per tool whose
|
`working-directory` (default `.`), one version input per tool whose
|
||||||
defaults are the pinned versions above, and it installs the tools from PyPI
|
defaults are the pinned versions above, and `tools-ref` (default `v1`, the
|
||||||
into a virtual environment. A run passes when every selected tool exits 0 and
|
tag or branch from which the workflow fetches its script
|
||||||
|
`tools/quality-checks.sh`), and it installs the tools from PyPI into a virtual
|
||||||
|
environment. A call at an exact tag is pinned completely only when `tools-ref`
|
||||||
|
names the same tag; with the default the script follows the major tag. A run passes when every selected tool exits 0 and
|
||||||
fails when any exits non-zero, and a language with no files is skipped with a
|
fails when any exits non-zero, and a language with no files is skipped with a
|
||||||
notice and counts as a pass.
|
notice and counts as a pass.
|
||||||
|
|
||||||
@@ -122,3 +125,4 @@ The rules that follow from it:
|
|||||||
[US-001]: ../user-stories.md
|
[US-001]: ../user-stories.md
|
||||||
[ADR-0004]: ./adr-0004-shared-wiki-publishing-opt-in.md
|
[ADR-0004]: ./adr-0004-shared-wiki-publishing-opt-in.md
|
||||||
[385d2fb]: https://git.tirsystem.com/TirSystem/github-action/commit/385d2fb7cb9be1fdc8fd3503d0af624fa38eafc7
|
[385d2fb]: https://git.tirsystem.com/TirSystem/github-action/commit/385d2fb7cb9be1fdc8fd3503d0af624fa38eafc7
|
||||||
|
[670f0ac]: https://git.tirsystem.com/TirSystem/github-action/commit/670f0ac469043bb166c84290c0dbf62b4908e3cc
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ each document lives in *this* project and the next version to use.
|
|||||||
| BC | Business Case | docs/business-case.md | 002 |
|
| BC | Business Case | docs/business-case.md | 002 |
|
||||||
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
|
| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
|
||||||
| PP | Project Plan | docs/project-plan.md | 002 |
|
| PP | Project Plan | docs/project-plan.md | 002 |
|
||||||
| MIL | Milestone / Gateway | docs/milestones/*.md | 007 |
|
| MIL | Milestone / Gateway | docs/milestones/*.md | 008 |
|
||||||
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 048 |
|
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 054 |
|
||||||
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
|
| 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 | 0008 |
|
||||||
| UCD | Use Case Diagram | docs/use-case-diagram.md | 002 |
|
| UCD | Use Case Diagram | docs/use-case-diagram.md | 002 |
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Target date 2026-11-28 confirmed on 2026-10-10 by S01 (stand-in for S05) | [ea06eaa] |
|
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added the verification results of the first release (v1.0.0) | [6933e91] |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Added task 6 (embedded scripts to files) and Go/No-Go criterion 5; traceability adds O2 (RC-034) | [616c5d2] |
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 3 verified with pinned consumers after v1.0.1 and v1.1.0 (RC-048) | [05b635c] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -71,10 +71,26 @@ reference that a release can pin, instead of Python embedded in their YAML.
|
|||||||
| 5 | Implement the reusable release workflow | Validate the version, build release notes from the changelog and publish to the chosen destination. | Yes | Use case candidate: publish a release |
|
| 5 | Implement the reusable release workflow | Validate the version, build release notes from the changelog and publish to the chosen destination. | Yes | Use case candidate: publish a release |
|
||||||
| 6 | Move the embedded scripts of the scoped workflows to files | The sync (`sync-github-metadata.yml`) and publish-wiki workflows embed 200 to 300 lines of Python in their YAML, which is hard to read, lint and review. Move the code to `tools/sync_github_metadata.py` and `tools/publish_wiki.py`; each scoped workflow then checks out `TirSystem/github-action` into its own folder with `actions/checkout` and runs the file, as verified on 2026-10-10 from repositories of two organizations. Keep the behaviour, the messages and the offline tests, which import the files instead of executing the YAML; use `ref: main` first, and let the release process of task 1 define how a consumer pins a tag. | No | |
|
| 6 | Move the embedded scripts of the scoped workflows to files | The sync (`sync-github-metadata.yml`) and publish-wiki workflows embed 200 to 300 lines of Python in their YAML, which is hard to read, lint and review. Move the code to `tools/sync_github_metadata.py` and `tools/publish_wiki.py`; each scoped workflow then checks out `TirSystem/github-action` into its own folder with `actions/checkout` and runs the file, as verified on 2026-10-10 from repositories of two organizations. Keep the behaviour, the messages and the offline tests, which import the files instead of executing the YAML; use `ref: main` first, and let the release process of task 1 define how a consumer pins a tag. | No | |
|
||||||
|
|
||||||
|
## Verification results
|
||||||
|
|
||||||
|
The first release was cut on 2026-10-11 with the Release workflow (run 623 on
|
||||||
|
`97ffa49`, after a dry run, run 622): the tag `v1.0.0`, the moving tag `v1`
|
||||||
|
and the release page were created, and the job token was enough (ADR-0007).
|
||||||
|
|
||||||
|
| # | Criterion | Result |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1 | A release is validated before a tag is created | Go: `tools/release.py` refuses unless the status `Validate workflows / validate (push)` of the tip of `main` is success; tested for failed and missing runs |
|
||||||
|
| 2 | Version tag and changelog entry that marks breaking changes | Go: `v1.0.0` and `CHANGELOG.md` `[1.0.0]`; `tools/changelog.py` checks the convention |
|
||||||
|
| 3 | A consumer pinned to the previous version keeps working | Go, verified on 2026-10-11 after `v1.0.1`: a caller in `TirSystem-BashScript/RepoFoundry` at `@v1.0.0` and one at `@v1` both passed (run 660); after `v1.1.0` a caller at `@v1.1.0` with `tools-ref: v1.1.0` and one at `@v1` passed (run 672). `v1.0.0` still points to `97ffa49` |
|
||||||
|
| 4 | Publish destination decided, token scope documented | Go: ADR-0007 |
|
||||||
|
| 5 | No embedded Python in the scoped workflows | Go: both run files of this repository, with offline tests that exercise the files (MIL-004 task 6) |
|
||||||
|
|
||||||
|
After the release the two scoped workflows fetch their scripts at `ref: v1`
|
||||||
|
(RC-043 action item).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[BC-001]: ../business-case.md
|
[BC-001]: ../business-case.md
|
||||||
[4de5438]: https://git.tirsystem.com/TirSystem/github-action/commit/4de5438a88b4bbf18b165f52f797d1a52af89f6d
|
|
||||||
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
||||||
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
[6933e91]: https://git.tirsystem.com/TirSystem/github-action/commit/6933e91c83075fb39b2dfbe41683cb2a0a0bce28
|
||||||
[616c5d2]: https://git.tirsystem.com/TirSystem/github-action/commit/616c5d2e48f0d76399a6f78923891fc7f50c8e22
|
[05b635c]: https://git.tirsystem.com/TirSystem/github-action/commit/05b635c1b3d79390c794e62e781595fbe5f1a4ea
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Decided how the wiki is published: source in `wiki/`, published by a workflow on merge<br>Added task 8 | [77c5277] |
|
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Target date 2026-12-12 confirmed on 2026-10-10 by S01 (stand-in for S05) | [ea06eaa] |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Target date 2026-12-12 confirmed on 2026-10-10 by S01 (stand-in for S05) | [ea06eaa] |
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 4 amended (accepted by S01 as stand-in when no native reader exists); added the verification results | [ead3d98] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ to `main`, and a pull request rule in `AGENTS.md` keeps the wiki current.
|
|||||||
| 1 | The wiki is enabled and contains the five pages in all three languages | 15 pages present | Any page missing |
|
| 1 | The wiki is enabled and contains the five pages in all three languages | 15 pages present | Any page missing |
|
||||||
| 2 | Each English page is generated from `README.md` or `guides/`, and a check reports a page that differs from its source | Check passes | Hand-edited page drifts |
|
| 2 | Each English page is generated from `README.md` or `guides/`, and a check reports a page that differs from its source | Check passes | Hand-edited page drifts |
|
||||||
| 3 | Each Danish and Bahasa Malaysia page names the English source version it follows | Named on every page | Missing |
|
| 3 | Each Danish and Bahasa Malaysia page names the English source version it follows | Named on every page | Missing |
|
||||||
| 4 | A native reader of each language has reviewed the translations | Review recorded | Unreviewed |
|
| 4 | The translations are reviewed and accepted: by a native reader of each language, or, when none is available, by S01 as the stand-in of ADR-0002, with the lack of a native reader stated | Acceptance recorded, and a native review where one exists | Unreviewed |
|
||||||
| 5 | `AGENTS.md` requires a wiki update in every pull request that changes a workflow, a guide or the README, and the PR description lists the pages changed | Rule present and used by one PR | Missing |
|
| 5 | `AGENTS.md` requires a wiki update in every pull request that changes a workflow, a guide or the README, and the PR description lists the pages changed | Rule present and used by one PR | Missing |
|
||||||
| 6 | The wiki is published only by the workflow from `main`; no agent or person pushes to the wiki repository by hand | Last wiki commit is by the workflow | A manual push exists |
|
| 6 | The wiki is published only by the workflow from `main`; no agent or person pushes to the wiki repository by hand | Last wiki commit is by the workflow | A manual push exists |
|
||||||
|
|
||||||
@@ -76,9 +76,22 @@ to `main`, and a pull request rule in `AGENTS.md` keeps the wiki current.
|
|||||||
| 7 | Publish and verify | Publish the pages, open them in the browser in each language and check that links, code blocks and the capability table render. | No | |
|
| 7 | Publish and verify | Publish the pages, open them in the browser in each language and check that links, code blocks and the capability table render. | No | |
|
||||||
| 8 | Add the wiki publishing workflow | Add a Gitea workflow, canonical in `.gitea/scoped_workflows/`, that runs on push to `main` when `wiki/` changes and copies `wiki/` to the wiki repository with the secret from task 2. It needs least-privilege permissions, must not print the secret, and gets offline tests like the metadata sync, with the same categorized error messages. | No | |
|
| 8 | Add the wiki publishing workflow | Add a Gitea workflow, canonical in `.gitea/scoped_workflows/`, that runs on push to `main` when `wiki/` changes and copies `wiki/` to the wiki repository with the secret from task 2. It needs least-privilege permissions, must not print the secret, and gets offline tests like the metadata sync, with the same categorized error messages. | No | |
|
||||||
|
|
||||||
|
## Verification results
|
||||||
|
|
||||||
|
Checked on 2026-10-11 against `main` at the merge of PR 83.
|
||||||
|
|
||||||
|
| # | Criterion | Result |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1 | The wiki is enabled and contains the pages in all three languages | Go: 21 pages (seven pages in English, Danish and Bahasa Malaysia), more than the 15 the criterion names |
|
||||||
|
| 2 | Each English page is generated from `README.md` or `guides/`, and a check reports a page that differs | Go: `python tools/build_wiki.py --check` passes and the tests fail on a stale page |
|
||||||
|
| 3 | Each translation names the English source version it follows | Go: every `.da` and `.ms` file starts with `translation of X.md, source sha256`, and the tests check it |
|
||||||
|
| 4 | The translations are reviewed and accepted | Go on the stand-in: no native reader of Danish or Bahasa Malaysia reviewed the pages. S01 accepted them on 2026-10-11 (RC-050) and the checklist `docs/wiki-translation-review.md` stays available for a native reader. The accuracy of the text rests on the author and S01, not on a native reader |
|
||||||
|
| 5 | `AGENTS.md` requires a wiki update and the PR lists the pages | Go: rule 8 of `AGENTS.md`; used by PR 78, PR 82 and others, each listing the wiki pages it changed |
|
||||||
|
| 6 | The wiki is published only by the workflow from `main` | Go: the last commit of all 21 pages has the message `Publish wiki from the repository`, which only the publisher writes |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[BC-001]: ../business-case.md
|
[BC-001]: ../business-case.md
|
||||||
[77c5277]: https://git.tirsystem.com/TirSystem/github-action/commit/77c52779c46bca35dee4d73e587ca7b611373790
|
|
||||||
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
||||||
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
||||||
|
[ead3d98]: https://git.tirsystem.com/TirSystem/github-action/commit/ead3d98d73fcab95fd57b0eb005a02aff9983256
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [6b8e36d] |
|
| 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-10 | Accepted | 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] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ repository other than this one that publishes its wiki through it.
|
|||||||
|
|
||||||
| # | Criterion (objectively checkable) | Go | No-Go |
|
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 1 | A repository without the opt-in marker is never written to, shown by offline tests and by a run in one such repository | No request writes to its wiki | Any write |
|
| 1 | A repository without the opt-in marker is never written to, shown by offline tests and by the trigger rule (a run in such a repository cannot be started: a scoped workflow is not dispatchable through the API and runs only on a push that changes `wiki/**`) | No request writes to its wiki | Any write |
|
||||||
| 2 | The workflow exists once: the copy in `.gitea/workflows/` is removed and no script is needed from `tools/` | Count is 1 | A second copy exists |
|
| 2 | The workflow exists once: the copy in `.gitea/workflows/` is removed and no script is needed from `tools/` | Count is 1 | A second copy exists |
|
||||||
| 3 | One repository outside this one publishes its wiki through the shared workflow | Pages on the wiki equal its `wiki/` | Pages differ or run fails |
|
| 3 | One repository outside this one publishes its wiki through the shared workflow | Pages on the wiki equal its `wiki/` | Pages differ or run fails |
|
||||||
| 4 | An empty or missing `wiki/` never deletes pages, and a failure names its category | Verified by tests | A wiki was emptied |
|
| 4 | An empty or missing `wiki/` never deletes pages, and a failure names its category | Verified by tests | A wiki was emptied |
|
||||||
@@ -72,9 +72,26 @@ repository other than this one that publishes its wiki through it.
|
|||||||
| 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 | |
|
| 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 | |
|
| 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 | |
|
||||||
|
|
||||||
|
## Verification results
|
||||||
|
|
||||||
|
The pilot was `TirSystem/sqa-qc-checklists` (its PR 10, merged 2026-10-11).
|
||||||
|
The scoped workflow ran as run 629 on `d4ddbb6`, fetched the scripts at `v1`,
|
||||||
|
passed the token preflight and reported `Published 13 page(s): 0 created,
|
||||||
|
0 updated, 0 deleted`. The 13 pages of the wiki were then read back through
|
||||||
|
the API and equal `wiki/*.md` on `main` (0 differences).
|
||||||
|
|
||||||
|
| # | Criterion | Result |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1 | A repository without the marker is never written to | Go by the offline tests (`test_a_repository_without_the_marker_is_never_written_to`: no request, the existing page unchanged; `..._does_not_need_the_secret`; `..._without_a_wiki_directory_is_skipped`) and by the trigger rule. A live run was tried on 2026-10-11 in `TirSystem/IaC.server-setup-4-linux`: the API answered 404, the workflow is not listed for that repository and cannot be dispatched. S01 accepted the weaker evidence on 2026-10-11 (RC-049) |
|
||||||
|
| 2 | The workflow exists once | Go: only `.gitea/scoped_workflows/publish-wiki.yml`; no copy in `.gitea/workflows/` and nothing is needed from `tools/` in the target repository (the script is fetched from `TirSystem/github-action`, MIL-004 task 6) |
|
||||||
|
| 3 | One repository outside this one publishes its wiki | Go: `TirSystem/sqa-qc-checklists`, run 629, 13 pages equal |
|
||||||
|
| 4 | An empty or missing `wiki/` never deletes pages; a failure names its category | Go: `test_an_empty_source_never_deletes_pages_even_with_prune` and the category tests |
|
||||||
|
| 5 | `TOKEN_FOR_GITEA_WIKI` is documented and stored in the pilot's organisation | Go: `guides/credentials.md`; run 629 used the organisation secret |
|
||||||
|
| 6 | The onboarding and credentials guides and their wiki languages describe opting in | Go: `wiki/.publish` and `TOKEN_FOR_GITEA_WIKI` appear in the guides and the English, Danish and Bahasa Malaysia pages |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[BC-001]: ../business-case.md
|
[BC-001]: ../business-case.md
|
||||||
[6b8e36d]: https://git.tirsystem.com/TirSystem/github-action/commit/6b8e36d67ac9af165b180bc0045289e41cfd1fc3
|
|
||||||
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
[ADR-0002]: ../adr/adr-0002-s01-approves-as-stand-in.md
|
||||||
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
||||||
|
[d575f27]: https://git.tirsystem.com/TirSystem/github-action/commit/d575f272fcb044e3165951013464177a6e659ea6
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# MIL-007: Quality checks for C++ and C#
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | MIL-007 |
|
||||||
|
| CrossReference | [BC-001], [US-001], [UC-005], [MIL-003], [MIL-004], [ADR-0005], [ADR-0006] |
|
||||||
|
|
||||||
|
## 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] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Decide whether a C++ or C# project can run the same kind of quality checks
|
||||||
|
as a Python or shell project, through a shared workflow of this repository,
|
||||||
|
and whether the runners of the instance can run them.
|
||||||
|
|
||||||
|
## Deliverable
|
||||||
|
|
||||||
|
Reusable quality-check workflows for C++ and for C#, each with a documented
|
||||||
|
set of inputs and pinned tool versions, a guide for reading its results on the
|
||||||
|
wiki in English, Danish and Bahasa Malaysia, a use of each in at least one
|
||||||
|
other repository, and a release that makes them available at the major tag.
|
||||||
|
The existing workflow `quality-checks.yml` for Python and shell keeps its
|
||||||
|
name and contract. The workflows run current tools only: a .NET SDK of version
|
||||||
|
10 or later, and the latest stable release of each clang tool; a tool that
|
||||||
|
is only available as an old version is not used.
|
||||||
|
|
||||||
|
## Go / No-Go Criteria
|
||||||
|
|
||||||
|
| # | Criterion (objectively checkable) | Go | No-Go |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | The runner of the instance can run the tools of each language (installed in the run or provided by the image), verified and recorded | Verified for both, at current versions (.NET SDK 10 or later) | A tool cannot be had without changing the runner, or only as an old version |
|
||||||
|
| 2 | The contract (tools, versions, inputs, what a pass and a fail mean) is decided in an ADR, and a language that cannot be checked without a build system says what it needs | ADR accepted | Open |
|
||||||
|
| 3 | A failing check shows the tool, file and line in the log, verified with a seeded failure for each workflow | Verified | Cause not visible |
|
||||||
|
| 4 | One other repository runs each workflow and its status appears on pull requests | Appears for both | Does not run |
|
||||||
|
| 5 | The workflows embed no script: each runs a file of this repository, and the offline tests exercise the file | Count of embedded scripts is 0 | Embedded script remains |
|
||||||
|
| 6 | A release (a minor version) makes both available, and the changelog and the wiki name them | Released | Unreleased |
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
| Depends on | Reason |
|
||||||
|
| --- | --- |
|
||||||
|
| MIL-003 | The contract, the reusable workflow mechanism and the guide for reading results |
|
||||||
|
| MIL-004 | The release process and the release workflow publish the result |
|
||||||
|
|
||||||
|
## Traceability
|
||||||
|
|
||||||
|
| Business Case objective / KPI / user story | Reference |
|
||||||
|
| --- | --- |
|
||||||
|
| O4 | [BC-001] |
|
||||||
|
| US-001.09, US-001.10 (extended to C++ and C#) | [US-001] |
|
||||||
|
|
||||||
|
## Ownership
|
||||||
|
|
||||||
|
| Role | Stakeholder ID (SA) |
|
||||||
|
| --- | --- |
|
||||||
|
| Owner | S05 |
|
||||||
|
| Approving reviewer | S01 |
|
||||||
|
|
||||||
|
## Target Date
|
||||||
|
|
||||||
|
2027-01-16 — confirmed on 2026-10-11 by S01, standing in for S05 (ADR-0002); it follows the last decision of the plan, 2026-12-26, with two weeks from 2027-01-04. The Business Case sets no deadline.
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | Write the use case and stories for C++ and C# checks | Extend UC-005 (Run Project Quality Checks) so that its Brief names C++ and C#, and add stories to US-001 for a C++ project and a C# project, each with a pass and a fail acceptance criterion. Review them with the checklists of the `artifact` skill. | Yes | UC-005, US-001.09, US-001.10 |
|
||||||
|
| 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 | |
|
||||||
|
| 6 | Write the guides and the wiki pages | One guide per workflow in `guides/` for reading its results, the wiki pages in English, Danish and Bahasa Malaysia, the Home workflow list and diagrams (a test requires every workflow to be listed), and an update of the upgrade guide. | No | |
|
||||||
|
| 7 | Adopt each workflow in one other repository | Onboard a real C++ project and a real C# project, or a throwaway repository when none exists, and fix the gaps in the guides that appear. Verify a seeded failure. | No | |
|
||||||
|
| 8 | Release | Add the changelog entry (a new workflow is a minor change, ADR-0006) and run the Release workflow; record the results in this milestone and review it. | No | |
|
||||||
|
|
||||||
|
## Verification results
|
||||||
|
|
||||||
|
Task 2 was run on 2026-10-11 with a throwaway branch, `verify-runner-tools`,
|
||||||
|
in `TirSystem/github-action` (run 692, deleted afterwards). One job on
|
||||||
|
`ubuntu-latest` printed what the image has and tried each way of installing a
|
||||||
|
tool.
|
||||||
|
|
||||||
|
| Fact | Result |
|
||||||
|
| --- | --- |
|
||||||
|
| Image | Ubuntu 24.04, `x86_64`, the job runs as root, `sudo`, `curl`, `python3` 3.12 and `pip` present |
|
||||||
|
| Present in the image | `gcc` and `g++` 13.3, `make`; missing: `clang-format`, `clang-tidy`, `cppcheck`, `cmake`, `dotnet` |
|
||||||
|
| `clang-format` | from PyPI in 2 s (23.1.3); from apt in 9 s |
|
||||||
|
| `clang-tidy` | from PyPI in 5 s (22.1.8); from apt in 25 s |
|
||||||
|
| `cppcheck` | apt gives 2.13.0 in 6 s, which is old (the latest release is 2.22.0); the PyPI package named `cppcheck` is a different project (1.5.3) and is not used; a current release needs a build from source |
|
||||||
|
| .NET SDK | the official script `dot.net/v1/dotnet-install.sh` with `--channel 10.0` gives 10.0.401 in 20 s; apt `dotnet-sdk-10.0` gives 10.0.112 in 23 s, an older feature band; the same script also offers 11.0 as a release candidate, which is not used |
|
||||||
|
|
||||||
|
A first run (run 692) looked at .NET SDK 8, which is not used: the requirement
|
||||||
|
is a .NET SDK of version 10 or later, and old tools are not run. A second run
|
||||||
|
(run 699, also deleted afterwards) checked current versions. The current
|
||||||
|
clang tools come from PyPI in a few seconds with an exact version, as
|
||||||
|
`quality-checks.yml` already does for its tools, and the .NET SDK 10 comes from
|
||||||
|
the official script in 20 s, with no change to the runner. `cppcheck` is the
|
||||||
|
exception: only an old version is a package, so the contract either drops it
|
||||||
|
(`clang-tidy` does the static analysis) or builds a current release from
|
||||||
|
source, which costs minutes per run.
|
||||||
|
Not covered by this task: running a tool against a real C++ project (a
|
||||||
|
`clang-tidy` run needs a compile database or flags) or a real C# solution
|
||||||
|
(`dotnet format` and a build need the project's restore of packages from the
|
||||||
|
network), a private runner with no internet, and an image that differs from
|
||||||
|
`ubuntu-latest`. Those belong to the contract (task 3) and to the adoption
|
||||||
|
(task 7).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[BC-001]: ../business-case.md
|
||||||
|
[US-001]: ../user-stories.md
|
||||||
|
[UC-005]: ../uc-005/uc.md
|
||||||
|
[MIL-003]: ./mil-003-quality-checks.md
|
||||||
|
[MIL-004]: ./mil-004-versioned-release.md
|
||||||
|
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
|
||||||
|
[ADR-0006]: ../adr/adr-0006-release-process-and-version-pinning.md
|
||||||
|
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
|
||||||
|
[7bcc67a]: https://git.tirsystem.com/TirSystem/github-action/commit/7bcc67a065ac5f67b4e13ebf243a4bbbe2af47d9
|
||||||
+15
-6
@@ -4,25 +4,25 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | PP-001 |
|
| ID | PP-001 |
|
||||||
| CrossReference | [BC-001], [SA-001], [ADR-0002], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] |
|
| CrossReference | [BC-001], [SA-001], [ADR-0002], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | P1 use cases written and accepted (UCD-001, US-001, UC-001 to UC-004): Open Issues updated | [a2bf2d4] |
|
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Dates confirmed by S01 (stand-in for S05); the confirmation item is removed from Open Issues | [ea06eaa] |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Dates confirmed by S01 (stand-in for S05); the confirmation item is removed from Open Issues | [ea06eaa] |
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added MIL-007 (quality checks for C++ and C#); reviewed (RC-053) | [e3ad1fa] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This plan schedules six milestones that move the repository from one
|
This plan schedules seven milestones that move the repository from one
|
||||||
workflow with known defects to a documented, versioned collection of shared
|
workflow with known defects to a documented, versioned collection of shared
|
||||||
workflows. The Business Case sets no deadline, so the dates are the plan's own; they were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
|
workflows. The Business Case sets no deadline, so the dates are the plan's own; they were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
|
||||||
|
|
||||||
## Planning Assumptions
|
## Planning Assumptions
|
||||||
|
|
||||||
- Week 1 starts 2026-10-05; phases are two weeks long; the last decision is 2026-12-26.
|
- Week 1 starts 2026-10-05; phases are two weeks long; the last decision is 2026-12-26; MIL-007 follows in January 2027 (2027-01-04 to 2027-01-16, confirmed on 2026-10-11 by S01).
|
||||||
- Work on a milestone starts only after its `MIL-*` document is `Accepted`.
|
- Work on a milestone starts only after its `MIL-*` document is `Accepted`.
|
||||||
- Dates were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
|
- Dates were confirmed on 2026-10-10 by S01, standing in for S05 (ADR-0002).
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ workflows. The Business Case sets no deadline, so the dates are the plan's own;
|
|||||||
| Versioned release and publishing | [MIL-004] | 2026-11-16 to 2026-11-28 | 2026-11-28 | S05 | None yet | Release process and reusable release workflow | [Milestone MIL-004] |
|
| Versioned release and publishing | [MIL-004] | 2026-11-16 to 2026-11-28 | 2026-11-28 | S05 | None yet | Release process and reusable release workflow | [Milestone MIL-004] |
|
||||||
| Wiki and translations | [MIL-005] | 2026-11-30 to 2026-12-12 | 2026-12-12 | S05 | None yet | Wiki pages in English, Danish and Bahasa Malaysia, kept current by every pull request | [Milestone MIL-005] |
|
| Wiki and translations | [MIL-005] | 2026-11-30 to 2026-12-12 | 2026-12-12 | S05 | None yet | Wiki pages in English, Danish and Bahasa Malaysia, kept current by every pull request | [Milestone MIL-005] |
|
||||||
| Shared wiki publishing | [MIL-006] | 2026-12-14 to 2026-12-26 | 2026-12-26 | S05 | None yet | Scoped publish-wiki workflow with opt-in, piloted in one other repository | [Milestone MIL-006] |
|
| Shared wiki publishing | [MIL-006] | 2026-12-14 to 2026-12-26 | 2026-12-26 | S05 | None yet | Scoped publish-wiki workflow with opt-in, piloted in one other repository | [Milestone MIL-006] |
|
||||||
|
| Quality checks for C++ and C# | [MIL-007] | 2027-01-04 to 2027-01-16 | 2027-01-16 | S05 | US-001.09, US-001.10 (to extend) | Reusable quality-check workflows for C++ and C#, released | [Milestone MIL-007] |
|
||||||
|
|
||||||
```plantuml
|
```plantuml
|
||||||
@startgantt
|
@startgantt
|
||||||
@@ -52,6 +53,8 @@ Project starts 2026-10-05
|
|||||||
[MIL-005 Go/No-Go] happens 2026-12-12
|
[MIL-005 Go/No-Go] happens 2026-12-12
|
||||||
[MIL-006 Shared wiki] starts 2026-12-14 and ends 2026-12-26
|
[MIL-006 Shared wiki] starts 2026-12-14 and ends 2026-12-26
|
||||||
[MIL-006 Go/No-Go] happens 2026-12-26
|
[MIL-006 Go/No-Go] happens 2026-12-26
|
||||||
|
[MIL-007 C++ and C#] starts 2027-01-04 and ends 2027-01-16
|
||||||
|
[MIL-007 Go/No-Go] happens 2027-01-16
|
||||||
@endgantt
|
@endgantt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,12 +68,14 @@ Project starts 2026-10-05
|
|||||||
| Gitea Actions workflows for software engineers (release and publishing) | [MIL-004] |
|
| Gitea Actions workflows for software engineers (release and publishing) | [MIL-004] |
|
||||||
| Wiki pages in English, Danish and Bahasa Malaysia | [MIL-005] |
|
| Wiki pages in English, Danish and Bahasa Malaysia | [MIL-005] |
|
||||||
| The wiki publisher shared with other repositories through scoped delivery | [MIL-006] |
|
| The wiki publisher shared with other repositories through scoped delivery | [MIL-006] |
|
||||||
|
| Gitea Actions workflows for software engineers (quality checks for C++ and C#) | [MIL-007] |
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```
|
```
|
||||||
MIL-001 → MIL-002 → MIL-003 → MIL-004
|
MIL-001 → MIL-002 → MIL-003 → MIL-004
|
||||||
MIL-002 → MIL-005 → MIL-006
|
MIL-002 → MIL-005 → MIL-006
|
||||||
|
MIL-003 + MIL-004 → MIL-007
|
||||||
```
|
```
|
||||||
|
|
||||||
A No-Go moves every later window by the rework time of the failed milestone.
|
A No-Go moves every later window by the rework time of the failed milestone.
|
||||||
@@ -79,6 +84,7 @@ A No-Go moves every later window by the rework time of the failed milestone.
|
|||||||
|
|
||||||
| Risk | Impact | Mitigation |
|
| Risk | Impact | Mitigation |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
| The runner cannot provide the C++ or C# tools (MIL-007) | The workflows need a custom runner image or a longer install | MIL-007 task 2 verifies it first; the ADR of task 3 says what a build-dependent check needs from the caller. |
|
||||||
| Reusable workflow support is missing on the instance | MIL-003 and MIL-004 change shape | Verify first in each milestone (MIL-002 task 2, MIL-003 task 1); fall back to copied templates. |
|
| Reusable workflow support is missing on the instance | MIL-003 and MIL-004 change shape | Verify first in each milestone (MIL-002 task 2, MIL-003 task 1); fall back to copied templates. |
|
||||||
| Security review by S05 is a bottleneck | Milestone decisions slip | Keep milestones small and plan review time before each decision date. |
|
| Security review by S05 is a bottleneck | Milestone decisions slip | Keep milestones small and plan review time before each decision date. |
|
||||||
|
|
||||||
@@ -251,11 +257,14 @@ no tests, no release process.
|
|||||||
[MIL-004]: ./milestones/mil-004-versioned-release.md
|
[MIL-004]: ./milestones/mil-004-versioned-release.md
|
||||||
[MIL-005]: ./milestones/mil-005-wiki-and-translations.md
|
[MIL-005]: ./milestones/mil-005-wiki-and-translations.md
|
||||||
[MIL-006]: ./milestones/mil-006-shared-wiki-publishing.md
|
[MIL-006]: ./milestones/mil-006-shared-wiki-publishing.md
|
||||||
|
[MIL-007]: ./milestones/mil-007-cpp-csharp-quality-checks.md
|
||||||
[Milestone MIL-001]: https://git.tirsystem.com/TirSystem/github-action/milestone/18
|
[Milestone MIL-001]: https://git.tirsystem.com/TirSystem/github-action/milestone/18
|
||||||
[Milestone MIL-002]: https://git.tirsystem.com/TirSystem/github-action/milestone/19
|
[Milestone MIL-002]: https://git.tirsystem.com/TirSystem/github-action/milestone/19
|
||||||
[Milestone MIL-003]: https://git.tirsystem.com/TirSystem/github-action/milestone/20
|
[Milestone MIL-003]: https://git.tirsystem.com/TirSystem/github-action/milestone/20
|
||||||
[Milestone MIL-004]: https://git.tirsystem.com/TirSystem/github-action/milestone/21
|
[Milestone MIL-004]: https://git.tirsystem.com/TirSystem/github-action/milestone/21
|
||||||
[Milestone MIL-005]: https://git.tirsystem.com/TirSystem/github-action/milestone/93
|
[Milestone MIL-005]: https://git.tirsystem.com/TirSystem/github-action/milestone/93
|
||||||
[Milestone MIL-006]: https://git.tirsystem.com/TirSystem/github-action/milestone/94
|
[Milestone MIL-006]: https://git.tirsystem.com/TirSystem/github-action/milestone/94
|
||||||
[a2bf2d4]: https://git.tirsystem.com/TirSystem/github-action/commit/a2bf2d420416f7aff2badc6fe32a7690e2e523fd
|
[Milestone MIL-007]: https://git.tirsystem.com/TirSystem/github-action/milestone/95
|
||||||
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
[ea06eaa]: https://git.tirsystem.com/TirSystem/github-action/commit/ea06eaaa698247d20e4a8e2694d7acbb1de58b63
|
||||||
|
[b74ee0e]: https://git.tirsystem.com/TirSystem/github-action/commit/b74ee0e5cfd04f25ba5f2c1addc80699147c479a
|
||||||
|
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Review Record: MIL-004 (verification results)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-048 |
|
||||||
|
| CrossReference | [MIL-004], [QC-MIL-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [6933e91] |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Criterion 3 verified; the action item is closed | [05b635c] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [MIL-004] after the first release, with its new Verification results section
|
||||||
|
- Checklist used: [QC-MIL-001]
|
||||||
|
|
||||||
|
## Checklist Results
|
||||||
|
|
||||||
|
| # | Criterion | Status | Evidence/Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | A concrete deliverable is defined for every gate | Pass | The release process, the upgrade guide, the release workflow and the scripts at a pinned reference now exist; the release page of `v1.0.0` is the proof. |
|
||||||
|
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | All five criteria have a result in the Verification results table, each naming its evidence. |
|
||||||
|
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged (MIL-003). |
|
||||||
|
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O2 and O4, unchanged. |
|
||||||
|
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01, unchanged. |
|
||||||
|
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-11-28; the criteria are met on 2026-10-11. |
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
Go - all six criteria pass, and the five Go/No-Go criteria of MIL-004 are met. Criterion 3 (a consumer pinned to the previous version keeps working) was met by construction at the first release and verified on 2026-10-11 with pinned consumers after `v1.0.1` and `v1.1.0` (see the Verification results of MIL-004). S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
|
||||||
|
|
||||||
|
## Action Items
|
||||||
|
|
||||||
|
| Action | Owner | Due |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Done 2026-10-11: criterion 3 verified with pinned consumers after `v1.0.1` (run 660) and `v1.1.0` (run 672) | S05 | done |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[MIL-004]: ../../milestones/mil-004-versioned-release.md
|
||||||
|
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||||
|
[6933e91]: https://git.tirsystem.com/TirSystem/github-action/commit/6933e91c83075fb39b2dfbe41683cb2a0a0bce28
|
||||||
|
[05b635c]: https://git.tirsystem.com/TirSystem/github-action/commit/05b635c1b3d79390c794e62e781595fbe5f1a4ea
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Review Record: MIL-006 (pilot results)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-049 |
|
||||||
|
| CrossReference | [MIL-006], [QC-MIL-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [d575f27] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [MIL-006] with its amended criterion 1 and its new Verification results section
|
||||||
|
- Checklist used: [QC-MIL-001]
|
||||||
|
|
||||||
|
## Checklist Results
|
||||||
|
|
||||||
|
| # | Criterion | Status | Evidence/Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | A concrete deliverable is defined for every gate | Pass | The scoped workflow, the opt-in rule, tests, guides and a pilot exist; run 629 is the proof. |
|
||||||
|
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Finding fixed during this review: criterion 1 demanded a live run in a repository without the marker, which the instance cannot produce (a scoped workflow is not dispatchable and runs only on a push that changes `wiki/**`). The criterion now names the offline tests and the trigger rule as its evidence. This is weaker than a live run, which the results state. |
|
||||||
|
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged (MIL-005, MIL-002). |
|
||||||
|
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O2 and O3, unchanged. |
|
||||||
|
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01, unchanged. |
|
||||||
|
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-12-26; the criteria are met on 2026-10-11. |
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
Go - all six criteria pass; the one finding (criterion 2) was fixed during the review, and the milestone's six Go/No-Go criteria are met, criterion 1 on the weaker evidence stated. 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 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Observe the first push that changes `wiki/**` in a repository without the marker, if one occurs, and record that the run only logs that publishing is not enabled | S05 | when it occurs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[MIL-006]: ../../milestones/mil-006-shared-wiki-publishing.md
|
||||||
|
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||||
|
[d575f27]: https://git.tirsystem.com/TirSystem/github-action/commit/d575f272fcb044e3165951013464177a6e659ea6
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Review Record: MIL-005 (translations accepted)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-050 |
|
||||||
|
| CrossReference | [MIL-005], [QC-MIL-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [ead3d98] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [MIL-005] with its amended criterion 4 and its new Verification results section
|
||||||
|
- Checklist used: [QC-MIL-001]
|
||||||
|
|
||||||
|
## Checklist Results
|
||||||
|
|
||||||
|
| # | Criterion | Status | Evidence/Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | A concrete deliverable is defined for every gate | Pass | The wiki in three languages, generated and published from `wiki/`; 21 pages are published. |
|
||||||
|
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Finding fixed during this review: criterion 4 demanded a native reader, which the project does not have. It now allows acceptance by S01 as the stand-in of ADR-0002 and says that the lack of a native reader is stated. This is weaker than a native review, and the results say so. |
|
||||||
|
| 3 | Dependencies on other milestones are explicitly mapped | Pass | Unchanged (MIL-002). |
|
||||||
|
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Unchanged. |
|
||||||
|
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01, unchanged. |
|
||||||
|
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-12-12; the criteria are met on 2026-10-11. |
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
Go - all six criteria pass; the one finding (criterion 2) was fixed during the review. The Danish and Bahasa Malaysia pages are accepted by S01 on 2026-10-11 without a native reader, standing in for the other reviewers as ADR-0002 records; there is no independent reader. Bahasa Malaysia is the weaker draft (`docs/wiki-translation-review.md`).
|
||||||
|
|
||||||
|
## Action Items
|
||||||
|
|
||||||
|
| Action | Owner | Due |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Have a native reader of each language use `docs/wiki-translation-review.md` when one is available; fix the findings through a pull request | S05 | when a reader is available |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[MIL-005]: ../../milestones/mil-005-wiki-and-translations.md
|
||||||
|
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||||
|
[ead3d98]: https://git.tirsystem.com/TirSystem/github-action/commit/ead3d98d73fcab95fd57b0eb005a02aff9983256
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Review Record: ADR-0005 (tools-ref)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-051 |
|
||||||
|
| CrossReference | [ADR-0005], [QC-ADR-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [670f0ac] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [ADR-0005] after the addition of the input `tools-ref`
|
||||||
|
- 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 | Unchanged. |
|
||||||
|
| 2 | Context states the problem, the forces (cost, risk, constraints) and the options evaluated | Pass | Unchanged; the move of the shell steps to a script file is an implementation of the decided contract, not a new option. |
|
||||||
|
| 3 | At least two options were considered, or the absence of alternatives is justified | Pass | Unchanged. |
|
||||||
|
| 4 | Decision is stated in one or two unhedged sentences and matches one of the evaluated options | Pass | The decision sentence names the new optional input. |
|
||||||
|
| 5 | Consequences list both Positive and Negative outcomes | Pass | Finding noted for the next revision, not a blocker: a reusable workflow cannot learn the ref it was called at (the context fields `workflow_ref`, `workflow_sha`, `job_workflow_sha` and `action_ref` are empty on this instance, verified on 2026-10-11), so the script ref is an input and a call at an exact tag is pinned completely only with `tools-ref` set to the same tag. |
|
||||||
|
| 6 | Quality-attribute impacts (performance, security, portability, etc.) are named where the decision affects them | Pass | Maintainability gains (a script of this repository, linted and tested as a file); the pin limitation above is the reliability cost. |
|
||||||
|
| 7 | Affected Artifacts are listed as links, and each is also in CrossReference | Pass | Unchanged. |
|
||||||
|
| 8 | Status changes are recorded as new Version History rows with a Change summary and Commit link; retained rows are never rewritten | Pass | The earlier row is kept with status Deprecated and a new row added. |
|
||||||
|
| 9 | A superseded or deprecated ADR names its successor, and the successor links back | N-A | Nothing is superseded. |
|
||||||
|
| 10 | Written in business or technical language of the domain, with no unexplained abbreviations | Pass | Unchanged. |
|
||||||
|
| 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. Adding an optional input is a minor change under ADR-0006. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
|
||||||
|
|
||||||
|
## Action Items
|
||||||
|
|
||||||
|
| Action | Owner | Due |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Run a pinned consumer (`@v1.0.1` with `tools-ref: v1.0.1`) after the next release to confirm the complete pin | S05 | next release |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[ADR-0005]: ../../adr/adr-0005-quality-check-contract.md
|
||||||
|
[QC-ADR-001]: ../../../framework/qc/qc-adr.md
|
||||||
|
[670f0ac]: https://git.tirsystem.com/TirSystem/github-action/commit/670f0ac469043bb166c84290c0dbf62b4908e3cc
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Review Record: MIL-007
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-052 |
|
||||||
|
| CrossReference | [MIL-007], [QC-MIL-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [e3ad1fa] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [MIL-007]
|
||||||
|
- Checklist used: [QC-MIL-001]
|
||||||
|
|
||||||
|
## Checklist Results
|
||||||
|
|
||||||
|
| # | Criterion | Status | Evidence/Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | A concrete deliverable is defined for every gate | Pass | Two reusable workflows with pinned tools, guides and wiki pages in three languages, a use in another repository and a release. |
|
||||||
|
| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Six criteria, each with a Go and a No-Go: runner verified, ADR accepted, seeded failure visible, a run in another repository, no embedded script, released. |
|
||||||
|
| 3 | Dependencies on other milestones are explicitly mapped | Pass | MIL-003 for the contract and mechanism, MIL-004 for the release; both are closed. |
|
||||||
|
| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | O4, and US-001.09 and US-001.10 which the milestone extends. |
|
||||||
|
| 5 | Milestone owner and approving reviewer are identified | Pass | Owner S05, approving reviewer S01. |
|
||||||
|
| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2027-01-16, after the last decision of the plan; the Business Case sets no deadline. |
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
Go - all six criteria pass; no findings. The plan-first order holds inside the milestone: the use case and stories (task 1), the runner check (task 2) and the contract ADR (task 3) come before any workflow (tasks 4 and 5). The decision between one workflow and one per language is left to the ADR and is not made here. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
|
||||||
|
|
||||||
|
## Action Items
|
||||||
|
|
||||||
|
| Action | Owner | Due |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Run `sync-project.sh --apply` so that the milestone and its issues exist | S05 | 2026-10-11 |
|
||||||
|
| Decide in the ADR (task 3) one workflow or one per language, and whether C is included | S01 | before tasks 4 and 5 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[MIL-007]: ../../milestones/mil-007-cpp-csharp-quality-checks.md
|
||||||
|
[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
|
||||||
|
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Review Record: PP-001 Project Plan (MIL-007)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
| Key | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| ID | RC-053 |
|
||||||
|
| CrossReference | [PP-001], [BC-001] |
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [e3ad1fa] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Artifact Under Review
|
||||||
|
|
||||||
|
- Instance reviewed: [PP-001]
|
||||||
|
- Checklist used: none: the Project Plan has no QC checklist. Validated against the Business Case [BC-001] and the Go / No-Go criteria of each listed milestone, as `PP.md` prescribes.
|
||||||
|
|
||||||
|
## Checklist Results
|
||||||
|
|
||||||
|
| # | Criterion | Status | Evidence/Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | Every milestone in the plan has a `MIL-*` document and the plan's dates equal that document's target date | Pass | MIL-001 to MIL-007 exist; the MIL-007 decision date 2027-01-16 equals its Target Date. |
|
||||||
|
| 2 | Every Business Case scope item is covered by a gateway | Pass | Quality checks for C++ and C# are mapped to MIL-007 in Scope Coverage under the quality-check scope item (O4). |
|
||||||
|
| 3 | The schedule respects the Business Case constraints | Pass | The Business Case sets no deadline; the dates are the plan's own and say so. |
|
||||||
|
| 4 | Dependencies between milestones are stated | Pass | The Dependencies diagram shows MIL-003 and MIL-004 to MIL-007, and MIL-007 lists them in its own document. |
|
||||||
|
| 5 | Every gateway has an owner who is a stakeholder ID | Pass | MIL-007 is owned by S05. |
|
||||||
|
| 6 | Plan content is internally consistent | Pass | "Seven milestones", the Planning Assumptions, the Gantt entries, the Gateway Schedule and the Scope Coverage agree. |
|
||||||
|
| 7 | Open Issues are current | Pass | Unchanged items remain open; a plan risk was added for the runner's tools. |
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
Go - all seven criteria pass; no findings. S01 gave the Go in chat on 2026-10-11, standing in for the other reviewers as ADR-0002 records; there is no independent reader.
|
||||||
|
|
||||||
|
## Action Items
|
||||||
|
|
||||||
|
| Action | Owner | Due |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Add the link to the Gitea milestone of MIL-007 to the Gateway Schedule after `--apply` | S05 | 2026-10-11 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[PP-001]: ../../project-plan.md
|
||||||
|
[BC-001]: ../../business-case.md
|
||||||
|
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | TM-001 |
|
| ID | TM-001 |
|
||||||
| CrossReference | [BC-001], [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [RC-001], [RC-002], [RC-003], [RC-004], [RC-005], [RC-006], [RC-007], [RC-008], [RC-009], [RC-010], [RC-011], [RC-012], [RC-013], [RC-014], [RC-015], [RC-016], [RC-017], [RC-018], [RC-019], [RC-020], [RC-021], [RC-022], [RC-023], [RC-024], [RC-025], [RC-026], [RC-027], [RC-028], [RC-029], [RC-030], [RC-031], [RC-032], [RC-033], [RC-034], [RC-035], [RC-036], [RC-037], [RC-038], [RC-039], [RC-040], [RC-041], [RC-042], [RC-043], [RC-044], [RC-045], [RC-046], [RC-047], [ADR-0007], [UC-007], [UC-006], [ADR-0006], [UC-005], [ADR-0005], [UCD-001], [US-001], [UC-001], [UC-002], [UC-003], [UC-004], [ADR-0001], [ADR-0002], [ADR-0003], [ADR-0004] |
|
| CrossReference | [BC-001], [SA-001], [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007], [RC-001], [RC-002], [RC-003], [RC-004], [RC-005], [RC-006], [RC-007], [RC-008], [RC-009], [RC-010], [RC-011], [RC-012], [RC-013], [RC-014], [RC-015], [RC-016], [RC-017], [RC-018], [RC-019], [RC-020], [RC-021], [RC-022], [RC-023], [RC-024], [RC-025], [RC-026], [RC-027], [RC-028], [RC-029], [RC-030], [RC-031], [RC-032], [RC-033], [RC-034], [RC-035], [RC-036], [RC-037], [RC-038], [RC-039], [RC-040], [RC-041], [RC-042], [RC-043], [RC-044], [RC-045], [RC-046], [RC-047], [RC-048], [RC-049], [RC-050], [RC-051], [RC-052], [RC-053], [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] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Added UC-007 and RC-044 to RC-046 | [4cf52af] |
|
| 2026-10-11 | Deprecated | Jens Tirsvad Nielsen | S01 | Added RC-051 (ADR-0005 tools-ref) | [670f0ac] |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Added ADR-0007 and RC-047 | [d9cd3c6] |
|
| 2026-10-11 | Accepted | Jens Tirsvad Nielsen | S01 | Added MIL-007, RC-052 and RC-053 | [e3ad1fa] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,19 +26,20 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| [SA-001] | SA | - | [BC-001], [UCD-001] | [RC-004] |
|
| [SA-001] | SA | - | [BC-001], [UCD-001] | [RC-004] |
|
||||||
| [BC-001] | BC | [SA-001] | [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] | [RC-001], [RC-008] |
|
| [BC-001] | BC | [SA-001] | [PP-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006] | [RC-001], [RC-008] |
|
||||||
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [US-001] | [RC-002], [RC-009], [RC-015], [RC-017], [RC-025], [RC-032] |
|
| [PP-001] | PP | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007], [US-001] | [RC-002], [RC-009], [RC-015], [RC-017], [RC-025], [RC-032], [RC-053] |
|
||||||
| [MIL-001] | MIL | [BC-001], [PP-001] | [MIL-002] | [RC-003], [RC-026] |
|
| [MIL-001] | MIL | [BC-001], [PP-001] | [MIL-002] | [RC-003], [RC-026] |
|
||||||
| [MIL-002] | MIL | [BC-001], [PP-001], [MIL-001] | [MIL-003], [MIL-005] | [RC-005], [RC-027] |
|
| [MIL-002] | MIL | [BC-001], [PP-001], [MIL-001] | [MIL-003], [MIL-005] | [RC-005], [RC-027] |
|
||||||
| [MIL-003] | MIL | [BC-001], [PP-001], [MIL-002] | [MIL-004] | [RC-006], [RC-028], [RC-033], [RC-039] |
|
| [MIL-003] | MIL | [BC-001], [PP-001], [MIL-002] | [MIL-004] | [RC-006], [RC-028], [RC-033], [RC-039] |
|
||||||
| [MIL-004] | MIL | [BC-001], [PP-001], [MIL-003] | - | [RC-007], [RC-029], [RC-034] |
|
| [MIL-004] | MIL | [BC-001], [PP-001], [MIL-003] | - | [RC-007], [RC-029], [RC-034], [RC-048] |
|
||||||
| [RC-001] | RC | [BC-001] | - | - |
|
| [RC-001] | RC | [BC-001] | - | - |
|
||||||
| [RC-002] | RC | [PP-001] | - | - |
|
| [RC-002] | RC | [PP-001] | - | - |
|
||||||
| [RC-003] | RC | [MIL-001] | - | - |
|
| [RC-003] | RC | [MIL-001] | - | - |
|
||||||
| [RC-004] | RC | [SA-001] | - | - |
|
| [RC-004] | RC | [SA-001] | - | - |
|
||||||
| [RC-005] | RC | [MIL-002] | - | - |
|
| [RC-005] | RC | [MIL-002] | - | - |
|
||||||
| [RC-006] | RC | [MIL-003] | - | - |
|
| [RC-006] | RC | [MIL-003] | - | - |
|
||||||
| [MIL-005] | MIL | [BC-001], [PP-001], [MIL-002] | [MIL-006] | [RC-010], [RC-011], [RC-030] |
|
| [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] |
|
| [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] |
|
||||||
| [RC-007] | RC | [MIL-004] | - | - |
|
| [RC-007] | RC | [MIL-004] | - | - |
|
||||||
| [RC-008] | RC | [BC-001] | - | - |
|
| [RC-008] | RC | [BC-001] | - | - |
|
||||||
| [RC-009] | RC | [PP-001] | - | - |
|
| [RC-009] | RC | [PP-001] | - | - |
|
||||||
@@ -62,7 +63,7 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
| [UC-003] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-023] |
|
| [UC-003] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-023] |
|
||||||
| [UC-004] | UC | [UCD-001], [US-001], [SA-001] | - | [RC-024] |
|
| [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] |
|
||||||
| [ADR-0005] | ADR | [MIL-003], [UC-005], [US-001], [ADR-0004] | - | [RC-038] |
|
| [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] |
|
| [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-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-0007] | ADR | [MIL-004], [UC-006], [ADR-0006] | - | [RC-047] |
|
||||||
@@ -96,6 +97,12 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
| [RC-045] | RC | [UCD-001] | - | - |
|
| [RC-045] | RC | [UCD-001] | - | - |
|
||||||
| [RC-046] | RC | [US-001] | - | - |
|
| [RC-046] | RC | [US-001] | - | - |
|
||||||
| [RC-047] | RC | [ADR-0007] | - | - |
|
| [RC-047] | RC | [ADR-0007] | - | - |
|
||||||
|
| [RC-048] | RC | [MIL-004] | - | - |
|
||||||
|
| [RC-049] | RC | [MIL-006] | - | - |
|
||||||
|
| [RC-050] | RC | [MIL-005] | - | - |
|
||||||
|
| [RC-051] | RC | [ADR-0005] | - | - |
|
||||||
|
| [RC-052] | RC | [MIL-007] | - | - |
|
||||||
|
| [RC-053] | RC | [PP-001] | - | - |
|
||||||
|
|
||||||
## Coverage Notes
|
## Coverage Notes
|
||||||
|
|
||||||
@@ -115,6 +122,7 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
[MIL-004]: ../milestones/mil-004-versioned-release.md
|
[MIL-004]: ../milestones/mil-004-versioned-release.md
|
||||||
[MIL-005]: ../milestones/mil-005-wiki-and-translations.md
|
[MIL-005]: ../milestones/mil-005-wiki-and-translations.md
|
||||||
[MIL-006]: ../milestones/mil-006-shared-wiki-publishing.md
|
[MIL-006]: ../milestones/mil-006-shared-wiki-publishing.md
|
||||||
|
[MIL-007]: ../milestones/mil-007-cpp-csharp-quality-checks.md
|
||||||
[RC-001]: ./reviews/rc-001-business-case.md
|
[RC-001]: ./reviews/rc-001-business-case.md
|
||||||
[RC-002]: ./reviews/rc-002-project-plan.md
|
[RC-002]: ./reviews/rc-002-project-plan.md
|
||||||
[RC-003]: ./reviews/rc-003-mil-001.md
|
[RC-003]: ./reviews/rc-003-mil-001.md
|
||||||
@@ -172,11 +180,17 @@ updated whenever an artifact instance is created or reviewed.
|
|||||||
[RC-045]: ./reviews/rc-045-ucd-001-consume.md
|
[RC-045]: ./reviews/rc-045-ucd-001-consume.md
|
||||||
[RC-046]: ./reviews/rc-046-us-001-consume.md
|
[RC-046]: ./reviews/rc-046-us-001-consume.md
|
||||||
[RC-047]: ./reviews/rc-047-adr-0007.md
|
[RC-047]: ./reviews/rc-047-adr-0007.md
|
||||||
|
[RC-048]: ./reviews/rc-048-mil-004-outcome.md
|
||||||
|
[RC-049]: ./reviews/rc-049-mil-006-outcome.md
|
||||||
|
[RC-050]: ./reviews/rc-050-mil-005-outcome.md
|
||||||
|
[RC-051]: ./reviews/rc-051-adr-0005-tools-ref.md
|
||||||
|
[RC-052]: ./reviews/rc-052-mil-007.md
|
||||||
|
[RC-053]: ./reviews/rc-053-pp-001-mil-007.md
|
||||||
[ADR-0007]: ../adr/adr-0007-release-publish-destination.md
|
[ADR-0007]: ../adr/adr-0007-release-publish-destination.md
|
||||||
[UC-007]: ../uc-007/uc.md
|
[UC-007]: ../uc-007/uc.md
|
||||||
[UC-006]: ../uc-006/uc.md
|
[UC-006]: ../uc-006/uc.md
|
||||||
[ADR-0006]: ../adr/adr-0006-release-process-and-version-pinning.md
|
[ADR-0006]: ../adr/adr-0006-release-process-and-version-pinning.md
|
||||||
[UC-005]: ../uc-005/uc.md
|
[UC-005]: ../uc-005/uc.md
|
||||||
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
|
[ADR-0005]: ../adr/adr-0005-quality-check-contract.md
|
||||||
[4cf52af]: https://git.tirsystem.com/TirSystem/github-action/commit/4cf52afe00f546c6b20424fb8dfc12796ffd9296
|
[670f0ac]: https://git.tirsystem.com/TirSystem/github-action/commit/670f0ac469043bb166c84290c0dbf62b4908e3cc
|
||||||
[d9cd3c6]: https://git.tirsystem.com/TirSystem/github-action/commit/d9cd3c67d4017984af8958f32240d3d66217e153
|
[e3ad1fa]: https://git.tirsystem.com/TirSystem/github-action/commit/e3ad1fa7e7eef57a6793a479edb41ac6fd2db688
|
||||||
|
|||||||
+8
-5
@@ -4,12 +4,13 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | UC-005 |
|
| ID | UC-005 |
|
||||||
| CrossReference | [UCD-001], [US-001], [SA-001], [ADR-0005] |
|
| CrossReference | [UCD-001], [US-001], [SA-001], [ADR-0005], [MIL-007] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Accepted | Jens Tirsvad Nielsen | S01 | Initial version | [385d2fb] |
|
| 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] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -20,18 +21,18 @@
|
|||||||
**Level:** user-goal
|
**Level:** user-goal
|
||||||
**Primary Actor:** Software Engineer
|
**Primary Actor:** Software Engineer
|
||||||
**Stakeholders:** S02, S05 (interests below)
|
**Stakeholders:** S02, S05 (interests below)
|
||||||
**Stories:** US-001.09, US-001.10
|
**Stories:** US-001.09, US-001.10, US-001.16, US-001.17
|
||||||
|
|
||||||
## Brief
|
## Brief
|
||||||
|
|
||||||
A Software Engineer opens a pull request in a repository that calls the shared quality-check workflow. The workflow installs the pinned tools, runs the checks for each selected language on the files of the repository (lint, format and types for Python; lint and format for shell), and reports one status for the pull request. When every selected tool passes, the status is green.
|
A Software Engineer opens a pull request in a repository that calls the shared quality-check workflow. The workflow installs the pinned tools, runs the checks for each selected language on the files of the repository (lint, format and types for Python; lint and format for shell; format and static checks for C++; format and analyzer checks for C#), and reports one status for the pull request. 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.
|
||||||
|
|
||||||
**Stakeholder interests**
|
**Stakeholder interests**
|
||||||
|
|
||||||
- S02 — checks run the same way in every project without writing a pipeline, and a failure says what to fix
|
- S02 — checks run the same way in every project without writing a pipeline, and a failure says what to fix
|
||||||
- S05 — the checks and their tool versions are defined once and change through a reviewed release
|
- S05 — the checks and their tool versions are defined once and change through a reviewed release
|
||||||
|
|
||||||
**Preconditions:** The repository is onboarded, the shared workflow is available through reusable workflow delivery, and the repository has files of at least one supported language.
|
**Preconditions:** The repository is onboarded, the shared workflow is available through reusable workflow delivery, and the repository has files of at least one supported language (Python, shell, C++ or C#).
|
||||||
|
|
||||||
**Postconditions (success guarantee):** The pull request has a pass or fail status that comes from every selected tool, and no file of the repository was changed.
|
**Postconditions (success guarantee):** The pull request has a pass or fail status that comes from every selected tool, and no file of the repository was changed.
|
||||||
|
|
||||||
@@ -41,4 +42,6 @@ A Software Engineer opens a pull request in a repository that calls the shared q
|
|||||||
[US-001]: ../user-stories.md
|
[US-001]: ../user-stories.md
|
||||||
[SA-001]: ../stakeholder-analysis.md
|
[SA-001]: ../stakeholder-analysis.md
|
||||||
[ADR-0005]: ../adr/adr-0005-quality-check-contract.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
|
[385d2fb]: https://git.tirsystem.com/TirSystem/github-action/commit/385d2fb7cb9be1fdc8fd3503d0af624fa38eafc7
|
||||||
|
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
|
||||||
|
|||||||
+34
-5
@@ -4,13 +4,13 @@
|
|||||||
| Key | Value |
|
| Key | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| ID | US-001 |
|
| ID | US-001 |
|
||||||
| CrossReference | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007] |
|
| CrossReference | [UCD-001], [BC-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [UC-001], [UC-002], [UC-003], [UC-004], [UC-005], [UC-006], [UC-007], [MIL-007] |
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
| Date | Status | Author | Reviewer | Change | Commit |
|
| Date | Status | Author | Reviewer | Change | Commit |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| 2026-10-10 | Deprecated | Jens Tirsvad Nielsen | S01 | Added US-001.11 to US-001.13 (releases, UC-006); US-001.13 traced to the epic (RC-041) | [044d8ba] |
|
| 2026-10-10 | 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-10 | Accepted | Jens Tirsvad Nielsen | S01 | Added US-001.14 and US-001.15 (UC-007); US-001.13 traced to UC-007 (RC-046) | [4cf52af] |
|
| 2026-10-11 | Proposed | Jens Tirsvad Nielsen | S01 | Added US-001.16 and US-001.17 (C++ and C# checks, MIL-007 task 1) | [32b5ab6] |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -218,9 +218,37 @@ actors of [UCD-001]. Stories for quality checks and releases (MIL-004) and for t
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [UC-007], [MIL-004] | fits one iteration | none |
|
| [UC-007], [MIL-004] | fits one iteration | none |
|
||||||
|
|
||||||
|
### US-001.16 — A C++ project gets the same checks
|
||||||
|
|
||||||
|
**As a** Software Engineer, **I want** a pull request in a C++ repository to run format and static checks, **so that** a defect is found before review without me writing a pipeline.
|
||||||
|
|
||||||
|
**Acceptance Criteria**
|
||||||
|
|
||||||
|
- Given a repository that calls the shared C++ quality-check workflow and has C++ files, when a pull request is opened, then the format and static checks run and the status is pass or fail.
|
||||||
|
- Given a file with a finding, when the check runs, then the job fails and the log shows the tool name with `path:line` and the tool's message.
|
||||||
|
- Given a repository that lacks what a check needs, when the check runs, then it fails with a `[configuration]` message that names what is missing instead of passing.
|
||||||
|
|
||||||
|
| Traces to | Size | INVEST exceptions |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [UC-005], [MIL-007] | fits one iteration | none |
|
||||||
|
|
||||||
|
### US-001.17 — A C# project gets the same checks
|
||||||
|
|
||||||
|
**As a** Software Engineer, **I want** a pull request in a C# repository to run format and analyzer checks, **so that** a defect is found before review without me writing a pipeline.
|
||||||
|
|
||||||
|
**Acceptance Criteria**
|
||||||
|
|
||||||
|
- Given a repository that calls the shared C# quality-check workflow and has a project or solution, when a pull request is opened, then the format and analyzer checks run and the status is pass or fail.
|
||||||
|
- Given a file with a finding, when the check runs, then the job fails and the log shows the tool name with `path:line` and the tool's message.
|
||||||
|
- Given a repository without a project or solution, when the check runs, then it fails with a `[configuration]` message that names what is missing instead of passing.
|
||||||
|
|
||||||
|
| Traces to | Size | INVEST exceptions |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [UC-005], [MIL-007] | fits one iteration | none |
|
||||||
|
|
||||||
## INVEST Check
|
## INVEST Check
|
||||||
|
|
||||||
All fifteen stories are independent of each other except that US-001.05 and
|
All seventeen stories are independent of each other except that US-001.05 and
|
||||||
US-001.06 build on US-001.04 (the secrets must exist before a repository can
|
US-001.06 build on US-001.04 (the secrets must exist before a repository can
|
||||||
run the workflow). Each states one goal and can be negotiated, delivers value
|
run the workflow). Each states one goal and can be negotiated, delivers value
|
||||||
to the named role, is small enough for one iteration, and has acceptance
|
to the named role, is small enough for one iteration, and has acceptance
|
||||||
@@ -236,12 +264,13 @@ behaviour is tested rather than built.
|
|||||||
[MIL-002]: ./milestones/mil-002-onboarding-and-operations.md
|
[MIL-002]: ./milestones/mil-002-onboarding-and-operations.md
|
||||||
[MIL-003]: ./milestones/mil-003-quality-checks.md
|
[MIL-003]: ./milestones/mil-003-quality-checks.md
|
||||||
[MIL-004]: ./milestones/mil-004-versioned-release.md
|
[MIL-004]: ./milestones/mil-004-versioned-release.md
|
||||||
|
[MIL-007]: ./milestones/mil-007-cpp-csharp-quality-checks.md
|
||||||
[UC-001]: ./uc-001/uc.md
|
[UC-001]: ./uc-001/uc.md
|
||||||
[UC-002]: ./uc-002/uc.md
|
[UC-002]: ./uc-002/uc.md
|
||||||
[UC-003]: ./uc-003/uc.md
|
[UC-003]: ./uc-003/uc.md
|
||||||
[UC-004]: ./uc-004/uc.md
|
[UC-004]: ./uc-004/uc.md
|
||||||
[UC-005]: ./uc-005/uc.md
|
[UC-005]: ./uc-005/uc.md
|
||||||
[UC-006]: ./uc-006/uc.md
|
[UC-006]: ./uc-006/uc.md
|
||||||
[044d8ba]: https://git.tirsystem.com/TirSystem/github-action/commit/044d8ba21f96f4aceb807d62addc35cdcbb56051
|
|
||||||
[UC-007]: ./uc-007/uc.md
|
[UC-007]: ./uc-007/uc.md
|
||||||
[4cf52af]: https://git.tirsystem.com/TirSystem/github-action/commit/4cf52afe00f546c6b20424fb8dfc12796ffd9296
|
[4cf52af]: https://git.tirsystem.com/TirSystem/github-action/commit/4cf52afe00f546c6b20424fb8dfc12796ffd9296
|
||||||
|
[32b5ab6]: https://git.tirsystem.com/TirSystem/github-action/commit/32b5ab62ab5a82638b71b8fcfb43a819e92ab346
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ a proofreader of the English.
|
|||||||
This is a working document for reviewers, like [the term list](wiki-terms.md).
|
This is a working document for reviewers, like [the term list](wiki-terms.md).
|
||||||
It is not a project artifact.
|
It is not a project artifact.
|
||||||
|
|
||||||
|
**Status (2026-10-11):** no native reader was available; S01 accepted the
|
||||||
|
translations as the stand-in of ADR-0002 (RC-050). This checklist stays for
|
||||||
|
a native reader who wants to review them; the findings go in a pull request.
|
||||||
|
|
||||||
## What to review
|
## What to review
|
||||||
|
|
||||||
Fifteen pages exist on the wiki. You review the five pages of your language.
|
Fifteen pages exist on the wiki. You review the five pages of your language.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
quality:
|
quality:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
|
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1
|
||||||
with:
|
with:
|
||||||
languages: python,shell
|
languages: python,shell
|
||||||
```
|
```
|
||||||
@@ -32,10 +32,17 @@ jobs:
|
|||||||
| `mypy-version` | `1.11.2` | Version of mypy |
|
| `mypy-version` | `1.11.2` | Version of mypy |
|
||||||
| `shellcheck-py-version` | `0.10.0.1` | Version of the shellcheck-py package (ShellCheck 0.10.0) |
|
| `shellcheck-py-version` | `0.10.0.1` | Version of the shellcheck-py package (ShellCheck 0.10.0) |
|
||||||
| `shfmt-py-version` | `3.11.0.2` | Version of the shfmt-py package (shfmt 3.11.0) |
|
| `shfmt-py-version` | `3.11.0.2` | Version of the shfmt-py package (shfmt 3.11.0) |
|
||||||
|
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks.sh` is fetched |
|
||||||
|
|
||||||
Reference the workflow at `main` or at a tag, never at the branch of a pull
|
Reference the workflow at the major tag (`@v1`) or at an exact tag
|
||||||
request: that branch is deleted when the pull request is merged and the
|
(`@v1.0.0`), never at `main` and never at the branch of a pull request: that
|
||||||
reference stops working.
|
branch is deleted when the pull request is merged and the reference stops
|
||||||
|
working. See the upgrade guide for what each choice receives.
|
||||||
|
|
||||||
|
The workflow file calls a script of this repository, fetched at `tools-ref`. A
|
||||||
|
call at an exact tag is pinned completely only when `tools-ref` names the same
|
||||||
|
tag, for example `@v1.0.1` with `tools-ref: v1.0.1`; with the default the
|
||||||
|
script follows `v1`.
|
||||||
|
|
||||||
## What is checked
|
## What is checked
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ never starts, or stops before the step) is a **runner** problem.
|
|||||||
|
|
||||||
## Not an error
|
## Not an error
|
||||||
|
|
||||||
`No GitHub push mirror configured for <repo>; nothing to sync.` The run
|
`No GitHub push mirror configured for <repo>; nothing to sync.` followed by
|
||||||
succeeds. Not every Gitea repository has a GitHub mirror, so this is expected
|
`Skipped`. The run succeeds. Not every Gitea repository has a GitHub mirror, so
|
||||||
for those. If the repository should have one, add it in the repository
|
this is expected for those. If the repository should have one, add it in the repository
|
||||||
settings.
|
settings.
|
||||||
|
|
||||||
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not
|
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ 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`
|
A breaking release gets a new major version (`v2`), so a pipeline on `@v1`
|
||||||
never receives it until you change the line yourself.
|
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
|
||||||
|
`tools-ref` to the same tag; otherwise the script follows the major tag.
|
||||||
|
|
||||||
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
|
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
|
||||||
wiki**) are delivered by the instance and are not in your `uses:` lines; you
|
wiki**) are delivered by the instance and are not in your `uses:` lines; you
|
||||||
cannot pin them, but they fetch their scripts at the major tag.
|
cannot pin them, but they fetch their scripts at the major tag.
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
pytest>=8,<10
|
pytest>=8,<10
|
||||||
PyYAML>=6,<7
|
PyYAML>=6,<7
|
||||||
|
coverage>=7,<8
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Offline tests for tools/build_wiki.py."""
|
"""Offline tests for tools/build_wiki.py."""
|
||||||
|
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -91,9 +92,10 @@ def _write_sources(root: Path) -> None:
|
|||||||
(root / "README.md").write_text(
|
(root / "README.md").write_text(
|
||||||
"# 🚀 Name\nIntro.\n\n## 📚 Table of Contents\n- [x](#-overview)\n\n"
|
"# 🚀 Name\nIntro.\n\n## 📚 Table of Contents\n- [x](#-overview)\n\n"
|
||||||
"## 🧭 Overview\nSee [credentials](guides/credentials.md).\n\n"
|
"## 🧭 Overview\nSee [credentials](guides/credentials.md).\n\n"
|
||||||
|
"## 🔧 Workflows\nA table and diagrams.\n\n### 🔄 Sync\nDetails.\n\n"
|
||||||
"## 📋 Requirements\nNeeds a runner.\n\n## 🛠️ Setup\nRun [it](#-requirements).\n\n"
|
"## 📋 Requirements\nNeeds a runner.\n\n## 🛠️ Setup\nRun [it](#-requirements).\n\n"
|
||||||
"## ▶️ Run\nGo.\n\n## 🧪 Tests\nPytest.\n\n## 🟢 Capabilities\nA table.\n\n"
|
"## ▶️ Run\nGo.\n\n## 🧪 Tests\nPytest.\n\n## 🟢 Capabilities\nA table.\n\n### 🔎 Detail\nMore.\n\n"
|
||||||
"### 🔄 Sync\nDetails.\n\n## 📄 License\nMIT.\n",
|
"## 📄 License\nMIT.\n",
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
for name in ("onboarding", "credentials", "troubleshooting", "quality-checks", "upgrading"):
|
for name in ("onboarding", "credentials", "troubleshooting", "quality-checks", "upgrading"):
|
||||||
@@ -122,7 +124,8 @@ class TestRenderPage:
|
|||||||
page = next(p for p in build_wiki.PAGES if p.name == "Capabilities")
|
page = next(p for p in build_wiki.PAGES if p.name == "Capabilities")
|
||||||
text = build_wiki.render_page(page, repo)
|
text = build_wiki.render_page(page, repo)
|
||||||
assert "## Capabilities" in text
|
assert "## Capabilities" in text
|
||||||
assert "### Sync" in text
|
assert "### Detail" in text
|
||||||
|
assert "### Sync" not in text
|
||||||
assert "## Overview" not in text
|
assert "## Overview" not in text
|
||||||
|
|
||||||
def test_every_page_names_its_source_and_warns(self, repo):
|
def test_every_page_names_its_source_and_warns(self, repo):
|
||||||
@@ -154,7 +157,8 @@ class TestWriteAndCheck:
|
|||||||
def test_write_then_check_passes(self, repo, tmp_path):
|
def test_write_then_check_passes(self, repo, tmp_path):
|
||||||
wiki = tmp_path / "wiki"
|
wiki = tmp_path / "wiki"
|
||||||
changed = build_wiki.write_pages(wiki, repo)
|
changed = build_wiki.write_pages(wiki, repo)
|
||||||
assert sorted(changed) == sorted(f"{p.name}.md" for p in build_wiki.PAGES)
|
expected = [f"{p.name}.md" for p in build_wiki.PAGES] + [build_wiki.SIDEBAR_NAME]
|
||||||
|
assert sorted(changed) == sorted(expected)
|
||||||
assert build_wiki.check_pages(wiki, repo) == []
|
assert build_wiki.check_pages(wiki, repo) == []
|
||||||
assert build_wiki.write_pages(wiki, repo) == []
|
assert build_wiki.write_pages(wiki, repo) == []
|
||||||
|
|
||||||
@@ -267,3 +271,39 @@ def test_committed_translations_follow_the_english_structure(page, code):
|
|||||||
def test_committed_translations_are_current():
|
def test_committed_translations_are_current():
|
||||||
"""No translation follows an older version of its English page."""
|
"""No translation follows an older version of its English page."""
|
||||||
assert build_wiki.check_translations() == []
|
assert build_wiki.check_translations() == []
|
||||||
|
|
||||||
|
|
||||||
|
class TestSidebar:
|
||||||
|
"""Gitea shows subpages only through _Sidebar, so it must reach every page."""
|
||||||
|
|
||||||
|
def test_links_every_page_in_every_language(self):
|
||||||
|
sidebar = build_wiki.render_sidebar()
|
||||||
|
for page in build_wiki.PAGES:
|
||||||
|
assert f"]({page.name})" in sidebar
|
||||||
|
for code, _label in build_wiki.LANGUAGES:
|
||||||
|
assert f"]({page.name}.{code})" in sidebar
|
||||||
|
|
||||||
|
def test_every_link_names_a_committed_page(self):
|
||||||
|
sidebar = build_wiki.render_sidebar()
|
||||||
|
targets = re.findall(r"\]\(([^)]+)\)", sidebar)
|
||||||
|
assert targets
|
||||||
|
for target in targets:
|
||||||
|
assert (build_wiki.WIKI_DIR / f"{target}.md").is_file(), target
|
||||||
|
|
||||||
|
def test_has_one_label_per_page_and_language(self):
|
||||||
|
for code in ("en", *(c for c, _ in build_wiki.LANGUAGES)):
|
||||||
|
assert len(build_wiki.SIDEBAR_LABELS[code]) == len(build_wiki.PAGES)
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
files = sorted(
|
||||||
|
path.name
|
||||||
|
for folder in (".gitea/scoped_workflows", ".gitea/workflows")
|
||||||
|
for path in (REPO_ROOT / folder).glob("*.yml")
|
||||||
|
)
|
||||||
|
assert files
|
||||||
|
for name in files:
|
||||||
|
assert f"[`{name}`]" in home, f"{name} is not listed on the Home page"
|
||||||
|
assert home.count("@startuml") == len(files)
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ class TestWorkflow:
|
|||||||
assert steps[0]["uses"].startswith("actions/checkout@")
|
assert steps[0]["uses"].startswith("actions/checkout@")
|
||||||
assert steps[1]["with"] == {
|
assert steps[1]["with"] == {
|
||||||
"repository": "TirSystem/github-action",
|
"repository": "TirSystem/github-action",
|
||||||
"ref": "main",
|
"ref": "v1",
|
||||||
"path": "shared-scripts",
|
"path": "shared-scripts",
|
||||||
}
|
}
|
||||||
assert steps[-1]["run"] == "python3 shared-scripts/tools/publish_wiki.py"
|
assert steps[-1]["run"] == "python3 shared-scripts/tools/publish_wiki.py"
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import yaml
|
|||||||
from workflow_source import REPO_ROOT
|
from workflow_source import REPO_ROOT
|
||||||
|
|
||||||
WORKFLOW = REPO_ROOT / ".gitea" / "workflows" / "quality-checks.yml"
|
WORKFLOW = REPO_ROOT / ".gitea" / "workflows" / "quality-checks.yml"
|
||||||
|
SCRIPT = REPO_ROOT / "tools" / "quality-checks.sh"
|
||||||
|
COMMANDS = {"Validate the inputs": "validate", "Install the tools": "install", "Run the checks": "run"}
|
||||||
BASH = shutil.which("bash")
|
BASH = shutil.which("bash")
|
||||||
|
|
||||||
pytestmark = pytest.mark.skipif(BASH is None, reason="bash is needed to run the workflow steps")
|
pytestmark = pytest.mark.skipif(BASH is None, reason="bash is needed to run the workflow steps")
|
||||||
@@ -25,7 +27,7 @@ def document() -> dict:
|
|||||||
return yaml.safe_load(WORKFLOW.read_text(encoding="utf-8"))
|
return yaml.safe_load(WORKFLOW.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
def step_script(document: dict, name: str) -> str:
|
def step_command(document: dict, name: str) -> str:
|
||||||
steps = document["jobs"]["quality-checks"]["steps"]
|
steps = document["jobs"]["quality-checks"]["steps"]
|
||||||
return next(step["run"] for step in steps if step.get("name") == name)
|
return next(step["run"] for step in steps if step.get("name") == name)
|
||||||
|
|
||||||
@@ -40,9 +42,11 @@ class TestDefinition:
|
|||||||
"mypy-version",
|
"mypy-version",
|
||||||
"shellcheck-py-version",
|
"shellcheck-py-version",
|
||||||
"shfmt-py-version",
|
"shfmt-py-version",
|
||||||
|
"tools-ref",
|
||||||
}
|
}
|
||||||
assert inputs["languages"]["default"] == "python,shell"
|
assert inputs["languages"]["default"] == "python,shell"
|
||||||
assert inputs["working-directory"]["default"] == "."
|
assert inputs["working-directory"]["default"] == "."
|
||||||
|
assert inputs["tools-ref"]["default"] == "v1"
|
||||||
|
|
||||||
def test_tool_versions_are_pinned_to_the_adr(self, document):
|
def test_tool_versions_are_pinned_to_the_adr(self, document):
|
||||||
inputs = document[True]["workflow_call"]["inputs"]
|
inputs = document[True]["workflow_call"]["inputs"]
|
||||||
@@ -60,14 +64,32 @@ class TestDefinition:
|
|||||||
for step in document["jobs"]["quality-checks"]["steps"]:
|
for step in document["jobs"]["quality-checks"]["steps"]:
|
||||||
assert "${{" not in step.get("run", ""), f"{step.get('name')} interpolates an expression"
|
assert "${{" not in step.get("run", ""), f"{step.get('name')} interpolates an expression"
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
def test_the_script_parses(self):
|
||||||
"name", ["Validate the inputs", "Install the tools", "Run the checks"]
|
result = subprocess.run([BASH, "-n", str(SCRIPT)], text=True, capture_output=True)
|
||||||
)
|
|
||||||
def test_every_script_parses(self, document, name):
|
|
||||||
script = step_script(document, name)
|
|
||||||
result = subprocess.run([BASH, "-n"], input=script, text=True, capture_output=True)
|
|
||||||
assert result.returncode == 0, result.stderr
|
assert result.returncode == 0, result.stderr
|
||||||
|
|
||||||
|
def test_the_workflow_embeds_no_script_and_runs_the_file(self, document):
|
||||||
|
steps = document["jobs"]["quality-checks"]["steps"]
|
||||||
|
commands = [step["run"] for step in steps if "run" in step]
|
||||||
|
assert commands == [
|
||||||
|
"bash shared-scripts/tools/quality-checks.sh validate",
|
||||||
|
"bash shared-scripts/tools/quality-checks.sh install",
|
||||||
|
"bash shared-scripts/tools/quality-checks.sh run",
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_the_script_is_fetched_at_the_tools_ref_input(self, document):
|
||||||
|
steps = document["jobs"]["quality-checks"]["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",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_an_unknown_command_is_refused(self):
|
||||||
|
result = subprocess.run([BASH, str(SCRIPT), "bogus"], text=True, capture_output=True)
|
||||||
|
assert result.returncode == 2
|
||||||
|
|
||||||
|
|
||||||
STUB = """#!/usr/bin/env bash
|
STUB = """#!/usr/bin/env bash
|
||||||
name="$(basename "$0")"
|
name="$(basename "$0")"
|
||||||
@@ -111,7 +133,7 @@ def add_files(root: Path, *relative: str) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def run_step(document, name, repo, bin_dir, tmp_path, **env):
|
def run_step(document, name, repo, bin_dir, tmp_path, **env):
|
||||||
script = step_script(document, name)
|
command = COMMANDS[name]
|
||||||
log = tmp_path / "tools.log"
|
log = tmp_path / "tools.log"
|
||||||
environment = dict(os.environ)
|
environment = dict(os.environ)
|
||||||
environment.update(
|
environment.update(
|
||||||
@@ -126,7 +148,7 @@ def run_step(document, name, repo, bin_dir, tmp_path, **env):
|
|||||||
)
|
)
|
||||||
environment.update(env)
|
environment.update(env)
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[BASH, "-c", script], cwd=repo, env=environment, text=True, capture_output=True
|
[BASH, str(SCRIPT), command], cwd=repo, env=environment, text=True, capture_output=True
|
||||||
)
|
)
|
||||||
calls = log.read_text(encoding="utf-8").splitlines() if log.exists() else []
|
calls = log.read_text(encoding="utf-8").splitlines() if log.exists() else []
|
||||||
return result, calls
|
return result, calls
|
||||||
|
|||||||
@@ -245,7 +245,9 @@ class TestMain:
|
|||||||
|
|
||||||
assert all(call[0] == "GET" for call in api.calls)
|
assert all(call[0] == "GET" for call in api.calls)
|
||||||
assert not any(call[1].startswith("https://api.github.com") for call in api.calls)
|
assert not any(call[1].startswith("https://api.github.com") for call in api.calls)
|
||||||
assert "No GitHub push mirror configured" in capsys.readouterr().out
|
output = capsys.readouterr().out
|
||||||
|
assert "No GitHub push mirror configured" in output
|
||||||
|
assert output.rstrip().splitlines()[-1] == "Skipped"
|
||||||
|
|
||||||
def test_fails_before_any_change_when_github_credentials_are_missing(
|
def test_fails_before_any_change_when_github_credentials_are_missing(
|
||||||
self, sync, environment, monkeypatch
|
self, sync, environment, monkeypatch
|
||||||
|
|||||||
@@ -0,0 +1,371 @@
|
|||||||
|
"""Offline tests for the parts of tools/ that the flow tests do not reach.
|
||||||
|
|
||||||
|
The flow tests of each tool replace its HTTP function with a fake, so the real
|
||||||
|
`request_json` of the three API tools and the command-line entry point of each
|
||||||
|
tool are tested here: the reply that is parsed, the HTTP error that is named by
|
||||||
|
category, and the exit code and message of a run as a process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from workflow_source import REPO_ROOT, load_script
|
||||||
|
|
||||||
|
TOOLS = REPO_ROOT / "tools"
|
||||||
|
|
||||||
|
changelog = load_script(TOOLS / "changelog.py", "changelog_entry")
|
||||||
|
build_wiki = load_script(TOOLS / "build_wiki.py", "build_wiki_entry")
|
||||||
|
release = load_script(TOOLS / "release.py", "release_entry")
|
||||||
|
publish = load_script(TOOLS / "publish_wiki.py", "publish_wiki_entry")
|
||||||
|
sync = load_script(TOOLS / "sync_github_metadata.py", "sync_entry")
|
||||||
|
|
||||||
|
API_TOOLS = pytest.mark.parametrize(
|
||||||
|
"tool", [release, publish, sync], ids=["release", "publish_wiki", "sync_github_metadata"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeResponse:
|
||||||
|
def __init__(self, body: bytes) -> None:
|
||||||
|
self._body = body
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *exc):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def read(self) -> bytes:
|
||||||
|
return self._body
|
||||||
|
|
||||||
|
|
||||||
|
def http_error(code: int) -> urllib.error.HTTPError:
|
||||||
|
return urllib.error.HTTPError("https://git.example/api", code, "reason", {}, io.BytesIO(b""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def urlopen(monkeypatch):
|
||||||
|
"""Replace urllib.request.urlopen; set `.reply` to a body or an exception."""
|
||||||
|
|
||||||
|
class Opener:
|
||||||
|
reply: object = b"{}"
|
||||||
|
requests: list = []
|
||||||
|
|
||||||
|
def __call__(self, request, timeout=None):
|
||||||
|
self.requests.append(request)
|
||||||
|
if isinstance(self.reply, BaseException):
|
||||||
|
raise self.reply
|
||||||
|
return FakeResponse(self.reply)
|
||||||
|
|
||||||
|
opener = Opener()
|
||||||
|
opener.requests = []
|
||||||
|
monkeypatch.setattr("urllib.request.urlopen", opener)
|
||||||
|
return opener
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequestJson:
|
||||||
|
@API_TOOLS
|
||||||
|
def test_parses_a_json_reply(self, tool, urlopen):
|
||||||
|
urlopen.reply = b'{"name": "x"}'
|
||||||
|
assert tool["request_json"]("https://git.example/api", headers={"A": "b"}) == {"name": "x"}
|
||||||
|
|
||||||
|
@API_TOOLS
|
||||||
|
def test_an_empty_reply_is_none(self, tool, urlopen):
|
||||||
|
urlopen.reply = b""
|
||||||
|
assert tool["request_json"]("https://git.example/api", method="DELETE") is None
|
||||||
|
|
||||||
|
@API_TOOLS
|
||||||
|
def test_a_body_is_sent_as_json(self, tool, urlopen):
|
||||||
|
urlopen.reply = b"{}"
|
||||||
|
tool["request_json"]("https://git.example/api", method="POST", body={"k": 1})
|
||||||
|
assert json.loads(urlopen.requests[0].data) == {"k": 1}
|
||||||
|
assert urlopen.requests[0].get_method() == "POST"
|
||||||
|
|
||||||
|
@API_TOOLS
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"code, category",
|
||||||
|
[(401, "credentials"), (403, "permissions"), (500, "api")],
|
||||||
|
)
|
||||||
|
def test_an_http_error_is_named_by_category(self, tool, urlopen, code, category):
|
||||||
|
urlopen.reply = http_error(code)
|
||||||
|
with pytest.raises(tool["WorkflowError"]) as error:
|
||||||
|
tool["request_json"]("https://git.example/api")
|
||||||
|
assert error.value.category == category
|
||||||
|
assert str(code) in str(error.value)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tool", [publish, sync], ids=["publish_wiki", "sync_github_metadata"])
|
||||||
|
def test_a_missing_repository_is_a_configuration_error(self, tool, urlopen):
|
||||||
|
urlopen.reply = http_error(404)
|
||||||
|
with pytest.raises(tool["WorkflowError"]) as error:
|
||||||
|
tool["request_json"]("https://git.example/api")
|
||||||
|
assert error.value.category == "configuration"
|
||||||
|
|
||||||
|
@API_TOOLS
|
||||||
|
def test_an_unreachable_host_is_an_api_error(self, tool, urlopen):
|
||||||
|
urlopen.reply = urllib.error.URLError("no route")
|
||||||
|
with pytest.raises(tool["WorkflowError"]) as error:
|
||||||
|
tool["request_json"]("https://git.example/api")
|
||||||
|
assert error.value.category == "api"
|
||||||
|
assert "unreachable" in str(error.value)
|
||||||
|
|
||||||
|
def test_the_sync_tool_names_the_service_in_its_message(self, urlopen):
|
||||||
|
urlopen.reply = http_error(500)
|
||||||
|
with pytest.raises(sync["WorkflowError"]) as github:
|
||||||
|
sync["request_json"]("https://api.github.com/repos/o/r")
|
||||||
|
assert "GitHub API" in str(github.value)
|
||||||
|
with pytest.raises(sync["WorkflowError"]) as gitea:
|
||||||
|
sync["request_json"]("https://git.example/api/v1/repos/o/r")
|
||||||
|
assert "Gitea API" in str(gitea.value)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPagination:
|
||||||
|
def test_release_reads_every_page_of_tags(self):
|
||||||
|
pages = {1: [{"name": f"v{n}"} for n in range(50)], 2: [{"name": "v50"}], 3: []}
|
||||||
|
|
||||||
|
def request(url, headers=None):
|
||||||
|
page = int(url.split("page=")[1])
|
||||||
|
return pages[page]
|
||||||
|
|
||||||
|
names = release["list_tag_names"]("https://git.example/api", {}, request)
|
||||||
|
assert len(names) == 51 and names[-1] == "v50"
|
||||||
|
|
||||||
|
def test_release_stops_on_an_empty_first_page(self):
|
||||||
|
assert release["list_tag_names"]("https://git.example/api", {}, lambda *a, **k: []) == []
|
||||||
|
|
||||||
|
def test_publish_reads_every_page_of_wiki_titles(self):
|
||||||
|
full = [{"sub_url": f"Page-{n}"} for n in range(publish["PAGE_LIMIT"])]
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def send(url, headers=None):
|
||||||
|
calls.append(url)
|
||||||
|
return full if "page=1&" in url else [{"sub_url": "Last"}]
|
||||||
|
|
||||||
|
titles = publish["list_wiki_titles"]("https://git.example/wiki", {}, send)
|
||||||
|
assert len(calls) == 2
|
||||||
|
assert "Last" in titles and "Page-0" in titles
|
||||||
|
|
||||||
|
def test_publish_refuses_a_list_that_is_not_a_list(self):
|
||||||
|
with pytest.raises(publish["WorkflowError"]) as error:
|
||||||
|
publish["list_wiki_titles"](
|
||||||
|
"https://git.example/wiki", {}, lambda *a, **k: {"message": "x"}
|
||||||
|
)
|
||||||
|
assert error.value.category == "api"
|
||||||
|
|
||||||
|
|
||||||
|
class TestReleaseInputs:
|
||||||
|
@pytest.fixture()
|
||||||
|
def env(self, tmp_path, monkeypatch):
|
||||||
|
changelog_file = tmp_path / "CHANGELOG.md"
|
||||||
|
changelog_file.write_text(
|
||||||
|
"## [Unreleased]\n\n## [1.0.0] - 2026-10-10\n\n### Added\n\n- First.\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
for key, value in {
|
||||||
|
"GITEA_API_URL": "https://git.example/api/v1",
|
||||||
|
"SOURCE_REPOSITORY": "o/r",
|
||||||
|
"RELEASE_CREDENTIALS": "t" * 40,
|
||||||
|
"RELEASE_VERSION": "1.0.0",
|
||||||
|
"RELEASE_SHA": "a" * 40,
|
||||||
|
"RELEASE_DRY_RUN": "true",
|
||||||
|
"CHANGELOG_FILE": str(changelog_file),
|
||||||
|
}.items():
|
||||||
|
monkeypatch.setenv(key, value)
|
||||||
|
return monkeypatch
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("repository", ["", "owner", "/repo", "owner/"])
|
||||||
|
def test_a_malformed_repository_is_refused(self, env, repository):
|
||||||
|
env.setenv("SOURCE_REPOSITORY", repository)
|
||||||
|
with pytest.raises(release["WorkflowError"]) as error:
|
||||||
|
release["main"](request=lambda *a, **k: None)
|
||||||
|
assert error.value.category == "configuration"
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("sha", ["", "abc", "g" * 40])
|
||||||
|
def test_a_malformed_commit_is_refused(self, env, sha):
|
||||||
|
env.setenv("RELEASE_SHA", sha)
|
||||||
|
with pytest.raises(release["WorkflowError"]) as error:
|
||||||
|
release["main"](request=lambda *a, **k: None)
|
||||||
|
assert "RELEASE_SHA" in str(error.value)
|
||||||
|
|
||||||
|
def test_an_unreadable_changelog_is_a_configuration_error(self, env, tmp_path):
|
||||||
|
env.setenv("CHANGELOG_FILE", str(tmp_path / "missing.md"))
|
||||||
|
with pytest.raises(release["WorkflowError"]) as error:
|
||||||
|
release["main"](request=lambda *a, **k: None)
|
||||||
|
assert error.value.category == "configuration"
|
||||||
|
|
||||||
|
def test_a_changelog_that_breaks_its_convention_is_a_validation_error(self, env, tmp_path):
|
||||||
|
bad = tmp_path / "bad.md"
|
||||||
|
bad.write_text("## [1.0.0] - 2026-10-10\n\n### Added\n\n- X.\n", encoding="utf-8")
|
||||||
|
env.setenv("CHANGELOG_FILE", str(bad))
|
||||||
|
with pytest.raises(release["WorkflowError"]) as error:
|
||||||
|
release["main"](request=lambda *a, **k: None)
|
||||||
|
assert error.value.category == "validation"
|
||||||
|
assert "Unreleased" in str(error.value)
|
||||||
|
|
||||||
|
|
||||||
|
class TestChangelogCommandLine:
|
||||||
|
@pytest.fixture()
|
||||||
|
def good(self, tmp_path):
|
||||||
|
path = tmp_path / "CHANGELOG.md"
|
||||||
|
path.write_text(
|
||||||
|
"## [Unreleased]\n\n## [1.1.0] - 2026-10-11\n\n### Added\n\n- A.\n\n"
|
||||||
|
"## [1.0.0] - 2026-10-10\n\n### Fixed\n\n- B.\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def test_check_passes_a_good_file(self, good, capsys):
|
||||||
|
assert changelog["main"](["check", "--file", str(good)]) == 0
|
||||||
|
assert "follows the convention" in capsys.readouterr().out
|
||||||
|
|
||||||
|
def test_check_names_a_missing_version(self, good, capsys):
|
||||||
|
assert changelog["main"](["check", "--file", str(good), "--version", "2.0.0"]) == 1
|
||||||
|
assert "no changelog entry with changes for version 2.0.0" in capsys.readouterr().err
|
||||||
|
|
||||||
|
def test_check_reports_each_problem(self, tmp_path, capsys):
|
||||||
|
path = tmp_path / "CHANGELOG.md"
|
||||||
|
path.write_text("## [1.0.0]\n\n### Odd\n\n", encoding="utf-8")
|
||||||
|
assert changelog["main"](["check", "--file", str(path)]) == 1
|
||||||
|
err = capsys.readouterr().err
|
||||||
|
assert "first section must be `## [Unreleased]`" in err
|
||||||
|
assert "not one of Breaking, Added, Changed, Fixed" in err
|
||||||
|
assert "needs a date" in err
|
||||||
|
|
||||||
|
def test_notes_prints_the_release_page(self, good, capsys):
|
||||||
|
assert changelog["main"](["notes", "1.1.0", "--file", str(good)]) == 0
|
||||||
|
out = capsys.readouterr().out
|
||||||
|
assert out.startswith("## 1.1.0 - 2026-10-11") and "- A." in out
|
||||||
|
|
||||||
|
def test_notes_needs_a_version(self, good, capsys):
|
||||||
|
assert changelog["main"](["notes", "--file", str(good)]) == 1
|
||||||
|
assert "needs a version" in capsys.readouterr().err
|
||||||
|
|
||||||
|
def test_notes_names_an_unknown_version(self, good, capsys):
|
||||||
|
assert changelog["main"](["notes", "9.9.9", "--file", str(good)]) == 1
|
||||||
|
assert "no changelog entry" in capsys.readouterr().err
|
||||||
|
|
||||||
|
def test_a_group_without_an_item_and_a_release_without_a_group_are_problems(self):
|
||||||
|
text = "## [Unreleased]\n\n### Added\n\n## [1.0.0] - 2026-10-10\n"
|
||||||
|
problems = changelog["validate"](text)
|
||||||
|
assert any("has no item" in p for p in problems)
|
||||||
|
assert any("has no change group" in p for p in problems)
|
||||||
|
|
||||||
|
def test_an_unreleased_section_has_no_date_and_versions_descend(self):
|
||||||
|
text = (
|
||||||
|
"## [Unreleased] - 2026-10-10\n\n## [1.0.0] - 2026-10-10\n\n### Added\n\n- A.\n\n"
|
||||||
|
"## [1.1.0] - 2026-10-11\n\n### Added\n\n- B.\n"
|
||||||
|
)
|
||||||
|
problems = changelog["validate"](text)
|
||||||
|
assert any("has no date" in p for p in problems)
|
||||||
|
assert any("must be lower than the version above it" in p for p in problems)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildWikiCommandLine:
|
||||||
|
def test_hash_prints_twelve_hex_digits_for_a_page(self, capsys):
|
||||||
|
assert build_wiki["main"](["--hash", "Home"]) == 0
|
||||||
|
assert len(capsys.readouterr().out.strip()) == build_wiki["HASH_LENGTH"]
|
||||||
|
|
||||||
|
def test_hash_of_an_unknown_page_fails(self, capsys):
|
||||||
|
assert build_wiki["main"](["--hash", "Nope"]) == 1
|
||||||
|
assert "unknown page" in capsys.readouterr().err
|
||||||
|
|
||||||
|
def test_check_passes_on_the_committed_wiki(self, capsys):
|
||||||
|
assert build_wiki["main"](["--check"]) == 0
|
||||||
|
assert "up to date" in capsys.readouterr().out
|
||||||
|
|
||||||
|
def test_check_lists_every_problem_and_the_command_that_fixes_it(self, monkeypatch, capsys):
|
||||||
|
monkeypatch.setattr(build_wiki._module, "check_pages", lambda: ["Home.md: missing"])
|
||||||
|
monkeypatch.setattr(build_wiki._module, "check_translations", lambda: [])
|
||||||
|
assert build_wiki["main"](["--check"]) == 1
|
||||||
|
err = capsys.readouterr().err
|
||||||
|
assert "ERROR: wiki/Home.md: missing" in err
|
||||||
|
assert "python tools/build_wiki.py" in err
|
||||||
|
|
||||||
|
def test_generate_reports_the_changed_pages(self, monkeypatch, capsys):
|
||||||
|
monkeypatch.setattr(build_wiki._module, "write_pages", lambda: ["Home.md"])
|
||||||
|
assert build_wiki["main"]([]) == 0
|
||||||
|
assert "Wrote 1 page(s): Home.md" in capsys.readouterr().out
|
||||||
|
|
||||||
|
def test_generate_reports_a_build_error(self, monkeypatch, capsys):
|
||||||
|
def broken():
|
||||||
|
raise build_wiki["WikiBuildError"]("README.md is missing")
|
||||||
|
|
||||||
|
monkeypatch.setattr(build_wiki._module, "write_pages", broken)
|
||||||
|
assert build_wiki["main"]([]) == 1
|
||||||
|
assert "ERROR: README.md is missing" in capsys.readouterr().err
|
||||||
|
|
||||||
|
|
||||||
|
def run_tool(name: str, **env: str) -> subprocess.CompletedProcess:
|
||||||
|
"""Run a tool as `python tools/<name>` with only the given environment."""
|
||||||
|
environment = {"PATH": "", "SYSTEMROOT": "", **env}
|
||||||
|
environment = {k: v for k, v in environment.items() if v != "" or k in env}
|
||||||
|
return subprocess.run(
|
||||||
|
[sys.executable, str(TOOLS / name)],
|
||||||
|
env=environment,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
cwd=REPO_ROOT,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRunAsAProcess:
|
||||||
|
"""The `if __name__ == "__main__"` block: exit code 1 and ERROR: on stderr."""
|
||||||
|
|
||||||
|
def test_release_without_a_version_exits_1(self):
|
||||||
|
result = run_tool("release.py")
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert result.stderr.startswith("ERROR: [configuration]")
|
||||||
|
|
||||||
|
def test_publish_wiki_without_a_repository_exits_1(self):
|
||||||
|
result = run_tool("publish_wiki.py", WIKI_DIR=str(REPO_ROOT / "wiki"), GITEA_API_URL="https://x")
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert "ERROR:" in result.stderr
|
||||||
|
|
||||||
|
def test_sync_without_a_token_exits_1(self):
|
||||||
|
result = run_tool("sync_github_metadata.py", GITEA_API_URL="https://x", SOURCE_REPOSITORY="o/r")
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert "ERROR:" in result.stderr and "TOKEN_FOR_GITEA" in result.stderr
|
||||||
|
|
||||||
|
def test_changelog_checks_the_committed_file(self):
|
||||||
|
result = run_tool("changelog.py", **{})
|
||||||
|
assert result.returncode != 0 # the command is required
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, str(TOOLS / "changelog.py"), "check"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
cwd=REPO_ROOT,
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, result.stderr
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemainingBranches:
|
||||||
|
def test_notes_of_a_release_without_changes_is_not_a_page(self):
|
||||||
|
text = "## [Unreleased]\n\n## [1.0.0] - 2026-10-10\n"
|
||||||
|
with pytest.raises(LookupError):
|
||||||
|
changelog["notes"](text, "1.0.0")
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("repository", [None, "", "owner", "/repo", "owner/"])
|
||||||
|
def test_publish_refuses_a_malformed_repository(self, repository):
|
||||||
|
with pytest.raises(publish["WorkflowError"]) as error:
|
||||||
|
publish["split_repository"](repository)
|
||||||
|
assert error.value.category == "configuration"
|
||||||
|
|
||||||
|
def test_publish_treats_a_wiki_without_pages_as_empty(self):
|
||||||
|
def send(url, headers=None):
|
||||||
|
raise publish["WorkflowError"]("configuration", "not found")
|
||||||
|
|
||||||
|
assert publish["list_wiki_titles"]("https://git.example/wiki", {}, send) == set()
|
||||||
|
|
||||||
|
def test_publish_does_not_hide_a_failure_on_a_later_page(self):
|
||||||
|
full = [{"sub_url": f"P-{n}"} for n in range(publish["PAGE_LIMIT"])]
|
||||||
|
|
||||||
|
def send(url, headers=None):
|
||||||
|
if "page=1&" in url:
|
||||||
|
return full
|
||||||
|
raise publish["WorkflowError"]("configuration", "gone")
|
||||||
|
|
||||||
|
with pytest.raises(publish["WorkflowError"]):
|
||||||
|
publish["list_wiki_titles"]("https://git.example/wiki", {}, send)
|
||||||
@@ -73,3 +73,19 @@ def test_no_workflow_copy_outside_the_workflow_directories():
|
|||||||
if path.name == SYNC_WORKFLOW.name
|
if path.name == SYNC_WORKFLOW.name
|
||||||
]
|
]
|
||||||
assert not stray, f"duplicate workflow copies: {stray}"
|
assert not stray, f"duplicate workflow copies: {stray}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_validation_runs_the_tests_under_a_coverage_gate():
|
||||||
|
"""validate-workflows.yml measures tools/ and fails below the .coveragerc limit."""
|
||||||
|
text = (REPO_ROOT / ".gitea" / "workflows" / "validate-workflows.yml").read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
)
|
||||||
|
assert "-m coverage run -m pytest -q tests" in text
|
||||||
|
assert "-m coverage report" in text
|
||||||
|
config = (REPO_ROOT / ".coveragerc").read_text(encoding="utf-8")
|
||||||
|
assert "source = tools" in config and "branch = True" in config
|
||||||
|
assert any(
|
||||||
|
line.replace(" ", "") == "fail_under=95" for line in config.splitlines()
|
||||||
|
), "the gate is 95 percent"
|
||||||
|
requirements = (REPO_ROOT / "tests" / "requirements.txt").read_text(encoding="utf-8")
|
||||||
|
assert "coverage" in requirements
|
||||||
|
|||||||
+37
-5
@@ -39,11 +39,11 @@ class Page:
|
|||||||
|
|
||||||
|
|
||||||
PAGES: tuple[Page, ...] = (
|
PAGES: tuple[Page, ...] = (
|
||||||
Page("Home", "README.md", ("Overview", "Requirements", "Setup", "Run", "Tests")),
|
Page("Home", "README.md", ("Overview", "Workflows", "Requirements", "Setup", "Run", "Tests")),
|
||||||
Page("Onboarding", "guides/onboarding.md"),
|
Page("Onboarding", "guides/onboarding.md"),
|
||||||
Page("Credentials", "guides/credentials.md"),
|
Page("Credentials", "guides/credentials.md"),
|
||||||
Page("Troubleshooting", "guides/troubleshooting.md"),
|
Page("Troubleshooting", "guides/troubleshooting.md"),
|
||||||
Page("QualityChecks", "guides/quality-checks.md"),
|
Page("QualityChecksPythonShell", "guides/quality-checks.md"),
|
||||||
Page("Upgrading", "guides/upgrading.md"),
|
Page("Upgrading", "guides/upgrading.md"),
|
||||||
Page("Capabilities", "README.md", ("Capabilities",)),
|
Page("Capabilities", "README.md", ("Capabilities",)),
|
||||||
)
|
)
|
||||||
@@ -61,7 +61,7 @@ _PAGE_FOR_SOURCE = {
|
|||||||
"guides/onboarding.md": "Onboarding",
|
"guides/onboarding.md": "Onboarding",
|
||||||
"guides/credentials.md": "Credentials",
|
"guides/credentials.md": "Credentials",
|
||||||
"guides/troubleshooting.md": "Troubleshooting",
|
"guides/troubleshooting.md": "Troubleshooting",
|
||||||
"guides/quality-checks.md": "QualityChecks",
|
"guides/quality-checks.md": "QualityChecksPythonShell",
|
||||||
"guides/upgrading.md": "Upgrading",
|
"guides/upgrading.md": "Upgrading",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,9 +184,41 @@ def render_page(page: Page, repo_root: Path = REPO_ROOT) -> str:
|
|||||||
return banner + body + "\n"
|
return banner + body + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
# 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"),
|
||||||
|
}
|
||||||
|
SIDEBAR_NAME = "_Sidebar.md"
|
||||||
|
|
||||||
|
|
||||||
|
def render_sidebar() -> str:
|
||||||
|
"""Return the navigation shown beside every wiki page.
|
||||||
|
|
||||||
|
Gitea lists subpages only through a ``_Sidebar`` page, so without it a
|
||||||
|
visitor sees the home page and no way to the others.
|
||||||
|
"""
|
||||||
|
languages = (("en", "English", ""), *((code, label, f".{code}") for code, label in LANGUAGES))
|
||||||
|
lines = [
|
||||||
|
f"<!-- Generated by {GENERATOR}. Edit the generator, not this page. -->",
|
||||||
|
"",
|
||||||
|
f"**{SIDEBAR_TITLE}**",
|
||||||
|
]
|
||||||
|
for code, label, suffix in languages:
|
||||||
|
labels = SIDEBAR_LABELS[code]
|
||||||
|
assert len(labels) == len(PAGES), "one sidebar label per page"
|
||||||
|
lines += ["", f"**{label}**", ""]
|
||||||
|
lines += [f"- [{text}]({page.name}{suffix})" for text, page in zip(labels, PAGES)]
|
||||||
|
return chr(10).join(lines) + chr(10)
|
||||||
|
|
||||||
|
|
||||||
def build_all(repo_root: Path = REPO_ROOT) -> dict[str, str]:
|
def build_all(repo_root: Path = REPO_ROOT) -> dict[str, str]:
|
||||||
"""Return ``{file name: content}`` for every English page."""
|
"""Return ``{file name: content}`` for every English page and the sidebar."""
|
||||||
return {f"{page.name}.md": render_page(page, repo_root) for page in PAGES}
|
pages = {f"{page.name}.md": render_page(page, repo_root) for page in PAGES}
|
||||||
|
pages[SIDEBAR_NAME] = render_sidebar()
|
||||||
|
return pages
|
||||||
|
|
||||||
|
|
||||||
def write_pages(wiki_dir: Path = WIKI_DIR, repo_root: Path = REPO_ROOT) -> list[str]:
|
def write_pages(wiki_dir: Path = WIKI_DIR, repo_root: Path = REPO_ROOT) -> list[str]:
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Steps of the reusable workflow .gitea/workflows/quality-checks.yml (ADR-0005).
|
||||||
|
# The workflow checks out the calling repository, fetches this file into
|
||||||
|
# shared-scripts/ and runs one command per step:
|
||||||
|
#
|
||||||
|
# quality-checks.sh validate check the inputs, before anything is installed
|
||||||
|
# quality-checks.sh install install the pinned tools into a virtual environment
|
||||||
|
# quality-checks.sh run run every selected tool on the tracked files
|
||||||
|
#
|
||||||
|
# Settings come from the environment, never from interpolated expressions:
|
||||||
|
# LANGUAGES, WORKING_DIRECTORY, RUFF_VERSION, MYPY_VERSION,
|
||||||
|
# SHELLCHECK_PY_VERSION, SHFMT_PY_VERSION, QC_VENV (and QC_BIN for tests).
|
||||||
|
# Every failure is printed as ::error::[category] message.
|
||||||
|
|
||||||
|
validate_inputs() {
|
||||||
|
set -u
|
||||||
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
||||||
|
if [ "${#langs[@]}" -eq 0 ]; then
|
||||||
|
echo "::error::[configuration] languages is empty; use python, shell or both, comma separated."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
for lang in "${langs[@]}"; do
|
||||||
|
case "$lang" in
|
||||||
|
python | shell) ;;
|
||||||
|
*)
|
||||||
|
echo "::error::[configuration] Unknown language '$lang'; use python and shell, comma separated."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
case "$WORKING_DIRECTORY" in
|
||||||
|
"" | /* | .. | ../* | */.. | */../*)
|
||||||
|
echo "::error::[configuration] working-directory must be a relative path inside the repository."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "Checking ${LANGUAGES} in ${WORKING_DIRECTORY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_tools() {
|
||||||
|
set -eu
|
||||||
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
||||||
|
packages=()
|
||||||
|
for lang in "${langs[@]}"; do
|
||||||
|
case "$lang" in
|
||||||
|
python) packages+=("ruff==${RUFF_VERSION}" "mypy==${MYPY_VERSION}") ;;
|
||||||
|
shell) packages+=("shellcheck-py==${SHELLCHECK_PY_VERSION}" "shfmt-py==${SHFMT_PY_VERSION}") ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
python3 -m venv "$QC_VENV"
|
||||||
|
"$QC_VENV/bin/pip" install --quiet "${packages[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
cd "$WORKING_DIRECTORY"
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
wanted() {
|
||||||
|
local lang
|
||||||
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
||||||
|
for lang in "${langs[@]}"; do
|
||||||
|
[ "$lang" = "$1" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if wanted python; then
|
||||||
|
mapfile -t files < <(git ls-files -- '*.py')
|
||||||
|
if [ "${#files[@]}" -eq 0 ]; then
|
||||||
|
echo "::notice::No python files in '$WORKING_DIRECTORY'; nothing was checked."
|
||||||
|
else
|
||||||
|
run_tool "ruff check" "$QC_BIN/ruff" check "${files[@]}"
|
||||||
|
run_tool "ruff format --check" "$QC_BIN/ruff" format --check "${files[@]}"
|
||||||
|
run_tool "mypy --strict" "$QC_BIN/mypy" --strict "${files[@]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if wanted shell; then
|
||||||
|
mapfile -t files < <(git ls-files -- '*.sh')
|
||||||
|
if [ "${#files[@]}" -eq 0 ]; then
|
||||||
|
echo "::notice::No shell files in '$WORKING_DIRECTORY'; nothing was checked."
|
||||||
|
else
|
||||||
|
run_tool "shellcheck" "$QC_BIN/shellcheck" "${files[@]}"
|
||||||
|
run_tool "shfmt -d" "$QC_BIN/shfmt" -d "${files[@]}"
|
||||||
|
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.sh validate|install|run" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -170,6 +170,7 @@ def main():
|
|||||||
"No GitHub push mirror configured for "
|
"No GitHub push mirror configured for "
|
||||||
f"{source_owner}/{source_repo}; nothing to sync."
|
f"{source_owner}/{source_repo}; nothing to sync."
|
||||||
)
|
)
|
||||||
|
print("Skipped")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
github_token = parse_github_token(os.environ.get("PAT_FOR_GITHUB"))
|
github_token = parse_github_token(os.environ.get("PAT_FOR_GITHUB"))
|
||||||
|
|||||||
+5
-71
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Capabilities.md, source sha256 94af1c3e6949 -->
|
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
|
||||||
|
|
||||||
> Dette er en oversættelse af [`Capabilities`](Capabilities). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
> Dette er en oversættelse af [`Capabilities`](Capabilities). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||||
|
|
||||||
@@ -12,73 +12,7 @@ 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 |
|
| 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)) |
|
| 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 andre repositories er ikke verificeret endnu; korte use cases er åbne (MIL-002) |
|
| 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; pilotforsøget i et andet repository afventer (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) |
|
||||||
| 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; tilslutningen i RepoFoundry er til gennemgang ([vejledning](QualityChecks.da)) |
|
| 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)) |
|
||||||
| Versioneret udgivelse og publicering | Udgivelsesproces, changelog og opgraderingsvejledning er defineret; udgivelsesworkflowet findes; den første udgivelse `v1.0.0` mangler (MIL-004) ([vejledning](Upgrading.da)) |
|
| Versioneret udgivelse og publicering | Udgivelsesproces, changelog og opgraderingsvejledning er defineret; udgivelsesworkflowet findes, og `v1.0.0` er udgivet (MIL-004) ([vejledning](Upgrading.da)) |
|
||||||
|
|
||||||
### Synkronisering af GitHub-metadata
|
|
||||||
|
|
||||||
Synkroniserer Gitea-repositoryets beskrivelse og emner til GitHub push-spejlet.
|
|
||||||
|
|
||||||
#### Tidsplan (cron)
|
|
||||||
|
|
||||||
Dagligt kl. 03:17 UTC (`17 3 * * *`) samt ved hvert push til `main` og manuel `workflow_dispatch`.
|
|
||||||
|
|
||||||
#### Workflow
|
|
||||||
|
|
||||||
```plantuml
|
|
||||||
@startuml
|
|
||||||
title Sync Gitea repository description and topics to GitHub
|
|
||||||
|
|
||||||
autonumber
|
|
||||||
|
|
||||||
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
|
||||||
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
|
||||||
participant "Gitea REST API" as Gitea
|
|
||||||
participant "GitHub REST API" as GitHub
|
|
||||||
|
|
||||||
Trigger -> Workflow: Start workflow
|
|
||||||
activate Workflow
|
|
||||||
|
|
||||||
Workflow -> Workflow: Read and validate secrets
|
|
||||||
note right
|
|
||||||
TOKEN_FOR_GITEA
|
|
||||||
PAT_FOR_GITHUB
|
|
||||||
end note
|
|
||||||
|
|
||||||
alt secret validation failed
|
|
||||||
Workflow --> Trigger: workflow failed
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
|
||||||
Gitea --> Workflow: Description and topics
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
|
||||||
Gitea --> Workflow: Push mirror response
|
|
||||||
|
|
||||||
alt mirrors is not a list
|
|
||||||
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
|
||||||
else mirrors is a list with no GitHub mirror
|
|
||||||
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
|
||||||
else mirrors is a list
|
|
||||||
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
|
||||||
|
|
||||||
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
|
||||||
GitHub --> Workflow: Repository updated
|
|
||||||
|
|
||||||
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
|
||||||
GitHub --> Workflow: Topics updated
|
|
||||||
|
|
||||||
Workflow --> Trigger: Sync completed
|
|
||||||
else Gitea API denies access
|
|
||||||
Gitea --> Workflow: HTTP 403 Forbidden
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
else GitHub API denies access
|
|
||||||
GitHub --> Workflow: HTTP error
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
end
|
|
||||||
deactivate Workflow
|
|
||||||
@enduml
|
|
||||||
```
|
|
||||||
|
|||||||
+4
-70
@@ -12,73 +12,7 @@ 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 |
|
| 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)) |
|
| 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 other repositories not yet verified; brief use cases open (MIL-002) |
|
| 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; the pilot in a second repository is pending (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) |
|
||||||
| 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; adoption in RepoFoundry is in review ([guide](QualityChecks)) |
|
| 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)) |
|
||||||
| Versioned release and publishing | Release process, changelog and upgrade guide defined; the release workflow exists; the first release `v1.0.0` is pending (MIL-004) ([guide](Upgrading)) |
|
| 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)) |
|
||||||
|
|
||||||
### Sync GitHub metadata
|
|
||||||
|
|
||||||
Syncs the Gitea repository description and topics to the GitHub push mirror.
|
|
||||||
|
|
||||||
#### Cron
|
|
||||||
|
|
||||||
Daily at 03:17 UTC (`17 3 * * *`), plus every push to `main` and manual `workflow_dispatch`.
|
|
||||||
|
|
||||||
#### Workflow
|
|
||||||
|
|
||||||
```plantuml
|
|
||||||
@startuml
|
|
||||||
title Sync Gitea repository description and topics to GitHub
|
|
||||||
|
|
||||||
autonumber
|
|
||||||
|
|
||||||
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
|
||||||
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
|
||||||
participant "Gitea REST API" as Gitea
|
|
||||||
participant "GitHub REST API" as GitHub
|
|
||||||
|
|
||||||
Trigger -> Workflow: Start workflow
|
|
||||||
activate Workflow
|
|
||||||
|
|
||||||
Workflow -> Workflow: Read and validate secrets
|
|
||||||
note right
|
|
||||||
TOKEN_FOR_GITEA
|
|
||||||
PAT_FOR_GITHUB
|
|
||||||
end note
|
|
||||||
|
|
||||||
alt secret validation failed
|
|
||||||
Workflow --> Trigger: workflow failed
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
|
||||||
Gitea --> Workflow: Description and topics
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
|
||||||
Gitea --> Workflow: Push mirror response
|
|
||||||
|
|
||||||
alt mirrors is not a list
|
|
||||||
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
|
||||||
else mirrors is a list with no GitHub mirror
|
|
||||||
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
|
||||||
else mirrors is a list
|
|
||||||
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
|
||||||
|
|
||||||
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
|
||||||
GitHub --> Workflow: Repository updated
|
|
||||||
|
|
||||||
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
|
||||||
GitHub --> Workflow: Topics updated
|
|
||||||
|
|
||||||
Workflow --> Trigger: Sync completed
|
|
||||||
else Gitea API denies access
|
|
||||||
Gitea --> Workflow: HTTP 403 Forbidden
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
else GitHub API denies access
|
|
||||||
GitHub --> Workflow: HTTP error
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
end
|
|
||||||
deactivate Workflow
|
|
||||||
@enduml
|
|
||||||
```
|
|
||||||
|
|||||||
+5
-71
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Capabilities.md, source sha256 94af1c3e6949 -->
|
<!-- translation of Capabilities.md, source sha256 a8c03a001880 -->
|
||||||
|
|
||||||
> Ini ialah terjemahan [`Capabilities`](Capabilities). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
> Ini ialah terjemahan [`Capabilities`](Capabilities). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||||
|
|
||||||
@@ -12,73 +12,7 @@ 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 |
|
| 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)) |
|
| 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 lain belum disahkan; use case ringkas masih terbuka (MIL-002) |
|
| 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; juruterbang dalam repositori kedua belum dibuat (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) |
|
||||||
| 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; penerimaan dalam RepoFoundry sedang disemak ([panduan](QualityChecks.ms)) |
|
| 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)) |
|
||||||
| Keluaran berversi dan penerbitan | Proses keluaran, changelog dan panduan naik taraf telah ditakrifkan; aliran kerja keluaran sudah ada; keluaran pertama `v1.0.0` belum ada (MIL-004) ([panduan](Upgrading.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)) |
|
||||||
|
|
||||||
### Menyegerakkan metadata GitHub
|
|
||||||
|
|
||||||
Menyegerakkan penerangan dan topik repositori Gitea ke push mirror GitHub.
|
|
||||||
|
|
||||||
#### Jadual (cron)
|
|
||||||
|
|
||||||
Setiap hari pada 03:17 UTC (`17 3 * * *`), serta pada setiap push ke `main` dan `workflow_dispatch` manual.
|
|
||||||
|
|
||||||
#### Aliran kerja
|
|
||||||
|
|
||||||
```plantuml
|
|
||||||
@startuml
|
|
||||||
title Sync Gitea repository description and topics to GitHub
|
|
||||||
|
|
||||||
autonumber
|
|
||||||
|
|
||||||
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
|
||||||
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
|
||||||
participant "Gitea REST API" as Gitea
|
|
||||||
participant "GitHub REST API" as GitHub
|
|
||||||
|
|
||||||
Trigger -> Workflow: Start workflow
|
|
||||||
activate Workflow
|
|
||||||
|
|
||||||
Workflow -> Workflow: Read and validate secrets
|
|
||||||
note right
|
|
||||||
TOKEN_FOR_GITEA
|
|
||||||
PAT_FOR_GITHUB
|
|
||||||
end note
|
|
||||||
|
|
||||||
alt secret validation failed
|
|
||||||
Workflow --> Trigger: workflow failed
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
|
||||||
Gitea --> Workflow: Description and topics
|
|
||||||
|
|
||||||
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
|
||||||
Gitea --> Workflow: Push mirror response
|
|
||||||
|
|
||||||
alt mirrors is not a list
|
|
||||||
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
|
||||||
else mirrors is a list with no GitHub mirror
|
|
||||||
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
|
||||||
else mirrors is a list
|
|
||||||
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
|
||||||
|
|
||||||
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
|
||||||
GitHub --> Workflow: Repository updated
|
|
||||||
|
|
||||||
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
|
||||||
GitHub --> Workflow: Topics updated
|
|
||||||
|
|
||||||
Workflow --> Trigger: Sync completed
|
|
||||||
else Gitea API denies access
|
|
||||||
Gitea --> Workflow: HTTP 403 Forbidden
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
else GitHub API denies access
|
|
||||||
GitHub --> Workflow: HTTP error
|
|
||||||
Workflow --> Trigger: Workflow fails
|
|
||||||
end
|
|
||||||
deactivate Workflow
|
|
||||||
@enduml
|
|
||||||
```
|
|
||||||
|
|||||||
+253
-4
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Home.md, source sha256 eedaeddbea3e -->
|
<!-- translation of Home.md, source sha256 510b243ec5f2 -->
|
||||||
|
|
||||||
> Dette er en oversættelse af [`Home`](Home). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
> Dette er en oversættelse af [`Home`](Home). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||||
|
|
||||||
@@ -13,7 +13,255 @@ 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.
|
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 i øjeblikket Gitea-workflowet [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml), som kopierer repositoryets beskrivelse og emner (topics) fra Gitea til GitHub-spejlet ved hvert push til `main`, ved manuel kørsel og dagligt kl. 03:17 UTC.
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
| Workflow | Fil | Type | Starter ved | Formål |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push til `main`, manuelt, dagligt kl. 03:17 UTC | Kopierer beskrivelsen og emnerne for et Gitea-repository til dets GitHub push-spejl |
|
||||||
|
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, tilmelding med `wiki/.publish` | push til `main`, der ændrer `wiki/**`, manuelt | Publicerer siderne i `wiki/` til repositoryets wiki |
|
||||||
|
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Genbrugeligt (`workflow_call`) | et kald fra et andet repository | Kører ruff, mypy, shellcheck og shfmt på de sporede filer og ændrer intet |
|
||||||
|
| 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 |
|
||||||
|
| 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
|
||||||
|
|
||||||
|
Synkroniserer Gitea-repositoryets beskrivelse og emner til GitHub push-spejlet.
|
||||||
|
|
||||||
|
#### Tidsplan (cron)
|
||||||
|
|
||||||
|
Dagligt kl. 03:17 UTC (`17 3 * * *`) samt ved hvert push til `main` og manuel `workflow_dispatch`.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Sync Gitea repository description and topics to GitHub
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
||||||
|
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
participant "GitHub REST API" as GitHub
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Read and validate secrets
|
||||||
|
note right
|
||||||
|
TOKEN_FOR_GITEA
|
||||||
|
PAT_FOR_GITHUB
|
||||||
|
end note
|
||||||
|
|
||||||
|
alt secret validation failed
|
||||||
|
Workflow --> Trigger: workflow failed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
||||||
|
Gitea --> Workflow: Description and topics
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
||||||
|
Gitea --> Workflow: Push mirror response
|
||||||
|
|
||||||
|
alt mirrors is not a list
|
||||||
|
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
||||||
|
else mirrors is a list with no GitHub mirror
|
||||||
|
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
||||||
|
else mirrors is a list
|
||||||
|
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
||||||
|
|
||||||
|
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
||||||
|
GitHub --> Workflow: Repository updated
|
||||||
|
|
||||||
|
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
||||||
|
GitHub --> Workflow: Topics updated
|
||||||
|
|
||||||
|
Workflow --> Trigger: Sync completed
|
||||||
|
else Gitea API denies access
|
||||||
|
Gitea --> Workflow: HTTP 403 Forbidden
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
else GitHub API denies access
|
||||||
|
GitHub --> Workflow: HTTP error
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publicering af wiki
|
||||||
|
|
||||||
|
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/`.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Publish wiki/ to the repository wiki
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main that changes wiki/**,\nor manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\npublish-wiki" as Workflow
|
||||||
|
participant "shared-scripts\n(tools/publish_wiki.py at v1)" as Script
|
||||||
|
participant "Gitea wiki API" as Wiki
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Script: Check out the repository and the script, run it
|
||||||
|
activate Script
|
||||||
|
|
||||||
|
alt wiki/.publish does not exist
|
||||||
|
Script --> Workflow: Log that publishing is not enabled and succeed\n(nothing is written)
|
||||||
|
else wiki/ has no Markdown pages
|
||||||
|
Script --> Workflow: Fail with [configuration]\n(an empty wiki/ never deletes pages)
|
||||||
|
else
|
||||||
|
Script -> Script: Read the marker (empty, or the word prune)\nand 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 marker says prune
|
||||||
|
Script -> Wiki: Delete pages that are not in wiki/
|
||||||
|
end
|
||||||
|
Script --> Workflow: Log created, updated and deleted counts
|
||||||
|
end
|
||||||
|
deactivate Script
|
||||||
|
Workflow --> Trigger: Workflow result
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kvalitetskontrol
|
||||||
|
|
||||||
|
Et genbrugeligt workflow til Python og shell, kaldt med `uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1` (se [vejledningen](QualityChecksPythonShell)).
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Shared quality checks (reusable workflow)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Calling repository\nuses: ...quality-checks.yml@v1" as Caller
|
||||||
|
participant "Gitea Actions\nquality-checks" as Workflow
|
||||||
|
participant "PyPI" as PyPI
|
||||||
|
|
||||||
|
Caller -> Workflow: workflow_call with languages,\nworking-directory and tool versions
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Validate the inputs
|
||||||
|
alt languages or working-directory is invalid
|
||||||
|
Workflow --> Caller: Fail with [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check out the calling repository
|
||||||
|
Workflow -> PyPI: Install the pinned tools in a virtual environment\n(ruff, mypy, shellcheck-py, shfmt-py as selected)
|
||||||
|
PyPI --> Workflow: Tools installed
|
||||||
|
|
||||||
|
loop for each selected language
|
||||||
|
Workflow -> Workflow: List tracked files
|
||||||
|
alt no files of that language
|
||||||
|
Workflow -> Workflow: Notice: nothing was checked
|
||||||
|
else
|
||||||
|
Workflow -> Workflow: Run every tool and record PASS or FAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alt any tool failed
|
||||||
|
Workflow --> Caller: Fail and list the failed tools
|
||||||
|
else
|
||||||
|
Workflow --> Caller: All selected checks passed
|
||||||
|
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)).
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Release this repository
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Maintainer\n(workflow_dispatch: version, dry_run)" as Trigger
|
||||||
|
participant "Gitea Actions\nrelease" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start with version and dry_run
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check the version and read CHANGELOG.md
|
||||||
|
alt version malformed or no changelog entry
|
||||||
|
Workflow --> Trigger: Fail with [validation] or [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET branch main and status of the commit
|
||||||
|
Gitea --> Workflow: Tip of main and the validation run
|
||||||
|
alt commit is not the tip of main,\nor the validation run is not green
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(no tag is created)
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET tags
|
||||||
|
Gitea --> Workflow: Existing tags
|
||||||
|
alt tag vMAJOR.MINOR.PATCH exists
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(tags are never moved)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt dry_run is true (default)
|
||||||
|
Workflow --> Trigger: Log what would be created and stop
|
||||||
|
else
|
||||||
|
Workflow -> Gitea: POST release (creates the version tag,\nbody is the changelog entry)
|
||||||
|
opt this is the highest version of its major
|
||||||
|
Workflow -> Gitea: Delete and recreate the major tag vMAJOR
|
||||||
|
end
|
||||||
|
Workflow --> Trigger: Released
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validering af workflows
|
||||||
|
|
||||||
|
Repositoryets egen validering: de offline-tests, der er en betingelse for hver pull request.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Validate workflows (this repository's own checks)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Pull request,\npush to main, or manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\nvalidate-workflows" as Workflow
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Workflow: Check out the repository
|
||||||
|
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
|
||||||
|
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
|
||||||
|
|
||||||
|
alt a test fails
|
||||||
|
Workflow --> Trigger: Workflow fails (the pull request is not ready)
|
||||||
|
else
|
||||||
|
Workflow --> Trigger: Workflow succeeds
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Krav
|
## Krav
|
||||||
@@ -51,9 +299,10 @@ Workflow-filerne og scripts i `tools/` valideres af offline-tests, som hverken k
|
|||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
||||||
python -m pip install -r tests/requirements.txt
|
python -m pip install -r tests/requirements.txt
|
||||||
python -m pytest -q tests
|
python -m coverage run -m pytest -q tests
|
||||||
|
python -m coverage report
|
||||||
```
|
```
|
||||||
|
|
||||||
De samme kontroller kører ved hver pull request og hvert push til `main` gennem [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). De parser alle workflows som YAML, kontrollerer at ingen indlejrer Python, kompilerer scripts i `tools/`, kræver eksplicitte jobtilladelser og tester parsing af credentials, parsing af push-spejlets adresse og synkroniserings- og publiceringsforløbene mod et falsk API.
|
De samme kontroller kører ved hver pull request og hvert push til `main` gennem [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). De parser alle workflows som YAML, kontrollerer at ingen indlejrer Python, kompilerer scripts i `tools/`, kræver eksplicitte jobtilladelser og tester parsing af credentials, parsing af push-spejlets adresse og synkroniserings- og publiceringsforløbene mod et falsk API. Kørslen fejler, når linje- og forgreningsdækningen af `tools/` er under 95 % (`.coveragerc`).
|
||||||
|
|
||||||
Efter en ændring af synkroniseringsworkflowet skal du også starte **Sync GitHub mirror metadata** manuelt i Gitea og sammenligne beskrivelsen og emnerne på GitHub-spejlet.
|
Efter en ændring af synkroniseringsworkflowet skal du også starte **Sync GitHub mirror metadata** manuelt i Gitea og sammenligne beskrivelsen og emnerne på GitHub-spejlet.
|
||||||
|
|||||||
+252
-3
@@ -13,7 +13,255 @@ 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.
|
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 currently contains the Gitea workflow [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml), which copies the repository description and topics from Gitea to the GitHub mirror on every push to `main`, on manual dispatch, and daily at 03:17 UTC.
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
| Workflow | File | Kind | Starts on | Purpose |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push to `main`, manual, daily 03:17 UTC | Copies the description and topics of a Gitea repository to its GitHub push mirror |
|
||||||
|
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, opt-in with `wiki/.publish` | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki |
|
||||||
|
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Reusable (`workflow_call`) | a call from another repository | Runs ruff, mypy, shellcheck and shfmt on the tracked files and changes nothing |
|
||||||
|
| 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 |
|
||||||
|
| 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
|
||||||
|
|
||||||
|
Syncs the Gitea repository description and topics to the GitHub push mirror.
|
||||||
|
|
||||||
|
#### Cron
|
||||||
|
|
||||||
|
Daily at 03:17 UTC (`17 3 * * *`), plus every push to `main` and manual `workflow_dispatch`.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Sync Gitea repository description and topics to GitHub
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
||||||
|
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
participant "GitHub REST API" as GitHub
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Read and validate secrets
|
||||||
|
note right
|
||||||
|
TOKEN_FOR_GITEA
|
||||||
|
PAT_FOR_GITHUB
|
||||||
|
end note
|
||||||
|
|
||||||
|
alt secret validation failed
|
||||||
|
Workflow --> Trigger: workflow failed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
||||||
|
Gitea --> Workflow: Description and topics
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
||||||
|
Gitea --> Workflow: Push mirror response
|
||||||
|
|
||||||
|
alt mirrors is not a list
|
||||||
|
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
||||||
|
else mirrors is a list with no GitHub mirror
|
||||||
|
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
||||||
|
else mirrors is a list
|
||||||
|
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
||||||
|
|
||||||
|
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
||||||
|
GitHub --> Workflow: Repository updated
|
||||||
|
|
||||||
|
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
||||||
|
GitHub --> Workflow: Topics updated
|
||||||
|
|
||||||
|
Workflow --> Trigger: Sync completed
|
||||||
|
else Gitea API denies access
|
||||||
|
Gitea --> Workflow: HTTP 403 Forbidden
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
else GitHub API denies access
|
||||||
|
GitHub --> Workflow: HTTP error
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publish wiki
|
||||||
|
|
||||||
|
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/`.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Publish wiki/ to the repository wiki
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main that changes wiki/**,\nor manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\npublish-wiki" as Workflow
|
||||||
|
participant "shared-scripts\n(tools/publish_wiki.py at v1)" as Script
|
||||||
|
participant "Gitea wiki API" as Wiki
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Script: Check out the repository and the script, run it
|
||||||
|
activate Script
|
||||||
|
|
||||||
|
alt wiki/.publish does not exist
|
||||||
|
Script --> Workflow: Log that publishing is not enabled and succeed\n(nothing is written)
|
||||||
|
else wiki/ has no Markdown pages
|
||||||
|
Script --> Workflow: Fail with [configuration]\n(an empty wiki/ never deletes pages)
|
||||||
|
else
|
||||||
|
Script -> Script: Read the marker (empty, or the word prune)\nand 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 marker says prune
|
||||||
|
Script -> Wiki: Delete pages that are not in wiki/
|
||||||
|
end
|
||||||
|
Script --> Workflow: Log created, updated and deleted counts
|
||||||
|
end
|
||||||
|
deactivate Script
|
||||||
|
Workflow --> Trigger: Workflow result
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quality checks
|
||||||
|
|
||||||
|
A reusable workflow for Python and shell, called with `uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1` (see the [guide](QualityChecksPythonShell)).
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Shared quality checks (reusable workflow)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Calling repository\nuses: ...quality-checks.yml@v1" as Caller
|
||||||
|
participant "Gitea Actions\nquality-checks" as Workflow
|
||||||
|
participant "PyPI" as PyPI
|
||||||
|
|
||||||
|
Caller -> Workflow: workflow_call with languages,\nworking-directory and tool versions
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Validate the inputs
|
||||||
|
alt languages or working-directory is invalid
|
||||||
|
Workflow --> Caller: Fail with [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check out the calling repository
|
||||||
|
Workflow -> PyPI: Install the pinned tools in a virtual environment\n(ruff, mypy, shellcheck-py, shfmt-py as selected)
|
||||||
|
PyPI --> Workflow: Tools installed
|
||||||
|
|
||||||
|
loop for each selected language
|
||||||
|
Workflow -> Workflow: List tracked files
|
||||||
|
alt no files of that language
|
||||||
|
Workflow -> Workflow: Notice: nothing was checked
|
||||||
|
else
|
||||||
|
Workflow -> Workflow: Run every tool and record PASS or FAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alt any tool failed
|
||||||
|
Workflow --> Caller: Fail and list the failed tools
|
||||||
|
else
|
||||||
|
Workflow --> Caller: All selected checks passed
|
||||||
|
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)).
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Release this repository
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Maintainer\n(workflow_dispatch: version, dry_run)" as Trigger
|
||||||
|
participant "Gitea Actions\nrelease" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start with version and dry_run
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check the version and read CHANGELOG.md
|
||||||
|
alt version malformed or no changelog entry
|
||||||
|
Workflow --> Trigger: Fail with [validation] or [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET branch main and status of the commit
|
||||||
|
Gitea --> Workflow: Tip of main and the validation run
|
||||||
|
alt commit is not the tip of main,\nor the validation run is not green
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(no tag is created)
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET tags
|
||||||
|
Gitea --> Workflow: Existing tags
|
||||||
|
alt tag vMAJOR.MINOR.PATCH exists
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(tags are never moved)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt dry_run is true (default)
|
||||||
|
Workflow --> Trigger: Log what would be created and stop
|
||||||
|
else
|
||||||
|
Workflow -> Gitea: POST release (creates the version tag,\nbody is the changelog entry)
|
||||||
|
opt this is the highest version of its major
|
||||||
|
Workflow -> Gitea: Delete and recreate the major tag vMAJOR
|
||||||
|
end
|
||||||
|
Workflow --> Trigger: Released
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validate workflows
|
||||||
|
|
||||||
|
The repository's own validation: the offline tests that gate every pull request.
|
||||||
|
|
||||||
|
#### Workflow
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Validate workflows (this repository's own checks)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Pull request,\npush to main, or manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\nvalidate-workflows" as Workflow
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Workflow: Check out the repository
|
||||||
|
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
|
||||||
|
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
|
||||||
|
|
||||||
|
alt a test fails
|
||||||
|
Workflow --> Trigger: Workflow fails (the pull request is not ready)
|
||||||
|
else
|
||||||
|
Workflow --> Trigger: Workflow succeeds
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
@@ -51,9 +299,10 @@ The workflow files and the scripts in `tools/` are validated by offline tests th
|
|||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
||||||
python -m pip install -r tests/requirements.txt
|
python -m pip install -r tests/requirements.txt
|
||||||
python -m pytest -q tests
|
python -m coverage run -m pytest -q tests
|
||||||
|
python -m coverage report
|
||||||
```
|
```
|
||||||
|
|
||||||
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API.
|
The same checks run on every pull request and push to `main` through [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). They parse every workflow as YAML, check that none embeds Python, compile the scripts in `tools/`, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync and publish flows against a fake API. The run fails when the line and branch coverage of `tools/` falls below 95% (`.coveragerc`).
|
||||||
|
|
||||||
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
|
After a change to the sync workflow, also trigger **Sync GitHub mirror metadata** manually in Gitea and compare the description and topics on the GitHub mirror.
|
||||||
|
|||||||
+253
-4
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Home.md, source sha256 eedaeddbea3e -->
|
<!-- translation of Home.md, source sha256 510b243ec5f2 -->
|
||||||
|
|
||||||
> Ini ialah terjemahan [`Home`](Home). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
> Ini ialah terjemahan [`Home`](Home). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||||
|
|
||||||
@@ -13,7 +13,255 @@ 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.
|
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.
|
||||||
|
|
||||||
Buat masa ini ia mengandungi aliran kerja Gitea [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml), yang menyalin penerangan dan topik repositori dari Gitea ke cermin GitHub pada setiap push ke `main`, pada pencetusan manual dan setiap hari pada 03:17 UTC.
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
| Aliran kerja | Fail | Jenis | Bermula apabila | Tujuan |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push ke `main`, manual, setiap hari 03:17 UTC | Menyalin penerangan dan topik repositori Gitea ke push mirror GitHub-nya |
|
||||||
|
| Publish wiki | [`publish-wiki.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/scoped_workflows/publish-wiki.yml) | Scoped, pilih menyertai dengan `wiki/.publish` | push ke `main` yang mengubah `wiki/**`, manual | Menerbitkan halaman dalam `wiki/` ke wiki repositori |
|
||||||
|
| Quality checks | [`quality-checks.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/quality-checks.yml) | Boleh guna semula (`workflow_call`) | panggilan daripada repositori lain | Menjalankan ruff, mypy, shellcheck dan shfmt pada fail yang dijejaki dan tidak mengubah apa-apa |
|
||||||
|
| 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 |
|
||||||
|
| 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
|
||||||
|
|
||||||
|
Menyegerakkan penerangan dan topik repositori Gitea ke push mirror GitHub.
|
||||||
|
|
||||||
|
#### Jadual (cron)
|
||||||
|
|
||||||
|
Setiap hari pada 03:17 UTC (`17 3 * * *`), serta pada setiap push ke `main` dan `workflow_dispatch` manual.
|
||||||
|
|
||||||
|
#### Aliran kerja
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Sync Gitea repository description and topics to GitHub
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main,\nmanual trigger, or schedule" as Trigger
|
||||||
|
participant "Gitea Actions\nsync-github-metadata" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
participant "GitHub REST API" as GitHub
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Read and validate secrets
|
||||||
|
note right
|
||||||
|
TOKEN_FOR_GITEA
|
||||||
|
PAT_FOR_GITHUB
|
||||||
|
end note
|
||||||
|
|
||||||
|
alt secret validation failed
|
||||||
|
Workflow --> Trigger: workflow failed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}
|
||||||
|
Gitea --> Workflow: Description and topics
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET /repos/{owner}/{repo}/push_mirrors
|
||||||
|
Gitea --> Workflow: Push mirror response
|
||||||
|
|
||||||
|
alt mirrors is not a list
|
||||||
|
Workflow --> Trigger: Log a warning and succeed\n(GitHub metadata not synced)
|
||||||
|
else mirrors is a list with no GitHub mirror
|
||||||
|
Workflow --> Trigger: Log that there is nothing to sync and succeed
|
||||||
|
else mirrors is a list
|
||||||
|
Workflow -> Workflow: Find GitHub owner and repo from remote_address
|
||||||
|
|
||||||
|
Workflow -> GitHub: PATCH /repos/{owner}/{repo}\n{description}
|
||||||
|
GitHub --> Workflow: Repository updated
|
||||||
|
|
||||||
|
Workflow -> GitHub: PUT /repos/{owner}/{repo}/topics\n{names}
|
||||||
|
GitHub --> Workflow: Topics updated
|
||||||
|
|
||||||
|
Workflow --> Trigger: Sync completed
|
||||||
|
else Gitea API denies access
|
||||||
|
Gitea --> Workflow: HTTP 403 Forbidden
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
else GitHub API denies access
|
||||||
|
GitHub --> Workflow: HTTP error
|
||||||
|
Workflow --> Trigger: Workflow fails
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Menerbitkan wiki
|
||||||
|
|
||||||
|
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/`.
|
||||||
|
|
||||||
|
#### Aliran kerja
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Publish wiki/ to the repository wiki
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Push to main that changes wiki/**,\nor manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\npublish-wiki" as Workflow
|
||||||
|
participant "shared-scripts\n(tools/publish_wiki.py at v1)" as Script
|
||||||
|
participant "Gitea wiki API" as Wiki
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Script: Check out the repository and the script, run it
|
||||||
|
activate Script
|
||||||
|
|
||||||
|
alt wiki/.publish does not exist
|
||||||
|
Script --> Workflow: Log that publishing is not enabled and succeed\n(nothing is written)
|
||||||
|
else wiki/ has no Markdown pages
|
||||||
|
Script --> Workflow: Fail with [configuration]\n(an empty wiki/ never deletes pages)
|
||||||
|
else
|
||||||
|
Script -> Script: Read the marker (empty, or the word prune)\nand 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 marker says prune
|
||||||
|
Script -> Wiki: Delete pages that are not in wiki/
|
||||||
|
end
|
||||||
|
Script --> Workflow: Log created, updated and deleted counts
|
||||||
|
end
|
||||||
|
deactivate Script
|
||||||
|
Workflow --> Trigger: Workflow result
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Semakan kualiti
|
||||||
|
|
||||||
|
Aliran kerja boleh guna semula untuk Python dan shell, dipanggil dengan `uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1` (lihat [panduan](QualityChecksPythonShell)).
|
||||||
|
|
||||||
|
#### Aliran kerja
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Shared quality checks (reusable workflow)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Calling repository\nuses: ...quality-checks.yml@v1" as Caller
|
||||||
|
participant "Gitea Actions\nquality-checks" as Workflow
|
||||||
|
participant "PyPI" as PyPI
|
||||||
|
|
||||||
|
Caller -> Workflow: workflow_call with languages,\nworking-directory and tool versions
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Validate the inputs
|
||||||
|
alt languages or working-directory is invalid
|
||||||
|
Workflow --> Caller: Fail with [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check out the calling repository
|
||||||
|
Workflow -> PyPI: Install the pinned tools in a virtual environment\n(ruff, mypy, shellcheck-py, shfmt-py as selected)
|
||||||
|
PyPI --> Workflow: Tools installed
|
||||||
|
|
||||||
|
loop for each selected language
|
||||||
|
Workflow -> Workflow: List tracked files
|
||||||
|
alt no files of that language
|
||||||
|
Workflow -> Workflow: Notice: nothing was checked
|
||||||
|
else
|
||||||
|
Workflow -> Workflow: Run every tool and record PASS or FAIL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alt any tool failed
|
||||||
|
Workflow --> Caller: Fail and list the failed tools
|
||||||
|
else
|
||||||
|
Workflow --> Caller: All selected checks passed
|
||||||
|
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)).
|
||||||
|
|
||||||
|
#### Aliran kerja
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Release this repository
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Maintainer\n(workflow_dispatch: version, dry_run)" as Trigger
|
||||||
|
participant "Gitea Actions\nrelease" as Workflow
|
||||||
|
participant "Gitea REST API" as Gitea
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start with version and dry_run
|
||||||
|
activate Workflow
|
||||||
|
|
||||||
|
Workflow -> Workflow: Check the version and read CHANGELOG.md
|
||||||
|
alt version malformed or no changelog entry
|
||||||
|
Workflow --> Trigger: Fail with [validation] or [configuration]
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET branch main and status of the commit
|
||||||
|
Gitea --> Workflow: Tip of main and the validation run
|
||||||
|
alt commit is not the tip of main,\nor the validation run is not green
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(no tag is created)
|
||||||
|
end
|
||||||
|
|
||||||
|
Workflow -> Gitea: GET tags
|
||||||
|
Gitea --> Workflow: Existing tags
|
||||||
|
alt tag vMAJOR.MINOR.PATCH exists
|
||||||
|
Workflow --> Trigger: Fail with [validation]\n(tags are never moved)
|
||||||
|
end
|
||||||
|
|
||||||
|
alt dry_run is true (default)
|
||||||
|
Workflow --> Trigger: Log what would be created and stop
|
||||||
|
else
|
||||||
|
Workflow -> Gitea: POST release (creates the version tag,\nbody is the changelog entry)
|
||||||
|
opt this is the highest version of its major
|
||||||
|
Workflow -> Gitea: Delete and recreate the major tag vMAJOR
|
||||||
|
end
|
||||||
|
Workflow --> Trigger: Released
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mengesahkan aliran kerja
|
||||||
|
|
||||||
|
Pengesahan repositori sendiri: ujian luar talian yang menjadi syarat bagi setiap pull request.
|
||||||
|
|
||||||
|
#### Aliran kerja
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
title Validate workflows (this repository's own checks)
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
actor "Pull request,\npush to main, or manual trigger" as Trigger
|
||||||
|
participant "Gitea Actions\nvalidate-workflows" as Workflow
|
||||||
|
|
||||||
|
Trigger -> Workflow: Start workflow
|
||||||
|
activate Workflow
|
||||||
|
Workflow -> Workflow: Check out the repository
|
||||||
|
Workflow -> Workflow: Create a virtual environment and\ninstall tests/requirements.txt
|
||||||
|
Workflow -> Workflow: Run pytest on tests/ under coverage (offline, no secrets):\nworkflows parse as YAML, no embedded Python,\nscripts compile, wiki pages and translations are current,\nsync, publish and release flows against a fake API
|
||||||
|
|
||||||
|
alt a test fails
|
||||||
|
Workflow --> Trigger: Workflow fails (the pull request is not ready)
|
||||||
|
else
|
||||||
|
Workflow --> Trigger: Workflow succeeds
|
||||||
|
end
|
||||||
|
deactivate Workflow
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Keperluan
|
## Keperluan
|
||||||
@@ -51,9 +299,10 @@ Fail aliran kerja dan skrip dalam `tools/` disahkan oleh ujian luar talian yang
|
|||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
source .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
|
||||||
python -m pip install -r tests/requirements.txt
|
python -m pip install -r tests/requirements.txt
|
||||||
python -m pytest -q tests
|
python -m coverage run -m pytest -q tests
|
||||||
|
python -m coverage report
|
||||||
```
|
```
|
||||||
|
|
||||||
Semakan yang sama dijalankan pada setiap pull request dan setiap push ke `main` melalui [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). Semakan itu menghurai setiap aliran kerja sebagai YAML, memastikan tiada yang menanam Python, mengkompil skrip dalam `tools/`, memerlukan kebenaran kerja yang jelas, dan menguji penghuraian kelayakan (credentials), penghuraian alamat push mirror serta aliran penyegerakan dan penerbitan terhadap API palsu.
|
Semakan yang sama dijalankan pada setiap pull request dan setiap push ke `main` melalui [`validate-workflows.yml`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/.gitea/workflows/validate-workflows.yml). Semakan itu menghurai setiap aliran kerja sebagai YAML, memastikan tiada yang menanam Python, mengkompil skrip dalam `tools/`, memerlukan kebenaran kerja yang jelas, dan menguji penghuraian kelayakan (credentials), penghuraian alamat push mirror serta aliran penyegerakan dan penerbitan terhadap API palsu. Larian gagal apabila liputan baris dan cabang `tools/` di bawah 95% (`.coveragerc`).
|
||||||
|
|
||||||
Selepas perubahan pada aliran kerja penyegerakan, cetuskan juga **Sync GitHub mirror metadata** secara manual dalam Gitea dan bandingkan penerangan dan topik pada cermin GitHub.
|
Selepas perubahan pada aliran kerja penyegerakan, cetuskan juga **Sync GitHub mirror metadata** secara manual dalam Gitea dan bandingkan penerangan dan topik pada cermin GitHub.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<!-- translation of QualityChecks.md, source sha256 84ed5e09689a -->
|
<!-- translation of QualityChecksPythonShell.md, source sha256 2a0c9d43c77d -->
|
||||||
|
|
||||||
> Dette er en oversættelse af [`QualityChecks`](QualityChecks). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
> Dette er en oversættelse af [`QualityChecksPythonShell`](QualityChecksPythonShell). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||||
|
|
||||||
[English](QualityChecks) | Dansk | [Bahasa Melayu](QualityChecks.ms)
|
[English](QualityChecksPythonShell) | Dansk | [Bahasa Melayu](QualityChecksPythonShell.ms)
|
||||||
|
|
||||||
# Aflæsning af resultater fra kvalitetskontrol
|
# Aflæsning af resultater fra kvalitetskontrol
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
quality:
|
quality:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
|
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1
|
||||||
with:
|
with:
|
||||||
languages: python,shell
|
languages: python,shell
|
||||||
```
|
```
|
||||||
@@ -35,8 +35,11 @@ jobs:
|
|||||||
| `mypy-version` | `1.11.2` | Version af mypy |
|
| `mypy-version` | `1.11.2` | Version af mypy |
|
||||||
| `shellcheck-py-version` | `0.10.0.1` | Version af pakken shellcheck-py (ShellCheck 0.10.0) |
|
| `shellcheck-py-version` | `0.10.0.1` | Version af pakken shellcheck-py (ShellCheck 0.10.0) |
|
||||||
| `shfmt-py-version` | `3.11.0.2` | Version af pakken shfmt-py (shfmt 3.11.0) |
|
| `shfmt-py-version` | `3.11.0.2` | Version af pakken shfmt-py (shfmt 3.11.0) |
|
||||||
|
| `tools-ref` | `v1` | Tag eller gren i `TirSystem/github-action`, hvorfra scriptet `tools/quality-checks.sh` hentes |
|
||||||
|
|
||||||
Henvis til workflowet ved `main` eller et tag, aldrig ved en pull requests gren: den gren slettes, når pull requesten flettes, og henvisningen holder op med at virke.
|
Henvis til workflowet ved major-tagget (`@v1`) eller et præcist tag (`@v1.0.0`), aldrig ved `main` og aldrig ved en pull requests gren: den gren slettes, når pull requesten flettes, og henvisningen holder op med at virke. Se opgraderingsvejledningen for, hvad hvert valg modtager.
|
||||||
|
|
||||||
|
Workflowfilen kalder et script i dette repository, hentet ved `tools-ref`. Et kald ved et præcist tag er kun fuldt fastlåst, når `tools-ref` angiver samme tag, for eksempel `@v1.0.1` med `tools-ref: v1.0.1`; med standardværdien følger scriptet `v1`.
|
||||||
|
|
||||||
## Hvad der kontrolleres
|
## Hvad der kontrolleres
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> This page is generated from [`guides/quality-checks.md`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/quality-checks.md). Changes made here are overwritten the next time the wiki is published.
|
> This page is generated from [`guides/quality-checks.md`](https://git.tirsystem.com/TirSystem/github-action/src/branch/main/guides/quality-checks.md). Changes made here are overwritten the next time the wiki is published.
|
||||||
|
|
||||||
English | [Dansk](QualityChecks.da) | [Bahasa Melayu](QualityChecks.ms)
|
English | [Dansk](QualityChecksPythonShell.da) | [Bahasa Melayu](QualityChecksPythonShell.ms)
|
||||||
|
|
||||||
# Reading quality-check results
|
# Reading quality-check results
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
quality:
|
quality:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
|
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1
|
||||||
with:
|
with:
|
||||||
languages: python,shell
|
languages: python,shell
|
||||||
```
|
```
|
||||||
@@ -38,10 +38,17 @@ jobs:
|
|||||||
| `mypy-version` | `1.11.2` | Version of mypy |
|
| `mypy-version` | `1.11.2` | Version of mypy |
|
||||||
| `shellcheck-py-version` | `0.10.0.1` | Version of the shellcheck-py package (ShellCheck 0.10.0) |
|
| `shellcheck-py-version` | `0.10.0.1` | Version of the shellcheck-py package (ShellCheck 0.10.0) |
|
||||||
| `shfmt-py-version` | `3.11.0.2` | Version of the shfmt-py package (shfmt 3.11.0) |
|
| `shfmt-py-version` | `3.11.0.2` | Version of the shfmt-py package (shfmt 3.11.0) |
|
||||||
|
| `tools-ref` | `v1` | Tag or branch of `TirSystem/github-action` from which the script `tools/quality-checks.sh` is fetched |
|
||||||
|
|
||||||
Reference the workflow at `main` or at a tag, never at the branch of a pull
|
Reference the workflow at the major tag (`@v1`) or at an exact tag
|
||||||
request: that branch is deleted when the pull request is merged and the
|
(`@v1.0.0`), never at `main` and never at the branch of a pull request: that
|
||||||
reference stops working.
|
branch is deleted when the pull request is merged and the reference stops
|
||||||
|
working. See the upgrade guide for what each choice receives.
|
||||||
|
|
||||||
|
The workflow file calls a script of this repository, fetched at `tools-ref`. A
|
||||||
|
call at an exact tag is pinned completely only when `tools-ref` names the same
|
||||||
|
tag, for example `@v1.0.1` with `tools-ref: v1.0.1`; with the default the
|
||||||
|
script follows `v1`.
|
||||||
|
|
||||||
## What is checked
|
## What is checked
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<!-- translation of QualityChecks.md, source sha256 84ed5e09689a -->
|
<!-- translation of QualityChecksPythonShell.md, source sha256 2a0c9d43c77d -->
|
||||||
|
|
||||||
> Ini ialah terjemahan [`QualityChecks`](QualityChecks). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
> Ini ialah terjemahan [`QualityChecksPythonShell`](QualityChecksPythonShell). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||||
|
|
||||||
[English](QualityChecks) | [Dansk](QualityChecks.da) | Bahasa Melayu
|
[English](QualityChecksPythonShell) | [Dansk](QualityChecksPythonShell.da) | Bahasa Melayu
|
||||||
|
|
||||||
# Membaca keputusan semakan kualiti
|
# Membaca keputusan semakan kualiti
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
quality:
|
quality:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
|
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@v1
|
||||||
with:
|
with:
|
||||||
languages: python,shell
|
languages: python,shell
|
||||||
```
|
```
|
||||||
@@ -35,8 +35,11 @@ jobs:
|
|||||||
| `mypy-version` | `1.11.2` | Versi mypy |
|
| `mypy-version` | `1.11.2` | Versi mypy |
|
||||||
| `shellcheck-py-version` | `0.10.0.1` | Versi pakej shellcheck-py (ShellCheck 0.10.0) |
|
| `shellcheck-py-version` | `0.10.0.1` | Versi pakej shellcheck-py (ShellCheck 0.10.0) |
|
||||||
| `shfmt-py-version` | `3.11.0.2` | Versi pakej shfmt-py (shfmt 3.11.0) |
|
| `shfmt-py-version` | `3.11.0.2` | Versi pakej shfmt-py (shfmt 3.11.0) |
|
||||||
|
| `tools-ref` | `v1` | Tag atau cabang `TirSystem/github-action` tempat skrip `tools/quality-checks.sh` diambil |
|
||||||
|
|
||||||
Rujuk aliran kerja pada `main` atau pada tag, jangan sekali-kali pada cabang pull request: cabang itu dipadam apabila pull request digabungkan dan rujukan itu berhenti berfungsi.
|
Rujuk aliran kerja pada tag major (`@v1`) atau pada tag tepat (`@v1.0.0`), jangan sekali-kali pada `main` dan jangan pada cabang pull request: cabang itu dipadam apabila pull request digabungkan dan rujukan itu berhenti berfungsi. Lihat panduan naik taraf untuk apa yang diterima oleh setiap pilihan.
|
||||||
|
|
||||||
|
Fail aliran kerja memanggil skrip dalam repositori ini, yang diambil pada `tools-ref`. Panggilan pada tag tepat hanya disematkan sepenuhnya apabila `tools-ref` menamakan tag yang sama, contohnya `@v1.0.1` dengan `tools-ref: v1.0.1`; dengan nilai lalai skrip mengikuti `v1`.
|
||||||
|
|
||||||
## Perkara yang disemak
|
## Perkara yang disemak
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Troubleshooting.md, source sha256 e8a34cbe7e93 -->
|
<!-- translation of Troubleshooting.md, source sha256 eb63f4109a0d -->
|
||||||
|
|
||||||
> Dette er en oversættelse af [`Troubleshooting`](Troubleshooting). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
> Dette er en oversættelse af [`Troubleshooting`](Troubleshooting). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Kategorien fortæller, hvor du skal kigge. En fejl uden for scriptet (jobbet sta
|
|||||||
|
|
||||||
## Ikke en fejl
|
## Ikke en fejl
|
||||||
|
|
||||||
`No GitHub push mirror configured for <repo>; nothing to sync.` Kørslen lykkes. Ikke alle Gitea-repositories har et GitHub-spejl, så det er forventet for dem. Hvis repositoryet skal have et, så tilføj det i repositoryets indstillinger.
|
`No GitHub push mirror configured for <repo>; nothing to sync.` efterfulgt af `Skipped`. Kørslen lykkes. Ikke alle Gitea-repositories har et GitHub-spejl, så det er forventet for dem. Hvis repositoryet skal have et, så tilføj det i repositoryets indstillinger.
|
||||||
|
|
||||||
`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.
|
`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.
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ never starts, or stops before the step) is a **runner** problem.
|
|||||||
|
|
||||||
## Not an error
|
## Not an error
|
||||||
|
|
||||||
`No GitHub push mirror configured for <repo>; nothing to sync.` The run
|
`No GitHub push mirror configured for <repo>; nothing to sync.` followed by
|
||||||
succeeds. Not every Gitea repository has a GitHub mirror, so this is expected
|
`Skipped`. The run succeeds. Not every Gitea repository has a GitHub mirror, so
|
||||||
for those. If the repository should have one, add it in the repository
|
this is expected for those. If the repository should have one, add it in the repository
|
||||||
settings.
|
settings.
|
||||||
|
|
||||||
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not
|
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Troubleshooting.md, source sha256 e8a34cbe7e93 -->
|
<!-- translation of Troubleshooting.md, source sha256 eb63f4109a0d -->
|
||||||
|
|
||||||
> Ini ialah terjemahan [`Troubleshooting`](Troubleshooting). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
> Ini ialah terjemahan [`Troubleshooting`](Troubleshooting). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Kategori menunjukkan di mana perlu dilihat. Kegagalan di luar skrip (kerja tidak
|
|||||||
|
|
||||||
## Bukan satu ralat
|
## Bukan satu ralat
|
||||||
|
|
||||||
`No GitHub push mirror configured for <repo>; nothing to sync.` Larian berjaya. Tidak semua repositori Gitea mempunyai cermin GitHub, jadi ini dijangka bagi repositori tersebut. Jika repositori itu sepatutnya mempunyainya, tambahkannya dalam tetapan repositori.
|
`No GitHub push mirror configured for <repo>; nothing to sync.` diikuti oleh `Skipped`. Larian berjaya. Tidak semua repositori Gitea mempunyai cermin GitHub, jadi ini dijangka bagi repositori tersebut. Jika repositori itu sepatutnya mempunyainya, tambahkannya dalam tetapan repositori.
|
||||||
|
|
||||||
`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.
|
`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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Upgrading.md, source sha256 ff8a06c4a03f -->
|
<!-- translation of Upgrading.md, source sha256 3f119a1ab12d -->
|
||||||
|
|
||||||
> Dette er en oversættelse af [`Upgrading`](Upgrading). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
> Dette er en oversættelse af [`Upgrading`](Upgrading). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres.
|
||||||
|
|
||||||
@@ -18,6 +18,8 @@ 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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## Aflæsning af en changelog-post
|
## Aflæsning af en changelog-post
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ 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`
|
A breaking release gets a new major version (`v2`), so a pipeline on `@v1`
|
||||||
never receives it until you change the line yourself.
|
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
|
||||||
|
`tools-ref` to the same tag; otherwise the script follows the major tag.
|
||||||
|
|
||||||
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
|
The two scoped workflows (**Sync GitHub mirror metadata** and **Publish
|
||||||
wiki**) are delivered by the instance and are not in your `uses:` lines; you
|
wiki**) are delivered by the instance and are not in your `uses:` lines; you
|
||||||
cannot pin them, but they fetch their scripts at the major tag.
|
cannot pin them, but they fetch their scripts at the major tag.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- translation of Upgrading.md, source sha256 ff8a06c4a03f -->
|
<!-- translation of Upgrading.md, source sha256 3f119a1ab12d -->
|
||||||
|
|
||||||
> Ini ialah terjemahan [`Upgrading`](Upgrading). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
> Ini ialah terjemahan [`Upgrading`](Upgrading). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya.
|
||||||
|
|
||||||
@@ -18,6 +18,8 @@ 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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## Membaca satu catatan changelog
|
## Membaca satu catatan changelog
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!-- Generated by tools/build_wiki.py. Edit the generator, not this page. -->
|
||||||
|
|
||||||
|
**TirSystem GitHub Actions**
|
||||||
|
|
||||||
|
**English**
|
||||||
|
|
||||||
|
- [Home](Home)
|
||||||
|
- [Onboarding](Onboarding)
|
||||||
|
- [Credentials](Credentials)
|
||||||
|
- [Troubleshooting](Troubleshooting)
|
||||||
|
- [Quality checks (Python, shell)](QualityChecksPythonShell)
|
||||||
|
- [Upgrading](Upgrading)
|
||||||
|
- [Capabilities](Capabilities)
|
||||||
|
|
||||||
|
**Dansk**
|
||||||
|
|
||||||
|
- [Hjem](Home.da)
|
||||||
|
- [Tilslutning](Onboarding.da)
|
||||||
|
- [Credentials](Credentials.da)
|
||||||
|
- [Fejlfinding](Troubleshooting.da)
|
||||||
|
- [Kvalitetskontrol (Python, shell)](QualityChecksPythonShell.da)
|
||||||
|
- [Opgradering](Upgrading.da)
|
||||||
|
- [Kapabiliteter](Capabilities.da)
|
||||||
|
|
||||||
|
**Bahasa Melayu**
|
||||||
|
|
||||||
|
- [Utama](Home.ms)
|
||||||
|
- [Menyertakan](Onboarding.ms)
|
||||||
|
- [Kelayakan](Credentials.ms)
|
||||||
|
- [Diagnosis](Troubleshooting.ms)
|
||||||
|
- [Semakan kualiti (Python, shell)](QualityChecksPythonShell.ms)
|
||||||
|
- [Menaik taraf](Upgrading.ms)
|
||||||
|
- [Keupayaan](Capabilities.ms)
|
||||||
Reference in New Issue
Block a user