Skip to content
Merged
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
137 changes: 137 additions & 0 deletions build-devcontainer/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: "build-devcontainer"

description: "Build devcontainer image"

inputs:
tag: {type: string, required: true, description: "Image tag"}
arch: {type: string, required: true, description: "Image arch"}
repo: {type: string, required: true, description: "Image repo"}
push: {type: string, required: true, description: "Whether to push the image"}
version: {type: string, required: true, description: "Repository version number"}
retries: {type: string, default: '3', description: "Number of times to retry the container build"}
workspace-dir: {type: string, default: '.', description: "Devcontainer workspace directory"}
devcontainer-json: {type: string, required: true, description: "Path to the devcontainer.json file"}

outputs:
hash_amd64:
value: "${{ steps.build.outputs.hash_amd64 }}"
hash_arm64:
value: "${{ steps.build.outputs.hash_arm64 }}"
repo:
value: "${{ steps.build.outputs.repo }}"
tag:
value: "${{ steps.build.outputs.tag }}"
name:
value: "${{ steps.build.outputs.name }}"
name_latest:
value: "${{ steps.build.outputs.name_latest }}"

runs:
using: composite
steps:
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '24'

- if: runner.environment != 'self-hosted'
name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4

- name: Create docker context
shell: bash
run: docker context create builder

- if: runner.environment != 'self-hosted'
name: Setup docker buildx on github-hosted runners
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
with:
endpoint: builder

- if: runner.environment == 'self-hosted'
name: Setup docker buildx on self-hosted runners
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
with:
buildkitd-config: /etc/buildkit/buildkitd.toml
buildkitd-flags: --config /etc/buildkit/buildkitd.toml
endpoint: builder

- if: runner.environment == 'self-hosted'
name: Setup proxy cache
uses: nv-gha-runners/setup-proxy-cache@c5e8f6fd27b493abfd6af230e6a5d4bf43d1d766
continue-on-error: true
with:
enable-apt: true

- name: Install devcontainers CLI
shell: bash
env:
push: "${{ inputs.push }}"
run: |
sudo apt update;
sudo apt install -y --no-install-recommends build-essential;
npm install -g @devcontainers/cli@v0.85.0;
if "${push}"; then
# HACK: remove the `-t` arg from the `docker buildx build` command generated by `devcontainer build`
sed -i 's/,t.map(G=>l.push("-t",G))//g' "$(npm list -g | head -n1)"/node_modules/@devcontainers/cli/dist/spec-node/devContainersSpecCLI.js;
fi

- id: build
name: Build ${{ inputs.repo }}:${{ inputs.tag }} (${{ inputs.arch }})
shell: bash
env:
NODE_NO_WARNINGS: 1
arch: "${{ inputs.arch }}"
push: "${{ inputs.push }}"
repo: "${{ inputs.repo }}"
retries: "${{ inputs.retries }}"
tag: "${{ inputs.tag }}"
version: "${{ inputs.version }}"
workspace_dir: "${{ inputs.workspace-dir }}"
devcontainer_json: "${{ inputs.devcontainer-json }}"
run: |
set -euo pipefail;

declare i=0;
declare -a outputs=();

# Ensure tag and repo are lowercase
tag="${tag,,}"
repo="${repo,,}"
name="${repo}:${version}-${tag}"
name_latest="${repo}:latest-${tag}"

echo "tag=${tag}" >> "$GITHUB_OUTPUT";
echo "repo=${repo}" >> "$GITHUB_OUTPUT";
echo "name=${name}" >> "$GITHUB_OUTPUT";
echo "name_latest=${name_latest}" >> "$GITHUB_OUTPUT";

if "${push}"; then
outputs+=(--output "type=image,compression=zstd,force-compression=true,oci-mediatypes=true,push=true,push-by-digest=true,name=${repo}");
fi

until devcontainer build \
--cache-from "${name}" \
--image-name "${name}" \
--platform "linux/${arch}" \
--config "$devcontainer_json" \
--workspace-folder "$workspace_dir" \
"${outputs[@]}" 2>&1 \
| tee "${{ runner.temp }}/${arch}.log" 1>&2
do
if test "${i}" -lt "${retries}"; then
j=$((i++));
t=$((i * i * 5));
echo "Attempt $j failed! Trying again in $t seconds...";
sleep $t;
else
echo "Failed to build ${name}";
exit 1;
fi
done

if test "${push}" = true; then
echo "hash_${arch}=$(grep 'exporting manifest sha256:' "${{ runner.temp }}/${arch}.log" | tail -n1 | grep -oP 'sha256:\w+')" >> "$GITHUB_OUTPUT";
else
echo "hash_${arch}=" >> "$GITHUB_OUTPUT";
fi
Loading