Skip to content

feat: add Alpine image - #1949

Closed
pat-s wants to merge 10 commits into
j178:masterfrom
pat-s:feat/alpine-image
Closed

feat: add Alpine image#1949
pat-s wants to merge 10 commits into
j178:masterfrom
pat-s:feat/alpine-image

Conversation

@pat-s

@pat-s pat-s commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

fix #1946

@pat-s
pat-s requested a review from j178 as a code owner April 18, 2026 08:27
Copilot AI review requested due to automatic review settings April 18, 2026 08:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an Alpine-based Docker image variant for prek (to cover common hook runtime dependencies) and updates docs/CI publishing to support it.

Changes:

  • Document two published images (scratch minimal and alpine) in Docker integration docs.
  • Extend the root Dockerfile with an alpine:3.23 target that installs common hook dependencies and includes the prek binary.
  • Update the Docker build/publish GitHub Actions workflow to build and publish both minimal and alpine image variants for multiple platforms.

Reviewed changes

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

File Description
docs/integrations.md Documents the new ghcr.io/j178/prek-alpine image and clarifies the minimal scratch image section.
Dockerfile Adds minimal and alpine build targets; Alpine target installs common hook dependencies and copies prek to /usr/local/bin.
.github/workflows/build-docker.yml Builds/publishes both image variants across linux/amd64 and linux/arm64, and separates digest artifacts per image+platform.

Comment thread .github/workflows/build-docker.yml Outdated
Comment on lines +70 to +106
@@ -87,10 +99,11 @@ jobs:
with:
context: .
platforms: ${{ matrix.platform }}
cache-from: type=gha,scope=prek-${{ env.PLATFORM_TUPLE }}
cache-to: type=gha,mode=min,scope=prek-${{ env.PLATFORM_TUPLE }}
target: ${{ matrix.image }}
cache-from: type=gha,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }}
cache-to: type=gha,mode=min,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.PREK_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

IMAGE_NAME is set via $GITHUB_ENV in a previous step, but later you reference it via the expression context (${{ env.IMAGE_NAME }}) in with: inputs. Environment variables written to $GITHUB_ENV are available to subsequent run: steps, but they are not reliably available for expression evaluation in later steps, which can cause images:/outputs: to be empty or incorrect. Prefer computing the image name directly in the expression (e.g., conditional on matrix.image), or set it as a step output and reference steps.<id>.outputs.* instead.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/build-docker.yml Outdated
Comment on lines 143 to 207
@@ -136,7 +163,7 @@ jobs:
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with:
images: ${{ env.PREK_BASE_IMG }}
images: ${{ env.IMAGE_NAME }}
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
tags: |
type=raw,value=${{ fromJson(inputs.plan).announcement_tag }}
@@ -151,27 +178,23 @@ jobs:
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
- name: Create manifest list and push
working-directory: /tmp/digests
# The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array
# The printf will expand the base image with the `<PREK_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
# The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <PREK_BASE_IMG>@sha256:<sha256_1> <PREK_BASE_IMG>@sha256:<sha256_2> ...`
run: |
# shellcheck disable=SC2046
readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done

docker buildx imagetools create \
"${annotations[@]}" \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf "${PREK_BASE_IMG}@sha256:%s " *)
$(printf "${IMAGE_NAME}@sha256:%s " *)

- name: Export manifest digest
id: manifest-digest
env:
IMAGE: ${{ env.PREK_BASE_IMG }}
VERSION: ${{ steps.meta.outputs.version }}
run: |
digest="$(
docker buildx imagetools inspect \
"${IMAGE}:${VERSION}" \
"${IMAGE_NAME}:${VERSION}" \
--format '{{json .Manifest}}' \
| jq -r '.digest'
)"
@@ -180,5 +203,5 @@ jobs:
- name: Generate artifact attestation
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-name: ${{ env.PREK_BASE_IMG }}
subject-name: ${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.manifest-digest.outputs.digest }}

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

Same issue as in the build job: IMAGE_NAME is set via $GITHUB_ENV, but later used in expression contexts (${{ env.IMAGE_NAME }}) for docker/metadata-action and actions/attest. This can result in publishing/attesting with an empty or wrong image name. Compute IMAGE_NAME via expressions (based on matrix.image) or expose it as a step output and reference steps.<id>.outputs.image_name.

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile Outdated
py3-pip
COPY --from=build /prek /usr/local/bin/prek
WORKDIR /io
ENTRYPOINT ["prek"]

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

