From 4cb46894718c4f74013e38aa8d3885508b3812f4 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Sun, 11 Oct 2026 10:38:54 +0800 Subject: [PATCH] List all workflows with their purpose and a diagram on the Home page Task: MIL-005#3 --- README.md | 282 ++++++++++++++++++++++++++++++++------- tests/test_build_wiki.py | 22 ++- tools/build_wiki.py | 2 +- wiki/Capabilities.da.md | 68 +--------- wiki/Capabilities.md | 66 --------- wiki/Capabilities.ms.md | 68 +--------- wiki/Home.da.md | 252 +++++++++++++++++++++++++++++++++- wiki/Home.md | 250 +++++++++++++++++++++++++++++++++- wiki/Home.ms.md | 252 +++++++++++++++++++++++++++++++++- 9 files changed, 1003 insertions(+), 259 deletions(-) diff --git a/README.md b/README.md index 216300e..e71fbe4 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ A collection of reusable Gitea Actions workflows for DevOps professionals and so ## 📚 Table of Contents - [Overview](#-overview) +- [Workflows](#-workflows) - [Requirements](#-requirements) - [Setup](#-setup) - [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. -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` -- 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` +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. -## 🛠️ 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 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 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)) | +| Workflow | File | Kind | Starts on | Purpose | +| --- | --- | --- | --- | --- | +| Sync GitHub mirror metadata | [`sync-github-metadata.yml`](.gitea/scoped_workflows/sync-github-metadata.yml) | Scoped | push to `main`, manual, daily 03:17 UTC | Copies the description and topics of a Gitea repository to its GitHub push mirror | +| Publish wiki | [`publish-wiki.yml`](.gitea/scoped_workflows/publish-wiki.yml) | Scoped, opt-in with `wiki/.publish` | push to `main` that changes `wiki/**`, manual | Publishes the pages in `wiki/` to the repository wiki | +| Quality checks | [`quality-checks.yml`](.gitea/workflows/quality-checks.yml) | Reusable (`workflow_call`) | a call from another repository | Runs ruff, mypy, shellcheck and shfmt on the tracked files and changes nothing | +| 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 | +| Validate workflows | [`validate-workflows.yml`](.gitea/workflows/validate-workflows.yml) | This repository only | pull request, push to `main`, manual | Parses every workflow and runs the offline tests | ### 🔄 Sync GitHub metadata @@ -136,6 +97,227 @@ 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](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/ (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 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 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 Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See [LICENSE](LICENSE). diff --git a/tests/test_build_wiki.py b/tests/test_build_wiki.py index 0c0cf43..52b8303 100644 --- a/tests/test_build_wiki.py +++ b/tests/test_build_wiki.py @@ -92,9 +92,10 @@ def _write_sources(root: Path) -> None: (root / "README.md").write_text( "# 🚀 Name\nIntro.\n\n## 📚 Table of Contents\n- [x](#-overview)\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" - "## ▶️ Run\nGo.\n\n## 🧪 Tests\nPytest.\n\n## 🟢 Capabilities\nA table.\n\n" - "### 🔄 Sync\nDetails.\n\n## 📄 License\nMIT.\n", + "## ▶️ Run\nGo.\n\n## 🧪 Tests\nPytest.\n\n## 🟢 Capabilities\nA table.\n\n### 🔎 Detail\nMore.\n\n" + "## 📄 License\nMIT.\n", encoding="utf-8", ) for name in ("onboarding", "credentials", "troubleshooting", "quality-checks", "upgrading"): @@ -123,7 +124,8 @@ class TestRenderPage: page = next(p for p in build_wiki.PAGES if p.name == "Capabilities") text = build_wiki.render_page(page, repo) assert "## Capabilities" in text - assert "### Sync" in text + assert "### Detail" in text + assert "### Sync" not in text assert "## Overview" not in text def test_every_page_names_its_source_and_warns(self, repo): @@ -291,3 +293,17 @@ class TestSidebar: 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) diff --git a/tools/build_wiki.py b/tools/build_wiki.py index c6a310d..fa4998a 100644 --- a/tools/build_wiki.py +++ b/tools/build_wiki.py @@ -39,7 +39,7 @@ class 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("Credentials", "guides/credentials.md"), Page("Troubleshooting", "guides/troubleshooting.md"), diff --git a/wiki/Capabilities.da.md b/wiki/Capabilities.da.md index 3f83fcd..9803fb9 100644 --- a/wiki/Capabilities.da.md +++ b/wiki/Capabilities.da.md @@ -1,4 +1,4 @@ - + > Dette er en oversættelse af [`Capabilities`](Capabilities). Den engelske side er autoritativ, og ændringer her bliver overskrevet, næste gang wikien publiceres. @@ -16,69 +16,3 @@ Rækker, der siger Implementeret eller Vejledninger er skrevet, findes i dag. Re | Publicering af et repositorys wiki fra `wiki/` (tilmelding, leveres til alle organisationer) | Implementeret i `.gitea/scoped_workflows/publish-wiki.yml`, med offline-tests; et pilotforsøg i et andet repository publicerer sin wiki (MIL-006) | | Fælles kvalitetskontrol (Python og shell) | Implementeret som det genbrugelige workflow `.gitea/workflows/quality-checks.yml`, med offline-tests og et forsøg i en anden organisation; taget i brug i RepoFoundry ([vejledning](QualityChecksPythonShell.da)) | | 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 -``` diff --git a/wiki/Capabilities.md b/wiki/Capabilities.md index 72e8055..20d7ab4 100644 --- a/wiki/Capabilities.md +++ b/wiki/Capabilities.md @@ -16,69 +16,3 @@ Rows that say Implemented or Guides written exist today. The rest is planned and | Publish a repository wiki from `wiki/` (opt-in, delivered to every organization) | Implemented in `.gitea/scoped_workflows/publish-wiki.yml`, with offline tests; a pilot in a second repository publishes its wiki (MIL-006) | | Shared quality checks (Python and shell) | Implemented as the reusable workflow `.gitea/workflows/quality-checks.yml`, with offline tests and a trial in a second organization; adopted in RepoFoundry ([guide](QualityChecksPythonShell)) | | 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 -``` diff --git a/wiki/Capabilities.ms.md b/wiki/Capabilities.ms.md index f9ae885..686fc07 100644 --- a/wiki/Capabilities.ms.md +++ b/wiki/Capabilities.ms.md @@ -1,4 +1,4 @@ - + > Ini ialah terjemahan [`Capabilities`](Capabilities). Halaman bahasa Inggeris ialah teks yang sah, dan perubahan di sini akan ditimpa pada penerbitan wiki yang seterusnya. @@ -16,69 +16,3 @@ Baris yang menyatakan Dilaksanakan atau Panduan telah ditulis wujud hari ini. Se | Menerbitkan wiki repositori daripada `wiki/` (pilih menyertai, dihantar ke setiap organisasi) | Dilaksanakan dalam `.gitea/scoped_workflows/publish-wiki.yml`, dengan ujian luar talian; satu juruterbang dalam repositori kedua menerbitkan wikinya (MIL-006) | | Semakan kualiti bersama (Python dan shell) | Dilaksanakan sebagai aliran kerja boleh guna semula `.gitea/workflows/quality-checks.yml`, dengan ujian luar talian dan percubaan dalam organisasi kedua; digunakan dalam RepoFoundry ([panduan](QualityChecksPythonShell.ms)) | | 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 -``` diff --git a/wiki/Home.da.md b/wiki/Home.da.md index 664e3fd..e8498fd 100644 --- a/wiki/Home.da.md +++ b/wiki/Home.da.md @@ -1,4 +1,4 @@ - + > 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. -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/ (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 diff --git a/wiki/Home.md b/wiki/Home.md index c8e842c..ace5bb7 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -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. -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/ (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 diff --git a/wiki/Home.ms.md b/wiki/Home.ms.md index bf475a7..b834340 100644 --- a/wiki/Home.ms.md +++ b/wiki/Home.ms.md @@ -1,4 +1,4 @@ - + > 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. -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/ (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