Skip to content

ENH: Convert from Docker action to composite action with setup-pixi#23

Merged
hjmjohnson merged 3 commits intomainfrom
composite-action
Apr 10, 2026
Merged

ENH: Convert from Docker action to composite action with setup-pixi#23
hjmjohnson merged 3 commits intomainfrom
composite-action

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

Summary

Convert the clang-format linter from a Docker-based action (FROM ubuntu:18.04) to a composite action that runs directly on the GitHub Actions runner using prefix-dev/setup-pixi@v0.9.4.

Problems fixed

1. Docker Hub rate limiting (401/429)

The Dockerfile pulls ubuntu:18.04 (EOL since April 2023) from Docker Hub. GitHub Actions shared runners share IP pools and frequently hit Docker Hub's anonymous rate limits (100 pulls/6hrs), causing intermittent failures across all ~55 ITK remote modules.

2. Transient pixi download failures (HTTP 502)

The entrypoint.sh installs pixi via curl -fsSL https://pixi.sh/install.sh | bash which has no retry logic. Transient CDN failures (HTTP 502 Bad Gateway) cause the linter to fail even when the code is correctly formatted.

Solution

Replace with a composite action that:

  • Uses prefix-dev/setup-pixi@v0.9.4 for reliable pixi installation with built-in caching and retry
  • Uses curl --retry 3 --retry-delay 10 --retry-all-errors for ITK config file downloads
  • Runs directly on the runner — no Docker pull needed at all
  • Preserves the same inputs (error-message, itk-branch) and behavior

Before vs After

Docker action (current) Composite action (this PR)
Docker pull ubuntu:18.04 from Docker Hub None
pixi install curl | bash (no retry) setup-pixi@v0.9.4 (cached, retries)
File downloads wget (no retry) curl --retry 3
Runner compat Linux only Linux, macOS, Windows

Test plan

  • Test on a remote module PR by referencing @composite-action branch
  • Verify clang-format version matches ITK's .pre-commit-config.yaml
  • Verify formatting violations are correctly detected and reported

🤖 Generated with Claude Code

@hjmjohnson hjmjohnson marked this pull request as draft April 3, 2026 12:46
hjmjohnson added a commit to InsightSoftwareConsortium/ITKCuberille that referenced this pull request Apr 3, 2026
Point clang-format-linter at ITKClangFormatLinterAction@composite-action
to test the new composite action. Build workflows disabled.
No code changes - clang-format should pass.

See: InsightSoftwareConsortium/ITKClangFormatLinterAction#23
hjmjohnson added a commit to InsightSoftwareConsortium/ITKCuberille that referenced this pull request Apr 3, 2026
Add badly formatted code to test that the composite clang-format
linter correctly detects and reports style violations.

See: InsightSoftwareConsortium/ITKClangFormatLinterAction#23
@hjmjohnson
Copy link
Copy Markdown
Member Author

Validation Results

Tested the composite action on ITKCuberille with two WIP PRs:

Test 1: Clean code (expect PASS) — ITKCuberille#96

Result: PASSEDlint job

Version verification from logs:

Detected clang-format version: 19.1.7
pixi global install "clang-format==19.1.7"
clang-format location: /home/runner/.pixi/bin/clang-format
clang-format version 19.1.7 (conda-forge/clangdev-feedstock)
clang-format ITK Coding Style check completed successfully.

Test 2: Deliberate violation (expect FAIL) — ITKCuberille#97

Result: FAILEDlint job

The linter correctly detected the violation and reported:

clang-format version 19.1.7 (conda-forge/clangdev-feedstock)
::error::Code is inconsistent with ITK Coding Style.

Files:
include/itkCuberilleImageToMeshFilter.h

Changes:
-  int    deliberately_bad_format   =    42 ;
+int deliberately_bad_format = 42;

Verified behaviors

