fix: Scope image build credentials #49
+7
-14
@@ -1,61 +1,54 @@
|
||||
ARG SOURCE_DATE_EPOCH=0
|
||||
|
||||
FROM rust:1.95.0-bookworm@sha256:6258907abe69656e41cd992e0b705cdcfabcbbe3db374f92ed2d47121282d4a1 AS source
|
||||
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
# The test suite is deliberately absent here. Its store tests refuse to pass
|
||||
# without a Postgres to run against, and an image build has none; running the
|
||||
# rest and calling it validation would say "verified" about the part that is
|
||||
# not. The full suite, database included, runs in pull-request.yml.
|
||||
FROM source AS validation
|
||||
ARG TARGETARCH
|
||||
RUN --mount=type=cache,id=syncode-control-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
|
||||
--mount=type=cache,id=syncode-control-validation-${TARGETARCH},target=/src/target,sharing=locked \
|
||||
--mount=type=secret,id=syncode_git_user,env=SYNCODE_GIT_USER \
|
||||
--mount=type=secret,id=syncode_git_token,env=SYNCODE_GIT_TOKEN \
|
||||
AUTHORIZATION="$(printf '%s:%s' "${SYNCODE_GIT_USER}" "${SYNCODE_GIT_TOKEN}" | base64 | tr -d '\n')" \
|
||||
&& git config --global http.https://syncode.sh/.extraheader "AUTHORIZATION: basic ${AUTHORIZATION}" \
|
||||
&& cargo fmt --check \
|
||||
&& cargo clippy --workspace --all-targets --all-features -- -D warnings \
|
||||
&& ./scripts/check-architecture.sh \
|
||||
&& ./scripts/check-rust-loc.sh \
|
||||
&& git config --global --unset-all http.https://syncode.sh/.extraheader
|
||||
|
||||
FROM source AS builder
|
||||
ARG TARGETARCH
|
||||
RUN --mount=type=cache,id=syncode-control-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
|
||||
--mount=type=cache,id=syncode-control-release-${TARGETARCH},target=/src/target,sharing=locked \
|
||||
--mount=type=secret,id=syncode_git_user,env=SYNCODE_GIT_USER \
|
||||
--mount=type=secret,id=syncode_git_token,env=SYNCODE_GIT_TOKEN \
|
||||
AUTHORIZATION="$(printf '%s:%s' "${SYNCODE_GIT_USER}" "${SYNCODE_GIT_TOKEN}" | base64 | tr -d '\n')" \
|
||||
&& git config --global http.https://syncode.sh/.extraheader "AUTHORIZATION: basic ${AUTHORIZATION}" \
|
||||
&& cargo build --locked --release \
|
||||
&& install -D -m 0755 target/release/syncode-control /out/syncode-control \
|
||||
&& git config --global --unset-all http.https://syncode.sh/.extraheader
|
||||
|
||||
FROM debian:bookworm-slim@sha256:7b140f374b289a7c2befc338f42ebe6441b7ea838a042bbd5acbfca6ec875818
|
||||
|
||||
ARG VERSION=dev
|
||||
|
||||
LABEL org.opencontainers.image.source="https://syncode.sh/syncode/control"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
|
||||
COPY --from=source /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /out/syncode-control /usr/local/bin/syncode-control
|
||||
|
||||
# Nodes open their session on one port and the forge delivers events on the
|
||||
# other. They are separate because they are addressed differently: one is
|
||||
# reached by runners, the other only by the forge.
|
||||
EXPOSE 8090 8091
|
||||
|
||||
USER nobody
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/syncode-control"]
|
||||
|
||||
# The binary defaults to the loopback, which is right when someone runs it on
|
||||
# their own machine and useless inside a container: the network is the only way
|
||||
# in. The image therefore listens on every interface, and the container's own
|
||||
# isolation is what keeps that private.
|
||||
CMD ["--listen", "0.0.0.0:8090", "--listen-events", "0.0.0.0:8091"]
|
||||
ARG SOURCE_DATE_EPOCH=0
|
||||
|
||||
FROM rust:1.95.0-bookworm@sha256:6258907abe69656e41cd992e0b705cdcfabcbbe3db374f92ed2d47121282d4a1 AS source
|
||||
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
# The test suite is deliberately absent here. Its store tests refuse to pass
|
||||
# without a Postgres to run against, and an image build has none; running the
|
||||
# rest and calling it validation would say "verified" about the part that is
|
||||
# not. The full suite, database included, runs in pull-request.yml.
|
||||
FROM source AS validation
|
||||
ARG TARGETARCH
|
||||
RUN --mount=type=cache,id=syncode-control-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
|
||||
--mount=type=cache,id=syncode-control-validation-${TARGETARCH},target=/src/target,sharing=locked \
|
||||
--mount=type=secret,id=syncode_git_config,target=/root/.gitconfig,required=true \
|
||||
cargo fmt --check \
|
||||
&& cargo clippy --workspace --all-targets --all-features -- -D warnings \
|
||||
&& cargo test --workspace --all-targets --all-features \
|
||||
&& ./scripts/check-architecture.sh \
|
||||
&& ./scripts/check-rust-loc.sh
|
||||
|
||||
FROM source AS builder
|
||||
ARG TARGETARCH
|
||||
RUN --mount=type=cache,id=syncode-control-cargo-registry-${TARGETARCH},target=/usr/local/cargo/registry,sharing=locked \
|
||||
--mount=type=cache,id=syncode-control-release-${TARGETARCH},target=/src/target,sharing=locked \
|
||||
--mount=type=secret,id=syncode_git_config,target=/root/.gitconfig,required=true \
|
||||
cargo build --locked --release \
|
||||
&& install -D -m 0755 target/release/syncode-control /out/syncode-control
|
||||
|
||||
FROM debian:bookworm-slim@sha256:7b140f374b289a7c2befc338f42ebe6441b7ea838a042bbd5acbfca6ec875818
|
||||
|
||||
ARG VERSION=dev
|
||||
|
||||
LABEL org.opencontainers.image.source="https://syncode.sh/syncode/control"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
|
||||
COPY --from=source /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /out/syncode-control /usr/local/bin/syncode-control
|
||||
|
||||
# Nodes open their session on one port and the forge delivers events on the
|
||||
# other. They are separate because they are addressed differently: one is
|
||||
# reached by runners, the other only by the forge.
|
||||
EXPOSE 8090 8091
|
||||
|
||||
USER nobody
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/syncode-control"]
|
||||
|
||||
# The binary defaults to the loopback, which is right when someone runs it on
|
||||
# their own machine and useless inside a container: the network is the only way
|
||||
# in. The image therefore listens on every interface, and the container's own
|
||||
# isolation is what keeps that private.
|
||||
CMD ["--listen", "0.0.0.0:8090", "--listen-events", "0.0.0.0:8091"]
|
||||
@@ -1,224 +1,221 @@
|
||||
name: build-image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, main]
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: control-build-image-${{ github.ref_name }}
|
||||
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
||||
|
||||
env:
|
||||
CONTROL_IMAGE: syncode.sh/syncode/control
|
||||
|
||||
jobs:
|
||||
resolve:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
operation: ${{ steps.release.outputs.operation }}
|
||||
product_version: ${{ steps.release.outputs.product_version }}
|
||||
source: ${{ steps.release.outputs.source }}
|
||||
tags: ${{ steps.release.outputs.tags }}
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- id: release
|
||||
name: Resolve release
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SHA="$(git rev-parse --short HEAD)"
|
||||
BASE_VERSION="$(tr -d '[:space:]' < VERSION)"
|
||||
OPERATION=build
|
||||
NAMES=
|
||||
case "${GITHUB_REF}" in
|
||||
refs/tags/*)
|
||||
VERSION="${BASE_VERSION}"
|
||||
test "${GITHUB_REF_NAME#v}" = "${BASE_VERSION}"
|
||||
OPERATION=promote
|
||||
;;
|
||||
refs/heads/develop)
|
||||
VERSION="${BASE_VERSION}-dev"
|
||||
NAMES="${SHA} develop ${VERSION}"
|
||||
;;
|
||||
refs/heads/main)
|
||||
VERSION="${BASE_VERSION}"
|
||||
NAMES="${SHA} main latest"
|
||||
;;
|
||||
*)
|
||||
echo "unsupported ref: ${GITHUB_REF}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# The digest of the sources the image is built from, so a rebuild of
|
||||
# the same tree reuses the published image instead of producing a
|
||||
# second one that differs only by timestamp.
|
||||
HASH="$( { git ls-files -s -- . \
|
||||
':(exclude).gitea/**' ':(exclude)*.md' ':(exclude)LICENSE'
|
||||
printf 'version=%s\n' "${VERSION}"; } | git hash-object --stdin | cut -c1-12)"
|
||||
refs() {
|
||||
local separator=""
|
||||
for name in "$@"; do
|
||||
printf '%s%s:%s' "${separator}" "${CONTROL_IMAGE}" "${name}"
|
||||
separator=,
|
||||
done
|
||||
}
|
||||
{
|
||||
echo "operation=${OPERATION}"
|
||||
echo "product_version=${VERSION}"
|
||||
echo "source=${CONTROL_IMAGE}:src-${HASH}"
|
||||
echo "tags=$(refs ${NAMES})"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
validate:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
target: validation
|
||||
outputs: type=cacheonly
|
||||
secrets: |
|
||||
"syncode_git_user=${{ secrets.REGISTRY_USER }}"
|
||||
"syncode_git_token=${{ secrets.REGISTRY_TOKEN }}"
|
||||
|
||||
published:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
exists: ${{ steps.check.outputs.exists }}
|
||||
steps:
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- id: check
|
||||
name: Look for the image in the registry
|
||||
env:
|
||||
SOURCE: ${{ needs.resolve.outputs.source }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if docker buildx imagetools inspect "${SOURCE}" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "exists=false" >> "${GITHUB_OUTPUT}"
|
||||
fi
|
||||
|
||||
# Each architecture builds natively on a runner labeled for it, rather than
|
||||
# one job cross-building both under QEMU — arm64 under emulation was slow
|
||||
# enough to stall the whole CI queue behind it (meta issue #42).
|
||||
image-amd64:
|
||||
needs: [resolve, validate, published]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' && needs.published.outputs.exists == 'false' }}
|
||||
runs-on: syncode-linux-amd64
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
provenance: false
|
||||
build-args: |
|
||||
SOURCE_DATE_EPOCH=0
|
||||
VERSION=${{ needs.resolve.outputs.product_version }}
|
||||
tags: ${{ needs.resolve.outputs.source }}-amd64
|
||||
cache-from: type=registry,ref=syncode.sh/syncode/control:buildcache-amd64
|
||||
cache-to: type=registry,ref=syncode.sh/syncode/control:buildcache-amd64,mode=max
|
||||
outputs: type=registry,rewrite-timestamp=true
|
||||
secrets: |
|
||||
"syncode_git_user=${{ secrets.REGISTRY_USER }}"
|
||||
"syncode_git_token=${{ secrets.REGISTRY_TOKEN }}"
|
||||
|
||||
image-arm64:
|
||||
needs: [resolve, validate, published]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' && needs.published.outputs.exists == 'false' }}
|
||||
runs-on: syncode-linux-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
provenance: false
|
||||
build-args: |
|
||||
SOURCE_DATE_EPOCH=0
|
||||
VERSION=${{ needs.resolve.outputs.product_version }}
|
||||
tags: ${{ needs.resolve.outputs.source }}-arm64
|
||||
cache-from: type=registry,ref=syncode.sh/syncode/control:buildcache-arm64
|
||||
cache-to: type=registry,ref=syncode.sh/syncode/control:buildcache-arm64,mode=max
|
||||
outputs: type=registry,rewrite-timestamp=true
|
||||
secrets: |
|
||||
"syncode_git_user=${{ secrets.REGISTRY_USER }}"
|
||||
"syncode_git_token=${{ secrets.REGISTRY_TOKEN }}"
|
||||
|
||||
image:
|
||||
needs: [resolve, published, image-amd64, image-arm64]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Combine per-arch images and point the release tags at them
|
||||
env:
|
||||
SOURCE: ${{ needs.resolve.outputs.source }}
|
||||
TAGS: ${{ needs.resolve.outputs.tags }}
|
||||
EXISTS: ${{ needs.published.outputs.exists }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${EXISTS}" = "false" ]; then
|
||||
docker buildx imagetools create --tag "${SOURCE}" "${SOURCE}-amd64" "${SOURCE}-arm64"
|
||||
fi
|
||||
for REF in ${TAGS//,/ }; do
|
||||
docker buildx imagetools create --tag "${REF}" "${SOURCE}"
|
||||
done
|
||||
|
||||
promote:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'promote' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Promote release manifests
|
||||
env:
|
||||
PRODUCT_VERSION: ${{ needs.resolve.outputs.product_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
MAIN_SHA="$(git ls-remote origin refs/heads/main | awk 'NR == 1 {print $1}')"
|
||||
test -n "${MAIN_SHA}"
|
||||
test "$(git rev-parse HEAD)" = "${MAIN_SHA}"
|
||||
docker buildx imagetools create \
|
||||
--tag "${CONTROL_IMAGE}:${PRODUCT_VERSION}" \
|
||||
"${CONTROL_IMAGE}:main"
|
||||
name: build-image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, main]
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: control-build-image-${{ github.ref_name }}
|
||||
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
||||
|
||||
env:
|
||||
CONTROL_IMAGE: syncode.sh/syncode/control
|
||||
|
||||
jobs:
|
||||
resolve:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
operation: ${{ steps.release.outputs.operation }}
|
||||
product_version: ${{ steps.release.outputs.product_version }}
|
||||
source: ${{ steps.release.outputs.source }}
|
||||
tags: ${{ steps.release.outputs.tags }}
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- id: release
|
||||
name: Resolve release
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SHA="$(git rev-parse --short HEAD)"
|
||||
BASE_VERSION="$(tr -d '[:space:]' < VERSION)"
|
||||
OPERATION=build
|
||||
NAMES=
|
||||
case "${GITHUB_REF}" in
|
||||
refs/tags/*)
|
||||
VERSION="${BASE_VERSION}"
|
||||
test "${GITHUB_REF_NAME#v}" = "${BASE_VERSION}"
|
||||
OPERATION=promote
|
||||
;;
|
||||
refs/heads/develop)
|
||||
VERSION="${BASE_VERSION}-dev"
|
||||
NAMES="${SHA} develop ${VERSION}"
|
||||
;;
|
||||
refs/heads/main)
|
||||
VERSION="${BASE_VERSION}"
|
||||
NAMES="${SHA} main latest"
|
||||
;;
|
||||
*)
|
||||
echo "unsupported ref: ${GITHUB_REF}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# The digest of the sources the image is built from, so a rebuild of
|
||||
# the same tree reuses the published image instead of producing a
|
||||
# second one that differs only by timestamp.
|
||||
HASH="$( { git ls-files -s -- . \
|
||||
':(exclude).gitea/**' ':(exclude)*.md' ':(exclude)LICENSE'
|
||||
printf 'version=%s\n' "${VERSION}"; } | git hash-object --stdin | cut -c1-12)"
|
||||
refs() {
|
||||
local separator=""
|
||||
for name in "$@"; do
|
||||
printf '%s%s:%s' "${separator}" "${CONTROL_IMAGE}" "${name}"
|
||||
separator=,
|
||||
done
|
||||
}
|
||||
{
|
||||
echo "operation=${OPERATION}"
|
||||
echo "product_version=${VERSION}"
|
||||
echo "source=${CONTROL_IMAGE}:src-${HASH}"
|
||||
echo "tags=$(refs ${NAMES})"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
validate:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
target: validation
|
||||
outputs: type=cacheonly
|
||||
secrets: |
|
||||
"syncode_git_config=${{ secrets.SYNCODE_GIT_CONFIG }}"
|
||||
|
||||
published:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
exists: ${{ steps.check.outputs.exists }}
|
||||
steps:
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- id: check
|
||||
name: Look for the image in the registry
|
||||
env:
|
||||
SOURCE: ${{ needs.resolve.outputs.source }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if docker buildx imagetools inspect "${SOURCE}" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "exists=false" >> "${GITHUB_OUTPUT}"
|
||||
fi
|
||||
|
||||
# Each architecture builds natively on a runner labeled for it, rather than
|
||||
# one job cross-building both under QEMU — arm64 under emulation was slow
|
||||
# enough to stall the whole CI queue behind it (meta issue #42).
|
||||
image-amd64:
|
||||
needs: [resolve, validate, published]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' && needs.published.outputs.exists == 'false' }}
|
||||
runs-on: syncode-linux-amd64
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
provenance: false
|
||||
build-args: |
|
||||
SOURCE_DATE_EPOCH=0
|
||||
VERSION=${{ needs.resolve.outputs.product_version }}
|
||||
tags: ${{ needs.resolve.outputs.source }}-amd64
|
||||
cache-from: type=registry,ref=syncode.sh/syncode/control:buildcache-amd64
|
||||
cache-to: type=registry,ref=syncode.sh/syncode/control:buildcache-amd64,mode=max
|
||||
outputs: type=registry,rewrite-timestamp=true
|
||||
secrets: |
|
||||
"syncode_git_config=${{ secrets.SYNCODE_GIT_CONFIG }}"
|
||||
|
||||
image-arm64:
|
||||
needs: [resolve, validate, published]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' && needs.published.outputs.exists == 'false' }}
|
||||
runs-on: syncode-linux-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
provenance: false
|
||||
build-args: |
|
||||
SOURCE_DATE_EPOCH=0
|
||||
VERSION=${{ needs.resolve.outputs.product_version }}
|
||||
tags: ${{ needs.resolve.outputs.source }}-arm64
|
||||
cache-from: type=registry,ref=syncode.sh/syncode/control:buildcache-arm64
|
||||
cache-to: type=registry,ref=syncode.sh/syncode/control:buildcache-arm64,mode=max
|
||||
outputs: type=registry,rewrite-timestamp=true
|
||||
secrets: |
|
||||
"syncode_git_config=${{ secrets.SYNCODE_GIT_CONFIG }}"
|
||||
|
||||
image:
|
||||
needs: [resolve, published, image-amd64, image-arm64]
|
||||
if: ${{ needs.resolve.outputs.operation == 'build' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Combine per-arch images and point the release tags at them
|
||||
env:
|
||||
SOURCE: ${{ needs.resolve.outputs.source }}
|
||||
TAGS: ${{ needs.resolve.outputs.tags }}
|
||||
EXISTS: ${{ needs.published.outputs.exists }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${EXISTS}" = "false" ]; then
|
||||
docker buildx imagetools create --tag "${SOURCE}" "${SOURCE}-amd64" "${SOURCE}-arm64"
|
||||
fi
|
||||
for REF in ${TAGS//,/ }; do
|
||||
docker buildx imagetools create --tag "${REF}" "${SOURCE}"
|
||||
done
|
||||
|
||||
promote:
|
||||
needs: resolve
|
||||
if: ${{ needs.resolve.outputs.operation == 'promote' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: syncode.sh
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Promote release manifests
|
||||
env:
|
||||
PRODUCT_VERSION: ${{ needs.resolve.outputs.product_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
MAIN_SHA="$(git ls-remote origin refs/heads/main | awk 'NR == 1 {print $1}')"
|
||||
test -n "${MAIN_SHA}"
|
||||
test "$(git rev-parse HEAD)" = "${MAIN_SHA}"
|
||||
docker buildx imagetools create \
|
||||
--tag "${CONTROL_IMAGE}:${PRODUCT_VERSION}" \
|
||||
"${CONTROL_IMAGE}:main"
|
||||
Reference in New Issue
Block a user