mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 03:38:23 +00:00
refactor(ci): fetch the diff baseline instead of mirroring main
The sync job force-pushed the source repository's main onto this one so that `origin/main` would mean "upstream main" for the three consumers that diff against it. Carrying .github/workflows/** in that push is what GitHub refuses for an App token, and `workflows` is not a GITHUB_TOKEN permission scope, so the job needed an app installation that may write workflow files. Run 37169357364 showed the fork has no such secret at all. Nothing reads the pushed branch. push_ci_policy.sh, affected_roles.sh and new_roles.sh each fetch `origin main` into their own runner's clone before reading it, and no caller queries the branch through the API. Pointing those fetches at the configured source repository gives the same baseline read-only: no push, no credential, no app permission to widen. baseline_remote.sh resolves where that baseline comes from and keeps the normalization and the disabled-value list in one place: `origin` for the source repository itself, for a disabled sync and for a local clone without GITHUB_REPOSITORY, and the upstream fetch URL otherwise. The fetches now carry an explicit `main:refs/remotes/origin/main` refspec, which a URL needs and a remote name tolerates. The release guard keeps fetching `origin`: it asks whether a tag commit sits on this repository's own main, which is a different question from the diff baseline. Removed: the sync-main job, its `needs` edge, main_from_repository.sh and the directory that held it. test_diff_affected_roles.py copies only the script under test into its fixture, so it needed the new helper too. It also inherited the full environment, and a GITHUB_REPOSITORY present in CI would have sent the fixture's baseline fetch to the real upstream instead of its own bare remote: three of its five cases fail that way, and the run takes 24s instead of 0.3s because it goes to the network. The variable is now dropped alongside BASH_ENV. Verified by running the helper in all four contexts and affected_roles.sh from an empty refs/remotes/origin/main in a scratch clone as the fork, as the source repository and locally; each populated the ref and completed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
a3e8587d93
commit
bf25eb2fc7
8 files changed
+35
-35
No files matched your search
@@ -19,28 +19,8 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync-main:
|
||||
name: 🔄 Sync main
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: ⬇️ Checkout repository
|
||||
uses: actions/checkout@v7.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🔄 Sync main from source repository
|
||||
shell: bash
|
||||
env:
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY_DEFAULT: infinito-nexus/core
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY: ${{ vars.CI_SYNC_MAIN_SOURCE_REPOSITORY }}
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY_IS_SET: ${{ contains(toJSON(vars), '"CI_SYNC_MAIN_SOURCE_REPOSITORY"') }}
|
||||
run: ./scripts/github/sync/main_from_repository.sh
|
||||
|
||||
run-policy:
|
||||
name: 🧭 Decide CI policy
|
||||
needs: sync-main
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -58,9 +38,13 @@ jobs:
|
||||
- name: ⬇️ Fetch main
|
||||
if: github.event.created == true
|
||||
shell: bash
|
||||
env:
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY_DEFAULT: infinito-nexus/core
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY: ${{ vars.CI_SYNC_MAIN_SOURCE_REPOSITORY }}
|
||||
CI_SYNC_MAIN_SOURCE_REPOSITORY_IS_SET: ${{ contains(toJSON(vars), '"CI_SYNC_MAIN_SOURCE_REPOSITORY"') }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch origin main:refs/remotes/origin/main --force
|
||||
git fetch "$(./scripts/meta/resolve/baseline_remote.sh)" main:refs/remotes/origin/main --force
|
||||
|
||||
- name: 🤔 Decide whether CI should run for this push
|
||||
id: decide
|
||||
|
||||
@@ -10,7 +10,6 @@ This directory holds the shell helpers that GitHub Actions workflows under [`.gi
|
||||
| [cancel/](cancel/) | Cancellation of in-progress workflow runs on PR-close and branch-delete events. |
|
||||
| [cleanup/](cleanup/) | Scheduled repository maintenance that prunes stale GitHub resources. |
|
||||
| [resolve/](resolve/) | Derivation of structured workflow inputs and outputs from repository state. |
|
||||
| [sync/](sync/) | Ref synchronization before workflow jobs derive CI scope from git history. |
|
||||
| [update/](update/) | The scheduled `🔄 Update versions` pipeline (version bumps and PR open/refresh). |
|
||||
| [release/](release/) | Release-time gates that decide whether a tagged commit may be released. |
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# GitHub Sync Helpers 🔄
|
||||
|
||||
This directory contains shell helpers that synchronize repository refs before later workflow jobs derive CI scope from git history.
|
||||
@@ -8,6 +8,7 @@ This directory contains scripts that resolve metadata and derived values used by
|
||||
|
||||
Examples in this folder and its subfolders:
|
||||
|
||||
- `baseline_remote.sh` resolves the remote whose main CI diffs against
|
||||
- `repository/name.sh` resolves the concrete repository name once for callers
|
||||
- `repository/owner.sh` resolves the concrete repository owner once for callers
|
||||
- See [pr/README.md](pr/README.md) for the Pull Request-specific resolvers.
|
||||
|
||||
+17
-6
@@ -1,7 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Output: the git remote carrying the upstream main that CI diffs against —
|
||||
# either the literal `origin` or a fetch URL, usable as
|
||||
# `git fetch "$(baseline_remote.sh)" main:refs/remotes/origin/main`.
|
||||
#
|
||||
# Env:
|
||||
# GITHUB_REPOSITORY - owner/repo of the running job; unset means a local clone
|
||||
# CI_SYNC_MAIN_SOURCE_REPOSITORY - upstream repository, a GitHub URL, or a disabled value
|
||||
# CI_SYNC_MAIN_SOURCE_REPOSITORY_IS_SET - "true" when the variable above is declared
|
||||
# CI_SYNC_MAIN_SOURCE_REPOSITORY_DEFAULT - fallback upstream (default: infinito-nexus/core)
|
||||
set -euo pipefail
|
||||
|
||||
: "${GITHUB_REPOSITORY:?Missing GITHUB_REPOSITORY}"
|
||||
if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
|
||||
echo origin
|
||||
exit 0
|
||||
fi
|
||||
|
||||
default_source="${CI_SYNC_MAIN_SOURCE_REPOSITORY_DEFAULT:-infinito-nexus/core}"
|
||||
configured_source="${CI_SYNC_MAIN_SOURCE_REPOSITORY:-}"
|
||||
@@ -18,7 +31,7 @@ source_lower="$(printf '%s' "${source_trimmed}" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
case "${source_lower}" in
|
||||
"" | "false" | "0" | "no" | "off" | "none")
|
||||
echo "Main sync skipped because CI_SYNC_MAIN_SOURCE_REPOSITORY is disabled."
|
||||
echo origin
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
@@ -37,7 +50,7 @@ target_repository="$(normalize_repository "${GITHUB_REPOSITORY}")"
|
||||
source_repository="$(normalize_repository "${source_trimmed}")"
|
||||
|
||||
if [[ "${source_repository}" == "${target_repository}" ]]; then
|
||||
echo "Main sync skipped because source repository matches current repository: ${GITHUB_REPOSITORY}."
|
||||
echo origin
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -46,6 +59,4 @@ if [[ "${source_repository}" != */* ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Syncing ${GITHUB_REPOSITORY}:main from ${source_repository}:main."
|
||||
git fetch "https://github.com/${source_repository}.git" main:refs/remotes/main-sync-source/main --force
|
||||
git push origin refs/remotes/main-sync-source/main:refs/heads/main --force
|
||||
echo "https://github.com/${source_repository}.git"
|
||||
@@ -55,8 +55,9 @@ emit_all() {
|
||||
exit 0
|
||||
}
|
||||
|
||||
git fetch --quiet --no-tags --prune --depth=50 origin main >/dev/null 2>&1 ||
|
||||
git fetch --quiet --no-tags --prune origin main
|
||||
baseline_remote="$(./scripts/meta/resolve/baseline_remote.sh)"
|
||||
git fetch --quiet --no-tags --depth=50 "${baseline_remote}" main:refs/remotes/origin/main --force >/dev/null 2>&1 ||
|
||||
git fetch --quiet --no-tags "${baseline_remote}" main:refs/remotes/origin/main --force
|
||||
|
||||
if base="$(git merge-base origin/main HEAD 2>/dev/null)"; then
|
||||
mapfile -t changed_paths < <(git diff --name-only "${base}" HEAD --)
|
||||
|
||||
@@ -8,7 +8,8 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
git fetch --quiet --no-tags --prune --depth=50 origin main >/dev/null 2>&1 ||
|
||||
git fetch --quiet --no-tags --prune origin main >/dev/null 2>&1 || true # nocheck: shell-or-true -- baseline fetch is best-effort; a missing origin/main means "no new roles" by contract
|
||||
baseline_remote="$(./scripts/meta/resolve/baseline_remote.sh)"
|
||||
git fetch --quiet --no-tags --depth=50 "${baseline_remote}" main:refs/remotes/origin/main --force >/dev/null 2>&1 ||
|
||||
git fetch --quiet --no-tags "${baseline_remote}" main:refs/remotes/origin/main --force >/dev/null 2>&1 || true # nocheck: shell-or-true -- baseline fetch is best-effort; a missing origin/main means "no new roles" by contract
|
||||
|
||||
"${PYTHON}" -m cli.meta.roles.applications.new_in_branch origin/main
|
||||
@@ -13,6 +13,7 @@ from . import PROJECT_ROOT
|
||||
|
||||
SCRIPT_REL = Path("scripts/meta/resolve/diff/affected_roles.sh")
|
||||
SCRIPT_PATH = PROJECT_ROOT / SCRIPT_REL
|
||||
BASELINE_REL = Path("scripts/meta/resolve/baseline_remote.sh")
|
||||
|
||||
ROLE_TASKS_MAIN_REL = f"roles/web-app-foo/{ROLE_FILE_TASKS_MAIN}"
|
||||
|
||||
@@ -57,6 +58,10 @@ class TestDiffAffectedRoles(unittest.TestCase):
|
||||
shutil.copy2(SCRIPT_PATH, script_target)
|
||||
script_target.chmod(0o755)
|
||||
|
||||
baseline_target = repo / BASELINE_REL
|
||||
shutil.copy2(PROJECT_ROOT / BASELINE_REL, baseline_target)
|
||||
baseline_target.chmod(0o755)
|
||||
|
||||
for rel, content in base_files.items():
|
||||
dest = repo / rel
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
@@ -92,6 +97,7 @@ class TestDiffAffectedRoles(unittest.TestCase):
|
||||
env["INFINITO_DISTRO"] = "test"
|
||||
env["PYTHON"] = str(fake_python)
|
||||
env.pop("BASH_ENV", None)
|
||||
env.pop("GITHUB_REPOSITORY", None)
|
||||
|
||||
return repo, env
|
||||
|
||||
|
||||
Reference in new issue
Block a user