Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions .github/workflows/__test-workflow-docker-build-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ jobs:
)
);

assert.equal(applicationMultiArchImage.platforms.length, 3);
assert(applicationMultiArchImage.platforms.includes("linux/amd64"));
assert(applicationMultiArchImage.platforms.includes("linux/arm64"));
assert(applicationMultiArchImage.platforms.includes("linux/arm/v7"));

const applicationMonoArchImage = builtImages["test-mono-arch"];

assert.equal(applicationMonoArchImage.name, "test-mono-arch");
Expand All @@ -121,6 +126,8 @@ jobs:
applicationMonoArchImage.images[0],
`ghcr.io/hoverkraft-tech/ci-github-container/test-mono-arch:0.1.0@${applicationMonoArchImage.digest}`
);
assert.equal(applicationMonoArchImage.platforms.length, 1);
assert(applicationMonoArchImage.platforms.includes("linux/amd64"));

- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
Expand Down Expand Up @@ -278,8 +285,8 @@ jobs:
secrets:
oci-registry-password: ${{ secrets.GITHUB_TOKEN }}
build-secrets: |
SECRET_REPOSITORY_OWNER=${{ github.repository_owner }}
SECRET_REPOSITORY=${{ github.repository }}
SECRET_TEST=test-secret
SECRET_ANOTHER_TEST=another-test-secret
build-secret-github-app-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
with:
cache-type: registry
Expand All @@ -293,12 +300,12 @@ jobs:
"platforms": ["linux/amd64","linux/arm64"],
"build-args": {
"BUILD_RUN_ID": "${{ github.run_id }}",
"BUILD_REPOSITORY_OWNER": "${{ github.repository_owner }}",
"BUILD_REPOSITORY": "${{ github.repository }}"
"BUILD_ARG_TEST": "test-arg",
"BUILD_ARG_ANOTHER_TEST": "another-test-arg"
},
"secret-envs": {
"SECRET_ENV_REPOSITORY_OWNER": "GITHUB_REPOSITORY_OWNER",
"SECRET_ENV_REPOSITORY": "GITHUB_REPOSITORY"
"SECRET_ENV_TEST": "GITHUB_ACTION",
"SECRET_ENV_ANOTHER_TEST": "GITHUB_JOB"
}
}
]
Expand Down
58 changes: 31 additions & 27 deletions .github/workflows/docker-build-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,6 @@ name: Docker build images

on: # yamllint disable-line rule:truthy
workflow_call:
outputs:
built-images:
description: |
Built images data.
Example:
```json
{
"application": {
"name": "application",
"registry": "ghcr.io",
"repository": "my-org/my-repo/application",
"tags": ["pr-63-5222075","pr-63"],
"images": [
"ghcr.io/my-org/my-repo/application:pr-63-5222075@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"ghcr.io/my-org/my-repo/application:pr-63@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d"
],
"digest": "sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"annotations": {
"org.opencontainers.image.created": "2021-09-30T14:00:00Z",
"org.opencontainers.image.description": "Application image"
}
}
}
```
value: ${{ jobs.publish-manifests.outputs.built-images }}
inputs:
runs-on:
description: |
Expand Down Expand Up @@ -141,6 +116,32 @@ on: # yamllint disable-line rule:truthy
GitHub App private key to generate GitHub token to be passed as build secret env.
See https://github.com/actions/create-github-app-token.
required: false
outputs:
built-images:
description: |
Built images data.
Example:
```json
{
"application": {
"name": "application",
"registry": "ghcr.io",
"repository": "my-org/my-repo/application",
"tags": ["pr-63-5222075","pr-63"],
"images": [
"ghcr.io/my-org/my-repo/application:pr-63-5222075@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"ghcr.io/my-org/my-repo/application:pr-63@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d"
],
"digest": "sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"annotations": {
"org.opencontainers.image.created": "2021-09-30T14:00:00Z",
"org.opencontainers.image.description": "Application image"
},
"platforms": ["linux/amd64", "linux/arm64"]
}
}
```
value: ${{ jobs.publish-manifests.outputs.built-images }}

permissions:
contents: read
Expand Down Expand Up @@ -474,15 +475,17 @@ jobs:
// Group by image name
const images = {};
builtImages.forEach(builtImage => {
const { name, image, ...rest } = builtImage;
const { name, image, platform, ...rest } = builtImage;
if (!images[name]) {
images[name] = {
name,
images: [image],
platforms: [platform],
...rest,
};
} else {
images[name].images = [...new Set([...images[name].images, image])];
images[name].platforms = [...new Set([...images[name].platforms, platform])];
}
});

Expand Down Expand Up @@ -512,6 +515,7 @@ jobs:
built-images: ${{ steps.built-images.outputs.built-images }}