Because the alpine stage is now the last stage in the Dockerfile, running docker build . without --target will produce the Alpine image rather than the previously default scratch/minimal image. If consumers rely on the default being the minimal image, consider keeping the minimal stage as the final/default stage (e.g., add a final FROM minimal stage at the end, or reorder stages) while still allowing --target alpine for the Alpine variant.

Suggested change
ENTRYPOINT ["prek"]
ENTRYPOINT ["prek"]
FROM minimal

Copilot uses AI. Check for mistakes.
@codecov

codecov Bot commented Apr 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.25%. Comparing base (de7ac64) to head (ac73e8d).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1949   +/-   ##
=======================================
  Coverage   93.25%   93.25%           
=======================================
  Files         127      127           
  Lines       27988    27988           
=======================================
  Hits        26099    26099           
  Misses       1889     1889           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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

@j178 j178 added the enhancement New feature or request label Apr 27, 2026
@j178

j178 commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Sorry for the back and forth here. After thinking more about the long-term maintenance tradeoff, I think the official prek image should stay as the minimal scratch-based image.

That keeps the image contract clear: we ship the prek binary, not a maintained set of hook runtimes and system packages. For CI setups that need git, Python, Node, etc., I think the better path is to copy/install prek into the project’s own base image.

Thanks again for the proposal and the PR. I’m going to close this and #1946 for now.

@j178 j178 closed this Apr 27, 2026
@pat-s

pat-s commented Apr 27, 2026

Copy link
Copy Markdown
Contributor Author

Uff, that's quite a bummer.

I didn't mean to replace the scratch image, just add an Alpine one on the side which will save multiple seconds and bandwith in CI on every run. There's almost no effort to build these in addition to the already existing base image.

It's easy to do this in the main source repo. By denying this, you indirectly force many individual's to build the same images and keep up with releases in a dynamic way etc. That is a lot of (unnecessary) overhead.

For CI setups that need git, Python, Node, etc., I think the better path is to copy/install prek into the project’s own base image.

A sophisticated use of prek in CI almost always needs these. The scratch image can't be used out-of-the box in a meaningful way.

@prek-ci-bot

prek-ci-bot Bot commented Apr 27, 2026

Copy link
Copy Markdown

📦 Cargo Bloat Comparison

Binary size change: +0.00% (25.8 MiB → 25.8 MiB)

Expand for cargo-bloat output

Head Branch Results

 File  .text     Size             Crate Name
 1.3%   2.6% 332.0KiB        aws_lc_sys aws_lc_0_39_1_aes_gcm_encrypt_avx512
 1.3%   2.6% 332.0KiB        aws_lc_sys aws_lc_0_39_1_aes_gcm_decrypt_avx512
 0.3%   0.7%  84.0KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.3%   0.7%  82.0KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.2%   0.5%  60.9KiB             prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.2%   0.4%  56.8KiB              prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.4%  53.3KiB annotate_snippets annotate_snippets::renderer::render::render
 0.2%   0.4%  46.8KiB              prek prek::run::{{closure}}
 0.2%   0.3%  41.3KiB              prek prek::cli::run::run::run::{{closure}}
 0.1%   0.3%  33.3KiB             prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.1%   0.2%  28.0KiB        aws_lc_sys aws_lc_0_39_1_edwards25519_scalarmuldouble_alt
 0.1%   0.2%  28.0KiB             prek? <prek::config::_::<impl serde_core::de::Deserialize for prek::config::Config>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2%  27.6KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2%  27.5KiB        aws_lc_sys aws_lc_0_39_1_edwards25519_scalarmuldouble
 0.1%   0.2%  26.9KiB               std core::ptr::drop_in_place<prek::languages::<impl prek::config::Language>::install::{{closure}}>
 0.1%   0.2%  26.3KiB              prek prek::cli::try_repo::try_repo::{{closure}}
 0.1%   0.2%  22.8KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2%  22.5KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2%  22.3KiB         [Unknown] Lp384_montjscalarmul_alt_p384_montjadd
 0.1%   0.2%  21.5KiB      clap_builder clap_builder::parser::parser::Parser::get_matches_with
