diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 629e991..8ed8442 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -38,6 +38,11 @@ on: required: false type: boolean default: false + pre_pull_docker_images: + description: "Comma-separated list of Docker images to pull in the background before the build starts (e.g. images used by Testcontainers). Default: empty, nothing is pulled" + required: false + type: string + default: "" # cancel in-progress runs of the same workflow # to avoid unnecessary runs when multiple commits pushed @@ -59,12 +64,60 @@ jobs: fetch-depth: ${{ inputs.fetch_all_commits == true && '0' || '1' }} persist-credentials: false + # Detached pulls carry on after this step ends, so they overlap with the Java/Maven setup and the build. + # Failures are harmless: Testcontainers pulls any missing image itself when it is first needed. + # Each pull writes .log (image name on the first line, then the pull output) and, once finished, + # .rc (exit code and seconds taken). The 'Report Docker pre-pull results' step prints them. + - name: Pre-pull Docker images in background + if: inputs.pre_pull_docker_images != '' + env: + INPUTS_PRE_PULL_DOCKER_IMAGES: ${{ inputs.pre_pull_docker_images }} + run: | + mkdir -p -- "${RUNNER_TEMP}/pre-pull" + n=0 + IFS=',' read -ra images <<< "${INPUTS_PRE_PULL_DOCKER_IMAGES}" + for image in "${images[@]}"; do + image="$(echo "${image}" | xargs)" + [ -n "${image}" ] || continue + if [[ ! "${image}" =~ ^[a-zA-Z0-9][a-zA-Z0-9._/:@-]*$ ]]; then + echo "::warning::Skipping invalid Docker image name '${image}'" + continue + fi + echo "Pre-pulling ${image} in background" + base="${RUNNER_TEMP}/pre-pull/$((++n))" + echo "${image}" > "${base}.log" + # shellcheck disable=SC2016 + setsid bash -c 'docker pull -- "$1" >> "$2.log" 2>&1; echo "$? ${SECONDS}" > "$2.rc"' _ "${image}" "${base}" > /dev/null 2>&1 < /dev/null & + disown + done + - uses: project-ncl/shared-github-actions/.github/actions/maven-build@e7102dd3bf74f91aaccae7a3539241c03a652d1a # v0.0.27 with: java_version: ${{ inputs.java_version }} build_command: ${{ inputs.build_command }} maven_version: ${{ inputs.maven_version }} + - name: Report Docker pre-pull results + # Also on failure: a failed pre-pull can explain a slow or failing integration test + if: always() && inputs.pre_pull_docker_images != '' + run: | + for log in "${RUNNER_TEMP}"/pre-pull/*.log; do + [ -e "${log}" ] || continue + image="$(head -n 1 "${log}")" + rc="" secs="" + [ ! -f "${log%.log}.rc" ] || read -r rc secs < "${log%.log}.rc" + if [ "${rc}" = "0" ]; then + echo "✅ Pre-pulled ${image} in ${secs}s" + else + status="${rc:+exit ${rc} after ${secs}s}" + echo "::warning::❌ Pre-pull of ${image} did not succeed (${status:-still running}), Testcontainers pulls it on demand instead" + echo "::group::Pre-pull log for ${image}" + # Registry output is untrusted: stop it from being interpreted as workflow commands + sed 's/::/: :/g' "${log}" + echo "::endgroup::" + fi + done + - name: Check for wrong code formatting # Straight after a maven-release the release plugin might have altered the format slightly. Don't fail # dependabot updates on formatting changes. diff --git a/README.md b/README.md index 974390d..a88b097 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ the Java version etc. It is possible to use this within a matrix job. * fetch_all_commits (default: `false`) * maven_version (default: `3.9.15`) * upload_artifacts (default: `false`) + * pre_pull_docker_images (default: empty, opt-in): comma-separated list of Docker images (e.g. `quay.io/keycloak/keycloak:21.1.0,redis:7.2`) to `docker pull` in the background right after checkout, so the download overlaps with Java/Maven setup and the build instead of Testcontainers pulling them lazily and serially. No images are cached and no registry login is performed (public images only). A failed pull is harmless: the image is then pulled on demand as usual. As the pulls are detached, a `Report Docker pre-pull results` step after the build prints one line per image (✅ with the time taken), and a warning plus the full pull log for any pull that failed or was still running - **Permissions**: `contents: read`