Julia CI/CD #57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Julia CI/CD | |
| on: | |
| schedule: | |
| - cron: 0 0 * * * | |
| push: | |
| branches: ["main"] | |
| tags: ["*"] | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| action: | |
| description: "Action" | |
| required: true | |
| default: "test" | |
| type: choice | |
| options: | |
| - test | |
| - release | |
| version: | |
| description: "Tag and release version:" | |
| required: false | |
| permissions: | |
| actions: read | |
| checks: read | |
| contents: write | |
| deployments: read | |
| discussions: read | |
| issues: read | |
| packages: read | |
| pages: read | |
| pull-requests: write | |
| repository-projects: read | |
| security-events: read | |
| statuses: read | |
| # ⚙️ CENTRALIZED PATH MANAGEMENT | |
| # NOTE: paths live on /blue, which is mounted on the compute nodes where the | |
| # srun jobs run. The runner checks out to /privapps, which is NOT exported to | |
| # compute nodes, so the checkout is staged onto /blue before each srun. | |
| # | |
| # CACHING STRATEGY: | |
| # We use a global system image and depot cache keyed by the Manifest.toml hash. | |
| # To prevent race conditions when multiple runners build the same manifest | |
| # simultaneously, we build into temporary run-id-scoped paths and then | |
| # atomically move (promote) the results to the final shared location. | |
| env: | |
| HPC_SYSIMAGE_DIR: "/blue/fairbanksj/gha/sysimages" | |
| HPC_SHARED_WORK: "/blue/fairbanksj/gha/work" | |
| HPC_SCRIPT_DIR: ".github/scripts" | |
| jobs: | |
| CI: | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.action == 'test') | |
| runs-on: [self-hosted, hpc-gpu] | |
| steps: | |
| - name: "🗂️ Checkout Repository" | |
| uses: actions/checkout@v4 | |
| - name: "🔄 Resolve Dynamic Library Manifest" | |
| run: | | |
| echo "Resolving local environment against upstream package registries..." | |
| source /etc/profile.d/modules.sh | |
| module load julia | |
| julia --project=. -e 'using Pkg; Pkg.resolve()' | |
| - name: "🔑 Compute Cache Keys and Paths" | |
| id: cache-setup | |
| run: | | |
| set -x | |
| MANIFEST_HASH=$(sha256sum Manifest.toml | awk '{print $1}') | |
| SYSIMAGE_PATH="$HPC_SYSIMAGE_DIR/sysimage-${MANIFEST_HASH}.so" | |
| # Scope the depot only by manifest so all runners can share the same cache | |
| DEPOT_PATH="$HPC_SYSIMAGE_DIR/depots/$MANIFEST_HASH" | |
| echo "SYSIMAGE_PATH=$SYSIMAGE_PATH" >> $GITHUB_ENV | |
| echo "DEPOT_PATH=$DEPOT_PATH" >> $GITHUB_ENV | |
| - name: "🛠️ System Image Cache Validation" | |
| run: | | |
| set -x | |
| source /etc/profile.d/slurm.sh | |
| # Stage the checkout onto /blue so compute nodes can read it. | |
| WORK_SHARED="$HPC_SHARED_WORK/$GITHUB_RUN_ID" | |
| mkdir -p "$WORK_SHARED" | |
| rsync -a --delete "$GITHUB_WORKSPACE/" "$WORK_SHARED/" | |
| # A valid cache hit requires BOTH the binary system image AND the artifact depot | |
| if [ ! -f "$SYSIMAGE_PATH" ] || [ ! -d "$DEPOT_PATH" ]; then | |
| echo "❌ Cache Miss: System image or depot missing. Launching pre-compilation routine" | |
| # Use temporary paths to prevent race conditions between concurrent runners | |
| TEMP_DEPOT="$HPC_SYSIMAGE_DIR/depots/tmp_$GITHUB_RUN_ID" | |
| TEMP_SYSIMAGE="$HPC_SYSIMAGE_DIR/tmp_sysimage_$GITHUB_RUN_ID.so" | |
| mkdir -p "$HPC_SYSIMAGE_DIR/depots" | |
| srun --partition=hpg-dev \ | |
| --time=00:20:00 \ | |
| --cpus-per-task=8 \ | |
| --job-name="gha-sysimg-compile" \ | |
| bash -c " | |
| source /etc/profile.d/modules.sh | |
| module load julia | |
| export JULIA_DEPOT_PATH=$TEMP_DEPOT | |
| mkdir -p $TEMP_DEPOT | |
| cd $WORK_SHARED | |
| julia -e 'using Pkg; Pkg.add(\"PackageCompiler\")' | |
| julia --project=. $HPC_SCRIPT_DIR/compile_sysimage.jl '$TEMP_SYSIMAGE' | |
| " | |
| # Atomic Promotion: ensure the build is complete before exposing it to other runners | |
| echo "Promoting build to shared cache..." | |
| # SAFETY: Target must be a specific sub-path in the GHA depot directory | |
| # Must match: /blue/fairbanksj/gha/sysimages/depots/<hash> | |
| if [[ -n "$DEPOT_PATH" && "$DEPOT_PATH" =~ ^/blue/fairbanksj/gha/sysimages/depots/[a-f0-9]{64}$ ]]; then | |
| rm -rf "$DEPOT_PATH" | |
| else | |
| echo "❌ SAFETY ERROR: Path '$DEPOT_PATH' does not match the strict depot pattern. Aborting to protect /blue/fairbanksj/" && exit 1 | |
| fi | |
| mv "$TEMP_DEPOT" "$DEPOT_PATH" | |
| mv "$TEMP_SYSIMAGE" "$SYSIMAGE_PATH" | |
| else | |
| echo "✅ Cache Hit: Both optimized binary blob and artifact depot found" | |
| fi | |
| - name: "🚀 Execute Test Suite via Slurm" | |
| run: | | |
| set -x | |
| source /etc/profile.d/slurm.sh | |
| WORK_SHARED="$HPC_SHARED_WORK/$GITHUB_RUN_ID" | |
| echo "Launching parallelized validation payload..." | |
| srun --partition=hpg-dev \ | |
| --cpus-per-task=8 \ | |
| --job-name="gha-cluster-test" \ | |
| bash -c " | |
| source /etc/profile.d/modules.sh | |
| module load julia | |
| export JULIA_DEPOT_PATH=$DEPOT_PATH:\$SLURM_TMPDIR/.julia | |
| mkdir -p \$SLURM_TMPDIR/.julia | |
| cd $WORK_SHARED | |
| julia -J '$SYSIMAGE_PATH' --project=. -e 'using Pkg; Pkg.test()' | |
| " | |
| - name: "🧹 Clean Up Staged Workspace" | |
| if: always() | |
| run: | | |
| TARGET_CLEAN="$HPC_SHARED_WORK/$GITHUB_RUN_ID" | |
| # SAFETY: Target must be a specific run ID directory inside the GHA work directory | |
| # Must match: /blue/fairbanksj/gha/work/<run_id> | |
| if [[ -n "$TARGET_CLEAN" && "$TARGET_CLEAN" =~ ^/blue/fairbanksj/gha/work/[0-9]+$ ]]; then | |
| rm -rf "$TARGET_CLEAN" | |
| else | |
| echo "❌ SAFETY ERROR: Path '$TARGET_CLEAN' does not match the strict workspace pattern. Aborting to protect /blue/fairbanksj/" && exit 1 | |
| fi | |
| CompatHelper: | |
| if: github.event_name == 'schedule' | |
| uses: AlgebraicJulia/.github/.github/workflows/julia_compat.yml@main | |
| secrets: inherit | |
| Release: | |
| if: github.event_name == 'workflow_dispatch' && inputs.action == 'release' && inputs.version != '' | |
| uses: AlgebraicJulia/.github/.github/workflows/julia_release.yml@main | |
| secrets: inherit |