41.2%  86.3%  10.6MiB                   And 23718 smaller methods. Use -n N to show more.
47.8% 100.0%  12.3MiB                   .text section size, the file size is 25.8MiB

Base Branch Results

 File  .text     Size             Crate Name
 1.3%   2.6% 332.0KiB        aws_lc_sys aws_lc_0_39_1_aes_gcm_encrypt_avx512
 1.3%   2.6% 332.0KiB        aws_lc_sys aws_lc_0_39_1_aes_gcm_decrypt_avx512
 0.3%   0.7%  88.9KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.3%   0.6%  81.6KiB              prek prek::languages::<impl prek::config::Language>::run::{{closure}}::{{closure}}
 0.3%   0.6%  71.8KiB             prek? <prek::cli::Command as clap_builder::derive::Subcommand>::augment_subcommands
 0.2%   0.5%  56.8KiB              prek prek::languages::<impl prek::config::Language>::install::{{closure}}
 0.2%   0.4%  53.3KiB annotate_snippets annotate_snippets::renderer::render::render
 0.2%   0.4%  46.7KiB              prek prek::run::{{closure}}
 0.2%   0.3%  40.9KiB              prek prek::cli::run::run::run::{{closure}}
 0.1%   0.3%  32.6KiB             prek? <prek::cli::RunArgs as clap_builder::derive::Args>::augment_args
 0.1%   0.2%  30.0KiB             prek? <prek::config::_::<impl serde_core::de::Deserialize for prek::config::Config>::deserialize::__Visitor as serde_core::de::Visitor>::visit_map
 0.1%   0.2%  28.0KiB        aws_lc_sys aws_lc_0_39_1_edwards25519_scalarmuldouble_alt
 0.1%   0.2%  27.6KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2%  27.5KiB        aws_lc_sys aws_lc_0_39_1_edwards25519_scalarmuldouble
 0.1%   0.2%  27.1KiB               std core::ptr::drop_in_place<prek::languages::<impl prek::config::Language>::install::{{closure}}>
 0.1%   0.2%  26.4KiB              prek prek::cli::try_repo::try_repo::{{closure}}
 0.1%   0.2%  23.2KiB              prek prek::hooks::meta_hooks::MetaHooks::run::{{closure}}
 0.1%   0.2%  22.5KiB      serde_saphyr saphyr_parser_bw::scanner::Scanner<T>::fetch_more_tokens
 0.1%   0.2%  22.3KiB         [Unknown] Lp384_montjscalarmul_alt_p384_montjadd
 0.1%   0.2%  21.5KiB      clap_builder clap_builder::parser::parser::Parser::get_matches_with
41.0%  86.1%  10.6MiB                   And 23756 smaller methods. Use -n N to show more.
47.6% 100.0%  12.3MiB                   .text section size, the file size is 25.8MiB

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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

Comment thread docs/integrations.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 233a2b871a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Dockerfile
Copilot AI review requested due to automatic review settings July 9, 2026 09:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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

Comment thread docs/integrations.md
Comment thread .github/workflows/build-docker.yml
Copilot AI review requested due to automatic review settings July 9, 2026 14:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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

@pat-s

pat-s commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@j178 Tried to make all automated reviewers happy. Would be great if you could take a look again if this would work for you!

@j178 j178 self-assigned this Jul 11, 2026
Comment thread Dockerfile

FROM scratch
FROM alpine:3.24 AS alpine
RUN apk add --no-cache \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Containerized hooks are also quite common. Would it make sense to add podman here as well?

@j178

j178 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Thanks @pat-s for your work in this PR! I continued the work in #2352 with a revised image and publishing setup, and I’ve added you as a co-author on that commit to credit your contribution. Thanks again!

@j178 j178 closed this Jul 15, 2026
j178 added a commit that referenced this pull request Jul 15, 2026
Git is installed only in the Alpine variant; the scratch image remains
the `prek` binary only. Git is included because it is required for
normal `prek` operation.

The Alpine variant is intended as a customizable base, not a
batteries-included development image. It does not include Python,
Node.js, or other language toolchains. Users should install the tools
required by their hooks in their own derived images.

Closes #1946 
Closes #1949

Co-authored-by: Patrick Schratz <patrick.schratz@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Alpine-based image

4 participants