Restructure the script embedded in the scoped sync workflow into testable functions, fix the invalid `exit 0` (now a successful run with a visible warning when Gitea returns an invalid push mirror list) and report errors as `ERROR: <message>` with exit code 1. Zero, several or malformed GitHub mirrors still fail. Add pytest-based offline tests (workflow YAML, embedded Python, credential and mirror parsing, sync flow against a fake API) that run in a virtual environment, and a validation workflow that runs them on pull requests and pushes to main. Remove the manual tests/test_.ps1 probe and the duplicate src/ copy of the workflow. Update the README and record the decisions for tasks 1 and 3 in MIL-001. Task: MIL-001#1 Task: MIL-001#2 Task: MIL-001#3 Task: MIL-001#4 Task: MIL-001#5 Task: MIL-001#6 Refs #1 Refs #2 Refs #3 Refs #4 Refs #5 Refs #6 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
🚀 TirSystem GitHub Actions
A collection of reusable Gitea Actions workflows for DevOps professionals and software engineers working on TirSystem projects.
📚 Table of Contents
🧭 Overview
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, 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.
📋 Requirements
- A Gitea instance with Actions enabled and a runner providing
ubuntu-latestwithpython3 - A configured GitHub push mirror on the Gitea repository (exactly one)
- Repository secrets:
TOKEN_FOR_GITEA: Gitea API token (plain string, or JSON withGITEA_TOKEN)CREDENTIALS_FOR_GITHUB: JSON object containingGITHUB_PAT, a GitHub personal access token allowed to edit the mirror repository
🛠️ Setup
No dependencies need to be installed; the workflow uses only the Python standard library.
- Clone the repository:
git clone ssh://git@git.tirsystem.com:10022/TirSystem/github-action.git - Add the secrets listed under Requirements to the repository settings in Gitea.
- 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 Python embedded in them are validated by offline tests that need no network access and no secrets:
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. They parse every workflow as YAML, compile the embedded Python, require explicit job permissions, and test credential parsing, push mirror address parsing and the sync flow 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
Only the first row is implemented. The rest is planned and tracked in the Project Plan, 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 | Partial: secrets are checked for format only |
| Onboard a repository, manage runners, diagnose failures | Planned (MIL-002) |
| Shared quality checks | Planned (MIL-003) |
| Versioned release and publishing | Planned (MIL-004) |
🔄 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
@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
CREDENTIALS_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
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
📄 License
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE.