Skip to content

Commit c7f623a

Browse files
committed
Build and publish docker image to ghcr.io/j178/prek
1 parent ae056af commit c7f623a

File tree

5 files changed

+183
-10
lines changed

5 files changed

+183
-10
lines changed

.github/workflows/build-binaries.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
# Build uv on all platforms.
1+
# Build prek on all platforms.
22
#
33
# Generates both wheels (for PyPI) and archived binaries (for GitHub releases).
4-
#
54
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
65
# artifacts job within `cargo-dist`.
6+
#
7+
# Adapted from https://github.com/astral-sh/uv/blob/main/.github/workflows/build-binaries.yml
8+
79
name: "Build binaries"
810

911
on:

.github/workflows/build-docker.yml

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Build and publish a Docker image.
2+
#
3+
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
4+
# artifacts job within `cargo-dist`.
5+
#
6+
# Adapted from https://github.com/astral-sh/ty/blob/main/.github/workflows/build-docker.yml
7+
name: "Build Docker image"
8+
9+
on:
10+
workflow_call:
11+
inputs:
12+
plan:
13+
required: true
14+
type: string
15+
pull_request:
16+
paths:
17+
- .github/workflows/build-docker.yml
18+
19+
env:
20+
PREK_BASE_IMG: ghcr.io/${{ github.repository_owner }}/prek
21+
22+
permissions:
23+
contents: read
24+
# TODO(zanieb): Ideally, this would be `read` on dry-run but that will require
25+
# significant changes to the workflow.
26+
packages: write # zizmor: ignore[excessive-permissions]
27+
28+
jobs:
29+
docker-build:
30+
name: Build Docker image ghcr.io/j178/prek for ${{ matrix.platform }}
31+
runs-on: ubuntu-latest
32+
environment:
33+
name: release
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
platform:
38+
- linux/amd64
39+
- linux/arm64
40+
steps:
41+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
42+
with:
43+
persist-credentials: false
44+
45+
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
46+
47+
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
48+
with:
49+
registry: ghcr.io
50+
username: ${{ github.repository_owner }}
51+
password: ${{ secrets.GITHUB_TOKEN }}
52+
53+
- name: Check tag consistency
54+
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
55+
env:
56+
TAG: ${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }}
57+
run: |
58+
version=$(grep -m 1 "^version = " dist-workspace.toml | sed -e 's/version = "\(.*\)"/\1/g')
59+
if [ "${TAG}" != "${version}" ]; then
60+
echo "The input tag does not match the version from dist-workspace.toml:" >&2
61+
echo "${TAG}" >&2
62+
echo "${version}" >&2
63+
exit 1
64+
else
65+
echo "Releasing ${version}"
66+
fi
67+
68+
- name: Extract metadata (tags, labels) for Docker
69+
id: meta
70+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
71+
with:
72+
images: ${{ env.PREK_BASE_IMG }}
73+
# Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name
74+
tags: |
75+
type=raw,value=dry-run,enable=${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }}
76+
type=pep440,pattern={{ version }},value=${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }},enable=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
77+
78+
- name: Normalize Platform Pair (replace / with -)
79+
run: |
80+
platform=${{ matrix.platform }}
81+
echo "PLATFORM_TUPLE=${platform//\//-}" >> "$GITHUB_ENV"
82+
83+
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
84+
- name: Build and push by digest
85+
id: build
86+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
87+
with:
88+
context: .
89+
platforms: ${{ matrix.platform }}
90+
cache-from: type=gha,scope=prek-${{ env.PLATFORM_TUPLE }}
91+
cache-to: type=gha,mode=min,scope=prek-${{ env.PLATFORM_TUPLE }}
92+
labels: ${{ steps.meta.outputs.labels }}
93+
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 }}
94+
95+
- name: Export digests
96+
env:
97+
digest: ${{ steps.build.outputs.digest }}
98+
run: |
99+
mkdir -p /tmp/digests
100+
touch "/tmp/digests/${digest#sha256:}"
101+
102+
- name: Upload digests
103+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
104+
with:
105+
name: digests-${{ env.PLATFORM_TUPLE }}
106+
path: /tmp/digests/*
107+
if-no-files-found: error
108+
retention-days: 1
109+
110+
docker-publish:
111+
name: Publish Docker image (ghcr.io/j178/prek)
112+
runs-on: ubuntu-latest
113+
environment:
114+
name: release
115+
needs:
116+
- docker-build
117+
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
118+
steps:
119+
- name: Download digests
120+
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
121+
with:
122+
path: /tmp/digests
123+
pattern: digests-*
124+
merge-multiple: true
125+
126+
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
127+
128+
- name: Extract metadata (tags, labels) for Docker
129+
id: meta
130+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
131+
env:
132+
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
133+
with:
134+
images: ${{ env.PREK_BASE_IMG }}
135+
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
136+
tags: |
137+
type=pep440,pattern={{ version }},value=${{ fromJson(inputs.plan).announcement_tag }}
138+
type=raw,value=${{ fromJson(inputs.plan).announcement_tag }}
139+
type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}
140+
141+
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
142+
with:
143+
registry: ghcr.io
144+
username: ${{ github.repository_owner }}
145+
password: ${{ secrets.GITHUB_TOKEN }}
146+
147+
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
148+
- name: Create manifest list and push
149+
working-directory: /tmp/digests
150+
# The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array
151+
# The printf will expand the base image with the `<PREK_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
152+
# The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <PREK_BASE_IMG>@sha256:<sha256_1> <PREK_BASE_IMG>@sha256:<sha256_2> ...`
153+
run: |
154+
# shellcheck disable=SC2046
155+
readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done
156+
157+
docker buildx imagetools create \
158+
"${annotations[@]}" \
159+
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
160+
$(printf "${PREK_BASE_IMG}@sha256:%s " *)

.github/workflows/release.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
# we specify bash to get pipefail; it guards against the `curl` command
6969
# failing. otherwise `sh` won't catch that `curl` returned non-0
7070
shell: bash
71-
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.0/cargo-dist-installer.sh | sh"
71+
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.3/cargo-dist-installer.sh | sh"
7272
- name: Cache dist
7373
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
7474
with:
@@ -100,11 +100,21 @@ jobs:
100100
plan: ${{ needs.plan.outputs.val }}
101101
secrets: inherit
102102

103+
custom-build-docker:
104+
needs:
105+
- plan
106+
if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
107+
uses: ./.github/workflows/build-docker.yml
108+
with:
109+
plan: ${{ needs.plan.outputs.val }}
110+
secrets: inherit
111+
103112
# Build and package all the platform-agnostic(ish) things
104113
build-global-artifacts:
105114
needs:
106115
- plan
107116
- custom-build-binaries
117+
- custom-build-docker
108118
runs-on: "ubuntu-latest"
109119
env:
110120
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -151,9 +161,10 @@ jobs:
151161
needs:
152162
- plan
153163
- custom-build-binaries
164+
- custom-build-docker
154165
- build-global-artifacts
155-
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
156-
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') }}
166+
# Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
167+
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }}
157168
env:
158169
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
159170
runs-on: "ubuntu-latest"

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ RUN rustup toolchain install
3232
RUN rustup target add $(cat rust_target.txt)
3333

3434
# Build
35-
COPY Cargo.toml Cargo.lock build.rs ./
36-
COPY src src
37-
COPY lib lib
35+
COPY ./Cargo.toml Cargo.toml
36+
COPY ./Cargo.lock Cargo.lock
37+
COPY crates crates
3838
RUN case "${TARGETPLATFORM}" in \
3939
"linux/arm64") export JEMALLOC_SYS_WITH_LG_PAGE=16;; \
4040
esac && \

dist-workspace.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ members = ["cargo:."]
44
# Config for 'dist'
55
[dist]
66
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
7-
cargo-dist-version = "0.30.0"
7+
cargo-dist-version = "0.30.3"
88
# The archive format to use for non-windows builds (defaults .tar.xz)
99
unix-archive = ".tar.gz"
1010
# CI backends to support
@@ -45,7 +45,7 @@ targets = [
4545
"i686-pc-windows-msvc"
4646
]
4747
# Local artifacts jobs to run in CI
48-
local-artifacts-jobs = ["./build-binaries"]
48+
local-artifacts-jobs = ["./build-binaries", "./build-docker"]
4949
# Publish jobs to run in CI
5050
publish-jobs = ["./publish", "homebrew"]
5151
# Post-announce jobs to run in CI

0 commit comments

Comments
 (0)