mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
* chore(nix): streamline pnpm deps hash maintenance Generated-By: looper 0.9.0 (runner=worker, agent=opencode) * fix(ci): satisfy actionlint in nix hash autofix Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): allow nix hash autofix on fork PRs Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): follow up nix hash review Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): tolerate nix hash bot token failures Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)
205 lines
9 KiB
YAML
205 lines
9 KiB
YAML
name: nix-hash-autofix
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: [ci]
|
|
types: [completed]
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
autofix:
|
|
if: ${{ github.repository == 'nexu-io/open-design' && github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure' }}
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Check for Nix hash refresh artifact
|
|
id: artifact
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPO: ${{ github.repository }}
|
|
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
artifact_id="$(gh api "repos/$REPO/actions/runs/$RUN_ID/artifacts" --jq '.artifacts[] | select(.name == "nix-hash-refresh") | .id' | head -n 1 || true)"
|
|
if [ -z "$artifact_id" ]; then
|
|
echo "present=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
echo "present=true" >> "$GITHUB_OUTPUT"
|
|
echo "artifact_id=$artifact_id" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Download Nix hash refresh artifact
|
|
if: ${{ steps.artifact.outputs.present == 'true' }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPO: ${{ github.repository }}
|
|
ARTIFACT_ID: ${{ steps.artifact.outputs.artifact_id }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p "$RUNNER_TEMP/nix-hash-refresh"
|
|
gh api \
|
|
-H 'Accept: application/vnd.github+json' \
|
|
"repos/$REPO/actions/artifacts/$ARTIFACT_ID/zip" > "$RUNNER_TEMP/nix-hash-refresh.zip"
|
|
unzip -q "$RUNNER_TEMP/nix-hash-refresh.zip" -d "$RUNNER_TEMP/nix-hash-refresh"
|
|
|
|
- name: Read PR and patch metadata
|
|
if: ${{ steps.artifact.outputs.present == 'true' }}
|
|
id: meta
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPO: ${{ github.repository }}
|
|
WORKFLOW_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }}
|
|
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
status="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1], "r", encoding="utf-8")); print(data.get("status", "missing"))' "$RUNNER_TEMP/nix-hash-refresh/metadata.json")"
|
|
artifact_head_sha="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1], "r", encoding="utf-8")); print(data.get("headSha", ""))' "$RUNNER_TEMP/nix-hash-refresh/metadata.json")"
|
|
|
|
pr_number="$WORKFLOW_PR_NUMBER"
|
|
if [ -z "$pr_number" ]; then
|
|
pr_number="$(gh api "repos/$REPO/commits/$WORKFLOW_HEAD_SHA/pulls" --jq '.[0].number // empty')"
|
|
fi
|
|
if ! [[ "$pr_number" =~ ^[0-9]+$ ]]; then
|
|
echo "Unable to derive PR number for workflow head $WORKFLOW_HEAD_SHA." >&2
|
|
exit 1
|
|
fi
|
|
|
|
pr_json="$(gh api "repos/$REPO/pulls/$pr_number")"
|
|
head_repo="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["repo"]["full_name"])')"
|
|
head_ref="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["ref"])')"
|
|
head_sha="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["sha"])')"
|
|
{
|
|
echo "status=$status"
|
|
echo "artifact_head_sha=$artifact_head_sha"
|
|
echo "pr_number=$pr_number"
|
|
echo "head_repo=$head_repo"
|
|
echo "head_ref=$head_ref"
|
|
echo "head_sha=$head_sha"
|
|
} >> "$GITHUB_OUTPUT"
|
|
if [ -n "$artifact_head_sha" ] && [ "$artifact_head_sha" = "$head_sha" ]; then
|
|
echo "head_sha_matches=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "head_sha_matches=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
if [ "$head_repo" = "$REPO" ] && [ "$status" = "patch-generated" ] && [ "$artifact_head_sha" = "$head_sha" ]; then
|
|
echo "can_autopush=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "can_autopush=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Detect bot credentials
|
|
if: ${{ steps.meta.outputs.can_autopush == 'true' }}
|
|
id: bot-secrets
|
|
env:
|
|
BOT_APP_ID: ${{ secrets.BOT_APP_ID }}
|
|
BOT_APP_PRIVATE_KEY: ${{ secrets.BOT_APP_PRIVATE_KEY }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -n "${BOT_APP_ID}" ] && [ -n "${BOT_APP_PRIVATE_KEY}" ]; then
|
|
echo "present=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "present=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Generate Open Design bot token
|
|
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-secrets.outputs.present == 'true' }}
|
|
id: bot-token
|
|
continue-on-error: true
|
|
uses: actions/create-github-app-token@v2
|
|
with:
|
|
app-id: ${{ secrets.BOT_APP_ID }}
|
|
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}
|
|
owner: nexu-io
|
|
repositories: open-design
|
|
permission-contents: write
|
|
|
|
- name: Checkout PR branch for auto-apply
|
|
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' }}
|
|
uses: actions/checkout@v6.0.2
|
|
with:
|
|
repository: ${{ steps.meta.outputs.head_repo }}
|
|
ref: ${{ steps.meta.outputs.head_ref }}
|
|
token: ${{ steps.bot-token.outputs.token }}
|
|
|
|
- name: Apply generated hash patch
|
|
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' }}
|
|
id: apply
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
patch_path="$RUNNER_TEMP/nix-hash-refresh/nix-pnpm-deps.patch"
|
|
if [ ! -f "$patch_path" ]; then
|
|
echo "applied=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
git apply --check "$patch_path"
|
|
git apply "$patch_path"
|
|
changed_files="$(git diff --name-only)"
|
|
if [ "$changed_files" != "nix/pnpm-deps.nix" ]; then
|
|
echo "Unexpected files changed after applying hash patch:" >&2
|
|
printf '%s\n' "$changed_files" >&2
|
|
exit 1
|
|
fi
|
|
if git diff --quiet --exit-code; then
|
|
echo "applied=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "applied=true" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Commit and push generated hash refresh
|
|
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' && steps.apply.outputs.applied == 'true' }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name 'open-design-bot[bot]'
|
|
git config user.email '282769551+open-design-bot[bot]@users.noreply.github.com'
|
|
git add nix/pnpm-deps.nix
|
|
git commit -m 'chore(nix): refresh pnpm deps hash'
|
|
git push origin "HEAD:${{ steps.meta.outputs.head_ref }}"
|
|
|
|
- name: Upsert fork/manual patch comment
|
|
if: ${{ steps.artifact.outputs.present == 'true' && steps.meta.outputs.head_sha_matches == 'true' && (steps.meta.outputs.can_autopush != 'true' || steps.bot-token.outcome != 'success' || steps.apply.outputs.applied != 'true') }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPO: ${{ github.repository }}
|
|
PR_NUMBER: ${{ steps.meta.outputs.pr_number }}
|
|
HASH_REFRESH_STATUS: ${{ steps.meta.outputs.status }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
body_file="$RUNNER_TEMP/nix-hash-refresh-comment.md"
|
|
patch_file="$RUNNER_TEMP/nix-hash-refresh/nix-pnpm-deps.patch"
|
|
marker='<!-- nix-hash-refresh -->'
|
|
|
|
{
|
|
printf '%s\n' "$marker"
|
|
if [ "${HASH_REFRESH_STATUS}" = 'patch-generated' ]; then
|
|
printf "A generated Nix hash refresh is available for this PR.\n\n"
|
|
printf "Apply the patch from the \`nix-hash-refresh\` artifact attached to the failed \`ci\` run, or paste the diff below into \`git apply\`:\n\n"
|
|
printf '```diff\n'
|
|
if [ -f "$patch_file" ]; then
|
|
cat "$patch_file"
|
|
else
|
|
printf '(artifact did not include nix-pnpm-deps.patch)\n'
|
|
fi
|
|
printf '\n```\n'
|
|
else
|
|
printf "The failed \`ci\` run attempted to refresh \`nix/pnpm-deps.nix\`, but it could not produce a hash-only patch.\n\n"
|
|
printf "Download the \`nix-hash-refresh\` artifact from that run and inspect \`update.log\` for details.\n"
|
|
fi
|
|
} > "$body_file"
|
|
|
|
comment_id="$(gh api --paginate "repos/$REPO/issues/$PR_NUMBER/comments" --jq ".[] | select(.body | contains(\"$marker\")) | .id" | tail -n 1 || true)"
|
|
if [ -n "$comment_id" ]; then
|
|
gh api --method PATCH "repos/$REPO/issues/comments/$comment_id" --field body="$(cat "$body_file")" >/dev/null
|
|
else
|
|
gh api --method POST "repos/$REPO/issues/$PR_NUMBER/comments" --field body="$(cat "$body_file")" >/dev/null
|
|
fi
|