From 5b2b6af14edba8291473644adc77c4e14cece8d2 Mon Sep 17 00:00:00 2001 From: Cai <115717560+CaiKDavis@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:47:20 +0000 Subject: [PATCH 1/5] release v0.8 (#17) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(templates): tweaked * fix(workflows): preventing workflows from triggering both self and main * feat(templates): cleaned templates, removing unnecessary elements * feat(template): simplification * feat(cleanup): cleaned docs and cicd * fix(build-and-tes): fixed reference to publish-on-release * ci(naming): shortened run names * fix(build-and-test): added pip for smoke testing * bump: version 0.1.0 → 0.2.0 * feat(repo_template): added ci-orchestrator.yaml to git keep * bump: version 0.2.0 → 0.3.0 * fix(post-release-private): fixed triggering of back sync * bump: version 0.3.0 → 0.4.0 * feat(sync-from-public): added for downstream templating * bump: version 0.4.0 → 0.5.0 * fix(public-release): entered correct private/public repos * bump: version 0.5.0 → 0.6.0 * feat(back-sync-release): prevent running of tests * fix(back-sync-release-to-main): admin bypasses merge * bump: version 0.6.0 → 0.7.0 * feat(.gitignore): kept all *.yaml in template workflows * refactor(workflows): refactored to remove repeat calls to config.yaml * feat(review): reviewd inc docs * bump: version 0.7.0 → 0.8.0 --- .../workflows/back-sync-release-to-main.yaml | 20 +++------ .github/workflows/build-and-test.yaml | 45 +++++-------------- .github/workflows/config.yaml | 2 +- .github/workflows/ensure-release-source.yaml | 24 +++------- .../workflows/pre-release-version-check.yaml | 9 +--- .github/workflows/publish-to-pypi.yaml | 28 ++++-------- .github/workflows/sync-from-public.yaml | 20 +++------ .github/workflows/sync-to-public.yaml | 26 +++-------- .github/workflows/workflow-orchestrator.yaml | 9 +++- CHANGELOG.md | 11 +++++ IMPLEMENTATION_SUMMARY.md | 13 ++++-- README.md | 9 ++-- docs/DEPLOYMENT_PATTERNS.md | 22 ++++----- docs/ORG_SETUP_GUIDE.md | 12 ++--- docs/TESTBED.md | 12 ++--- docs/usage-guide.md | 2 + pyproject.toml | 2 +- 17 files changed, 104 insertions(+), 162 deletions(-) diff --git a/.github/workflows/back-sync-release-to-main.yaml b/.github/workflows/back-sync-release-to-main.yaml index ae72cf6..9955036 100644 --- a/.github/workflows/back-sync-release-to-main.yaml +++ b/.github/workflows/back-sync-release-to-main.yaml @@ -27,24 +27,14 @@ concurrency: cancel-in-progress: false jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - private-repo: ${{ inputs.private-repo }} - private-repo-main-branch: ${{ inputs.private-repo-main-branch }} - private-repo-release-branch: ${{ inputs.private-repo-release-branch }} - secrets: inherit - back-sync-release-to-main: name: Back Sync - needs: env-config if: > - github.repository == needs.env-config.outputs.PRIVATE_REPO && + github.repository == (inputs.private-repo || github.repository) && ( github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && - github.ref_name == needs.env-config.outputs.PRIVATE_REPO_RELEASE_BRANCH) + github.ref_name == (inputs.private-repo-release-branch || 'release')) ) runs-on: ubuntu-latest @@ -57,9 +47,9 @@ jobs: shell: bash env: - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_MAIN_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_MAIN_BRANCH }} - PRIVATE_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_RELEASE_BRANCH }} + PRIVATE_REPO: ${{ inputs.private-repo || github.repository }} + PRIVATE_REPO_MAIN_BRANCH: ${{ inputs.private-repo-main-branch || 'main' }} + PRIVATE_REPO_RELEASE_BRANCH: ${{ inputs.private-repo-release-branch || 'release' }} MANAGEMENT_TOKEN: ${{ secrets.MANAGEMENT_TOKEN }} steps: diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index d664046..12aa731 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -52,37 +52,17 @@ on: type: string jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - package-name: ${{ inputs.package-name }} - package-slug: ${{ inputs.package-slug }} - private-repo: ${{ inputs.private-repo }} - private-repo-main-branch: ${{ inputs.private-repo-main-branch }} - private-repo-release-branch: ${{ inputs.private-repo-release-branch }} - private-repo-incoming-branch: ${{ inputs.private-repo-incoming-branch }} - public-repo: ${{ inputs.public-repo }} - public-repo-release-branch: ${{ inputs.public-repo-release-branch }} - public-repo-incoming-branch: ${{ inputs.public-repo-incoming-branch }} - build-smoke-python-version: ${{ inputs.build-smoke-python-version }} - test-matrix-json: ${{ inputs.test-matrix-json }} - version-check-python-version: ${{ inputs.version-check-python-version }} - publish-python-version: ${{ inputs.publish-python-version }} - publish-on-release: ${{ inputs.publish-on-release }} - build-and-smoke-test: name: Smoke Build - needs: env-config if: > - github.repository == needs.env-config.outputs.PRIVATE_REPO + github.repository == inputs.private-repo strategy: fail-fast: false matrix: include: - os: ubuntu-latest - python-version: ${{ needs.env-config.outputs.BUILD_SMOKE_PYTHON_VERSION }} + python-version: ${{ inputs.build-smoke-python-version }} runs-on: ${{ matrix.os }} @@ -91,10 +71,10 @@ jobs: shell: bash env: - PACKAGE_NAME: ${{ needs.env-config.outputs.PACKAGE_NAME }} - PACKAGE_SLUG: ${{ needs.env-config.outputs.PACKAGE_SLUG }} - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_MAIN_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_MAIN_BRANCH }} + PACKAGE_NAME: ${{ inputs.package-name }} + PACKAGE_SLUG: ${{ inputs.package-slug }} + PRIVATE_REPO: ${{ inputs.private-repo }} + PRIVATE_REPO_MAIN_BRANCH: ${{ inputs.private-repo-main-branch }} steps: - name: Checkout Code @@ -152,13 +132,12 @@ jobs: run-tests: name: Test Matrix - needs: env-config if: > - github.repository == needs.env-config.outputs.PRIVATE_REPO + github.repository == inputs.private-repo strategy: fail-fast: false - matrix: ${{ fromJson(needs.env-config.outputs.TEST_MATRIX_JSON) }} + matrix: ${{ fromJson(inputs.test-matrix-json) }} runs-on: ${{ matrix.os }} @@ -167,10 +146,10 @@ jobs: shell: bash env: - PACKAGE_NAME: ${{ needs.env-config.outputs.PACKAGE_NAME }} - PACKAGE_SLUG: ${{ needs.env-config.outputs.PACKAGE_SLUG }} - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_MAIN_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_MAIN_BRANCH }} + PACKAGE_NAME: ${{ inputs.package-name }} + PACKAGE_SLUG: ${{ inputs.package-slug }} + PRIVATE_REPO: ${{ inputs.private-repo }} + PRIVATE_REPO_MAIN_BRANCH: ${{ inputs.private-repo-main-branch }} steps: - name: Checkout Code diff --git a/.github/workflows/config.yaml b/.github/workflows/config.yaml index 34159f8..68bc8e2 100644 --- a/.github/workflows/config.yaml +++ b/.github/workflows/config.yaml @@ -105,7 +105,7 @@ env: PRIVATE_REPO_INCOMING_BRANCH: ${{ inputs.private-repo-incoming-branch || 'incoming_from_public' }} # mirrors incoming from public # Public Repo - PUBLIC_REPO: ${{ inputs.public-repo || 'SETT-Centre-Data-and-AI/workflows' }} + PUBLIC_REPO: ${{ inputs.public-repo }} PUBLIC_REPO_INCOMING_BRANCH: ${{ inputs.public-repo-incoming-branch || 'incoming_from_private' }} # mirrors incoming from private PUBLIC_REPO_RELEASE_BRANCH: ${{ inputs.public-repo-release-branch || 'release' }} # when PR closed, trigger PyPI publish diff --git a/.github/workflows/ensure-release-source.yaml b/.github/workflows/ensure-release-source.yaml index 39084f4..ce0ba8d 100644 --- a/.github/workflows/ensure-release-source.yaml +++ b/.github/workflows/ensure-release-source.yaml @@ -30,20 +30,8 @@ on: type: string jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - private-repo: ${{ inputs.private-repo }} - private-repo-main-branch: ${{ inputs.private-repo-main-branch }} - private-repo-release-branch: ${{ inputs.private-repo-release-branch }} - public-repo: ${{ inputs.public-repo }} - public-repo-release-branch: ${{ inputs.public-repo-release-branch }} - public-repo-incoming-branch: ${{ inputs.public-repo-incoming-branch }} - ensure-release-source: name: Validate Source - needs: env-config runs-on: ubuntu-latest defaults: @@ -51,12 +39,12 @@ jobs: shell: bash env: - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_MAIN_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_MAIN_BRANCH }} - PRIVATE_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_RELEASE_BRANCH }} - PUBLIC_REPO: ${{ needs.env-config.outputs.PUBLIC_REPO }} - PUBLIC_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PUBLIC_REPO_RELEASE_BRANCH }} - PUBLIC_REPO_INCOMING_BRANCH: ${{ needs.env-config.outputs.PUBLIC_REPO_INCOMING_BRANCH }} + PRIVATE_REPO: ${{ inputs.private-repo }} + PRIVATE_REPO_MAIN_BRANCH: ${{ inputs.private-repo-main-branch }} + PRIVATE_REPO_RELEASE_BRANCH: ${{ inputs.private-repo-release-branch }} + PUBLIC_REPO: ${{ inputs.public-repo }} + PUBLIC_REPO_RELEASE_BRANCH: ${{ inputs.public-repo-release-branch }} + PUBLIC_REPO_INCOMING_BRANCH: ${{ inputs.public-repo-incoming-branch }} steps: - name: Show PR Context diff --git a/.github/workflows/pre-release-version-check.yaml b/.github/workflows/pre-release-version-check.yaml index 736ea0a..bcfbd91 100644 --- a/.github/workflows/pre-release-version-check.yaml +++ b/.github/workflows/pre-release-version-check.yaml @@ -14,15 +14,8 @@ on: type: string jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - version-check-python-version: ${{ inputs.version-check-python-version }} - check-version-bump: name: Check Version - needs: env-config runs-on: ubuntu-latest @@ -31,7 +24,7 @@ jobs: shell: bash env: - PYTHON_VERSION: ${{ needs.env-config.outputs.VERSION_CHECK_PYTHON_VERSION }} + PYTHON_VERSION: ${{ inputs.version-check-python-version }} steps: - name: Show PR context diff --git a/.github/workflows/publish-to-pypi.yaml b/.github/workflows/publish-to-pypi.yaml index 6c60fc6..a946030 100644 --- a/.github/workflows/publish-to-pypi.yaml +++ b/.github/workflows/publish-to-pypi.yaml @@ -29,28 +29,16 @@ on: workflow_dispatch: {} jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - package-name: ${{ inputs.package-name }} - package-slug: ${{ inputs.package-slug }} - public-repo: ${{ inputs.public-repo }} - public-repo-release-branch: ${{ inputs.public-repo-release-branch }} - publish-python-version: ${{ inputs.publish-python-version }} - publish-on-release: ${{ inputs.publish-on-release }} - publish-to-pypi: name: Build and Publish - needs: env-config if: > # in public repo, and called by orchestrator or run manually on release - github.repository == needs.env-config.outputs.PUBLIC_REPO && + github.repository == (inputs.public-repo || 'SETT-Centre-Data-and-AI/workflows') && ( github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && - github.ref_name == needs.env-config.outputs.PUBLIC_REPO_RELEASE_BRANCH) + github.ref_name == (inputs.public-repo-release-branch || 'release')) ) && - needs.env-config.outputs.PUBLISH_ON_RELEASE == 'true' + (inputs.publish-on-release || 'true') == 'true' runs-on: ubuntu-latest permissions: @@ -59,12 +47,12 @@ jobs: env: # From shared config - PACKAGE_NAME: ${{ needs.env-config.outputs.PACKAGE_NAME }} - PACKAGE_SLUG: ${{ needs.env-config.outputs.PACKAGE_SLUG }} - PUBLIC_REPO: ${{ needs.env-config.outputs.PUBLIC_REPO }} - PUBLIC_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PUBLIC_REPO_RELEASE_BRANCH }} + PACKAGE_NAME: ${{ inputs.package-name }} + PACKAGE_SLUG: ${{ inputs.package-slug }} + PUBLIC_REPO: ${{ inputs.public-repo || 'SETT-Centre-Data-and-AI/workflows' }} + PUBLIC_REPO_RELEASE_BRANCH: ${{ inputs.public-repo-release-branch || 'release' }} # Publish config - PYTHON_VERSION: ${{ needs.env-config.outputs.PUBLISH_PYTHON_VERSION }} + PYTHON_VERSION: ${{ inputs.publish-python-version || '3.13' }} PYPI_USERNAME: __token__ steps: diff --git a/.github/workflows/sync-from-public.yaml b/.github/workflows/sync-from-public.yaml index 87f5f4e..8e249d4 100644 --- a/.github/workflows/sync-from-public.yaml +++ b/.github/workflows/sync-from-public.yaml @@ -33,20 +33,10 @@ on: required: true jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - private-repo: ${{ inputs.private-repo || '' }} - private-repo-main-branch: ${{ inputs.private-repo-main-branch || '' }} - private-repo-incoming-branch: ${{ inputs.private-repo-incoming-branch || '' }} - public-repo: ${{ inputs.public-repo || '' }} - sync-from-public: name: Sync Private - needs: env-config - if: github.repository == needs.env-config.outputs.PRIVATE_REPO + if: github.repository == (inputs.private-repo || github.repository) runs-on: ubuntu-latest @@ -56,11 +46,11 @@ jobs: env: # From shared config - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_MAIN_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_MAIN_BRANCH }} - PRIVATE_REPO_INCOMING_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_INCOMING_BRANCH }} + PRIVATE_REPO: ${{ inputs.private-repo || github.repository }} + PRIVATE_REPO_MAIN_BRANCH: ${{ inputs.private-repo-main-branch || 'main' }} + PRIVATE_REPO_INCOMING_BRANCH: ${{ inputs.private-repo-incoming-branch || 'incoming_from_public' }} - PUBLIC_REPO: ${{ needs.env-config.outputs.PUBLIC_REPO }} + PUBLIC_REPO: ${{ inputs.public-repo || 'SETT-Centre-Data-and-AI/workflows' }} MANAGEMENT_TOKEN: ${{ secrets.MANAGEMENT_TOKEN }} PUBLIC_BRANCH: ${{ inputs.public_branch || github.event.inputs.public_branch }} diff --git a/.github/workflows/sync-to-public.yaml b/.github/workflows/sync-to-public.yaml index 32fc8d7..5faa544 100644 --- a/.github/workflows/sync-to-public.yaml +++ b/.github/workflows/sync-to-public.yaml @@ -26,26 +26,14 @@ on: workflow_dispatch: {} jobs: - env-config: - name: Resolve Config - uses: ./.github/workflows/config.yaml - with: - private-repo: ${{ inputs.private-repo }} - private-repo-release-branch: ${{ inputs.private-repo-release-branch }} - public-repo: ${{ inputs.public-repo }} - public-repo-release-branch: ${{ inputs.public-repo-release-branch }} - public-repo-incoming-branch: ${{ inputs.public-repo-incoming-branch }} - secrets: inherit - sync-to-public: name: Sync Public - needs: env-config if: > # in private repo, and PR merged or run manually - github.repository == needs.env-config.outputs.PRIVATE_REPO && + github.repository == (inputs.private-repo || github.repository) && ( github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && - github.ref_name == needs.env-config.outputs.PRIVATE_REPO_RELEASE_BRANCH) + github.ref_name == (inputs.private-repo-release-branch || 'release')) ) runs-on: ubuntu-latest @@ -55,12 +43,12 @@ jobs: env: # From shared config - PRIVATE_REPO: ${{ needs.env-config.outputs.PRIVATE_REPO }} - PRIVATE_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PRIVATE_REPO_RELEASE_BRANCH }} + PRIVATE_REPO: ${{ inputs.private-repo || github.repository }} + PRIVATE_REPO_RELEASE_BRANCH: ${{ inputs.private-repo-release-branch || 'release' }} - PUBLIC_REPO: ${{ needs.env-config.outputs.PUBLIC_REPO }} - PUBLIC_REPO_RELEASE_BRANCH: ${{ needs.env-config.outputs.PUBLIC_REPO_RELEASE_BRANCH }} - PUBLIC_REPO_INCOMING_BRANCH: ${{ needs.env-config.outputs.PUBLIC_REPO_INCOMING_BRANCH }} + PUBLIC_REPO: ${{ inputs.public-repo || 'SETT-Centre-Data-and-AI/workflows' }} + PUBLIC_REPO_RELEASE_BRANCH: ${{ inputs.public-repo-release-branch || 'release' }} + PUBLIC_REPO_INCOMING_BRANCH: ${{ inputs.public-repo-incoming-branch || 'incoming_from_private' }} MANAGEMENT_TOKEN: ${{ secrets.MANAGEMENT_TOKEN }} diff --git a/.github/workflows/workflow-orchestrator.yaml b/.github/workflows/workflow-orchestrator.yaml index 63251a8..219fc2d 100644 --- a/.github/workflows/workflow-orchestrator.yaml +++ b/.github/workflows/workflow-orchestrator.yaml @@ -180,7 +180,9 @@ jobs: if [ "$EVENT_NAME" = "workflow_dispatch" ]; then if [ "$REPOSITORY_NAME" = "$PRIVATE_REPO" ] && [ "$REF_NAME" = "$PRIVATE_REPO_RELEASE_BRANCH" ]; then RUN_BACK_SYNC=true - RUN_SYNC_TO_PUBLIC=true + if [ -n "$PUBLIC_REPO" ] && [ "$PUBLIC_REPO" != "$PRIVATE_REPO" ]; then + RUN_SYNC_TO_PUBLIC=true + fi fi if [ "$REPOSITORY_NAME" = "$PUBLIC_REPO" ] && [ "$REF_NAME" = "$PUBLIC_REPO_RELEASE_BRANCH" ] && [ "$PUBLISH_ON_RELEASE" = "true" ]; then RUN_PUBLISH_TO_PYPI=true @@ -202,7 +204,9 @@ jobs: if [ "$EVENT_ACTION" = "closed" ] && [ "$PR_MERGED" = "true" ] && [ "$HEAD_REF" = "$PRIVATE_REPO_MAIN_BRANCH" ]; then RUN_BACK_SYNC=true - RUN_SYNC_TO_PUBLIC=true + if [ -n "$PUBLIC_REPO" ] && [ "$PUBLIC_REPO" != "$PRIVATE_REPO" ]; then + RUN_SYNC_TO_PUBLIC=true + fi fi fi @@ -312,4 +316,5 @@ jobs: public-repo: ${{ needs.env-config.outputs.PUBLIC_REPO }} public-repo-release-branch: ${{ needs.env-config.outputs.PUBLIC_REPO_RELEASE_BRANCH }} publish-python-version: ${{ needs.env-config.outputs.PUBLISH_PYTHON_VERSION }} + publish-on-release: ${{ needs.env-config.outputs.PUBLISH_ON_RELEASE }} secrets: inherit diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c48ff7..4498b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v0.8.0 (2026-03-23) + +### Feat + +- **review**: reviewd inc docs +- **.gitignore**: kept all *.yaml in template workflows + +### Refactor + +- **workflows**: refactored to remove repeat calls to config.yaml + ## v0.7.0 (2026-03-23) ### Feat diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md index a848b05..e15a8cb 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/IMPLEMENTATION_SUMMARY.md @@ -33,7 +33,7 @@ - **[pre-release-version-check.yaml](.github/workflows/pre-release-version-check.yaml)** - Validates version bump in `pyproject.toml` when targeting release branches - - **Required status check**: `validate-version-bump` + - **Required route/check target**: `pre-release-version-check` #### Promotion Workflows - **[back-sync-release-to-main.yaml](.github/workflows/back-sync-release-to-main.yaml)** @@ -73,6 +73,7 @@ - **[repo_template/](repo_template/)** — Copyable starter package for downstream adopters - [repo_template/.github/workflows/ci-orchestrator.yaml](repo_template/.github/workflows/ci-orchestrator.yaml) — Copyable caller workflow + - [repo_template/.github/workflows/sync-from-public.yaml](repo_template/.github/workflows/sync-from-public.yaml) — Manual downstream wrapper for public-to-private sync - [repo_template/.github/workflows/pre-install.sh](repo_template/.github/workflows/pre-install.sh) — Optional custom setup hook - [repo_template/.github/workflows/README.md](repo_template/.github/workflows/README.md) — Copy instructions for the folder @@ -93,19 +94,23 @@ workflow_call: workflow-orchestrator.yaml@release ← Stable release tag ↓ route outputs flags: RUN_BUILD, RUN_ENSURE_*, RUN_BACK_SYNC, RUN_SYNC_*, RUN_PUBLISH ↓ - conditional jobs call specific workflows + conditional jobs call specific workflows with resolved inputs ↓ -Workflows execute with inherited secrets + config +Routed workflows execute directly with inherited secrets ``` ### Configuration Resolution ``` -Downstream repo calls config.yaml with optional inputs +Downstream repo calls workflow-orchestrator.yaml with optional inputs + ↓ +workflow-orchestrator.yaml calls config.yaml once ↓ inputs provided? Yes → Use it No → Use built-in default + ↓ +Orchestrator passes resolved values to routed workflows ``` ### Configuration Scope diff --git a/README.md b/README.md index e195e7c..6963261 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,10 @@ This repository is the orchestration control plane for adopter repositories: 1. Keep this repository as the single source of orchestration logic. 2. In each downstream repository, add one lightweight entry workflow that calls this repository via uses and @release. 3. Configure non-secret behaviour in the downstream caller workflow `with:` block (repo names, package names, optional overrides). -4. Keep optional matrix and pre-install customization in `.github/workflows` files alongside the caller workflow. -5. Enforce required status checks with organisation rulesets. -6. Manage secrets at organisation scope (`MANAGEMENT_TOKEN`, `PYPI_TOKEN`) with selected-repo access. +4. The orchestrator resolves configuration once via `config.yaml` and passes resolved values to routed workflows. +5. Keep optional matrix and pre-install customization in `.github/workflows` files alongside the caller workflow. +6. Enforce required status checks with organisation rulesets. +7. Manage secrets at organisation scope (`MANAGEMENT_TOKEN`, `PYPI_TOKEN`) with selected-repo access. **Start here**: [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) for quick overview of what's ready and next steps. @@ -85,7 +86,7 @@ Purpose: Mirror private release to public incoming and create or reuse PR to pub Purpose: Build and publish package from public release branch. ### [.github/workflows/sync-from-public.yaml](.github/workflows/sync-from-public.yaml) -Purpose: Manual sync from selected public branch to private incoming, then PR to private main. +Purpose: Sync selected public branch to private incoming, then PR to private main (manual in this repo and reusable from downstream wrapper workflows). ## Licence diff --git a/docs/DEPLOYMENT_PATTERNS.md b/docs/DEPLOYMENT_PATTERNS.md index 15402b6..39affdb 100644 --- a/docs/DEPLOYMENT_PATTERNS.md +++ b/docs/DEPLOYMENT_PATTERNS.md @@ -11,7 +11,7 @@ Choose the pattern that matches the repository lifecycle and publication model. **Workflows triggered**: - `build-and-test`: PR to main - `ensure-release-source`: PR to release branch -- `validate-version-bump`: PR to release branch +- `pre-release-version-check`: PR to release branch **No sync/publish to public repo.** @@ -36,7 +36,7 @@ Choose the pattern that matches the repository lifecycle and publication model. 4. Branch protection for `release`: - Require: `ensure-release-source` - - Require: `validate-version-bump` + - Require: `pre-release-version-check` ### Example Flow @@ -46,7 +46,7 @@ Feature branch → PR to main Merge to main main → Create PR to release - ↓ (check: ensure-release-source passes, validate-version-bump passes) + ↓ (check: ensure-release-source passes, pre-release-version-check passes) Merge to release ↓ (end; no further sync) @@ -60,8 +60,8 @@ Merge to release **Workflows triggered**: - Private main: `build-and-test` -- Private release: `ensure-release-source`, `validate-version-bump`, `back-sync-release-to-main`, `sync-to-public` -- Public release: `ensure-release-source`, `validate-version-bump`, `publish-to-pypi` +- Private release: `ensure-release-source`, `pre-release-version-check`, `back-sync-release-to-main`, `sync-to-public` +- Public release: `ensure-release-source`, `pre-release-version-check`, `publish-to-pypi` **Mandatory for all adopters** unless configured otherwise. @@ -89,7 +89,7 @@ Merge to release 4. Branch protection: - `main`: require `build-and-test` - - `release`: require `ensure-release-source`, `validate-version-bump` + - `release`: require `ensure-release-source`, `pre-release-version-check` **Public Repository**: @@ -113,7 +113,7 @@ Merge to release - `PYPI_TOKEN` (for publishing) 4. Branch protection: - - `release`: require `ensure-release-source`, `validate-version-bump`, `publish-to-pypi` + - `release`: require `ensure-release-source`, `pre-release-version-check`, `publish-to-pypi` ### Example Flow @@ -123,7 +123,7 @@ Private main PR Merge to private main private main → PR to private release - ↓ (checks: ensure-release-source, validate-version-bump pass) + ↓ (checks: ensure-release-source, pre-release-version-check pass) Merge to private release ↓ (auto) ├─ back-sync: create PR release→main in private repo @@ -132,7 +132,7 @@ Merge to private release └─ Create PR public incoming_from_private→release public incoming PR - ↓ (checks: ensure-release-source, validate-version-bump pass) + ↓ (checks: ensure-release-source, pre-release-version-check pass) Merge to public release ↓ (auto) └─ publish-to-pypi: build and upload to PyPI (if publish-on-release/PUBLISH_ON_RELEASE is true) @@ -147,7 +147,7 @@ Merge to public release **Workflows triggered**: - `build-and-test` (if configured for public repo) - `ensure-release-source` -- `validate-version-bump` +- `pre-release-version-check` - `publish-to-pypi` ### Setup @@ -171,7 +171,7 @@ Merge to public release - `PYPI_TOKEN` 4. Branch protection: - - `release`: require `ensure-release-source`, `validate-version-bump`, `publish-to-pypi` + - `release`: require `ensure-release-source`, `pre-release-version-check`, `publish-to-pypi` ### Note diff --git a/docs/ORG_SETUP_GUIDE.md b/docs/ORG_SETUP_GUIDE.md index 9872b8d..036d967 100644 --- a/docs/ORG_SETUP_GUIDE.md +++ b/docs/ORG_SETUP_GUIDE.md @@ -50,15 +50,17 @@ This keeps behavior visible in code and removes dependency on GitHub variables f ## 3. Required Status Checks Configuration -### Check Names Produced by Orchestrator +### Route Targets Produced by Orchestrator -The orchestrator produces these check contexts. When _required_, they prevent merge until passing: +The orchestrator routes to these workflows. When their check contexts are required, they prevent merge until passing. + +Important: with reusable workflows, the final check context is nested (for example `Orchestrate / Check Version / Check Version`). Always select the exact context string from the PR checks UI after first run. | Check Name | Workflow | Condition | |------------|----------|-----------| | `build-and-test` | [build-and-test.yaml](./../.github/workflows/build-and-test.yaml) | Private PR to main | | `ensure-release-source` | [ensure-release-source.yaml](./../.github/workflows/ensure-release-source.yaml) | PR to private or public release branch | -| `validate-version-bump` | [pre-release-version-check.yaml](./../.github/workflows/pre-release-version-check.yaml) | Any PR to private/public release branch | +| `pre-release-version-check` | [pre-release-version-check.yaml](./../.github/workflows/pre-release-version-check.yaml) | Any PR to private/public release branch | | `back-sync-release-to-main` | [back-sync-release-to-main.yaml](./../.github/workflows/back-sync-release-to-main.yaml) | Merge to private release from main | | `sync-to-public` | [sync-to-public.yaml](./../.github/workflows/sync-to-public.yaml) | Merge to private release from main | | `publish-to-pypi` | [publish-to-pypi.yaml](./../.github/workflows/publish-to-pypi.yaml) | Merge to public release from incoming | @@ -95,7 +97,7 @@ Target: Regular expression: ^release$ Required status checks: ✓ ensure-release-source - ✓ validate-version-bump + ✓ pre-release-version-check Require code reviews: 1 Dismiss stale pull request approvals: true @@ -115,7 +117,7 @@ Target: Regular expression: ^release$ Required status checks: ✓ ensure-release-source - ✓ validate-version-bump + ✓ pre-release-version-check ✓ publish-to-pypi (optional, but recommended) Require code reviews: 1 (or more) diff --git a/docs/TESTBED.md b/docs/TESTBED.md index 64c437b..d7eaed1 100644 --- a/docs/TESTBED.md +++ b/docs/TESTBED.md @@ -90,11 +90,11 @@ git commit -m "bump: version 0.1.0 → 0.2.0" git push origin test/version-bump # Open PR against release branch via GitHub UI -# Expected: validate-version-bump check PASSES +# Expected: pre-release-version-check route check PASSES ``` **Expected behavior**: -- Check `validate-version-bump` appears in PR +- Check `pre-release-version-check` appears in PR - Check **passes** because version was bumped vs base release branch ### 5. Version Bump Check (Failure Case) @@ -114,11 +114,11 @@ git commit -m "docs: update readme" git push origin test/no-version-bump # Open PR against release branch via GitHub UI -# Expected: validate-version-bump check FAILS +# Expected: pre-release-version-check route check FAILS ``` **Expected behavior**: -- Check `validate-version-bump` appears in PR +- Check `pre-release-version-check` appears in PR - Check **fails** because pyproject.toml version unchanged - PR cannot be merged while check fails @@ -180,7 +180,7 @@ Event: pull_request Base branch is PRIVATE_REPO_RELEASE_BRANCH? Yes: Action is opened|reopened|synchronize? - Yes: run ensure-release-source, validate-version-bump + Yes: run ensure-release-source, pre-release-version-check Action is closed AND merged? Yes: run back-sync-release-to-main, sync-to-public Repository is PUBLIC_REPO? @@ -188,7 +188,7 @@ Event: pull_request Base branch is PUBLIC_REPO_RELEASE_BRANCH? Yes: Action is opened|reopened|synchronize? - Yes: run ensure-release-source, validate-version-bump + Yes: run ensure-release-source, pre-release-version-check Event: workflow_dispatch Repository is PRIVATE_REPO? diff --git a/docs/usage-guide.md b/docs/usage-guide.md index c1b19ef..4abdfbf 100644 --- a/docs/usage-guide.md +++ b/docs/usage-guide.md @@ -78,6 +78,8 @@ Run it from the Actions tab and provide `public_branch`. In the wrapper file, se ## Configuration Precedence +Configuration is resolved once in [workflow-orchestrator](../.github/workflows/workflow-orchestrator.yaml) via [config](../.github/workflows/config.yaml), then routed workflows receive resolved inputs directly. + The config workflow supports two layers: 1. `workflow_call` inputs (highest priority) diff --git a/pyproject.toml b/pyproject.toml index 8293dc0..2033cb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "workflows" -version = "0.7.0" +version = "0.8.0" description = "Data & AI Unit centralised CI/CD workflows" authors = [{ name = "Cai Davis", email = "Cai.Davis@uhs.nhs.uk" }] license = "CC-BY-NC-4.0" From 95743576d705df612c0a9feacba8f139d1a96642 Mon Sep 17 00:00:00 2001 From: Cai <115717560+CaiKDavis@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:58:01 +0000 Subject: [PATCH 2/5] release v0.8.1 (#20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(templates): tweaked * fix(workflows): preventing workflows from triggering both self and main * feat(templates): cleaned templates, removing unnecessary elements * feat(template): simplification * feat(cleanup): cleaned docs and cicd * fix(build-and-tes): fixed reference to publish-on-release * ci(naming): shortened run names * fix(build-and-test): added pip for smoke testing * bump: version 0.1.0 → 0.2.0 * feat(repo_template): added ci-orchestrator.yaml to git keep * bump: version 0.2.0 → 0.3.0 * fix(post-release-private): fixed triggering of back sync * bump: version 0.3.0 → 0.4.0 * feat(sync-from-public): added for downstream templating * bump: version 0.4.0 → 0.5.0 * fix(public-release): entered correct private/public repos * bump: version 0.5.0 → 0.6.0 * feat(back-sync-release): prevent running of tests * fix(back-sync-release-to-main): admin bypasses merge * bump: version 0.6.0 → 0.7.0 * feat(.gitignore): kept all *.yaml in template workflows * refactor(workflows): refactored to remove repeat calls to config.yaml * feat(review): reviewd inc docs * bump: version 0.7.0 → 0.8.0 * fix(sync-to-public): attempt override push * bump: version 0.8.0 → 0.8.1 --- .github/workflows/sync-to-public.yaml | 30 ++++++++++++++++++++++++++- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-to-public.yaml b/.github/workflows/sync-to-public.yaml index 5faa544..a98d42b 100644 --- a/.github/workflows/sync-to-public.yaml +++ b/.github/workflows/sync-to-public.yaml @@ -114,7 +114,35 @@ jobs: git remote add public https://x-access-token:${MANAGEMENT_TOKEN}@github.com/${PUBLIC_REPO}.git echo "Pushing HEAD → public:${PUBLIC_REPO_INCOMING_BRANCH}" - git push public HEAD:refs/heads/${PUBLIC_REPO_INCOMING_BRANCH} --force + set +e + git push public HEAD:refs/heads/${PUBLIC_REPO_INCOMING_BRANCH} + push_exit=$? + set -e + + if [ "$push_exit" -eq 0 ]; then + echo "Non-force push succeeded." + exit 0 + fi + + echo "Non-force push failed. Trying force push as fallback..." + set +e + force_output=$(git push public HEAD:refs/heads/${PUBLIC_REPO_INCOMING_BRANCH} --force 2>&1) + force_exit=$? + set -e + echo "$force_output" + + if [ "$force_exit" -eq 0 ]; then + echo "Force push succeeded." + exit 0 + fi + + if echo "$force_output" | grep -q "GH013"; then + echo "ERROR: Push blocked by repository rules (GH013)." + echo "The token actor must be explicitly listed in the target repo ruleset bypass list for branch ${PUBLIC_REPO_INCOMING_BRANCH}." + echo "Also confirm bypass mode allows direct pushes (not PR-only) for this actor." + fi + + exit "$force_exit" - name: Create PR for Release env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4498b21..9cd3e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v0.8.1 (2026-03-23) + +### Fix + +- **sync-to-public**: attempt override push + ## v0.8.0 (2026-03-23) ### Feat diff --git a/pyproject.toml b/pyproject.toml index 2033cb4..7ff31b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "workflows" -version = "0.8.0" +version = "0.8.1" description = "Data & AI Unit centralised CI/CD workflows" authors = [{ name = "Cai Davis", email = "Cai.Davis@uhs.nhs.uk" }] license = "CC-BY-NC-4.0" From 9e512062b4bbca40b77a05576074c56bc131dd6b Mon Sep 17 00:00:00 2001 From: Cai <115717560+CaiKDavis@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:04:02 +0000 Subject: [PATCH 3/5] release v0.8.2 (#23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(templates): tweaked * fix(workflows): preventing workflows from triggering both self and main * feat(templates): cleaned templates, removing unnecessary elements * feat(template): simplification * feat(cleanup): cleaned docs and cicd * fix(build-and-tes): fixed reference to publish-on-release * ci(naming): shortened run names * fix(build-and-test): added pip for smoke testing * bump: version 0.1.0 → 0.2.0 * feat(repo_template): added ci-orchestrator.yaml to git keep * bump: version 0.2.0 → 0.3.0 * fix(post-release-private): fixed triggering of back sync * bump: version 0.3.0 → 0.4.0 * feat(sync-from-public): added for downstream templating * bump: version 0.4.0 → 0.5.0 * fix(public-release): entered correct private/public repos * bump: version 0.5.0 → 0.6.0 * feat(back-sync-release): prevent running of tests * fix(back-sync-release-to-main): admin bypasses merge * bump: version 0.6.0 → 0.7.0 * feat(.gitignore): kept all *.yaml in template workflows * refactor(workflows): refactored to remove repeat calls to config.yaml * feat(review): reviewd inc docs * bump: version 0.7.0 → 0.8.0 * fix(sync-to-public): attempt override push * bump: version 0.8.0 → 0.8.1 * fix(sync-to-public2): new fix attempt * bump: version 0.8.1 → 0.8.2 --- .github/workflows/sync-to-public.yaml | 18 ++++++++++++++++++ CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sync-to-public.yaml b/.github/workflows/sync-to-public.yaml index a98d42b..5a2f90f 100644 --- a/.github/workflows/sync-to-public.yaml +++ b/.github/workflows/sync-to-public.yaml @@ -63,6 +63,24 @@ jobs: echo "Management token is present" fi + - name: Show Token Actor and Ruleset Diagnostics + env: + GH_TOKEN: ${{ env.MANAGEMENT_TOKEN }} + PUBLIC_REPO: ${{ env.PUBLIC_REPO }} + PUBLIC_REPO_INCOMING_BRANCH: ${{ env.PUBLIC_REPO_INCOMING_BRANCH }} + run: | + echo "Resolving token actor identity..." + token_actor=$(gh api user --jq .login 2>/dev/null || echo "unknown") + echo "Token actor: ${token_actor}" + echo "Target repo: ${PUBLIC_REPO}" + echo "Target branch: ${PUBLIC_REPO_INCOMING_BRANCH}" + + echo "Effective rulesets for target branch:" + gh api \ + "repos/${PUBLIC_REPO}/rules/branches/${PUBLIC_REPO_INCOMING_BRANCH}" \ + --jq '.[] | {name: .name, source: .source, enforcement: .enforcement, bypass_actors: (.bypass_actors // [])}' \ + || echo "Could not query branch rules via API (insufficient token permissions or endpoint not available)." + - name: Checkout Private Release Branch uses: actions/checkout@v5 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cd3e36..ea34f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v0.8.2 (2026-03-23) + +### Fix + +- **sync-to-public2**: new fix attempt + ## v0.8.1 (2026-03-23) ### Fix diff --git a/pyproject.toml b/pyproject.toml index 7ff31b1..a8a5dcf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "workflows" -version = "0.8.1" +version = "0.8.2" description = "Data & AI Unit centralised CI/CD workflows" authors = [{ name = "Cai Davis", email = "Cai.Davis@uhs.nhs.uk" }] license = "CC-BY-NC-4.0" From 961be82135b7a6f943340caa6df600c15d4d5f37 Mon Sep 17 00:00:00 2001 From: Cai <115717560+CaiKDavis@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:42:47 +0000 Subject: [PATCH 4/5] release v0.8.3 (#26) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(templates): tweaked * fix(workflows): preventing workflows from triggering both self and main * feat(templates): cleaned templates, removing unnecessary elements * feat(template): simplification * feat(cleanup): cleaned docs and cicd * fix(build-and-tes): fixed reference to publish-on-release * ci(naming): shortened run names * fix(build-and-test): added pip for smoke testing * bump: version 0.1.0 → 0.2.0 * feat(repo_template): added ci-orchestrator.yaml to git keep * bump: version 0.2.0 → 0.3.0 * fix(post-release-private): fixed triggering of back sync * bump: version 0.3.0 → 0.4.0 * feat(sync-from-public): added for downstream templating * bump: version 0.4.0 → 0.5.0 * fix(public-release): entered correct private/public repos * bump: version 0.5.0 → 0.6.0 * feat(back-sync-release): prevent running of tests * fix(back-sync-release-to-main): admin bypasses merge * bump: version 0.6.0 → 0.7.0 * feat(.gitignore): kept all *.yaml in template workflows * refactor(workflows): refactored to remove repeat calls to config.yaml * feat(review): reviewd inc docs * bump: version 0.7.0 → 0.8.0 * fix(sync-to-public): attempt override push * bump: version 0.8.0 → 0.8.1 * fix(sync-to-public2): new fix attempt * bump: version 0.8.1 → 0.8.2 * fix(development): force both workflows repos to use own orchestrators * bump: version 0.8.2 → 0.8.3 * fix(orchestrator): fix to internal/external entries --- .github/workflows/workflow-orchestrator.yaml | 11 ++++++++++ CHANGELOG.md | 6 ++++++ README.md | 21 ++++++++++++-------- docs/usage-guide.md | 5 +++-- pyproject.toml | 2 +- repo_template/.github/workflows/README.md | 3 +++ 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/.github/workflows/workflow-orchestrator.yaml b/.github/workflows/workflow-orchestrator.yaml index 219fc2d..efab71f 100644 --- a/.github/workflows/workflow-orchestrator.yaml +++ b/.github/workflows/workflow-orchestrator.yaml @@ -132,6 +132,7 @@ jobs: CTX_HEAD_REF: ${{ github.head_ref || '' }} CTX_REF_NAME: ${{ github.ref_name || '' }} CTX_PR_MERGED: ${{ github.event.pull_request.merged || false }} + WORKFLOW_REF: ${{ github.workflow_ref || '' }} steps: - name: Show Event Context @@ -170,6 +171,16 @@ jobs: REPOSITORY_NAME="${CALLER_REPOSITORY:-$GITHUB_REPOSITORY}" PR_MERGED="${CALLER_PR_MERGED:-$CTX_PR_MERGED}" + if [ "$REPOSITORY_NAME" = "SETT-Centre-Data-and-AI/workflows" ] || [ "$REPOSITORY_NAME" = "SETT-Centre-Data-and-AI/workflows_development" ]; then + if [ -n "$WORKFLOW_REF" ] && [[ "$WORKFLOW_REF" == *"@release" ]]; then + echo "ERROR: Internal workflow repositories must call their local entry workflow." + echo "Internal repos must use local paths: uses: ./.github/workflows/.yaml" + echo "Not: uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/.yaml@release" + echo "Actual workflow_ref: $WORKFLOW_REF" + exit 1 + fi + fi + RUN_BUILD_AND_TEST=false RUN_ENSURE_RELEASE_SOURCE=false RUN_PRE_RELEASE_VERSION_CHECK=false diff --git a/CHANGELOG.md b/CHANGELOG.md index ea34f66..4483aca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v0.8.3 (2026-03-23) + +### Fix + +- **development**: force both workflows repos to use own orchestrators + ## v0.8.2 (2026-03-23) ### Fix diff --git a/README.md b/README.md index 6963261..b5a062c 100644 --- a/README.md +++ b/README.md @@ -34,22 +34,27 @@ This repository is the orchestration control plane for adopter repositories: ## Rollout Model 1. Keep this repository as the single source of orchestration logic. -2. In each downstream repository, add one lightweight entry workflow that calls this repository via uses and @release. -3. Configure non-secret behaviour in the downstream caller workflow `with:` block (repo names, package names, optional overrides). -4. The orchestrator resolves configuration once via `config.yaml` and passes resolved values to routed workflows. -5. Keep optional matrix and pre-install customization in `.github/workflows` files alongside the caller workflow. -6. Enforce required status checks with organisation rulesets. -7. Manage secrets at organisation scope (`MANAGEMENT_TOKEN`, `PYPI_TOKEN`) with selected-repo access. +2. In each external downstream repository, add one lightweight entry workflow that calls this repository via uses and @release. +3. Keep internal workflow repos (`workflows` and `workflows_development`) on local orchestrator calls (`uses: ./.github/workflows/workflow-orchestrator.yaml`) so CI always tests local workflow changes. +4. Configure non-secret behaviour in the downstream caller workflow `with:` block (repo names, package names, optional overrides). +5. The orchestrator resolves configuration once via `config.yaml` and passes resolved values to routed workflows. +6. Keep optional matrix and pre-install customization in `.github/workflows` files alongside the caller workflow. +7. Enforce required status checks with organisation rulesets. +8. Manage secrets at organisation scope (`MANAGEMENT_TOKEN`, `PYPI_TOKEN`) with selected-repo access. **Start here**: [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) for quick overview of what's ready and next steps. ## Reference Strategy -Downstream repositories should consume **stable releases** of this orchestrator. +External downstream repositories should consume **stable releases** of this orchestrator. + +Internal workflow repositories must use local orchestrator references: +- `SETT-Centre-Data-and-AI/workflows` +- `SETT-Centre-Data-and-AI/workflows_development` Default: Use `@release` tag for production. - `@release` — stable, tested version -- `@main` — development version (use only in this repo during development) +- `@main` — development version (use only for controlled pre-release validation in external repos) For downstream repositories: copy [repo_template/.github/workflows](repo_template/.github/workflows) into the repository root and remove the outer `repo_template` folder. diff --git a/docs/usage-guide.md b/docs/usage-guide.md index 4abdfbf..5133732 100644 --- a/docs/usage-guide.md +++ b/docs/usage-guide.md @@ -59,8 +59,9 @@ jobs: ``` Important: -- Use `@release` to consume stable, tested versions of centralised workflows. -- Use `@main` only for pre-release testing in development. +- Internal workflow repositories (`workflows` and `workflows_development`) must call local orchestrator path: `uses: ./.github/workflows/workflow-orchestrator.yaml`. +- External downstream repositories should use `@release` to consume stable, tested centralised workflows. +- Use `@main` only for controlled pre-release validation in external repositories. - Tag releases in this repository using semantic versioning. ## Manual Sync From Public (Downstream Repos) diff --git a/pyproject.toml b/pyproject.toml index a8a5dcf..e07bf0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "workflows" -version = "0.8.2" +version = "0.8.3" description = "Data & AI Unit centralised CI/CD workflows" authors = [{ name = "Cai Davis", email = "Cai.Davis@uhs.nhs.uk" }] license = "CC-BY-NC-4.0" diff --git a/repo_template/.github/workflows/README.md b/repo_template/.github/workflows/README.md index eaf974b..c097311 100644 --- a/repo_template/.github/workflows/README.md +++ b/repo_template/.github/workflows/README.md @@ -2,6 +2,9 @@ Copy this `.github/workflows` folder into the repository root. +This template is for external adopter repositories. +Do not use it in `SETT-Centre-Data-and-AI/workflows` or `SETT-Centre-Data-and-AI/workflows_development`; those internal workflow repositories should call their local orchestrator path instead. + The path in this template is: `repo_template/.github/workflows` From 4e92bbb03f3b8e221b97f321a899394cb9d23a55 Mon Sep 17 00:00:00 2001 From: Cai <115717560+CaiKDavis@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:32:42 +0000 Subject: [PATCH 5/5] release v0.9.2 (#29) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(templates): tweaked * fix(workflows): preventing workflows from triggering both self and main * feat(templates): cleaned templates, removing unnecessary elements * feat(template): simplification * feat(cleanup): cleaned docs and cicd * fix(build-and-tes): fixed reference to publish-on-release * ci(naming): shortened run names * fix(build-and-test): added pip for smoke testing * bump: version 0.1.0 → 0.2.0 * feat(repo_template): added ci-orchestrator.yaml to git keep * bump: version 0.2.0 → 0.3.0 * fix(post-release-private): fixed triggering of back sync * bump: version 0.3.0 → 0.4.0 * feat(sync-from-public): added for downstream templating * bump: version 0.4.0 → 0.5.0 * fix(public-release): entered correct private/public repos * bump: version 0.5.0 → 0.6.0 * feat(back-sync-release): prevent running of tests * fix(back-sync-release-to-main): admin bypasses merge * bump: version 0.6.0 → 0.7.0 * feat(.gitignore): kept all *.yaml in template workflows * refactor(workflows): refactored to remove repeat calls to config.yaml * feat(review): reviewd inc docs * bump: version 0.7.0 → 0.8.0 * fix(sync-to-public): attempt override push * bump: version 0.8.0 → 0.8.1 * fix(sync-to-public2): new fix attempt * bump: version 0.8.1 → 0.8.2 * fix(development): force both workflows repos to use own orchestrators * bump: version 0.8.2 → 0.8.3 * fix(orchestrator): fix to internal/external entries * feat(publish-to-pypi): switched off by default * refactor(CI/CD): refactored to harden some flows, switch PYPI_PUBLISH to false by default, and sort naming clarity * bump: version 0.8.3 → 0.9.0 * build(self-orchestrator): runs simplified tests in development * bump: version 0.9.0 → 0.9.1 * fix(check-version): pip installed packaging * bump: version 0.9.1 → 0.9.2 --- ...strator.yaml => central-orchestrator.yaml} | 0 .github/workflows/config.yaml | 2 +- .../workflows/pre-release-version-check.yaml | 16 +++++- .github/workflows/publish-to-pypi.yaml | 2 +- .github/workflows/self-orchestrator.yaml | 3 +- CHANGELOG.md | 22 ++++++++ IMPLEMENTATION_SUMMARY.md | 18 +++--- README.md | 4 +- docs/DEPLOYMENT_PATTERNS.md | 24 ++++---- docs/ORG_SETUP_GUIDE.md | 22 ++++---- docs/TESTBED.md | 4 +- docs/installation-guide.md | 2 +- docs/usage-guide.md | 14 ++--- pyproject.toml | 2 +- repo_template/.github/workflows/README.md | 4 +- .../.github/workflows/ci-orchestrator.yaml | 2 +- .../.github/workflows/orchestrator.yaml | 55 +++++++++++++++++++ 17 files changed, 143 insertions(+), 53 deletions(-) rename .github/workflows/{workflow-orchestrator.yaml => central-orchestrator.yaml} (100%) create mode 100644 repo_template/.github/workflows/orchestrator.yaml diff --git a/.github/workflows/workflow-orchestrator.yaml b/.github/workflows/central-orchestrator.yaml similarity index 100% rename from .github/workflows/workflow-orchestrator.yaml rename to .github/workflows/central-orchestrator.yaml diff --git a/.github/workflows/config.yaml b/.github/workflows/config.yaml index 68bc8e2..263a6e6 100644 --- a/.github/workflows/config.yaml +++ b/.github/workflows/config.yaml @@ -126,7 +126,7 @@ env: TEST_MATRIX_JSON: ${{ inputs.test-matrix-json || '' }} VERSION_CHECK_PYTHON_VERSION: ${{ inputs.version-check-python-version || '3.12' }} PUBLISH_PYTHON_VERSION: ${{ inputs.publish-python-version || '3.13' }} - PUBLISH_ON_RELEASE_RAW: ${{ inputs.publish-on-release || vars.PUBLISH_ON_RELEASE || 'true' }} + PUBLISH_ON_RELEASE_RAW: ${{ inputs.publish-on-release || vars.PUBLISH_ON_RELEASE || 'false' }} # ================= # End Manual Config # ================= diff --git a/.github/workflows/pre-release-version-check.yaml b/.github/workflows/pre-release-version-check.yaml index bcfbd91..8bd23d6 100644 --- a/.github/workflows/pre-release-version-check.yaml +++ b/.github/workflows/pre-release-version-check.yaml @@ -45,6 +45,9 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} + - name: Install version parsing dependency + run: python -m pip install packaging + - name: Check version bumped vs release env: BASE_SHA: ${{ github.event.pull_request.base.sha }} @@ -116,9 +119,18 @@ jobs: print(f"Base (release) version: {base_version}") print(f"Head (PR) version: {head_version}") - if base_version == head_version: + from packaging import version + + try: + base_v = version.parse(base_version) + head_v = version.parse(head_version) + except Exception as e: + print(f"ERROR: Could not parse versions: {e}", file=sys.stderr) + sys.exit(1) + + if head_v <= base_v: print( - f"ERROR: Version has not been bumped (still {head_version}). " + f"ERROR: Version must be increased. Current: {base_version}, proposed: {head_version}. " "You probably need to run 'cz bump'.", file=sys.stderr, ) diff --git a/.github/workflows/publish-to-pypi.yaml b/.github/workflows/publish-to-pypi.yaml index a946030..7303bc2 100644 --- a/.github/workflows/publish-to-pypi.yaml +++ b/.github/workflows/publish-to-pypi.yaml @@ -38,7 +38,7 @@ jobs: (github.event_name == 'workflow_dispatch' && github.ref_name == (inputs.public-repo-release-branch || 'release')) ) && - (inputs.publish-on-release || 'true') == 'true' + (inputs.publish-on-release || 'false') == 'true' runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/self-orchestrator.yaml b/.github/workflows/self-orchestrator.yaml index dbb01b4..71c010d 100644 --- a/.github/workflows/self-orchestrator.yaml +++ b/.github/workflows/self-orchestrator.yaml @@ -16,7 +16,7 @@ permissions: jobs: call-local-orchestrator: name: Orchestrate - uses: ./.github/workflows/workflow-orchestrator.yaml + uses: ./.github/workflows/central-orchestrator.yaml with: event-name: ${{ github.event_name }} event-action: ${{ github.event.action || '' }} @@ -35,6 +35,7 @@ jobs: public-repo-release-branch: release public-repo-incoming-branch: incoming_from_private build-smoke-python-version: '3.13' + test-matrix-json: '{"include":[{"os":"ubuntu-latest","python-version":"3.13"}]}' version-check-python-version: '3.13' publish-python-version: '3.13' publish-on-release: 'false' diff --git a/CHANGELOG.md b/CHANGELOG.md index 4483aca..6d489f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## v0.9.2 (2026-03-23) + +### Fix + +- **check-version**: pip installed packaging + +## v0.9.1 (2026-03-23) + +## v0.9.0 (2026-03-23) + +### Feat + +- **publish-to-pypi**: switched off by default + +### Fix + +- **orchestrator**: fix to internal/external entries + +### Refactor + +- **CI/CD**: refactored to harden some flows, switch PYPI_PUBLISH to false by default, and sort naming clarity + ## v0.8.3 (2026-03-23) ### Fix diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md index e15a8cb..41ab58d 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/IMPLEMENTATION_SUMMARY.md @@ -7,7 +7,7 @@ ### What's Implemented #### Core Orchestrator -- **[workflow-orchestrator.yaml](.github/workflows/workflow-orchestrator.yaml)**: Main routing control plane +- **[central-orchestrator.yaml](.github/workflows/central-orchestrator.yaml)**: Main routing control plane - Callable reusable workflow invoked by entry workflows - Routes to specific validation and promotion workflows - Supports `workflow_call` from this repo and downstream repos @@ -16,7 +16,7 @@ - **[self-orchestrator.yaml](.github/workflows/self-orchestrator.yaml)**: Development entry point - This repository uses its own workflows during development - Acts as this repo's only direct PR/manual entry workflow - - Calls local `workflow-orchestrator.yaml` instead of published versions + - Calls local `central-orchestrator.yaml` instead of published versions - Enables testing workflow changes before release - **[config.yaml](.github/workflows/config.yaml)**: Centralised policy configuration @@ -86,7 +86,7 @@ ``` Downstream Repo Event ↓ -workflow_call: workflow-orchestrator.yaml@release ← Stable release tag +workflow_call: central-orchestrator.yaml@release ← Stable release tag ↓ route job reads resolved workflow inputs/defaults ↓ @@ -167,7 +167,7 @@ GitHub UI → Organisation Settings → Secrets and variables → Secrets • Add PYPI_TOKEN (PyPI publish token) # 2. Configure downstream caller workflow inputs -# Add package/repo identity values in .github/workflows/ci-orchestrator.yaml +# Add package/repo identity values in .github/workflows/orchestrator.yaml # Add optional branch/runtime/test-matrix overrides only where needed # 3. Configure rulesets @@ -182,7 +182,7 @@ GitHub UI → Organisation Settings → Rulesets ```bash # Copy repo_template/.github/workflows into the repository root, # then remove the outer `repo_template` folder so files end up under .github/workflows. -git add .github/workflows/ci-orchestrator.yaml .github/workflows/pre-install.sh +git add .github/workflows/orchestrator.yaml .github/workflows/pre-install.sh git commit -m "feat: add centralised CI/CD orchestrator" git push origin main @@ -251,7 +251,7 @@ GitHub UI → Repository Settings → Secrets and variables ## Support and Troubleshooting -- **Routing not working?** → Check [workflow-orchestrator.yaml](.github/workflows/workflow-orchestrator.yaml) branch conditions +- **Routing not working?** → Check [central-orchestrator.yaml](.github/workflows/central-orchestrator.yaml) branch conditions - **Check not appearing?** → Verify PR matches routing condition; check workflow syntax - **Merge blocked unexpectedly?** → Verify required check is passing; review [ORG_SETUP_GUIDE.md](docs/ORG_SETUP_GUIDE.md) ruleset config - **Secret not resolving?** → Confirm secret granted to repository in org settings @@ -274,7 +274,7 @@ GitHub UI → Repository Settings → Secrets and variables │ This Repository (workflows) │ │ Central Orchestrator & Testbed │ │ ┌─────────────────────────────────┐ │ -│ │ workflow-orchestrator.yaml │ │ ← Entry point (listens to all events) +│ │ central-orchestrator.yaml │ │ ← Entry point (listens to all events) │ └─────────────────────────────────┘ │ │ ┌─────────────────────────────────┐ │ │ │ config.yaml │ │ ← Config resolution (inputs → built-in defaults) @@ -288,13 +288,13 @@ GitHub UI → Repository Settings → Secrets and variables └─────────────────────────────────────┘ ↓ Uses: SETT-Centre-Data-and-AI/workflows - /.github/workflows/workflow-orchestrator.yaml@main + /.github/workflows/central-orchestrator.yaml@main ↓ ┌─────────────────────────────────────┐ │ Downstream Repos (many) │ │ ┌─────────────────────────────────┐ │ │ │ .github/workflows/ │ │ -│ │ ci-orchestrator.yaml │ │ ← Single file, calls central orchestrator +│ │ orchestrator.yaml │ │ ← Single file, calls central orchestrator │ └─────────────────────────────────┘ │ └─────────────────────────────────────┘ ``` diff --git a/README.md b/README.md index b5a062c..b8704a6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This repository is the orchestration control plane for adopter repositories: ## What Is Implemented -- Orchestrator entrypoint: [.github/workflows/workflow-orchestrator.yaml](.github/workflows/workflow-orchestrator.yaml) +- Orchestrator entrypoint: [.github/workflows/central-orchestrator.yaml](.github/workflows/central-orchestrator.yaml) - Centralised config contract: [.github/workflows/config.yaml](.github/workflows/config.yaml) - Policy workflow: [.github/workflows/ensure-release-source.yaml](.github/workflows/ensure-release-source.yaml) - Policy workflow: [.github/workflows/pre-release-version-check.yaml](.github/workflows/pre-release-version-check.yaml) @@ -35,7 +35,7 @@ This repository is the orchestration control plane for adopter repositories: 1. Keep this repository as the single source of orchestration logic. 2. In each external downstream repository, add one lightweight entry workflow that calls this repository via uses and @release. -3. Keep internal workflow repos (`workflows` and `workflows_development`) on local orchestrator calls (`uses: ./.github/workflows/workflow-orchestrator.yaml`) so CI always tests local workflow changes. +3. Keep internal workflow repos (`workflows` and `workflows_development`) on local orchestrator calls (`uses: ./.github/workflows/central-orchestrator.yaml`) so CI always tests local workflow changes. 4. Configure non-secret behaviour in the downstream caller workflow `with:` block (repo names, package names, optional overrides). 5. The orchestrator resolves configuration once via `config.yaml` and passes resolved values to routed workflows. 6. Keep optional matrix and pre-install customization in `.github/workflows` files alongside the caller workflow. diff --git a/docs/DEPLOYMENT_PATTERNS.md b/docs/DEPLOYMENT_PATTERNS.md index 39affdb..cda6fa6 100644 --- a/docs/DEPLOYMENT_PATTERNS.md +++ b/docs/DEPLOYMENT_PATTERNS.md @@ -17,9 +17,9 @@ Choose the pattern that matches the repository lifecycle and publication model. ### Setup -1. Copy [downstream-private-only-ci-orchestrator.yaml](examples/downstream-private-only-ci-orchestrator.yaml) to `.github/workflows/ci-orchestrator.yaml` +1. Copy [orchestrator.yaml](../../repo_template/.github/workflows/orchestrator.yaml) to `.github/workflows/orchestrator.yaml` -2. Edit `.github/workflows/ci-orchestrator.yaml` inputs: +2. Edit `.github/workflows/orchestrator.yaml` inputs: ``` private-repo: your-org/your-private-repo package-name: your_package @@ -69,9 +69,9 @@ Merge to release **Private Repository**: -1. Copy [downstream-private-to-public-ci-orchestrator.yaml](examples/downstream-private-to-public-ci-orchestrator.yaml) to `.github/workflows/ci-orchestrator.yaml` +1. Copy [orchestrator.yaml](../../repo_template/.github/workflows/orchestrator.yaml) to `.github/workflows/orchestrator.yaml` -2. Edit `.github/workflows/ci-orchestrator.yaml` inputs: +2. Edit `.github/workflows/orchestrator.yaml` inputs: ``` private-repo: your-org/your-private-repo public-repo: your-org/your-public-repo @@ -93,9 +93,9 @@ Merge to release **Public Repository**: -1. Copy [downstream-ci-orchestrator.yaml](examples/downstream-ci-orchestrator.yaml) to `.github/workflows/ci-orchestrator.yaml` +1. Copy [orchestrator.yaml](../../repo_template/.github/workflows/orchestrator.yaml) to `.github/workflows/orchestrator.yaml` -2. Edit `.github/workflows/ci-orchestrator.yaml` inputs: +2. Edit `.github/workflows/orchestrator.yaml` inputs: ``` public-repo: your-org/your-public-repo package-name: your_package @@ -135,7 +135,7 @@ public incoming PR ↓ (checks: ensure-release-source, pre-release-version-check pass) Merge to public release ↓ (auto) - └─ publish-to-pypi: build and upload to PyPI (if publish-on-release/PUBLISH_ON_RELEASE is true) + └─ publish-to-pypi: build and upload to PyPI (if publish-on-release/PUBLISH_ON_RELEASE is true; disabled by default, enable opt-in) ``` ## Pattern 3: Public-Only Repository @@ -152,9 +152,9 @@ Merge to public release ### Setup -1. Copy [downstream-ci-orchestrator.yaml](examples/downstream-ci-orchestrator.yaml) to `.github/workflows/ci-orchestrator.yaml` +1. Copy [orchestrator.yaml](../../repo_template/.github/workflows/orchestrator.yaml) to `.github/workflows/orchestrator.yaml` -2. Edit `.github/workflows/ci-orchestrator.yaml` inputs: +2. Edit `.github/workflows/orchestrator.yaml` inputs: ``` public-repo: your-org/your-public-repo package-name: your_package @@ -190,7 +190,7 @@ This pattern bypasses the private-to-public sync workflow. Use only when no priv **Starting with Pattern 1 → Pattern 2**: 1. Create a public repository (e.g., `your-org/your-package`) -2. In private repo `ci-orchestrator.yaml`, set `public-repo: your-org/your-package` +2. In private repo `orchestrator.yaml`, set `public-repo: your-org/your-package` 3. Seed public repo with initial commit 4. Grant `MANAGEMENT_TOKEN` in org secrets 5. Trigger manual `back-sync` and `sync-to-public` workflows @@ -205,7 +205,7 @@ This pattern bypasses the private-to-public sync workflow. Use only when no priv ## Caller Workflow Overrides -If a downstream repo needs custom behavior, set overrides in `.github/workflows/ci-orchestrator.yaml`: +If a downstream repo needs custom behavior, set overrides in `.github/workflows/orchestrator.yaml`: ``` # Example: Custom branch names @@ -226,7 +226,7 @@ Workflow inputs take precedence over built-in defaults. ### "Why isn't sync-to-public running?" -- Confirm `public-repo` input is set in `ci-orchestrator.yaml` +- Confirm `public-repo` input is set in `orchestrator.yaml` - Check `MANAGEMENT_TOKEN` is granted to both repos - Verify merge was to private release (not another branch) diff --git a/docs/ORG_SETUP_GUIDE.md b/docs/ORG_SETUP_GUIDE.md index 036d967..7b5b915 100644 --- a/docs/ORG_SETUP_GUIDE.md +++ b/docs/ORG_SETUP_GUIDE.md @@ -30,7 +30,7 @@ Create these organisation secrets with **selected repository access** (grant acc ## 2. Non-Secret Configuration Model -Non-secret configuration is declared in each downstream repository's `.github/workflows/ci-orchestrator.yaml` using `with:` inputs. +Non-secret configuration is declared in each downstream repository's `.github/workflows/orchestrator.yaml` using `with:` inputs. Required per repo: - `package-name` @@ -41,7 +41,7 @@ Optional per repo: - branch overrides - runtime version overrides - `test-matrix-json` inline matrix override -- `publish-on-release` toggle (`true`/`false`) +- `publish-on-release` toggle (`true`/`false`; defaults to `false`) Optional repo variable fallback: - `PUBLISH_ON_RELEASE=true|false` @@ -164,10 +164,10 @@ Each downstream repository adopting this orchestrator needs: ### Minimal Setup -1. **Add entry workflow**: Copy [docs/examples/downstream-ci-orchestrator.yaml](examples/downstream-ci-orchestrator.yaml) to `.github/workflows/ci-orchestrator.yaml` +1. **Add entry workflow**: Copy [orchestrator.yaml](../../repo_template/.github/workflows/orchestrator.yaml) to `.github/workflows/orchestrator.yaml` 2. **Set caller workflow inputs**: - - Configure `.github/workflows/ci-orchestrator.yaml` `with:` inputs + - Configure `.github/workflows/orchestrator.yaml` `with:` inputs - Set required package/repo identity values - Add optional `test-matrix-json` only if custom matrix is needed @@ -180,11 +180,11 @@ Each downstream repository adopting this orchestrator needs: ```bash # 1. Copy entry workflow mkdir -p .github/workflows -curl https://raw.githubusercontent.com/SETT-Centre-Data-and-AI/workflows/main/docs/examples/downstream-ci-orchestrator.yaml \ - > .github/workflows/ci-orchestrator.yaml +curl https://raw.githubusercontent.com/SETT-Centre-Data-and-AI/workflows/release/repo_template/.github/workflows/orchestrator.yaml \ + > .github/workflows/orchestrator.yaml # 2. Commit and push -git add .github/workflows/ci-orchestrator.yaml +git add .github/workflows/orchestrator.yaml git commit -m "feat: add centralised CI/CD orchestrator" git push origin main @@ -207,9 +207,9 @@ Same as private, plus: Before rolling out across the organisation: - [ ] Org secrets created: `MANAGEMENT_TOKEN`, `PYPI_TOKEN` -- [ ] Pilot repo workflow has required `with:` inputs set in `ci-orchestrator.yaml` +- [ ] Pilot repo workflow has required `with:` inputs set in `orchestrator.yaml` - [ ] Rulesets configured in at least one pilot repository -- [ ] Pilot repo has entry workflow calling `SETT-Centre-Data-and-AI/workflows/.github/workflows/workflow-orchestrator.yaml@main` +- [ ] Pilot repo has entry workflow calling `SETT-Centre-Data-and-AI/workflows/.github/workflows/central-orchestrator.yaml@main` - [ ] Manual test: PR to pilot repo main → build-and-test check runs - [ ] Manual test: PR to pilot repo release from non-main → ensure-release-source check fails - [ ] Manual test: PR to pilot repo release from main → ensure-release-source check passes @@ -221,7 +221,7 @@ Before rolling out across the organisation: **Symptom**: Ruleset requires a check, but it doesn't appear in PR. -**Cause**: Routing logic determined that the check should not run. Review [workflow-orchestrator.yaml](../.github/workflows/workflow-orchestrator.yaml) conditions. +**Cause**: Routing logic determined that the check should not run. Review [central-orchestrator.yaml](../.github/workflows/central-orchestrator.yaml) conditions. **Fix**: Verify PR matches conditions (e.g., PR to main for build-and-test, PR to release for release checks). @@ -250,4 +250,4 @@ If a workflow change breaks pipelines: - [Installation and setup](installation-guide.md) - [Usage and integration](usage-guide.md) -- [Orchestrator source](../.github/workflows/workflow-orchestrator.yaml) +- [Orchestrator source](../.github/workflows/central-orchestrator.yaml) diff --git a/docs/TESTBED.md b/docs/TESTBED.md index d7eaed1..a0cda59 100644 --- a/docs/TESTBED.md +++ b/docs/TESTBED.md @@ -213,7 +213,7 @@ Event: workflow_dispatch ### Check doesn't appear in PR -- Verify routing conditions in [workflow-orchestrator.yaml](./.github/workflows/workflow-orchestrator.yaml) +- Verify routing conditions in [central-orchestrator.yaml](./.github/workflows/central-orchestrator.yaml) - Check PR matches a routing condition (e.g., base branch name) - Check workflow file syntax is valid (no YAML errors) @@ -250,5 +250,5 @@ Use GitHub API or Actions artifacts to collect metrics over time. ## Further Reading -- [Orchestrator source](../.github/workflows/workflow-orchestrator.yaml) +- [Orchestrator source](../.github/workflows/central-orchestrator.yaml) - [Config contract](../.github/workflows/config.yaml) diff --git a/docs/installation-guide.md b/docs/installation-guide.md index 0660473..bde084a 100644 --- a/docs/installation-guide.md +++ b/docs/installation-guide.md @@ -29,7 +29,7 @@ Notes: ## 3. Configure Non-Secret Settings in Caller Workflow -Set non-secret configuration directly in each downstream repo's `.github/workflows/ci-orchestrator.yaml` using the `with:` block. +Set non-secret configuration directly in each downstream repo's `.github/workflows/orchestrator.yaml` using the `with:` block. Required values: - `package-name` diff --git a/docs/usage-guide.md b/docs/usage-guide.md index 5133732..d5290f9 100644 --- a/docs/usage-guide.md +++ b/docs/usage-guide.md @@ -15,7 +15,7 @@ Copy [repo_template/.github/workflows](../repo_template/.github/workflows) into Manual example: ```yaml -name: CI Orchestrator Entry +name: Orchestrator Entry on: pull_request: @@ -29,7 +29,7 @@ permissions: jobs: call-central-orchestrator: - uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/workflow-orchestrator.yaml@release + uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/central-orchestrator.yaml@release with: event-name: ${{ github.event_name }} event-action: ${{ github.event.action || '' }} @@ -59,7 +59,7 @@ jobs: ``` Important: -- Internal workflow repositories (`workflows` and `workflows_development`) must call local orchestrator path: `uses: ./.github/workflows/workflow-orchestrator.yaml`. +- Internal workflow repositories (`workflows` and `workflows_development`) must call local orchestrator path: `uses: ./.github/workflows/central-orchestrator.yaml`. - External downstream repositories should use `@release` to consume stable, tested centralised workflows. - Use `@main` only for controlled pre-release validation in external repositories. - Tag releases in this repository using semantic versioning. @@ -79,7 +79,7 @@ Run it from the Actions tab and provide `public_branch`. In the wrapper file, se ## Configuration Precedence -Configuration is resolved once in [workflow-orchestrator](../.github/workflows/workflow-orchestrator.yaml) via [config](../.github/workflows/config.yaml), then routed workflows receive resolved inputs directly. +Configuration is resolved once in [central-orchestrator](../.github/workflows/central-orchestrator.yaml) via [config](../.github/workflows/config.yaml), then routed workflows receive resolved inputs directly. The config workflow supports two layers: @@ -96,11 +96,11 @@ Secrets (sensitive): - `PYPI_TOKEN` for publish workflow. Non-secrets: -- Store directly in `.github/workflows/ci-orchestrator.yaml` under `with:`. +- Store directly in `.github/workflows/orchestrator.yaml` under `with:`. - Required: `package-name`, `package-slug`, and the applicable repo identity (`private-repo`, `public-repo`, or both). - Optional: branch names, runtime versions, and `test-matrix-json`. -- Optional publish toggle: `publish-on-release` (`true` or `false`). -- Equivalent repo variable fallback: `PUBLISH_ON_RELEASE=true|false`. +- Optional publish toggle: `publish-on-release` (`true` or `false`; defaults to `false`, opt-in to publish). +- Equivalent repo variable fallback: `PUBLISH_ON_RELEASE=true|false` (defaults to `false`). Matrix note: - `test-matrix-json` is inline JSON input. diff --git a/pyproject.toml b/pyproject.toml index e07bf0b..376d146 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "workflows" -version = "0.8.3" +version = "0.9.2" description = "Data & AI Unit centralised CI/CD workflows" authors = [{ name = "Cai Davis", email = "Cai.Davis@uhs.nhs.uk" }] license = "CC-BY-NC-4.0" diff --git a/repo_template/.github/workflows/README.md b/repo_template/.github/workflows/README.md index c097311..02df850 100644 --- a/repo_template/.github/workflows/README.md +++ b/repo_template/.github/workflows/README.md @@ -11,14 +11,14 @@ The path in this template is: After copying, remove the outer `repo_template` folder so the target repository contains: -`/.github/workflows/ci-orchestrator.yaml` +`/.github/workflows/orchestrator.yaml` `/.github/workflows/sync-from-public.yaml` `/.github/workflows/pre-install.sh` `/.github/workflows/README.md` What to edit: -- `ci-orchestrator.yaml` +- `orchestrator.yaml` - set `package-name` - set `package-slug` - set `private-repo` and/or `public-repo` diff --git a/repo_template/.github/workflows/ci-orchestrator.yaml b/repo_template/.github/workflows/ci-orchestrator.yaml index 898dabc..74355f9 100644 --- a/repo_template/.github/workflows/ci-orchestrator.yaml +++ b/repo_template/.github/workflows/ci-orchestrator.yaml @@ -16,7 +16,7 @@ permissions: jobs: call-central-orchestrator: - uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/workflow-orchestrator.yaml@release + uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/central-orchestrator.yaml@release with: event-name: ${{ github.event_name }} event-action: ${{ github.event.action || '' }} diff --git a/repo_template/.github/workflows/orchestrator.yaml b/repo_template/.github/workflows/orchestrator.yaml new file mode 100644 index 0000000..74355f9 --- /dev/null +++ b/repo_template/.github/workflows/orchestrator.yaml @@ -0,0 +1,55 @@ +name: CI Orchestrator Entry + +# Reminder: +# grant MANAGEMENT_TOKEN to repos that use sync workflows +# grant PYPI_TOKEN to public repos that publish to PyPI + +on: + pull_request: + branches: ['**'] + types: [opened, reopened, synchronize, closed] + workflow_dispatch: {} + +permissions: + contents: write + pull-requests: write + +jobs: + call-central-orchestrator: + uses: SETT-Centre-Data-and-AI/workflows/.github/workflows/central-orchestrator.yaml@release + with: + event-name: ${{ github.event_name }} + event-action: ${{ github.event.action || '' }} + base-ref: ${{ github.base_ref || '' }} + head-ref: ${{ github.head_ref || '' }} + ref-name: ${{ github.ref_name }} + repository: ${{ github.repository }} + pr-merged: ${{ github.event.pull_request.merged || false }} + + # Required identity values + package-name: your_package + package-slug: your-package + private-repo: your-org/your-private-repo + public-repo: your-org/your-public-repo + + # Optional branch overrides + # private-repo-main-branch: main + # private-repo-release-branch: release + # private-repo-incoming-branch: incoming_from_public + # public-repo-release-branch: release + # public-repo-incoming-branch: incoming_from_private + + # Optional runtime overrides + # build-smoke-python-version: '3.13' + # version-check-python-version: '3.12' + # publish-python-version: '3.13' + + # Optional: disable publish workflow on public release PR merges + # publish-on-release: 'false' + + # Optional: disable publish via repo variable fallback instead + # PUBLISH_ON_RELEASE=false + + # Optional matrix override (compact JSON on one line) + # test-matrix-json: '{"include":[{"os":"ubuntu-latest","python-version":"3.13"}]}' + secrets: inherit