feat: extract build infrastructure into standalone scripts#227
feat: extract build infrastructure into standalone scripts#227
Conversation
There was a problem hiding this comment.
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.shto build base images (Debian stable base and CUDA base/runtime). - Add
build-eic.shto build EIC environment images with CI/local mode behavior. - Update
.gitlab-ci.ymlanddocs/building-locally.mdto 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
| 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 |
There was a problem hiding this comment.
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.
| | 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`) | |
There was a problem hiding this comment.
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.
| ### 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` | |
There was a problem hiding this comment.
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.
fafdb52 to
3ffa5ef
Compare
| 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 |
There was a problem hiding this comment.
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.
| ## 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 |
There was a problem hiding this comment.
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.
| # 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`. | ||
|
|
There was a problem hiding this comment.
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.
| | `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` | |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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).
| 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 |
There was a problem hiding this comment.
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.
| ### 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`. |
There was a problem hiding this comment.
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).
| BUILD_TARGET="${BUILD_TARGET:-final}" | ||
| PLATFORM="${PLATFORM:-linux/amd64}" | ||
| JOBS="${JOBS:-$(nproc)}" | ||
| LOCAL_TAG="${LOCAL_TAG:-local}" |
There was a problem hiding this comment.
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.
| ## 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 |
There was a problem hiding this comment.
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.
.pre-commit-config.yaml
Outdated
| language: system | ||
| types: [shell] | ||
| args: [--severity=warning, -x] | ||
| files: ^[^/]+\.sh$ |
There was a problem hiding this comment.
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).
| files: ^[^/]+\.sh$ |
| | 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` | |
There was a problem hiding this comment.
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).
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>
- 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>
ed4dcd1 to
3f0fdb0
Compare
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>
| 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 |
There was a problem hiding this comment.
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.
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>
| ### 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 |
Summary
Add
build-base.shandbuild-eic.shas standalone scripts that encapsulate the fulldocker buildx buildinvocations previously embedded in.gitlab-ci.ymland.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.ymlpreviously contained 130+ lines of inlinedocker buildx buildcommands with ~20–30--build-argflags each. This made local builds difficult because:docs/building-locally.md"Full Build Script" was missing ~15--build-argentries (SHAs, cherry-picks, duplicate allowlists, etc.)Changes
New files
build-base.sh— buildsdebian_stable_base,cuda_devel,cuda_runtimebuild-eic.sh— builds any EIC environment (ci,xl,cuda,dbg, etc.)CI/local mode detection
Scripts auto-detect their context via
CI_REGISTRY:--push--load--cache-toto CI registrymirrors.yamlINTERNAL_TAG,EXPORT_TAG--tag localLocal usage
.gitlab-ci.yml
The
baseandeicjob scripts are each reduced to two lines:All CI matrix variables (
BUILD_IMAGE,ENV,BUILD_TYPE, etc.) flow through naturally as environment variables..github/workflows/build-push.yml
The
baseandeicjobs are reduced to, essentially:docs/building-locally.md
Replaced the incomplete inline script with references to
build-base.shandbuild-eic.sh, updated all examples and troubleshooting steps.