251 lines
9.7 KiB
YAML
251 lines
9.7 KiB
YAML
name: Build Docker image
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
repo:
|
||
description: 仓库地址
|
||
required: true
|
||
type: string
|
||
|
||
ref:
|
||
description: 分支名称
|
||
required: true
|
||
type: string
|
||
|
||
image_name:
|
||
description: 镜像名称
|
||
required: true
|
||
type: string
|
||
|
||
image_tag:
|
||
description: 镜像标签
|
||
required: false
|
||
default: latest
|
||
type: string
|
||
|
||
build_context:
|
||
description: 构建上下文目录
|
||
required: false
|
||
type: string
|
||
default: .
|
||
|
||
dockerfile:
|
||
description: Dockerfile 在仓库中的路径
|
||
required: false
|
||
type: string
|
||
default: Dockerfile
|
||
|
||
architectures:
|
||
description: 构建架构
|
||
required: false
|
||
type: string
|
||
default: "linux/amd64, linux/arm64, linux/arm/v7"
|
||
|
||
build_args:
|
||
description: 以空格分隔的列表,格式为`arg_name=value`,用于定义Dockerfile中指定的构建参数
|
||
required: false
|
||
type: string
|
||
|
||
build_target:
|
||
description: 构建目标
|
||
required: false
|
||
type: string
|
||
|
||
env:
|
||
IMAGE_DESCRIPTION: Built by GitHub Actions, the associated workflow is https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
id-token: write
|
||
attestations: write
|
||
|
||
jobs:
|
||
publish-docker:
|
||
name: Build and publish
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- name: Confirm current parameters
|
||
env:
|
||
REPO_URL: ${{ github.event.inputs.repo }}
|
||
TARGET_REF: ${{ github.event.inputs.ref }}
|
||
IMAGE_NAME: ${{ github.event.inputs.image_name }}
|
||
IMAGE_TAG: ${{ github.event.inputs.image_tag }}
|
||
BUILD_CONTEXT: ${{ github.event.inputs.build_context }}
|
||
DOCKERFILE: ${{ github.event.inputs.dockerfile }}
|
||
ARCHITECTURES: ${{ github.event.inputs.architectures }}
|
||
BUILD_ARGS: ${{ github.event.inputs.build_args }}
|
||
BUILD_TARGET: ${{ github.event.inputs.build_target }}
|
||
run: |
|
||
echo "REPO_URL=$REPO_URL"
|
||
echo "TARGET_REF=$TARGET_REF"
|
||
echo "IMAGE_NAME=$IMAGE_NAME"
|
||
echo "IMAGE_TAG=$IMAGE_TAG"
|
||
echo "BUILD_CONTEXT=$BUILD_CONTEXT"
|
||
echo "DOCKERFILE=$DOCKERFILE"
|
||
echo "ARCHITECTURES=$ARCHITECTURES"
|
||
echo "BUILD_ARGS=$BUILD_ARGS"
|
||
echo "BUILD_TARGET=$BUILD_TARGET"
|
||
|
||
- name: Set env
|
||
env:
|
||
IMAGE_NAME: ${{ github.event.inputs.image_name }}
|
||
IMAGE_TAG: ${{ github.event.inputs.image_tag }}
|
||
run: |
|
||
owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')
|
||
echo "OWNER=$owner" >> "$GITHUB_ENV"
|
||
echo "IMAGE_FULL_NAME=ghcr.io/$owner/$IMAGE_NAME" >> $GITHUB_ENV
|
||
echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV
|
||
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
|
||
echo "FIRST_TAG=$(echo $IMAGE_TAG | cut -d',' -f1)" >> $GITHUB_ENV
|
||
|
||
- name: Set multiple tags
|
||
id: set-tags
|
||
run: |
|
||
TAGS_ARRAY=($(echo "${{ env.IMAGE_TAG }}" | tr ',' ' '))
|
||
TAGS_MULTILINE=""
|
||
for tag in "${TAGS_ARRAY[@]}"; do
|
||
TAGS_MULTILINE+="type=raw,value=${tag}\n"
|
||
done
|
||
if [[ "${{ env.IMAGE_TAG }}" != *"latest"* ]]; then
|
||
TAGS_MULTILINE+="type=raw,value=latest\n"
|
||
fi
|
||
echo "tags<<EOF" >> $GITHUB_OUTPUT
|
||
echo -e "$TAGS_MULTILINE" >> $GITHUB_OUTPUT
|
||
echo "EOF" >> $GITHUB_OUTPUT
|
||
|
||
- name: Checkout repository
|
||
env:
|
||
REPO_URL: ${{ github.event.inputs.repo }}
|
||
TARGET_REF: ${{ github.event.inputs.ref }}
|
||
run: |
|
||
git clone $REPO_URL .
|
||
git fetch --tags
|
||
git checkout $TARGET_REF
|
||
|
||
- name: Set up Ruby
|
||
uses: ruby/setup-ruby@v1
|
||
with:
|
||
ruby-version: '4.0.1'
|
||
- name: Get license
|
||
run: |
|
||
gem install licensee
|
||
license_result=$(licensee detect --json | jq -r '.licenses[0].spdx_id' 2>&1)
|
||
status=$?
|
||
if [ $status -eq 0 ]; then
|
||
if [ "$license_result" = "null" ] || [ -z "$license_result" ]; then
|
||
echo "LICENSES=none" >> "$GITHUB_ENV"
|
||
else
|
||
echo "LICENSES=$license_result" >> "$GITHUB_ENV"
|
||
fi
|
||
else
|
||
echo "LICENSES=none" >> "$GITHUB_ENV"
|
||
fi
|
||
|
||
- name: Confirm current version
|
||
run: |
|
||
git describe --tags --always
|
||
|
||
- name: Login to GitHub Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ env.OWNER }}
|
||
password: ${{ github.token }}
|
||
|
||
- name: Extract metadata (tags, labels) for image registry
|
||
id: meta
|
||
uses: docker/metadata-action@v5
|
||
with:
|
||
images: ${{ env.IMAGE_FULL_NAME }}
|
||
tags: ${{ steps.set-tags.outputs.tags }}
|
||
annotations: |
|
||
org.opencontainers.image.description=${{ env.IMAGE_DESCRIPTION }}
|
||
org.opencontainers.image.url=${{ github.event.inputs.repo }}
|
||
org.opencontainers.image.source=${{ github.event.inputs.repo }}
|
||
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
|
||
org.opencontainers.image.version=${{ env.FIRST_TAG }}
|
||
${{ env.LICENSES != 'none' && format('org.opencontainers.image.licenses={0}', env.LICENSES) || '' }}
|
||
labels: |
|
||
org.opencontainers.image.description=${{ env.IMAGE_DESCRIPTION }}
|
||
org.opencontainers.image.url=${{ github.event.inputs.repo }}
|
||
org.opencontainers.image.source=${{ github.event.inputs.repo }}
|
||
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
|
||
org.opencontainers.image.version=${{ env.FIRST_TAG }}
|
||
${{ env.LICENSES != 'none' && format('org.opencontainers.image.licenses={0}', env.LICENSES) || '' }}
|
||
env:
|
||
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
|
||
|
||
- name: Set up QEMU
|
||
uses: docker/setup-qemu-action@v3
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
- name: Build and push
|
||
id: push
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
build-args: |
|
||
${{ github.event.inputs.build_args }}
|
||
context: ${{ github.event.inputs.build_context}}
|
||
target: ${{ github.event.inputs.build_target }}
|
||
push: true
|
||
file: ${{ github.event.inputs.dockerfile }}
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
annotations: ${{ steps.meta.outputs.annotations }}
|
||
labels: ${{ steps.meta.outputs.labels }}
|
||
cache-from: type=gha
|
||
cache-to: type=gha,mode=max
|
||
platforms: ${{ github.event.inputs.architectures }}
|
||
|
||
- name: Calculate image size
|
||
run: |
|
||
docker manifest inspect ${{ env.IMAGE_FULL_NAME }}:${{ env.FIRST_TAG }} -v > manifest.json
|
||
curl -o ./get_image_size.sh -s https://raw.githubusercontent.com/${{ github.repository }}/refs/heads/script/get_image_size.sh
|
||
chmod +x get_image_size.sh
|
||
|
||
- name: Get the package id
|
||
run: |
|
||
gh auth login --with-token <<< "${{ github.token }}"
|
||
response=$(gh api \
|
||
-H "Accept: application/vnd.github+json" \
|
||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||
/users/${{ env.OWNER }}/packages/container/${{ env.IMAGE_NAME }}/versions)
|
||
version_id=$(echo "$response" | jq -r '.[] | select(.metadata.container.tags[]? == "${{ env.FIRST_TAG }}") | .id')
|
||
echo "VERSION_ID=$version_id" >> $GITHUB_ENV
|
||
|
||
- name: Add a summary for the job
|
||
run: |
|
||
arch_array=($(echo ${{ github.event.inputs.architectures }} | tr -d '"' | tr ',' '\n' | tr -d ' '))
|
||
echo "## Build Report" >> $GITHUB_STEP_SUMMARY
|
||
echo "### Get the image" >> $GITHUB_STEP_SUMMARY
|
||
echo '<pre lang="bash">' >> $GITHUB_STEP_SUMMARY
|
||
echo "<code>docker pull ${{ env.IMAGE_FULL_NAME }}:${{ env.FIRST_TAG }}</code>" >> $GITHUB_STEP_SUMMARY
|
||
echo "</pre>" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "Image Url: https://github.com/users/${{ env.OWNER }}/packages/container/${{ env.IMAGE_NAME }}/${{ env.VERSION_ID }}?tag=${{ env.FIRST_TAG }}" >> $GITHUB_STEP_SUMMARY
|
||
echo "### Image info" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| Repository | Reference / Branch / Tag | Push Time |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|:-:|:-:|:-:|" >> $GITHUB_STEP_SUMMARY
|
||
echo "| ${{ github.event.inputs.repo }} | [$(git log --pretty=format:"%h" -n 1)](${{ github.event.inputs.repo }}/tree/$(git log --pretty=format:"%H" -n 1)) |$(git log --pretty=format:"%ci" -n 1)|" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| Architecture | Image Size |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|:-:|:-:|" >> $GITHUB_STEP_SUMMARY
|
||
for arch in "${arch_array[@]}"; do
|
||
echo "| $arch | $(./get_image_size.sh --arch $arch) |" >> $GITHUB_STEP_SUMMARY
|
||
done
|
||
echo "### Verify the image" >> $GITHUB_STEP_SUMMARY
|
||
echo "You can use github cli to verify the image, run the command:" >> $GITHUB_STEP_SUMMARY
|
||
echo '<pre lang="bash"><code>' >> $GITHUB_STEP_SUMMARY
|
||
echo "gh attestation verify oci://${{ env.IMAGE_FULL_NAME }}:${{ env.FIRST_TAG }} -R ${{ github.repository }}" >> $GITHUB_STEP_SUMMARY
|
||
echo "</code></pre>" >> $GITHUB_STEP_SUMMARY
|
||
|
||
- name: Generate artifact attestation
|
||
uses: actions/attest@v4
|
||
with:
|
||
subject-name: ${{ env.IMAGE_FULL_NAME }}
|
||
subject-digest: ${{ steps.push.outputs.digest }}
|
||
push-to-registry: true
|