Skip to content

feat: extract build infrastructure into standalone scripts#227

Open
wdconinc wants to merge 19 commits intomasterfrom
copilot/extract-build-scripts
Open

feat: extract build infrastructure into standalone scripts#227
wdconinc wants to merge 19 commits intomasterfrom
copilot/extract-build-scripts

Conversation

@wdconinc
Copy link
Copy Markdown
Contributor

@wdconinc wdconinc commented Apr 6, 2026

Summary

Add build-base.sh and build-eic.sh as standalone scripts that encapsulate the full docker buildx build invocations previously embedded in .gitlab-ci.yml and .github/workflows/build-push.yml. These scripts are now the single source of truth for build logic — they are called by the CI and can be run directly by users for local builds.

Motivation

The .gitlab-ci.yml previously contained 130+ lines of inline docker buildx build commands with ~20–30 --build-arg flags each. This made local builds difficult because:

  • The embedded scripts couldn't be run directly
  • The docs/building-locally.md "Full Build Script" was missing ~15 --build-arg entries (SHAs, cherry-picks, duplicate allowlists, etc.)
  • Any change to build logic required updating both CI and docs separately

Changes

New files

  • build-base.sh — builds debian_stable_base, cuda_devel, cuda_runtime
  • build-eic.sh — builds any EIC environment (ci, xl, cuda, dbg, etc.)

CI/local mode detection

Scripts auto-detect their context via CI_REGISTRY:

Feature CI mode Local mode
Output --push --load
Build cache write --cache-to to CI registry omitted
Build cache read CI + ghcr.io registries public ghcr.io only
mirrors.yaml full template with credentials public-only, no credentials
Image tags INTERNAL_TAG, EXPORT_TAG --tag local

Local usage

# Build base image
bash build-base.sh --jobs 8

# Build EIC XL environment
bash build-eic.sh --env xl --jobs 8

# Build EIC CI environment (faster)
bash build-eic.sh --env ci

.gitlab-ci.yml

The base and eic job scripts are each reduced to two lines:

script:
  - apk add git
  - bash build-<x>.sh

All CI matrix variables (BUILD_IMAGE, ENV, BUILD_TYPE, etc.) flow through naturally as environment variables.

.github/workflows/build-push.yml

The base and eic jobs are reduced to, essentially:

      - name: Build and push
        env:
          BUILD_IMAGE: ${{ matrix.BUILD_IMAGE }}
          BASE_IMAGE: ${{ matrix.BASE_IMAGE }}
        run: bash build-base.sh

docs/building-locally.md

Replaced the incomplete inline script with references to build-base.sh and build-eic.sh, updated all examples and troubleshooting steps.

Copilot AI review requested due to automatic review settings April 6, 2026 18:31
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 extracts the long docker buildx build invocations from .gitlab-ci.yml into two standalone root-level scripts (build-base.sh, build-eic.sh) intended to be the single source of truth for both CI and local builds, and updates local build documentation to use these scripts.

Changes:

  • Add build-base.sh to build base images (Debian stable base and CUDA base/runtime).
  • Add build-eic.sh to build EIC environment images with CI/local mode behavior.
  • Update .gitlab-ci.yml and docs/building-locally.md to delegate build logic to the new scripts.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
build-base.sh New script encapsulating the base image docker buildx build logic.
build-eic.sh New script encapsulating the EIC environment image build logic (tagging, caching, secrets, mirrors).
.gitlab-ci.yml Replaces large inline build command blocks with calls to the new scripts.
docs/building-locally.md Updates local build instructions to use the new scripts and revises build-arg guidance.

