Skip to content

Commit c345589

Browse files
committed
feat(ci): refactor package building to be common between tags and pr
1 parent d1451e8 commit c345589

File tree

4 files changed

+318
-116
lines changed

4 files changed

+318
-116
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
name: 'Build Package'
18+
description: 'Common steps for building and pushing Docker images'
19+
20+
inputs:
21+
package_name:
22+
required: true
23+
description: 'Name of the package to build'
24+
tags:
25+
required: true
26+
description: 'Docker tags to apply (can be multiline YAML string)'
27+
registry:
28+
required: false
29+
default: 'ghcr.io'
30+
description: 'Container registry domain'
31+
image_name:
32+
required: false
33+
description: 'Base image name (repository name)'
34+
build_args:
35+
required: false
36+
default: ''
37+
description: 'Build arguments from preprocess script'
38+
generate_attestation:
39+
required: false
40+
default: 'false'
41+
description: 'Whether to generate artifact attestation'
42+
save_image_info:
43+
required: false
44+
default: 'false'
45+
description: 'Whether to save image tags to an artifact (for PR builds)'
46+
47+
outputs:
48+
image_tags:
49+
description: 'The tags that were applied to the built image'
50+
value: ${{ steps.meta.outputs.tags }}
51+
image_digest:
52+
description: 'The digest of the built image'
53+
value: ${{ steps.push.outputs.digest }}
54+
55+
runs:
56+
using: 'composite'
57+
steps:
58+
- name: Log in to the Container registry
59+
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
60+
with:
61+
registry: ${{ inputs.registry }}
62+
username: ${{ github.actor }}
63+
password: ${{ secrets.GITHUB_TOKEN }}
64+
65+
- name: Generate package version map
66+
id: package-versions
67+
run: |
68+
# Get all tags, extract package/version pairs, find latest for each package
69+
PACKAGE_VERSIONS=$(git tag -l | \
70+
grep -E '^[^/]+/[0-9]+\.[0-9]+\.[0-9]+$' | \
71+
sort -t/ -k1,1 -k2,2V | \
72+
awk -F/ '
73+
{
74+
package = $1
75+
version = $2
76+
packages[package] = version
77+
}
78+
END {
79+
printf "{"
80+
first = 1
81+
for (package in packages) {
82+
if (!first) printf ","
83+
printf "\"%s\":\"%s\"", package, packages[package]
84+
first = 0
85+
}
86+
printf "}"
87+
}
88+
')
89+
90+
echo "PACKAGE_VERSIONS=${PACKAGE_VERSIONS}" >> $GITHUB_OUTPUT
91+
echo "Generated package version map: ${PACKAGE_VERSIONS}"
92+
93+
- name: Run preprocess script
94+
id: preprocess
95+
shell: bash
96+
run: |
97+
PREPROCESS_SCRIPT="${{ inputs.package_name }}/preprocess.sh"
98+
if [ -f "$PREPROCESS_SCRIPT" ]; then
99+
echo "Running preprocess script: $PREPROCESS_SCRIPT"
100+
chmod +x "$PREPROCESS_SCRIPT"
101+
"$PREPROCESS_SCRIPT"
102+
else
103+
echo "No preprocess script found at $PREPROCESS_SCRIPT"
104+
echo "BUILD_ARGS=" >> $GITHUB_OUTPUT
105+
fi
106+
107+
- name: Extract metadata (tags, labels) for Docker
108+
id: meta
109+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
110+
with:
111+
images: ${{ inputs.registry }}/${{ inputs.image_name }}/${{ inputs.package_name }}
112+
tags: ${{ inputs.tags }}
113+
114+
- name: Set up QEMU
115+
uses: docker/setup-qemu-action@v3
116+
117+
- name: Set up Docker Buildx
118+
uses: docker/setup-buildx-action@v3
119+
120+
- name: Build and push Docker image
121+
id: push
122+
uses: docker/build-push-action@v6
123+
with:
124+
context: ${{ inputs.package_name }}
125+
push: true
126+
tags: ${{ steps.meta.outputs.tags }}
127+
labels: ${{ steps.meta.outputs.labels }}
128+
platforms: linux/amd64,linux/arm64
129+
build-args: ${{ steps.preprocess.outputs.BUILD_ARGS != '' && steps.preprocess.outputs.BUILD_ARGS || inputs.build_args }}
130+
131+
- name: Generate artifact attestation
132+
if: inputs.generate_attestation == 'true'
133+
uses: actions/attest-build-provenance@v2
134+
with:
135+
subject-name: ${{ inputs.registry }}/${{ inputs.image_name }}/${{ inputs.package_name }}
136+
subject-digest: ${{ steps.push.outputs.digest }}
137+
push-to-registry: true
138+
139+
- name: Save image info
140+
if: inputs.save_image_info == 'true'
141+
shell: bash
142+
run: |
143+
mkdir -p /tmp/image-info
144+
echo "${{ steps.meta.outputs.tags }}" > /tmp/image-info/${{ inputs.package_name }}.txt
145+
146+
- name: Upload image info
147+
if: inputs.save_image_info == 'true'
148+
uses: actions/upload-artifact@v4
149+
with:
150+
name: image-info-${{ inputs.package_name }}
151+
path: /tmp/image-info/${{ inputs.package_name }}.txt
152+
retention-days: 1

.github/workflows/build_container.yaml

Lines changed: 14 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ env:
2828
REGISTRY: ghcr.io
2929
IMAGE_NAME: ${{ github.repository }}
3030

31-
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
31+
# There is a single job in this workflow. It uses the composite build-package action.
3232
jobs:
3333
build-and-push-image:
3434
runs-on: ubuntu-latest
@@ -38,71 +38,23 @@ jobs:
3838
packages: write
3939
attestations: write
4040
id-token: write
41-
#
4241
steps:
4342
- name: Checkout repository
4443
uses: actions/checkout@v4
45-
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
46-
- name: Log in to the Container registry
47-
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
48-
with:
49-
registry: ${{ env.REGISTRY }}
50-
username: ${{ github.actor }}
51-
password: ${{ secrets.GITHUB_TOKEN }}
52-
- name: Setup env vars
53-
run: echo "PACKAGE_NAME=$(echo "${{ github.ref_name }}" | sed 's;refs/tags;;g'| cut -f 1 -d /)" >> $GITHUB_ENV
54-
55-
# Run preprocess script if it exists to get build args (e.g., dependency versions)
56-
- name: Run preprocess script
57-
id: preprocess
58-
env:
59-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
45+
- name: Extract package name from tag
46+
id: extract
6047
run: |
61-
PREPROCESS_SCRIPT="${{ env.PACKAGE_NAME }}/preprocess.sh"
62-
if [ -f "$PREPROCESS_SCRIPT" ]; then
63-
echo "Running preprocess script: $PREPROCESS_SCRIPT"
64-
chmod +x "$PREPROCESS_SCRIPT"
65-
"$PREPROCESS_SCRIPT"
66-
else
67-
echo "No preprocess script found at $PREPROCESS_SCRIPT"
68-
echo "BUILD_ARGS=" >> $GITHUB_OUTPUT
69-
fi
70-
71-
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
72-
- name: Extract metadata (tags, labels) for Docker
73-
id: meta
74-
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
75-
with:
76-
images: ${{ env.REGISTRY }}/${{env.IMAGE_NAME}}/${{ env.PACKAGE_NAME }}
77-
tags: |
78-
type=match,pattern=\d.\d.\d
79-
80-
# Setup for multi-platform
81-
- name: Set up QEMU
82-
uses: docker/setup-qemu-action@v3
48+
PACKAGE_NAME=$(echo "${{ github.ref_name }}" | cut -f 1 -d /)
49+
echo "package_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
8350
84-
- name: Set up Docker Buildx
85-
uses: docker/setup-buildx-action@v3
86-
87-
88-
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
89-
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository.
90-
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
9151
- name: Build and push Docker image
92-
id: push
93-
uses: docker/build-push-action@v6
94-
with:
95-
context: ${{ env.PACKAGE_NAME }}
96-
push: true
97-
tags: ${{ steps.meta.outputs.tags }}
98-
labels: ${{ steps.meta.outputs.labels }}
99-
platforms: linux/amd64,linux/arm64
100-
build-args: ${{ steps.preprocess.outputs.BUILD_ARGS }}
101-
102-
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
103-
- name: Generate artifact attestation
104-
uses: actions/attest-build-provenance@v2
52+
uses: ./.github/actions/build-package
10553
with:
106-
subject-name: ${{ env.REGISTRY }}/${{env.IMAGE_NAME}}/${{ env.PACKAGE_NAME }}
107-
subject-digest: ${{ steps.push.outputs.digest }}
108-
push-to-registry: true
54+
package_name: ${{ steps.extract.outputs.package_name }}
55+
tags: |
56+
type=match,pattern=\d.\d.\d
57+
registry: ${{ env.REGISTRY }}
58+
image_name: ${{ env.IMAGE_NAME }}
59+
generate_attestation: 'true'
60+
save_image_info: 'false'
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
name: Build Package (Reusable)
18+
19+
on:
20+
workflow_call:
21+
inputs:
22+
package_name:
23+
required: true
24+
type: string
25+
description: Name of the package to build
26+
tags:
27+
required: true
28+
type: string
29+
description: Docker tags to apply (can be multiline YAML string)
30+
registry:
31+
required: false
32+
type: string
33+
default: ghcr.io
34+
description: Container registry domain
35+
image_name:
36+
required: false
37+
type: string
38+
default: ${{ github.repository }}
39+
description: Base image name (repository name)
40+
build_args:
41+
required: false
42+
type: string
43+
default: ''
44+
description: Build arguments from preprocess script
45+
generate_attestation:
46+
required: false
47+
type: boolean
48+
default: false
49+
description: Whether to generate artifact attestation
50+
save_image_info:
51+
required: false
52+
type: boolean
53+
default: false
54+
description: Whether to save image tags to an artifact (for PR builds)
55+
outputs:
56+
image_tags:
57+
description: The tags that were applied to the built image
58+
value: ${{ jobs.build.outputs.image_tags }}
59+
image_digest:
60+
description: The digest of the built image
61+
value: ${{ jobs.build.outputs.image_digest }}
62+
63+
jobs:
64+
build:
65+
runs-on: ubuntu-latest
66+
permissions:
67+
contents: read
68+
packages: write
69+
attestations: write
70+
id-token: write
71+
outputs:
72+
image_tags: ${{ steps.meta.outputs.tags }}
73+
image_digest: ${{ steps.push.outputs.digest }}
74+
steps:
75+
- name: Checkout repository
76+
uses: actions/checkout@v4
77+
78+
- name: Log in to the Container registry
79+
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
80+
with:
81+
registry: ${{ inputs.registry }}
82+
username: ${{ github.actor }}
83+
password: ${{ secrets.GITHUB_TOKEN }}
84+
85+
- name: Run preprocess script
86+
id: preprocess
87+
env:
88+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89+
run: |
90+
PREPROCESS_SCRIPT="${{ inputs.package_name }}/preprocess.sh"
91+
if [ -f "$PREPROCESS_SCRIPT" ]; then
92+
echo "Running preprocess script: $PREPROCESS_SCRIPT"
93+
chmod +x "$PREPROCESS_SCRIPT"
94+
"$PREPROCESS_SCRIPT"
95+
else
96+
echo "No preprocess script found at $PREPROCESS_SCRIPT"
97+
echo "BUILD_ARGS=" >> $GITHUB_OUTPUT
98+
fi
99+
100+
- name: Extract metadata (tags, labels) for Docker
101+
id: meta
102+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
103+
with:
104+
images: ${{ inputs.registry }}/${{ inputs.image_name }}/${{ inputs.package_name }}
105+
tags: ${{ inputs.tags }}
106+
107+
- name: Set up QEMU
108+
uses: docker/setup-qemu-action@v3
109+
110+
- name: Set up Docker Buildx
111+
uses: docker/setup-buildx-action@v3
112+
113+
- name: Build and push Docker image
114+
id: push
115+
uses: docker/build-push-action@v6
116+
with:
117+
context: ${{ inputs.package_name }}
118+
push: true
119+
tags: ${{ steps.meta.outputs.tags }}
120+
labels: ${{ steps.meta.outputs.labels }}
121+
platforms: linux/amd64,linux/arm64
122+
build-args: ${{ steps.preprocess.outputs.BUILD_ARGS != '' && steps.preprocess.outputs.BUILD_ARGS || inputs.build_args }}
123+
124+
- name: Generate artifact attestation
125+
if: inputs.generate_attestation
126+
uses: actions/attest-build-provenance@v2
127+
with:
128+
subject-name: ${{ inputs.registry }}/${{ inputs.image_name }}/${{ inputs.package_name }}
129+
subject-digest: ${{ steps.push.outputs.digest }}
130+
push-to-registry: true
131+
132+
- name: Save image info
133+
if: inputs.save_image_info
134+
run: |
135+
mkdir -p /tmp/image-info
136+
echo "${{ steps.meta.outputs.tags }}" > /tmp/image-info/${{ inputs.package_name }}.txt
137+
138+
- name: Upload image info
139+
if: inputs.save_image_info
140+
uses: actions/upload-artifact@v4
141+
with:
142+
name: image-info-${{ inputs.package_name }}
143+
path: /tmp/image-info/${{ inputs.package_name }}.txt
144+
retention-days: 1

0 commit comments

Comments
 (0)