mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 03:41:31 +00:00
fix: OFL workflow checkpoint and clear ordering
This commit is contained in:
@@ -12,9 +12,9 @@ name: Daily OFL OTA Update
|
|||||||
# vendor-dispatch path is also what makes post_merge_profiles.yml call the OTA auto-publish API after
|
# vendor-dispatch path is also what makes post_merge_profiles.yml call the OTA auto-publish API after
|
||||||
# uploading - see post_merge_profiles.yml for both sides of that contract.
|
# uploading - see post_merge_profiles.yml for both sides of that contract.
|
||||||
#
|
#
|
||||||
# At the start of each run, the pending-publish table is cleared up to a captured
|
# Each run captures a timestamp, dispatches the needed OFL publishers, waits for
|
||||||
# timestamp (POST /api/v1/ota/ofl/pending/clear?timestamp=...). Changes merged after
|
# all of them to finish, then clears the pending-publish table once. Changes merged
|
||||||
# that timestamp remain pending for the next run.
|
# after that timestamp remain pending for the next run.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -34,32 +34,14 @@ jobs:
|
|||||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' }}
|
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Capture start timestamp and clear OFL pending queue
|
- name: Capture start timestamp
|
||||||
id: start
|
id: start
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
|
||||||
OTA_API_BASE_URL: ${{ vars.OTA_API_BASE_URL }}
|
|
||||||
OTA_API_KEY: ${{ secrets.OFL_OTA_PUBLISH_KEY }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
[ -n "$OTA_API_BASE_URL" ] || { echo "::error::vars.OTA_API_BASE_URL is not set"; exit 1; }
|
|
||||||
[ -n "$OTA_API_KEY" ] || { echo "::error::secrets.OFL_OTA_PUBLISH_KEY is not set"; exit 1; }
|
|
||||||
|
|
||||||
timestamp="$(date -u +%s)"
|
timestamp="$(date -u +%s)"
|
||||||
echo "timestamp=$timestamp" >> "$GITHUB_OUTPUT"
|
echo "timestamp=$timestamp" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
resp_file="$RUNNER_TEMP/ota-pending-clear-response.json"
|
|
||||||
status="$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
|
||||||
"${OTA_API_BASE_URL%/}/api/v1/ota/ofl/pending/clear?timestamp=$timestamp" \
|
|
||||||
-H "Authorization: Bearer $OTA_API_KEY")"
|
|
||||||
body="$(cat "$resp_file")"
|
|
||||||
echo "$body"
|
|
||||||
|
|
||||||
if [ "$status" != "200" ]; then
|
|
||||||
echo "::error::OTA pending-clear call failed with HTTP $status"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
@@ -93,15 +75,17 @@ jobs:
|
|||||||
# by $branch would never match anything except main. post_merge_profiles.yml
|
# by $branch would never match anything except main. post_merge_profiles.yml
|
||||||
# genuinely runs per-branch (this dispatch below sets --ref "$branch"),
|
# genuinely runs per-branch (this dispatch below sets --ref "$branch"),
|
||||||
# so its history is the real per-branch checkpoint. It also means a
|
# so its history is the real per-branch checkpoint. It also means a
|
||||||
# failed publish naturally gets retried tomorrow: the checkpoint only
|
# failed publish naturally gets retried tomorrow. Only runs marked by
|
||||||
# advances on a run that actually succeeded.
|
# this cron count, so an unrelated successful manual run cannot advance
|
||||||
|
# the OFL checkpoint.
|
||||||
# --method GET is required, not cosmetic: gh api defaults to POST
|
# --method GET is required, not cosmetic: gh api defaults to POST
|
||||||
# whenever -f fields are present unless a method is given
|
# whenever -f fields are present unless a method is given
|
||||||
# explicitly, and POST on this list-runs endpoint 404s - confirmed
|
# explicitly, and POST on this list-runs endpoint 404s - confirmed
|
||||||
# on real Actions infrastructure, not just reasoned about.
|
# on real Actions infrastructure, not just reasoned about.
|
||||||
since="$(gh api --method GET "repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
successful_runs="$(gh api --method GET "repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
||||||
-f status=success -f branch="$branch" -f per_page=1 \
|
-f status=success -f branch="$branch" -f per_page=100 --paginate \
|
||||||
--jq '.workflow_runs[0].run_started_at // empty')"
|
--jq '.workflow_runs[] | select((.display_title // "") | contains("[OFL cron "))')"
|
||||||
|
since="$(jq -rs 'sort_by(.run_started_at) | last.run_started_at // empty' <<< "$successful_runs")"
|
||||||
|
|
||||||
if [ -z "$since" ]; then
|
if [ -z "$since" ]; then
|
||||||
echo "No prior successful run for $branch; checking OFL changes up to $SCAN_UNTIL."
|
echo "No prior successful run for $branch; checking OFL changes up to $SCAN_UNTIL."
|
||||||
@@ -124,16 +108,106 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$changed" = true ]; then
|
if [ "$changed" = true ]; then
|
||||||
# Tolerate a per-branch failure (e.g. a pre-existing release branch
|
dispatch_id="${GITHUB_RUN_ID}-${branch//\//-}"
|
||||||
# whose post_merge_profiles.yml predates the vendor/auto_publish
|
# Record successful dispatches for the barrier step below. A
|
||||||
# inputs) rather than aborting the whole scan under set -e.
|
# dispatch failure prevents clearing, so the branch is retried
|
||||||
if ! gh workflow run post_merge_profiles.yml \
|
# on the next cron run.
|
||||||
|
if gh workflow run post_merge_profiles.yml \
|
||||||
--repo "${{ github.repository }}" \
|
--repo "${{ github.repository }}" \
|
||||||
--ref "$branch" \
|
--ref "$branch" \
|
||||||
-f vendor="$VENDOR" -f auto_publish=true; then
|
-f vendor="$VENDOR" -f auto_publish=true \
|
||||||
echo "::warning::failed to dispatch post_merge_profiles.yml for $branch - its post_merge_profiles.yml at this ref may predate the vendor/auto_publish inputs"
|
-f ofl_cron_dispatch_id="$dispatch_id"; then
|
||||||
|
printf '%s\t%s\n' "$branch" "$dispatch_id" >> "$RUNNER_TEMP/ofl-dispatches.tsv"
|
||||||
|
else
|
||||||
|
echo "::error::failed to dispatch post_merge_profiles.yml for $branch"
|
||||||
|
printf '%s\n' "$branch" >> "$RUNNER_TEMP/ofl-dispatch-failures.txt"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
- name: Wait for OFL publishers
|
||||||
|
id: wait
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
DISPATCHES_FILE: ${{ runner.temp }}/ofl-dispatches.tsv
|
||||||
|
DISPATCH_FAILURES_FILE: ${{ runner.temp }}/ofl-dispatch-failures.txt
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -s "$DISPATCH_FAILURES_FILE" ]; then
|
||||||
|
echo "::error::one or more OFL publisher workflows could not be dispatched:"
|
||||||
|
sed 's/^/ - /' "$DISPATCH_FAILURES_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -s "$DISPATCHES_FILE" ]; then
|
||||||
|
echo "No OFL publisher workflows were dispatched; pending queue will not be cleared."
|
||||||
|
echo "publishers_dispatched=false" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
: > "$RUNNER_TEMP/ofl-run-ids.tsv"
|
||||||
|
while IFS=$'\t' read -r branch dispatch_id; do
|
||||||
|
[ -n "$branch" ] || continue
|
||||||
|
echo "Waiting for OFL publisher on $branch ($dispatch_id)"
|
||||||
|
|
||||||
|
run_id=""
|
||||||
|
for _ in {1..120}; do
|
||||||
|
runs_json="$(gh api --method GET \
|
||||||
|
"repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
||||||
|
-f branch="$branch" -f event=workflow_dispatch -f per_page=100)"
|
||||||
|
run_id="$(jq -r --arg marker "[OFL cron $dispatch_id]" \
|
||||||
|
'[.workflow_runs[] | select((.display_title // "") | contains($marker))] \
|
||||||
|
| sort_by(.created_at) | last | .id // empty' <<< "$runs_json")"
|
||||||
|
[ -n "$run_id" ] && break
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$run_id" ]; then
|
||||||
|
echo "::error::could not find dispatched post_merge_profiles run for $branch ($dispatch_id)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf '%s\t%s\n' "$branch" "$run_id" >> "$RUNNER_TEMP/ofl-run-ids.tsv"
|
||||||
|
done < "$DISPATCHES_FILE"
|
||||||
|
|
||||||
|
all_success=true
|
||||||
|
while IFS=$'\t' read -r branch run_id; do
|
||||||
|
[ -n "$run_id" ] || continue
|
||||||
|
echo "Watching OFL publisher run $run_id for $branch"
|
||||||
|
if ! gh run watch "$run_id" --repo "${{ github.repository }}" --exit-status; then
|
||||||
|
all_success=false
|
||||||
|
fi
|
||||||
|
done < "$RUNNER_TEMP/ofl-run-ids.tsv"
|
||||||
|
|
||||||
|
if [ "$all_success" != true ]; then
|
||||||
|
echo "::error::one or more OFL publisher workflows failed; pending queue will not be cleared"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "publishers_dispatched=true" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Clear OFL pending queue
|
||||||
|
if: steps.wait.outputs.publishers_dispatched == 'true'
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
OTA_API_BASE_URL: ${{ vars.OTA_API_BASE_URL }}
|
||||||
|
OTA_API_KEY: ${{ secrets.OFL_OTA_PUBLISH_KEY }}
|
||||||
|
TIMESTAMP: ${{ steps.start.outputs.timestamp }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
[ -n "$OTA_API_BASE_URL" ] || { echo "::error::vars.OTA_API_BASE_URL is not set"; exit 1; }
|
||||||
|
[ -n "$OTA_API_KEY" ] || { echo "::error::secrets.OFL_OTA_PUBLISH_KEY is not set"; exit 1; }
|
||||||
|
|
||||||
|
resp_file="$RUNNER_TEMP/ota-pending-clear-response.json"
|
||||||
|
status="$(curl -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
||||||
|
"${OTA_API_BASE_URL%/}/api/v1/ota/ofl/pending/clear?timestamp=$TIMESTAMP" \
|
||||||
|
-H "Authorization: Bearer $OTA_API_KEY")"
|
||||||
|
body="$(cat "$resp_file")"
|
||||||
|
echo "$body"
|
||||||
|
|
||||||
|
if [ "$status" != "200" ]; then
|
||||||
|
echo "::error::OTA pending-clear call failed with HTTP $status"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
name: Post-merge profiles
|
name: Post-merge profiles
|
||||||
|
|
||||||
|
run-name: >-
|
||||||
|
Post-merge profiles${{
|
||||||
|
inputs.ofl_cron_dispatch_id != '' &&
|
||||||
|
inputs.vendor == 'OrcaFilamentLibrary' &&
|
||||||
|
(inputs.auto_publish == true || inputs.auto_publish == 'true') &&
|
||||||
|
format(' [OFL cron {0}]', inputs.ofl_cron_dispatch_id) ||
|
||||||
|
''
|
||||||
|
}}
|
||||||
|
|
||||||
# Push-triggered counterpart to check_profiles.yml (which only gates PRs). When a
|
# Push-triggered counterpart to check_profiles.yml (which only gates PRs). When a
|
||||||
# profile change lands on main or a release branch, rebuild the affected vendors'
|
# profile change lands on main or a release branch, rebuild the affected vendors'
|
||||||
# binary preset caches (<vendor>.opc) and publish each as a versioned ZIP asset on
|
# binary preset caches (<vendor>.opc) and publish each as a versioned ZIP asset on
|
||||||
@@ -59,6 +68,12 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
ofl_cron_dispatch_id:
|
||||||
|
description: >-
|
||||||
|
Unique marker supplied by the trusted OFL daily cron so it can find
|
||||||
|
and wait for this dispatched workflow run.
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
Reference in New Issue
Block a user