build-eic.sh Outdated
Comment on lines +184 to +193
if [ -n "${CI_REGISTRY}" ]; then
build_cmd+=(--build-arg "DOCKER_REGISTRY=${CI_REGISTRY}/${CI_PROJECT_PATH}/")
build_cmd+=(--build-arg "INTERNAL_TAG=${INTERNAL_TAG}")
build_cmd+=(--build-arg "CI_COMMIT_SHA=${CI_COMMIT_SHA}")
build_cmd+=(--build-arg "EIC_CONTAINER_VERSION=${EXPORT_TAG}-${BUILD_TYPE}-$(git rev-parse HEAD)")
else
build_cmd+=(--build-arg "DOCKER_REGISTRY=ghcr.io/eic/")
build_cmd+=(--build-arg "INTERNAL_TAG=${LOCAL_BASE_TAG}")
build_cmd+=(--build-arg "EIC_CONTAINER_VERSION=local-${BUILD_TYPE}-$(git rev-parse HEAD 2>/dev/null || echo unknown)")
fi
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

In local mode the script sets DOCKER_REGISTRY=ghcr.io/eic/, but containers/eic/Dockerfile uses ${DOCKER_REGISTRY}${BUILDER_IMAGE}:${INTERNAL_TAG} for its FROM lines. With the current defaults this makes local builds pull ghcr.io/eic/debian_stable_base:local instead of using the locally-built debian_stable_base:local, which contradicts the docs and breaks the “build base locally then build eic on top” workflow. Consider defaulting DOCKER_REGISTRY to an empty string in local mode (and keeping ghcr.io only for cache sources), or providing an explicit flag/env var to choose the registry prefix.

Copilot uses AI. Check for mistakes.
Comment on lines 170 to +176
| Argument | Description | Default |
|----------|-------------|---------|
| `BASE_IMAGE` | Base Debian image | `debian:stable-slim` |
| `BASE_IMAGE` | Base Debian image | `debian:trixie-slim` |
| `SPACK_ORGREPO` | Spack GitHub org/repo | `spack/spack` |
| `SPACK_VERSION` | Spack version/branch | `develop` |
| `SPACK_VERSION` | Spack version/branch | (from `spack.sh`) |
| `SPACK_SHA` | Specific commit SHA | (resolved from version) |
| `SPACK_CHERRYPICKS` | Space-separated cherry-pick SHAs | |
| `SPACKPACKAGES_*` | Similar args for spack-packages | |
| `KEY4HEPSPACK_*` | Similar args for key4hep-spack | |
| `EICSPACK_*` | Similar args for eic-spack | |
| `SPACK_CHERRYPICKS` | Newline-separated cherry-pick SHAs | (from `spack.sh`) |
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

This table presents BASE_IMAGE’s default as debian:trixie-slim, but containers/debian/Dockerfile still defaults ARG BASE_IMAGE to amd64/debian:stable-slim. If the new scripts are the intended interface, consider clarifying that this is the scripts’ default (not the Dockerfile’s), or update the Dockerfile default to match to avoid confusing users who build the Dockerfile directly.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 6, 2026 19:57
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 4 out of 4 changed files in this pull request and generated 7 comments.

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 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines 182 to +190
### EIC Image (containers/eic/Dockerfile)

| Argument | Description | Default |
|----------|-------------|---------|
| `DOCKER_REGISTRY` | Registry prefix for base images | `eicweb/` |
| `DOCKER_REGISTRY` | Registry prefix for base images | `ghcr.io/eic/` |
| `BUILDER_IMAGE` | Builder base image name | `debian_stable_base` |
| `RUNTIME_IMAGE` | Runtime base image name | `debian_stable_base` |
| `INTERNAL_TAG` | Tag for base images | `master` |
| `ENV` | Environment type (`ci` or `xl`) | `xl` |
| `INTERNAL_TAG` | Tag for base images | `local` |
| `ENV` | Environment type | `xl` |
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This “EIC Image (containers/eic/Dockerfile)” table lists defaults like DOCKER_REGISTRY=ghcr.io/eic/ and INTERNAL_TAG=local, but containers/eic/Dockerfile currently defaults to DOCKER_REGISTRY="eicweb/" and INTERNAL_TAG="master". Either clarify that these are script defaults/overrides, or adjust the table to reflect the Dockerfile’s actual defaults to avoid confusion.

