CI: add layered musl toolchain retrieval with cache-first and artifact fallback#216
Conversation
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/7e127b92-21f8-4257-ba2a-cd70a0944178 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/7e127b92-21f8-4257-ba2a-cd70a0944178 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8496a7e000
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if: startsWith(matrix.os, 'ubuntu-') && github.event_name != 'pull_request' && steps.musl-cache-bin.outputs.cache-hit != 'true' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: musl-i486-toolchain |
There was a problem hiding this comment.
Make musl backup artifact name unique per matrix job
Using a constant artifact name here will intermittently break non-PR CI runs when both Ubuntu matrix jobs execute this step: actions/upload-artifact@v4 does not support multiple jobs uploading the same artifact name in one workflow run and returns a 409 conflict. I checked the action's upstream docs (README section "(Not) Uploading to the same artifact"), which explicitly warns that matrix jobs must use distinct names. This means the first run after a cache-key bump/eviction can fail even though toolchain preparation succeeded.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR hardens the Ubuntu CI path that builds the static i486 musl binary by introducing a layered musl toolchain retrieval strategy to reduce cold-start time and avoid relying on a single upstream download URL.
Changes:
- Adds cache-first restoration for both an extracted musl toolchain directory and the musl toolchain archive.
- Adds a fallback path to download the toolchain archive from the latest non-expired workflow artifact when the upstream URL is unavailable.
- Grants
actions: readpermission and uploads the toolchain archive as a reusable backup artifact on non-PR runs.
| artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?name=musl-i486-toolchain&per_page=100" | ||
| artifact_json="${RUNNER_TEMP}/musl-i486-artifacts.json" | ||
| artifact_zip="${RUNNER_TEMP}/musl-i486-artifact.zip" | ||
| artifact_archive="${RUNNER_TEMP}/i486-linux-musl-cross.from-artifact.tgz" | ||
| artifact_download_url="" | ||
| if curl -fsSL \ | ||
| -H "Authorization: Bearer ${GITHUB_TOKEN}" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| "${artifact_api_url}" \ | ||
| -o "${artifact_json}"; then | ||
| artifact_download_url="$(python3 - "${artifact_json}" <<'PY' | ||
| import json | ||
| import sys | ||
|
|
||
| with open(sys.argv[1], "r", encoding="utf-8") as f: | ||
| payload = json.load(f) | ||
|
|
||
| artifacts = payload.get("artifacts", []) | ||
| artifacts = [a for a in artifacts if not a.get("expired")] | ||
| artifacts.sort(key=lambda a: a.get("created_at", ""), reverse=True) | ||
|
|
||
| if artifacts: | ||
| print(artifacts[0].get("archive_download_url", "")) |
| - name: Restore musl i486 extracted cache (Ubuntu) | ||
| id: musl-cache-bin | ||
| if: startsWith(matrix.os, 'ubuntu-') | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ${{ github.workspace }}/.musl-toolchain/i486-linux-musl-cross | ||
| key: musl-i486-bin-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 | ||
|
|
||
| - name: Restore musl i486 archive cache (Ubuntu) | ||
| id: musl-cache-archive | ||
| if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ${{ runner.temp }}/i486-linux-musl-cross.tgz | ||
| key: musl-i486-archive-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 | ||
|
|
||
| - name: Prepare musl.cc i486 toolchain (Ubuntu) | ||
| if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' |
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a7b953bac
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| fi | ||
| fi | ||
|
|
||
| if [ ! -s "${MUSL_ARCHIVE}" ]; then |
There was a problem hiding this comment.
Treat failed primary download as cache miss
If curl -fL fails after writing some bytes, curl can leave a partial output file unless --remove-on-error is used (see curl --manual for --remove-on-error). The fallback path is currently gated by if [ ! -s "${MUSL_ARCHIVE}" ], so a non-empty partial file skips artifact fallback and then fails at checksum verification, causing the job to fail even when a valid backup artifact exists.
Useful? React with 👍 / 👎.
| fi | ||
|
|
||
| if [ ! -s "${MUSL_ARCHIVE}" ]; then | ||
| artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?per_page=100" |
There was a problem hiding this comment.
Paginate or name-filter artifact fallback lookup
The artifact query uses .../actions/artifacts?per_page=100 and then filters client-side, which only inspects page 1. GitHub's artifacts API is paginated (max 100 per page), so once the repo has more than 100 newer artifacts, this lookup can miss an existing non-expired musl-i486-toolchain-* artifact and fail the fallback during upstream download outages.
Useful? React with 👍 / 👎.
This PR addresses the musl toolchain availability/performance gap in CI by introducing a multi-level retrieval path. Goal: prefer the fastest local hit path and avoid single-source failure when upstream download URLs become unavailable.
Retrieval strategy (fastest-first)
.musl-toolchain/...)$RUNNER_TEMP/i486-linux-musl-cross.tgz)musl-i486-toolchain)Integrity and failure handling
Workflow hardening
actions: readpermission for artifact API access.GITHUB_TOKEN: ${{ github.token }}).actions/upload-artifact@v4.