Skip to content
This repository has been archived by the owner on Oct 13, 2024. It is now read-only.

refactor: restructure source code #1341

refactor: restructure source code

refactor: restructure source code #1341

Workflow file for this run

---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# This workflow is intended to work with all our organization Docker projects. A readme named `DOCKER_README.md`
# will be used to update the description on Docker hub.
# custom comments in dockerfiles:
# `# platforms: `
# Comma separated list of platforms, i.e. `# platforms: linux/386,linux/amd64`. Docker platforms can alternatively
# be listed in a file named `.docker_platforms`.
# `# platforms_pr: `
# Comma separated list of platforms to run for PR events, i.e. `# platforms_pr: linux/amd64`. This will take
# precedence over the `# platforms: ` directive.
# `# artifacts: `
# `true` to build in two steps, stopping at `artifacts` build stage and extracting the image from there to the
# GitHub runner.
name: CI Docker
on:
pull_request:
branches: [master]
types: [opened, synchronize, reopened]
push:
branches: [master]
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
check_dockerfiles:
name: Check Dockerfiles
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Find dockerfiles
id: find
run: |
dockerfiles=$(find . -type f -iname "Dockerfile" -o -iname "*.dockerfile")
echo "found dockerfiles: ${dockerfiles}"
# do not quote to keep this as a single line
echo dockerfiles=${dockerfiles} >> $GITHUB_OUTPUT
MATRIX_COMBINATIONS=""
for FILE in ${dockerfiles}; do
# extract tag from file name
tag=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*\/(Dockerfile)/None/gm')
if [[ $tag == "None" ]]; then
MATRIX_COMBINATIONS="$MATRIX_COMBINATIONS {\"dockerfile\": \"$FILE\"},"
else
tag=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*\/(.+)(\.dockerfile)/-\2/gm')
MATRIX_COMBINATIONS="$MATRIX_COMBINATIONS {\"dockerfile\": \"$FILE\", \"tag\": \"$tag\"},"
fi
done
# removes the last character (i.e. comma)
MATRIX_COMBINATIONS=${MATRIX_COMBINATIONS::-1}
# setup matrix for later jobs
matrix=$((
echo "{ \"include\": [$MATRIX_COMBINATIONS] }"
) | jq -c .)
echo $matrix
echo $matrix | jq .
echo "matrix=$matrix" >> $GITHUB_OUTPUT
- name: Find dotnet solution file
id: find_dotnet
run: |
solution=$(find . -maxdepth 1 -type f -iname "*.sln")
echo "found solution: ${solution}"
# do not quote to keep this as a single line
echo solution=${solution} >> $GITHUB_OUTPUT
if [[ $solution != "" ]]; then
echo "dotnet=true" >> $GITHUB_OUTPUT
else
echo "dotnet=false" >> $GITHUB_OUTPUT
fi
outputs:
dockerfiles: ${{ steps.find.outputs.dockerfiles }}
matrix: ${{ steps.find.outputs.matrix }}
dotnet: ${{ steps.find_dotnet.outputs.dotnet }}
solution: ${{ steps.find_dotnet.outputs.solution }}
setup_release:
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
name: Setup Release
needs:
- check_dockerfiles
outputs:
publish_release: ${{ steps.setup_release.outputs.publish_release }}
release_body: ${{ steps.setup_release.outputs.release_body }}
release_commit: ${{ steps.setup_release.outputs.release_commit }}
release_generate_release_notes: ${{ steps.setup_release.outputs.release_generate_release_notes }}
release_tag: ${{ steps.setup_release.outputs.release_tag }}
release_version: ${{ steps.setup_release.outputs.release_version }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Release
id: setup_release
uses: LizardByte/[email protected]
with:
dotnet: ${{ needs.check_dockerfiles.outputs.dotnet }}
github_token: ${{ secrets.GITHUB_TOKEN }}
lint_dockerfile:
needs: [check_dockerfiles]
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.check_dockerfiles.outputs.matrix) }}
name: Lint Dockerfile${{ matrix.tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Hadolint
id: hadolint
uses: hadolint/[email protected]
with:
dockerfile: ${{ matrix.dockerfile }}
ignore: DL3008,DL3013,DL3016,DL3018,DL3028,DL3059
output-file: ./hadolint.log
verbose: true
- name: Log
if: failure()
run: |
echo "Hadolint outcome: ${{ steps.hadolint.outcome }}" >> $GITHUB_STEP_SUMMARY
cat "./hadolint.log" >> $GITHUB_STEP_SUMMARY
docker:
needs: [check_dockerfiles, setup_release]
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
runs-on: ubuntu-latest
permissions:
packages: write
contents: write
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.check_dockerfiles.outputs.matrix) }}
name: Docker${{ matrix.tag }}
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@v10
with:
root-reserve-mb: 30720 # https://github.com/easimon/maximize-build-space#caveats
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Prepare
id: prepare
env:
NV: ${{ needs.setup_release.outputs.release_tag }}
run: |
# get branch name
BRANCH=${GITHUB_HEAD_REF}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
if [ -z "$BRANCH" ]; then
echo "This is a PUSH event"
BRANCH=${{ github.ref_name }}
CLONE_URL=${{ github.event.repository.clone_url }}
else
echo "This is a PULL REQUEST event"
CLONE_URL=${{ github.event.pull_request.head.repo.clone_url }}
fi
# determine to push image to dockerhub and ghcr or not
if [[ $GITHUB_EVENT_NAME == "push" ]]; then
PUSH=true
else
PUSH=false
fi
# setup the tags
REPOSITORY=${{ github.repository }}
BASE_TAG=$(echo $REPOSITORY | tr '[:upper:]' '[:lower:]')
TAGS="${BASE_TAG}:${COMMIT:0:7}${{ matrix.tag }},ghcr.io/${BASE_TAG}:${COMMIT:0:7}${{ matrix.tag }}"
if [[ $GITHUB_REF == refs/heads/master ]]; then
TAGS="${TAGS},${BASE_TAG}:latest${{ matrix.tag }},ghcr.io/${BASE_TAG}:latest${{ matrix.tag }}"
TAGS="${TAGS},${BASE_TAG}:master${{ matrix.tag }},ghcr.io/${BASE_TAG}:master${{ matrix.tag }}"
else
TAGS="${TAGS},${BASE_TAG}:test${{ matrix.tag }},ghcr.io/${BASE_TAG}:test${{ matrix.tag }}"
fi
if [[ ${NV} != "" ]]; then
TAGS="${TAGS},${BASE_TAG}:${NV}${{ matrix.tag }},ghcr.io/${BASE_TAG}:${NV}${{ matrix.tag }}"
fi
# parse custom directives out of dockerfile
# try to get the platforms from the dockerfile custom directive, i.e. `# platforms: xxx,yyy`
# directives for PR event, i.e. not push event
if [[ ${RELEASE} == "false" ]]; then
while read -r line; do
if [[ $line == "# platforms_pr: "* && $PLATFORMS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
PLATFORMS=$(echo -e "$line" | sed 's/# platforms_pr: //')
elif [[ $PLATFORMS != "" ]]; then
# break while loop once all custom "PR" event directives are found
break
fi
done <"${{ matrix.dockerfile }}"
fi
# directives for all events... above directives will not be parsed if they were already found
while read -r line; do
if [[ $line == "# platforms: "* && $PLATFORMS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
PLATFORMS=$(echo -e "$line" | sed 's/# platforms: //')
elif [[ $line == "# artifacts: "* && $ARTIFACTS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
ARTIFACTS=$(echo -e "$line" | sed 's/# artifacts: //')
elif [[ $line == "# no-cache-filters: "* && $NO_CACHE_FILTERS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
NO_CACHE_FILTERS=$(echo -e "$line" | sed 's/# no-cache-filters: //')
elif [[ $PLATFORMS != "" && $ARTIFACTS != "" && $NO_CACHE_FILTERS != "" ]]; then
# break while loop once all custom directives are found
break
fi
done <"${{ matrix.dockerfile }}"
# if PLATFORMS is blank, fall back to the legacy method of reading from the `.docker_platforms` file
if [[ $PLATFORMS == "" ]]; then
# read the platforms from `.docker_platforms`
PLATFORMS=$(<.docker_platforms)
fi
# if PLATFORMS is still blank, fall back to `linux/amd64`
if [[ $PLATFORMS == "" ]]; then
PLATFORMS="linux/amd64"
fi
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "clone_url=${CLONE_URL}" >> $GITHUB_OUTPUT
echo "artifacts=${ARTIFACTS}" >> $GITHUB_OUTPUT
echo "no_cache_filters=${NO_CACHE_FILTERS}" >> $GITHUB_OUTPUT
echo "platforms=${PLATFORMS}" >> $GITHUB_OUTPUT
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Set Up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
id: buildx
- name: Cache Docker Layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: Docker-buildx${{ matrix.tag }}-${{ github.sha }}
restore-keys: |
Docker-buildx${{ matrix.tag }}-
- name: Log in to Docker Hub
if: ${{ needs.setup_release.outputs.publish_release == 'true' }} # PRs do not have access to secrets
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to the Container registry
if: ${{ needs.setup_release.outputs.publish_release == 'true' }} # PRs do not have access to secrets
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GH_BOT_NAME }}
password: ${{ secrets.GH_BOT_TOKEN }}
- name: Build artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
id: build_artifacts
uses: docker/build-push-action@v6
with:
context: ./
file: ${{ matrix.dockerfile }}
target: artifacts
outputs: type=local,dest=artifacts
push: false
platforms: ${{ steps.prepare.outputs.platforms }}
build-args: |
BRANCH=${{ steps.prepare.outputs.branch }}
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
BUILD_VERSION=${{ needs.setup_release.outputs.release_tag }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
CLONE_URL=${{ steps.prepare.outputs.clone_url }}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
tags: ${{ steps.prepare.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
no-cache-filters: ${{ steps.prepare.outputs.no_cache_filters }}
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: ./
file: ${{ matrix.dockerfile }}
push: ${{ needs.setup_release.outputs.publish_release }}
platforms: ${{ steps.prepare.outputs.platforms }}
build-args: |
BRANCH=${{ steps.prepare.outputs.branch }}
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
BUILD_VERSION=${{ needs.setup_release.outputs.release_tag }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
CLONE_URL=${{ steps.prepare.outputs.clone_url }}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
tags: ${{ steps.prepare.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
no-cache-filters: ${{ steps.prepare.outputs.no_cache_filters }}
- name: Arrange Artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
working-directory: artifacts
run: |
# artifacts will be in sub directories named after the docker target platform, e.g. `linux_amd64`
# so move files to the artifacts directory
# https://unix.stackexchange.com/a/52816
find ./ -type f -exec mv -t ./ -n '{}' +
# remove provenance file
rm -f ./provenance.json
- name: Upload Artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
uses: actions/upload-artifact@v4
with:
name: Docker${{ matrix.tag }}
path: artifacts/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.publish_release == 'true' && steps.prepare.outputs.artifacts == 'true' }}
uses: LizardByte/[email protected]
with:
allowUpdates: true
artifacts: "*artifacts/*"
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
generateReleaseNotes: ${{ needs.setup_release.outputs.release_generate_release_notes }}
name: ${{ needs.setup_release.outputs.release_tag }}
prerelease: true
tag: ${{ needs.setup_release.outputs.release_tag }}
token: ${{ secrets.GH_BOT_TOKEN }}
- name: Update Docker Hub Description
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }} # token is not currently supported
repository: ${{ env.BASE_TAG }}
short-description: ${{ github.event.repository.description }}
readme-filepath: ./DOCKER_README.md