- id: get-images-to-sign
if: inputs.sign
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
Expand All @@ -527,7 +531,7 @@ jobs:
const imagesToSign = Object.values(builtImages).map(image => image.images).flat();
core.setOutput('images-to-sign', JSON.stringify(imagesToSign));
- uses: ./self-workflow/actions/docker/sign-images
if: inputs.sign
if: steps.get-images-to-sign.outputs.images-to-sign
with:
images: ${{ steps.get-images-to-sign.outputs.images-to-sign }}
github-token: ${{ secrets.GITHUB_TOKEN }}
154 changes: 104 additions & 50 deletions actions/docker/build-image/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,6 @@ branding:
icon: package
color: blue

outputs:
built-image:
description: |
Built image data.
Example:
```json
{
"name": "application",
"registry": "ghcr.io",
"repository": "my-org/my-repo/application",
"digest": "sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"image": "ghcr.io/my-org/my-repo/application@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"tags": [
"pr-63-5222075",
"pr-63"
],
"annotations": {
"org.opencontainers.image.created": "2021-09-30T14:00:00Z",
"org.opencontainers.image.description": "Application image"
}
}
```
value: ${{ steps.get-built-image.outputs.built-image }}

inputs:
oci-registry:
description: "OCI registry where to pull and push images"
Expand Down Expand Up @@ -70,7 +46,7 @@ inputs:
required: false
platform:
description: |
Platform to build for.
Platform to build for. Example: `linux/amd64`.
See https://github.com/docker/build-push-action#inputs.
required: true
context:
Expand Down Expand Up @@ -112,6 +88,31 @@ inputs:
default: "gha"
required: false

outputs:
built-image:
description: |
Built image data.
Example:
```json
{
"name": "application",
"registry": "ghcr.io",
"repository": "my-org/my-repo/application",
"digest": "sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"image": "ghcr.io/my-org/my-repo/application@sha256:d31aa93410434ac9dcfc9179cac2cb1fd4d7c27f11527addc40299c7c675f49d",
"tags": [
"pr-63-5222075",
"pr-63"
],
"annotations": {
"org.opencontainers.image.created": "2021-09-30T14:00:00Z",
"org.opencontainers.image.description": "Application image"
},
"platform": "linux/amd64"
}
```
value: ${{ steps.get-built-image.outputs.built-image }}

runs:
using: "composite"
steps:
Expand Down Expand Up @@ -142,6 +143,14 @@ runs:
- id: get-docker-config
shell: bash
run: |
DOCKERFILE_PATH="${{ github.workspace }}/${{ inputs.context }}/${{ inputs.dockerfile }}"
if [ ! -f "$DOCKERFILE_PATH" ]; then
echo "::error::Dockerfile not found at path: $DOCKERFILE_PATH"
exit 1
fi
DOCKERFILE_PATH=$(realpath "$DOCKERFILE_PATH")
echo "dockerfile-path=$DOCKERFILE_PATH" >> "$GITHUB_OUTPUT"

TAG_SUFFIX="-${{ steps.slugify-platform.outputs.result }}"

# Add tag suffix flavor
Expand Down Expand Up @@ -201,7 +210,24 @@ runs:
fi
fi

- id: cache
- if: steps.get-docker-config.outputs.docker-exists != 'true'
uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4.4.0

- if: steps.get-docker-config.outputs.platform-exists != 'true'
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
with:
platforms: ${{ inputs.platform }}

- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
with:
# FIXME: upgrade version when available (https://github.com/docker/buildx/releases)
version: v0.29.1
# FIXME: upgrade version when available (https://hub.docker.com/r/moby/buildkit)
driver-opts: |
image=moby/buildkit:v0.25.1

# Caching setup
- id: cache-arguments
uses: int128/docker-build-cache-config-action@fb186e80c08f14a2e56ed9105d4594562bff013f # v1.40.0
with:
image: ${{ steps.get-docker-config.outputs.cache-image }}
Expand All @@ -216,8 +242,8 @@ runs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const cacheFrom = `${{ steps.cache.outputs.cache-from }}`;
const cacheTo = `${{ steps.cache.outputs.cache-to }}`;
const cacheFrom = `${{ steps.cache-arguments.outputs.cache-from }}`;
const cacheTo = `${{ steps.cache-arguments.outputs.cache-to }}`;

core.info(`Original cache-from: ${cacheFrom}`);
core.info(`Original cache-to: ${cacheTo}`);
Expand All @@ -234,22 +260,19 @@ runs:
core.setOutput('cache-from', transformedCacheFrom);
core.setOutput('cache-to', transformedCacheTo);

- if: steps.get-docker-config.outputs.docker-exists != 'true'
uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4.4.0

- if: steps.get-docker-config.outputs.platform-exists != 'true'
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
id: cache
with:
platforms: ${{ inputs.platform }}
path: cache-mount
key: cache-mount-${{ hashFiles(steps.get-docker-config.outputs.dockerfile-path) }}