Behavior Status
Correct clang-format version (19.1.7 from ITK .pre-commit-config.yaml)
Version pinned with == via pixi global install
prefix-dev/setup-pixi@v0.9.4 installs pixi successfully
curl --retry used for all downloads
No Docker pull required
Clean code passes
Style violations detected and reported with file list + diff
Error annotation appears in GitHub UI (::error::)

Both WIP PRs will be closed after this review.

@hjmjohnson
Copy link
Copy Markdown
Member Author

Timing Comparison: Docker vs Composite Action

Measured on ITKCuberille using recent lint runs.

Docker action (current @main)

Run Docker Build Lint Total
23929699361 23s 3s 27s
23163109631 19s 6s 26s
23929698324 17s 3s 21s
Average 20s 4s 25s

Composite action (this PR)

Run Docker Build Lint Total
23946965792 (pass) N/A 3s 6s
23946978057 (fail) N/A 3s 6s
23946964100 (pass) N/A 3s 5s
Average 0s 3s 6s

Summary

Docker Composite
Total job time ~25s ~6s 4.4x faster
Docker build overhead ~20s 0s Eliminated
Lint execution ~4s ~3s Same

The ~20s Docker build step (FROM ubuntu:18.04 → apt-get install → copy entrypoint) runs on every invocation and is completely eliminated by the composite action. The actual clang-format check takes ~3s either way.

Additionally, when Docker Hub rate-limits the ubuntu:18.04 pull (which happens frequently on shared runners), the Docker action fails entirely after retries, wasting 30-60s before reporting the infrastructure error. The composite action eliminates this failure mode completely.

@hjmjohnson hjmjohnson marked this pull request as ready for review April 3, 2026 13:06
@hjmjohnson hjmjohnson requested review from Copilot and thewtex April 3, 2026 13:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the ITK clang-format linter GitHub Action from a Docker-based action to a composite action that runs directly on the GitHub Actions runner, aiming to avoid Docker Hub rate limits and make pixi installation more reliable via prefix-dev/setup-pixi.

Changes:

  • Replaced runs.using: docker with a composite action workflow of shell steps.
  • Added logic to determine the clang-format version from ITK’s .pre-commit-config.yaml and install it via pixi.
  • Switched ITK file/script downloads from wget to curl with retry behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@hjmjohnson
Copy link
Copy Markdown
Member Author

@thewtex I am trying to make the PRs for remote modules more robust and faster. Clang linting has been a common transient failure point. I asked claude-code to help identify more robust solutions. This PR is mostly the result of that effort.

It completely changes the approach, but I think I have demonstrated that it works the same.

● Prompts Used to Create and Test ITKClangFormatLinterAction PR #23

  Discovery and Problem Identification

  1. "review the .github ci behaviors for clang-format across all remote modules" — Surveyed all 55 modules' clang-format workflows, identified the
  @master (deleted branch) and ubuntu:18.04 Docker Hub rate limiting issues.
  2. "make a todo item with relevant context so that we may address it later, perhaps with caching of the downloaded docker image in github" —
  Documented the Docker Hub rate limiting problem as a memory item for future work.
  3. "identify the failure in FastBilateral" — Diagnosed the pixi HTTP 502 download failure, revealing the second reliability problem.
  4. "is there a common paradigm or github action that can deal with these transient download issues?" — Led to adding curl --retry to the v5.4.6
  workflows.
  5. "does github have an action for installing pixi?" — Discovered prefix-dev/setup-pixi@v0.9.4.

  PR Creation

  6. "create a PR for ITKClangFormatLinterAction to use the official GitHub Action" — Created PR #23, converting from Docker action to composite
  action using setup-pixi.

  Review and Improvement

  7. "Review PR 23 for ITKClangFormatLinterAction and determine if there are other improvements that could make this more robust" — Led to several
  fixes: run-install: false for setup-pixi, step outputs instead of env vars, simplified PATH handling, version verification step, consistent
  retry-delay, temp file cleanup, clearer step separation.
  8. "It is critical that the clang format version is pinned to the exact version specified in the itk-branch is that preserved?" — Verified the ==
  pin through both implementations and the double-check in clang-format.bash.
  9. "explain what is done in PR23 and how it differs from what was done previously" — Produced a detailed before/after comparison.

  Validation

  10. "Create 2 WIP PRs with Cuberille to verify that the new ITKClangFormatLinterAction code works as expected. One should introduce a clang-format
  error, the other should not." — Created Cuberille PRs #96 (pass) and #97 (fail), verified both behaved correctly, posted validation report with CI
  links proving clang-format 19.1.7 was used.

  Performance Analysis

  11. "can you report on the timing differences between previous ITKClangFormatLinterAction and PR23?" — Measured 4.4x speedup (25s → 6s), identified
  20s Docker build overhead eliminated.
  12. "report these findings to PR23" — Posted timing comparison with linked CI runs.