Copilot uses AI. Check for mistakes.
@wdconinc wdconinc force-pushed the copilot/extract-build-scripts branch from fafdb52 to 3ffa5ef Compare April 8, 2026 22:54
Copilot AI review requested due to automatic review settings April 8, 2026 23:38
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 5 out of 5 changed files in this pull request and generated 7 comments.

Comment on lines +216 to +220
else
build_cmd+=(--build-arg "DOCKER_REGISTRY=ghcr.io/eic/")
build_cmd+=(--build-arg "INTERNAL_TAG=${LOCAL_BASE_TAG}")
build_cmd+=(--build-arg "EIC_CONTAINER_VERSION=local-${BUILD_TYPE}-$(git rev-parse HEAD 2>/dev/null || echo unknown)")
fi
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

In local mode the script sets DOCKER_REGISTRY=ghcr.io/eic/ and INTERNAL_TAG=local, which makes the Dockerfile pull base images like ghcr.io/eic/debian_stable_base:local instead of using the locally-built debian_stable_base:local. This conflicts with the documented local workflow (build base locally, then build EIC on top). Consider defaulting DOCKER_REGISTRY to an empty prefix in local mode (or making it user-configurable) so FROM ${BUILDER_IMAGE}:${INTERNAL_TAG} resolves to the local daemon image by default.

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +249
## Secrets
build_cmd+=(--secret "id=mirrors,src=${SCRIPT_DIR}/mirrors.yaml")
if [ "${CI_MODE}" = "gitlab" ]; then
build_cmd+=(--secret "type=env,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER")
build_cmd+=(--secret "type=env,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD")
build_cmd+=(--secret "type=env,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER")
build_cmd+=(--secret "type=env,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN")
elif [ "${CI_MODE}" = "github" ]; then
build_cmd+=(--secret "type=env,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER")
build_cmd+=(--secret "type=env,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD")
build_cmd+=(--secret "type=env,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER")
build_cmd+=(--secret "type=env,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN")
fi
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Local mode does not pass the CI_REGISTRY_USER/CI_REGISTRY_PASSWORD/GITHUB_REGISTRY_USER/GITHUB_REGISTRY_TOKEN secrets, but containers/eic/Dockerfile unconditionally uses --mount=type=secret,id=... for these IDs in multiple RUN steps. Without providing these secrets (or marking the mounts as optional), local builds will fail with “secret not found”. Either always provide dummy/empty secrets in local mode, or update the Dockerfile secret mounts to required=false so local builds work without credentials.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +41
# Build the full XL environment (uses debian_stable_base:local as base)
bash build-eic.sh --env xl --jobs 8
```

This produces a local image tagged `eic_xl:local`.

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This example states build-eic.sh uses debian_stable_base:local as the base, but build-eic.sh currently sets DOCKER_REGISTRY=ghcr.io/eic/ in local mode, which would instead try to pull ghcr.io/eic/debian_stable_base:local. Update either the script (preferred) or this documentation so local users don’t hit a confusing pull failure.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 9, 2026 00:09
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 11 out of 11 changed files in this pull request and generated 6 comments.

Comment on lines +186 to +190
| `DOCKER_REGISTRY` | Registry prefix for base images | `ghcr.io/eic/` |
| `BUILDER_IMAGE` | Builder base image name | `debian_stable_base` |
| `RUNTIME_IMAGE` | Runtime base image name | `debian_stable_base` |
| `INTERNAL_TAG` | Tag for base images | `master` |
| `ENV` | Environment type (`ci` or `xl`) | `xl` |
| `INTERNAL_TAG` | Tag for base images | `local` |
| `ENV` | Environment type | `xl` |
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Docs table lists DOCKER_REGISTRY default as ghcr.io/eic/ and INTERNAL_TAG as local, but containers/eic/Dockerfile defaults are eicweb/ and master. Please either update the table to reflect the Dockerfile defaults or clarify that these are the defaults used by build-eic.sh for local builds.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 9, 2026 14:44
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 11 out of 11 changed files in this pull request and generated 5 comments.

Comment on lines +164 to +167
DIGEST=$(jq -r '."containerimage.digest"' /tmp/build-metadata.json)
IMAGE="${{ env.GH_REGISTRY }}/${{ env.GH_REGISTRY_USER }}/${{ matrix.BUILD_IMAGE }}"
mkdir -p /tmp/digests
echo "${{ steps.meta.outputs.tags }}@${{ steps.build.outputs.digest }}" > /tmp/digests/${{ matrix.BUILD_IMAGE }}-${{ matrix.arch }}.digest
echo "${IMAGE}@${DIGEST}" > /tmp/digests/${{ matrix.BUILD_IMAGE }}-${{ matrix.arch }}.digest
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The digest artifact written here is IMAGE@DIGEST without a tag. The later base-manifest job’s “Analyze digest artifacts” step parses the first digest assuming image:tag@digest (splits on :) to recover the image name/tag, so it will mis-parse (image name ends up including @sha...) and break manifest/tag creation. Either include a tag in the digest file format or update the manifest job to parse image@digest correctly (e.g., strip @... and derive image name from the matrix).

Copilot uses AI. Check for mistakes.
Comment on lines +425 to +428
DIGEST=$(jq -r '."containerimage.digest"' /tmp/build-metadata.json)
IMAGE="${{ env.GH_REGISTRY }}/${{ env.GH_REGISTRY_USER }}/${{ matrix.BUILD_IMAGE }}${{ matrix.ENV }}"
mkdir -p /tmp/digests
echo "${{ steps.meta.outputs.tags }}@${{ steps.build.outputs.digest }}" > /tmp/digests/${{ matrix.arch }}.digest
echo "${IMAGE}@${DIGEST}" > /tmp/digests/${{ matrix.arch }}.digest
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Same issue as the base job: this writes digest artifacts as IMAGE@DIGEST (no :tag), but the later eic-manifest job’s digest analysis expects image:tag@digest and will mis-parse the image name, breaking metadata/tagging. Align the digest file format with what the manifest job expects, or update the manifest job’s parsing logic accordingly.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 9, 2026 14:56
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 11 out of 11 changed files in this pull request and generated 1 comment.

Comment on lines 33 to +40
### Building the EIC Image

```bash
# Build the full XL environment
docker buildx build \
-f containers/eic/Dockerfile \
--build-context spack-environment=spack-environment \
--build-arg DOCKER_REGISTRY=ghcr.io/eic/ \
--build-arg BUILDER_IMAGE=debian_stable_base \
--build-arg RUNTIME_IMAGE=debian_stable_base \
--build-arg INTERNAL_TAG=latest \
--build-arg ENV=xl \
-t eic_xl:local \
containers/eic
# Build the full XL environment (uses debian_stable_base:local as base)
bash build-eic.sh --env xl --jobs 8
```

This produces a local image tagged `eic_xl:local`.
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The Quick Start says build-eic.sh “uses debian_stable_base:local as base”, but build-eic.sh currently sets DOCKER_REGISTRY=ghcr.io/eic/ in local mode and defaults --base-tag to local, which would instead reference ghcr.io/eic/debian_stable_base:local. Either adjust the script to use locally-built base images by default, or update these docs (and the default base tag) to reflect that local builds pull a published base tag (e.g. latest).

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 9, 2026 15:03
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 11 out of 11 changed files in this pull request and generated 4 comments.

Comment on lines +40 to +43
BUILD_TARGET="${BUILD_TARGET:-final}"
PLATFORM="${PLATFORM:-linux/amd64}"
JOBS="${JOBS:-$(nproc)}"
LOCAL_TAG="${LOCAL_TAG:-local}"
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

JOBS defaults to $(nproc), but nproc is not available on some local build hosts (notably macOS) and may be absent in minimal shells. Consider a portable fallback (e.g., getconf _NPROCESSORS_ONLN / sysctl -n hw.ncpu) or a default value when nproc is unavailable, to keep local builds working out-of-the-box.

Copilot uses AI. Check for mistakes.
Comment on lines +83 to +101
## Generate mirrors.yaml from template or create a public-only version.
## Uses sed rather than envsubst to avoid a runtime dependency on gettext.
if [ "${CI_MODE}" != "local" ]; then
## CI mode: expand CI_REGISTRY/CI_PROJECT_PATH variables in the template
sed -e "s|\${CI_REGISTRY}|${CI_REGISTRY}|g" \
-e "s|\${CI_PROJECT_PATH}|${CI_PROJECT_PATH}|g" \
-e "s|\${SPACKPACKAGES_VERSION}|${SPACKPACKAGES_VERSION}|g" \
"${SCRIPT_DIR}/mirrors.yaml.in" > "${SCRIPT_DIR}/mirrors.yaml"
else
## Local mode: public-only mirrors (no credentials required)
cat > "${SCRIPT_DIR}/mirrors.yaml" <<EOF
mirrors:
ghcr:
url: oci://ghcr.io/eic/spack-${SPACKPACKAGES_VERSION}
signed: false
spack:
url: https://binaries.spack.io/v1.0
signed: false
EOF
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The script writes ${SCRIPT_DIR}/mirrors.yaml during runs, but .gitignore doesn’t ignore mirrors.yaml, so local builds will leave an untracked file in the repo root. Consider writing this to a temp file (e.g., under ${TMPDIR:-/tmp}) and cleaning it up via trap, or add mirrors.yaml to .gitignore if keeping it in-tree is intentional.

Copilot uses AI. Check for mistakes.
language: system
types: [shell]
args: [--severity=warning, -x]
files: ^[^/]+\.sh$
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The files: ^[^/]+\.sh$ filter means this hook will only run on root-level *.sh files. Shell scripts without a .sh extension (e.g. .ci/resolve_git_ref) and scripts in subdirectories won’t be checked by ShellCheck. If the goal is to lint all shell scripts in the repo, widen the file pattern (or add additional hooks/patterns).

Suggested change
files: ^[^/]+\.sh$

Copilot uses AI. Check for mistakes.
Comment on lines 186 to +192
| Argument | Description | Default |
|----------|-------------|---------|
| `DOCKER_REGISTRY` | Registry prefix for base images | `eicweb/` |
| `DOCKER_REGISTRY` | Registry prefix for base images | `ghcr.io/eic/` |
| `BUILDER_IMAGE` | Builder base image name | `debian_stable_base` |
| `RUNTIME_IMAGE` | Runtime base image name | `debian_stable_base` |
| `INTERNAL_TAG` | Tag for base images | `master` |
| `ENV` | Environment type (`ci` or `xl`) | `xl` |
| `INTERNAL_TAG` | Tag for base images | `local` |
| `ENV` | Environment type | `xl` |
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

This table lists DOCKER_REGISTRY default as ghcr.io/eic/ and INTERNAL_TAG default as local, but containers/eic/Dockerfile currently defaults to DOCKER_REGISTRY="eicweb/" and INTERNAL_TAG="master". Either update the docs to reflect the Dockerfile defaults, or explicitly call out that these are the defaults used by build-eic.sh (not the Dockerfile’s ARG defaults).

Copilot uses AI. Check for mistakes.
wdconinc and others added 5 commits April 9, 2026 13:09
Add build-base.sh and build-eic.sh as standalone scripts that
encapsulate the full docker buildx build invocations previously
embedded in .gitlab-ci.yml. These scripts are now the single
source of truth for build logic and are called by the CI as well
as being directly usable by developers for local builds.

Key features:
- Auto-detect CI vs local mode via CI_REGISTRY env var
- CI mode: --push, --cache-to, full tag logic, credential mirrors
- Local mode: --load, public-only mirrors (no credentials needed)
- Use sed instead of envsubst for mirrors.yaml.in expansion
- All CI matrix variables (BUILD_IMAGE, ENV, BUILD_TYPE, etc.)
  flow through naturally as environment variables
- Safe quoting of multi-line SPACK_CHERRYPICKS via bash arrays

Also update docs/building-locally.md to reference the new scripts
and remove the incomplete inline build script that was missing
~15 --build-arg entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Wouter Deconinck <wdconinc@gmail.com>
Co-authored-by: Wouter Deconinck <wdconinc@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
wdconinc and others added 11 commits April 9, 2026 13:11
- Remove inline version-loading, mirrors.yaml, Docker meta, and
  docker/build-push-action steps from both base and eic jobs
- Add GitHub Actions CI mode (CI_MODE=github) to build-base.sh and
  build-eic.sh: slug-var mapping, push-by-digest output, metadata-file
- Add --target/BUILD_TARGET option to build-eic.sh
- Drop SPACK_DUPLICATE_ALLOWLIST from eic matrix (computed by script)
- Digest extraction now reads from --metadata-file JSON via jq

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- build-base.sh, build-eic.sh: use push-by-digest + --metadata-file
  in all CI modes (gitlab and github alike), removing the gitlab-only
  --push + --tag path
- After the build, read the digest and call 'docker buildx imagetools
  create' to apply INTERNAL_TAG / EXPORT_TAG / NIGHTLY_TAG in GitLab
  CI (GitHub Actions manifest jobs continue to handle tagging there)
- .gitlab-ci.yml: add jq and bash to apk installs so the scripts can
  parse the metadata file and run properly
- build-push.yml: drop env vars already available at the workflow level
  (GH_REGISTRY, GH_PUSH, JOBS, INTERNAL_TAG, etc.) from the step-level
  env blocks; keep only matrix variables, secrets, and METADATA_FILE;
  also remove the now-unused 'Load NVIDIA' step from the base job

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Only SPACKPACKAGES_VERSION (from spack-packages.sh) is needed to fill
mirrors.yaml.in. spack.sh, key4hep-spack.sh, and eic-spack.sh export
variables that build-eic.sh never reads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In the GitHub CI_MODE block, alias CI_REGISTRY and CI_PROJECT_PATH from
GH_REGISTRY/GH_REGISTRY_USER.  After that block, derive a single
CI_REGISTRY_PREFIX (= CI_REGISTRY/CI_PROJECT_PATH) and use it uniformly
throughout each script.

Changes:
- IMAGE_REPO: replace if gitlab/elif github with CI_REGISTRY_PREFIX
- Cache sources: replace four scattered if-blocks with a BUILDCACHE_REPOS
  loop (CI_REGISTRY_PREFIX when in CI, plus public ghcr.io/eic for
  GitLab and local modes)
- Cache destination: collapse if gitlab/elif github to if != local
- mirrors.yaml (build-eic.sh): collapse if gitlab/elif github to if != local
- DOCKER_REGISTRY build-arg (build-eic.sh): collapse if gitlab/elif github
  to if != local; keep EIC_CONTAINER_VERSION in separate branches because
  its format is intentionally different per CI system
- Secrets block (build-eic.sh): collapse identical gitlab/github branches
  to a single if != local block

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add .pre-commit-config.yaml with a local shellcheck hook that runs on
all .sh files in the repository root (files: ^[^/]+\.sh$) at warning
severity.  The hook uses the system shellcheck installation (-x to
follow sourced files).

To fix pre-existing shellcheck findings in the root scripts:
- spack.sh, spack-packages.sh, eic-spack.sh, key4hep-spack.sh: add
  '# shellcheck shell=bash' (SC2148 - no shebang in sourced files) and
  '# shellcheck disable=SC2034' (SC2034 - variables are used by the
  scripts that source these files, not within them)
- install.sh: replace $* with "$@" (SC2048 - word splitting bug)
- build-base.sh: remove unused CI_COMMIT_SHA from the GitHub CI_MODE
  block (SC2034; the variable is only consumed in build-eic.sh)
- build-base.sh, build-eic.sh: add '# shellcheck disable=SC2206'
  before the BUILD_OPTIONS expansion (word splitting is intentional)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@wdconinc wdconinc force-pushed the copilot/extract-build-scripts branch from ed4dcd1 to 3f0fdb0 Compare April 9, 2026 18:14
rlespinasse/github-slug-action writes slug values to $GITHUB_ENV
using Windows-style CRLF line endings. On Linux runners the \r is
preserved when the variable is read back, producing cache ref strings
like `...-amd64\r` that fail docker buildx with 'invalid reference
format'.

Strip any trailing \r via ${VAR//$'\r'/} before using the slug
values as cache-from/cache-to ref components in build-base.sh and
build-eic.sh.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 9, 2026 18:45
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 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +197 to +201
build_cmd+=(--build-arg "CI_COMMIT_SHA=${CI_COMMIT_SHA}")
else
build_cmd+=(--build-arg "DOCKER_REGISTRY=ghcr.io/eic/")
build_cmd+=(--build-arg "INTERNAL_TAG=${LOCAL_BASE_TAG}")
fi
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

In local mode the script sets DOCKER_REGISTRY=ghcr.io/eic/ and INTERNAL_TAG=${LOCAL_BASE_TAG}. With the default LOCAL_BASE_TAG=local, this makes the Dockerfile base images resolve to ghcr.io/eic/<base>:local instead of the locally-built debian_stable_base:local produced by build-base.sh, which will typically fail (no such tag on ghcr) and also contradicts the local-build docs. Consider using an empty DOCKER_REGISTRY in local mode (or deriving it from an env var) so local builds consume local base images by default.

Copilot uses AI. Check for mistakes.
wdconinc and others added 2 commits April 9, 2026 13:58
Remove the rlespinasse/github-slug-action@v5 dependency from both
the base and eic CI jobs.  The action was the only source of
GITHUB_REF_POINT_SLUG / GITHUB_BASE_REF_SLUG and was causing `\r`
corruption in OCI registry refs (CRLF written to $GITHUB_ENV on
Linux runners).

Replace with an inline `slugify()` shell function in build-base.sh
and build-eic.sh that mirrors GitLab's built-in CI_COMMIT_REF_SLUG
behaviour:
  - lowercase
  - replace runs of non-alphanumeric chars with '-'
  - strip leading/trailing '-'
  - truncate to 63 chars

The function is called with GITHUB_REF_NAME (current branch, always
set by the runner) and GITHUB_BASE_REF (PR target branch, empty for
direct pushes → defaults to 'master').  No extra workflow step needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
build-eic.sh had three lines with CRLF endings (lines 144-146, the
ARCH normalisation block).  In bash, a script line of the form

  ARCH=$(command)\r

treats the \r as a literal character appended to the command-
substitution result, because bash does not strip CR from the value;
$(…) only strips trailing newlines.  This produced ARCH='amd64\r'
which was then embedded in the OCI registry cache ref, causing:

  ERROR: invalid reference format

Fix: strip CRLF from build-eic.sh (sed -i 's/\r//').  Also add a
.gitattributes file that enforces LF line endings for all text files
going forward, preventing a recurrence.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 10, 2026 00:01
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 6 out of 6 changed files in this pull request and generated 2 comments.

Comment on lines 184 to +193
### EIC Image (containers/eic/Dockerfile)

| Argument | Description | Default |
|----------|-------------|---------|
| `DOCKER_REGISTRY` | Registry prefix for base images | `eicweb/` |
| `DOCKER_REGISTRY` | Registry prefix for base images | `ghcr.io/eic/` |
| `BUILDER_IMAGE` | Builder base image name | `debian_stable_base` |
| `RUNTIME_IMAGE` | Runtime base image name | `debian_stable_base` |
| `INTERNAL_TAG` | Tag for base images | `master` |
| `ENV` | Environment type (`ci` or `xl`) | `xl` |
| `INTERNAL_TAG` | Tag for base images | `local` |
| `ENV` | Environment type | `xl` |
| `SPACK_DUPLICATE_ALLOWLIST` | Pipe-separated allowed duplicates | (per ENV) |
cat mirrors.yaml.in | envsubst > mirrors.yaml
- name: Inject enhanced GitHub environment variables
uses: rlespinasse/github-slug-action@v5
- name: Set up QEMU
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.

3 participants