# jscpd:ignore-start
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Restore Docker cache mounts
uses: reproducible-containers/buildkit-cache-dance@5b81f4d29dc8397a7d341dba3aeecc7ec54d6361 # v3.3.0
with:
# FIXME: upgrade version when available (https://github.com/docker/buildx/releases)
version: v0.27.0
# FIXME: upgrade version when available (https://hub.docker.com/r/moby/buildkit)
driver-opts: |
image=moby/buildkit:v0.23.2
builder: ${{ steps.setup-buildx.outputs.name }}
cache-dir: cache-mount
dockerfile: ${{ steps.get-docker-config.outputs.dockerfile-path }}
skip-extraction: ${{ steps.cache.outputs.cache-hit }}

- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
Expand All @@ -264,19 +287,22 @@ runs:
context: ${{ inputs.context }}
build-args: ${{ inputs.build-args }}
target: ${{ inputs.target }}
file: ${{ github.workspace }}/${{ inputs.context }}/${{ inputs.dockerfile }}
file: ${{ steps.get-docker-config.outputs.dockerfile-path }}
secrets: ${{ inputs.secrets }}
secret-envs: ${{ inputs.secret-envs }}
platforms: ${{ inputs.platform }}
# FIXME: Remove 'inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-from ||'
# when https://github.com/int128/docker-build-cache-config-action/pull/1213 is merged
cache-from: ${{ inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-from || steps.cache.outputs.cache-from }}
cache-from: ${{ inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-from || steps.cache-arguments.outputs.cache-from }}
# FIXME: Remove 'inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-to ||'
# when https://github.com/int128/docker-build-cache-config-action/pull/1213 is merged
cache-to: ${{ inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-to || steps.cache.outputs.cache-to }}
outputs: "type=image,push=true,push-by-digest=true,name-canonical=true,name=${{ steps.metadata.outputs.image }}"
cache-to: ${{ inputs.cache-type == 'gha' && steps.transform-cache-gha.outputs.cache-to || steps.cache-arguments.outputs.cache-to }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
labels: ${{ steps.metadata.outputs.labels }}
annotations: ${{ steps.metadata.outputs.annotations }}
tags: ${{ steps.metadata.outputs.image }}
provenance: false # Disable provenance to avoid unknown/unknown arch
sbom: false # Disable sbom to avoid unknown/unknown arch

- id: get-built-image
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
Expand All @@ -288,10 +314,6 @@ runs:
return;
}

if (builtMetadata["containerimage.digest"] === undefined) {
return core.setFailed('Given "metadata"."containerimage.digest" output is undefined.');
}

const name = `${{ inputs.image }}`;
const image = `${{ steps.metadata.outputs.image }}`;
const registryMatch = image.match(/^([^\/]+)\/.*/);
Expand All @@ -304,6 +326,37 @@ runs:
.map(tag => tag.replace(/[^\/]+\/[^:]+:(.+)/,'$1').trim())
.filter(tag => tag !== "");

let platform;

const buildxProvenance = builtMetadata?.["buildx.build.provenance"];
if (buildxProvenance !== undefined) {
platform = buildxProvenance.invocation?.environment?.platform;
if (platform === undefined) {
return core.setFailed('Given "metadata"."buildx.build.provenance"."invocation"."environment"."platform" output is undefined.');
}
if (typeof platform !== "string") {
return core.setFailed('Given "metadata"."buildx.build.provenance"."invocation"."environment"."platform" is not a string.');
}
platform = platform.trim();
if (platform === "") {
return core.setFailed('Given "metadata"."buildx.build.provenance"."invocation"."environment"."platform" is empty.');
}
} else {
const descriptor = builtMetadata?.["containerimage.descriptor"];
if (descriptor?.["platform"] === undefined) {
return core.setFailed('Given "metadata"."containerimage.descriptor"."platform" output is undefined.');
}
const platformData = descriptor["platform"];
if (typeof platformData !== 'object' || platformData.os === undefined || platformData.architecture === undefined) {
return core.setFailed('Given "metadata"."containerimage.descriptor"."platform" does not contain required "os" and "architecture" fields.');
}
platform = `${platformData.os}/${platformData.architecture}${platformData.variant ? `/${platformData.variant}` : ''}`;
}

if (builtMetadata?.["containerimage.digest"] === undefined) {
return core.setFailed('Given "metadata"."containerimage.digest" output is undefined.');
}

const digests = builtMetadata["containerimage.digest"]
.split(",")
.map(digest => {
Expand Down Expand Up @@ -346,7 +399,8 @@ runs:
registry,
repository,
image: imageWithDigest,
digest
digest,
platform
};

core.setOutput("built-image", JSON.stringify(builtImage));
Loading
Loading