Replace the Docker-based action (FROM ubuntu:18.04) with a composite
action that runs directly on the GitHub Actions runner.

Problems fixed:
- Docker Hub rate limiting (401/429) pulling EOL ubuntu:18.04
- Transient pixi download failures (HTTP 502) from curl|bash

Implementation:
- prefix-dev/setup-pixi@v0.9.4 for reliable pixi installation with
  built-in caching (run-install: false, global install only)
- curl --retry 3 --retry-delay 30 for resilient downloads (without
  --retry-all-errors so 404 from invalid itk-branch fails fast)
- Step outputs for passing clang-format version between steps
- Version validation: empty/malformed version detection with clear
  error messages
- release-5.4/release branches: pip install clang-format==8.0.1
  (not available in conda-forge, available on PyPI)
- main/other branches: pixi global install with exact version from
  ITK .pre-commit-config.yaml

Tested on ITKCuberille:
- PR#96: clean code passed lint (clang-format 19.1.7 verified)
- PR#97: deliberate violation detected and reported correctly
- 4.4x faster than Docker action (6s vs 25s average)

The Dockerfile and entrypoint.sh are retained for reference but are
no longer used by action.yml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good on a glance. Someone else should review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Member

@thewtex thewtex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hjmjohnson fantastic! 🚀

hjmjohnson and others added 2 commits April 9, 2026 19:39
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add the pip scripts directory to $GITHUB_PATH after installing
clang-format via pip for release/release-5.4 branches. This ensures
the binary is discoverable by subsequent steps regardless of the
runner's default PATH configuration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@hjmjohnson
Copy link
Copy Markdown
Member Author

Re-validation After Addressing Review Comments

Tested the updated composite action (with pip PATH fix from commit cf3a9f1) on ITKCuberille:

Test 1: Clean code (expect PASS) — ITKCuberille#98

Result: PASSEDlint job

Detected clang-format version: 19.1.7
pixi global install "clang-format==19.1.7"
clang-format location: /home/runner/.pixi/bin/clang-format
clang-format version 19.1.7 (conda-forge/clangdev-feedstock)
clang-format ITK Coding Style check completed successfully.

Test 2: Deliberate violation (expect FAIL) — ITKCuberille#99

Result: FAILEDlint job

clang-format version 19.1.7 (conda-forge/clangdev-feedstock)
::error::Code is inconsistent with ITK Coding Style.

Files:
include/itkCuberilleImageToMeshFilter.h

Changes:
-int    deliberately_bad_format   =    42 ;
+int deliberately_bad_format = 42;

Review comment responses

Comment Status
pip PATH not set after install (Copilot) Fixed in cf3a9f1 — added sysconfig.get_path("scripts") to $GITHUB_PATH
::error :: extra space (Copilot) Already fixed in prior commit 4e7ed1e — current code uses correct ::error:: syntax

Both WIP PRs will be closed after this review.

@hjmjohnson hjmjohnson merged commit bab3a0b into main Apr 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants