Version update #1575
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: build | |
on: push | |
jobs: | |
check: | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
- name: Shellcheck | |
run: | | |
for file in $(find ./root/etc -type f); do | |
echo "Checking: $file" | |
shellcheck "$file" | |
done | |
build: | |
runs-on: ubuntu-22.04 | |
strategy: | |
matrix: | |
architecture: [linux-arm64, linux-amd64] | |
needs: [check] | |
outputs: | |
version: ${{ steps.prep.outputs.version }} | |
branch: ${{ steps.prep.outputs.branch }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
- name: Check if architecture exists | |
id: arch_check | |
run: | | |
(test -f ${{ matrix.architecture }}.Dockerfile && echo "check=passed" >> $GITHUB_OUTPUT) || echo "check=failed" >> $GITHUB_OUTPUT | |
- name: Set up QEMU | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
uses: docker/setup-qemu-action@v2 | |
- name: Set up Docker Buildx | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
uses: docker/setup-buildx-action@v2 | |
with: | |
install: true | |
version: latest | |
driver-opts: image=moby/buildkit:v0.10.6 | |
- name: Login to docker.io | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
uses: docker/login-action@v2 | |
with: | |
registry: docker.io | |
username: ${{ secrets.DOCKER_USER }} | |
password: ${{ secrets.DOCKER_TOKEN }} | |
- name: Login to ghcr.io | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
uses: docker/login-action@v2 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.PERSONAL_TOKEN }} | |
- name: Prepare | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
id: prep | |
run: | | |
ARCHITECTURE=${{ matrix.architecture }} | |
echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT | |
echo "title=${GITHUB_REPOSITORY}:${GITHUB_REF//refs\/heads\//}" >> $GITHUB_OUTPUT | |
echo "revision=${GITHUB_SHA}" >> $GITHUB_OUTPUT | |
echo "source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/tree/${GITHUB_REF//refs\/heads\//}" >> $GITHUB_OUTPUT | |
echo "vendor=${{ github.repository_owner }}" >> $GITHUB_OUTPUT | |
echo "url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/blob/master/README.md" >> $GITHUB_OUTPUT | |
echo "platform=${ARCHITECTURE//-/\/}" >> $GITHUB_OUTPUT | |
echo "cache=${GITHUB_REPOSITORY}:${GITHUB_REF//refs\/heads\//}-cache-${{ matrix.architecture }}" >> $GITHUB_OUTPUT | |
echo "tag=${GITHUB_REPOSITORY}:${GITHUB_REF//refs\/heads\//}-${GITHUB_SHA:0:7}-${GITHUB_RUN_NUMBER}-${{ matrix.architecture }}" >> $GITHUB_OUTPUT | |
VERSION=$(jq -r '.version // empty' < VERSION.json) | |
if [[ -z ${VERSION} ]]; then | |
VERSION=$(date --utc --date=@$(git show -s --format=%ct $(git rev-parse --short HEAD)) +'%Y%m%d%H%M%S') | |
fi | |
echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
BRANCH=$(jq -r '.branch // empty' < VERSION.json) | |
if [[ -n ${BRANCH} ]]; then | |
echo "branch=-${BRANCH}" >> $GITHUB_OUTPUT | |
fi | |
echo 'build-args<<EOF' >> $GITHUB_OUTPUT | |
jq -r 'to_entries[] | [(.key | ascii_upcase),.value] | join("=")' < VERSION.json >> $GITHUB_OUTPUT | |
echo 'EOF' >> $GITHUB_OUTPUT | |
echo "package-version=${GITHUB_REF//refs\/heads\//}-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT | |
- name: Build and push - Attempt 1 | |
continue-on-error: true | |
if: "contains(steps.arch_check.outputs.check, 'passed')" | |
id: build_attempt1 | |
uses: docker/build-push-action@v4 | |
with: | |
push: true | |
platforms: ${{ steps.prep.outputs.platform }} | |
file: ./${{ matrix.architecture }}.Dockerfile | |
cache-from: docker.io/${{ steps.prep.outputs.cache }} | |
cache-to: docker.io/${{ steps.prep.outputs.cache }} | |
tags: | | |
docker.io/${{ steps.prep.outputs.tag }} | |
ghcr.io/${{ steps.prep.outputs.tag }} | |
labels: | | |
org.opencontainers.image.created=${{ steps.prep.outputs.created }} | |
org.opencontainers.image.title=${{ steps.prep.outputs.title }} | |
org.opencontainers.image.revision=${{ steps.prep.outputs.revision }} | |
org.opencontainers.image.source=${{ steps.prep.outputs.source }} | |
org.opencontainers.image.vendor=${{ steps.prep.outputs.vendor }} | |
org.opencontainers.image.url=${{ steps.prep.outputs.url }} | |
org.opencontainers.image.version=${{ steps.prep.outputs.version }} | |
build-args: | | |
GITHUB_TOKEN=${{ secrets.PERSONAL_TOKEN }} | |
BUILD_ARCHITECTURE=${{ matrix.architecture }} | |
PACKAGE_VERSION=${{ steps.prep.outputs.package-version }} | |
${{ steps.prep.outputs.build-args }} | |
- name: Sleep | |
if: (steps.build_attempt1.outcome == 'failure') | |
run: | | |
sleep 30 | |
- name: Build and push - Attempt 2 | |
if: (steps.build_attempt1.outcome == 'failure') | |
uses: docker/build-push-action@v4 | |
with: | |
push: true | |
platforms: ${{ steps.prep.outputs.platform }} | |
file: ./${{ matrix.architecture }}.Dockerfile | |
cache-from: docker.io/${{ steps.prep.outputs.cache }} | |
cache-to: docker.io/${{ steps.prep.outputs.cache }} | |
tags: | | |
docker.io/${{ steps.prep.outputs.tag }} | |
ghcr.io/${{ steps.prep.outputs.tag }} | |
labels: | | |
org.opencontainers.image.created=${{ steps.prep.outputs.created }} | |
org.opencontainers.image.title=${{ steps.prep.outputs.title }} | |
org.opencontainers.image.revision=${{ steps.prep.outputs.revision }} | |
org.opencontainers.image.source=${{ steps.prep.outputs.source }} | |
org.opencontainers.image.vendor=${{ steps.prep.outputs.vendor }} | |
org.opencontainers.image.url=${{ steps.prep.outputs.url }} | |
org.opencontainers.image.version=${{ steps.prep.outputs.version }} | |
build-args: | | |
GITHUB_TOKEN=${{ secrets.PERSONAL_TOKEN }} | |
BUILD_ARCHITECTURE=${{ matrix.architecture }} | |
PACKAGE_VERSION=${{ steps.prep.outputs.package-version }} | |
${{ steps.prep.outputs.build-args }} | |
- name: Show installed packages | |
if: | | |
contains(steps.arch_check.outputs.check, 'passed') | |
run: | | |
version_json=$(cat ./VERSION.json) | |
upstream_tag=$(jq -r '.upstream_tag' <<< "${version_json}") | |
upstream_image=$(jq -r '.upstream_image' <<< "${version_json}") | |
if [[ ${upstream_tag} == alpine || ${upstream_image} == alpine ]]; then | |
docker run --rm --entrypoint="" "docker.io/${{ steps.prep.outputs.tag }}" apk -vv info | sort | |
else | |
docker run --rm --entrypoint="" "docker.io/${{ steps.prep.outputs.tag }}" apt list --installed | |
fi | |
- name: Prepare for test | |
if: | | |
contains(steps.arch_check.outputs.check, 'passed') && | |
contains(matrix.architecture, 'amd64') | |
id: prep_test | |
run: | | |
version_json=$(cat ./VERSION.json) | |
test_url=$(jq -r '.test_url' <<< "${version_json}") | |
if [[ ${test_url} != null ]]; then | |
echo "url=${test_url}" >> $GITHUB_OUTPUT | |
echo "check=passed" >> $GITHUB_OUTPUT | |
else | |
echo "check=failed" >> $GITHUB_OUTPUT | |
fi | |
- name: Run test | |
if: | | |
contains(steps.arch_check.outputs.check, 'passed') && | |
contains(steps.prep_test.outputs.check, 'passed') && | |
contains(matrix.architecture, 'amd64') | |
run: | | |
test_url=${{ steps.prep_test.outputs.url }} | |
docker run --network host -d --name service "docker.io/${{ steps.prep.outputs.tag }}" | |
currenttime=$(date +%s); maxtime=$((currenttime+120)); while (! curl -fsSL -m 10 -b /dev/shm/cookie "${test_url}" > /dev/null) && [[ "$currenttime" -lt "$maxtime" ]]; do sleep 1; currenttime=$(date +%s); done | |
if curl -fsSL -m 10 -b /dev/shm/cookie "${test_url}" > /dev/null; then | |
docker logs service | |
exit 0 | |
else | |
docker logs service | |
exit 1 | |
fi | |
- name: Take screenshot | |
continue-on-error: true | |
if: | | |
contains(steps.arch_check.outputs.check, 'passed') && | |
contains(steps.prep_test.outputs.check, 'passed') && | |
contains(matrix.architecture, 'amd64') | |
uses: swinton/[email protected] | |
with: | |
source: ${{ steps.prep_test.outputs.url }} | |
destination: screenshot.png | |
delay: 5 | |
publish: | |
runs-on: ubuntu-22.04 | |
strategy: | |
matrix: | |
registry: [docker.io, ghcr.io] | |
needs: [build] | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
- name: Login to docker.io | |
if: matrix.registry == 'docker.io' | |
uses: docker/login-action@v2 | |
with: | |
registry: docker.io | |
username: ${{ secrets.DOCKER_USER }} | |
password: ${{ secrets.DOCKER_TOKEN }} | |
- name: Login to ghcr.io | |
if: matrix.registry == 'ghcr.io' | |
uses: docker/login-action@v2 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.PERSONAL_TOKEN }} | |
- name: Create manifests - Attempt 1 | |
continue-on-error: true | |
id: manifest_attempt1 | |
env: | |
DOCKER_CLI_EXPERIMENTAL: enabled | |
run: | | |
IMAGE=${{ matrix.registry }}/${GITHUB_REPOSITORY} | |
TAG=${GITHUB_REF//refs\/heads\//} | |
SOURCE=${IMAGE}:${TAG}-${GITHUB_SHA:0:7}-${GITHUB_RUN_NUMBER} | |
VERSION=${{ needs.build.outputs.version }} | |
BRANCH=${{ needs.build.outputs.branch }} | |
[[ -f linux-amd64.Dockerfile ]] && AMD64=${SOURCE}-linux-amd64 | |
[[ -f linux-arm64.Dockerfile ]] && ARM64=${SOURCE}-linux-arm64 | |
[[ -f linux-arm-v7.Dockerfile ]] && ARMV7=${SOURCE}-linux-arm-v7 | |
docker manifest create ${IMAGE}:${TAG}${BRANCH} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}${BRANCH} | |
docker manifest create ${IMAGE}:${TAG}${BRANCH}-${VERSION//\~/-} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}${BRANCH}-${VERSION//\~/-} | |
docker manifest create ${IMAGE}:${TAG}-${GITHUB_SHA:0:7} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}-${GITHUB_SHA:0:7} | |
IS_LATEST=$(jq -r '.latest // empty' < VERSION.json) | |
if [[ ${IS_LATEST} == true ]]; then | |
docker manifest create ${IMAGE}:latest ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:latest | |
fi | |
- name: Sleep | |
if: (steps.manifest_attempt1.outcome == 'failure') | |
run: | | |
sleep 30 | |
- name: Create manifests - Attempt 2 | |
if: (steps.manifest_attempt1.outcome == 'failure') | |
env: | |
DOCKER_CLI_EXPERIMENTAL: enabled | |
run: | | |
IMAGE=${{ matrix.registry }}/${GITHUB_REPOSITORY} | |
TAG=${GITHUB_REF//refs\/heads\//} | |
SOURCE=${IMAGE}:${TAG}-${GITHUB_SHA:0:7}-${GITHUB_RUN_NUMBER} | |
VERSION=${{ needs.build.outputs.version }} | |
BRANCH=${{ needs.build.outputs.branch }} | |
[[ -f linux-amd64.Dockerfile ]] && AMD64=${SOURCE}-linux-amd64 | |
[[ -f linux-arm64.Dockerfile ]] && ARM64=${SOURCE}-linux-arm64 | |
[[ -f linux-arm-v7.Dockerfile ]] && ARMV7=${SOURCE}-linux-arm-v7 | |
docker manifest rm ${IMAGE}:${TAG}${BRANCH} || true | |
docker manifest create ${IMAGE}:${TAG}${BRANCH} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}${BRANCH} | |
docker manifest rm ${IMAGE}:${TAG}${BRANCH}-${VERSION//\~/-} || true | |
docker manifest create ${IMAGE}:${TAG}${BRANCH}-${VERSION//\~/-} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}${BRANCH}-${VERSION//\~/-} | |
docker manifest rm ${IMAGE}:${TAG}-${GITHUB_SHA:0:7} || true | |
docker manifest create ${IMAGE}:${TAG}-${GITHUB_SHA:0:7} ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:${TAG}-${GITHUB_SHA:0:7} | |
IS_LATEST=$(jq -r '.latest // empty' < VERSION.json) | |
if [[ ${IS_LATEST} == true ]]; then | |
docker manifest rm ${IMAGE}:latest || true | |
docker manifest create ${IMAGE}:latest ${AMD64} ${ARM64} ${ARMV7} | |
docker manifest push ${IMAGE}:latest | |
fi | |
notify: | |
runs-on: ubuntu-22.04 | |
if: always() | |
needs: [build, publish] | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
- name: Download screenshot | |
continue-on-error: true | |
uses: actions/download-artifact@v3 | |
with: | |
name: screenshot | |
- name: Login to docker.io | |
uses: docker/login-action@v2 | |
with: | |
registry: docker.io | |
username: ${{ secrets.DOCKER_USER }} | |
password: ${{ secrets.DOCKER_TOKEN }} | |
- name: Send discord notification | |
env: | |
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
EXTRA_DISCORD_WEBHOOK: ${{ secrets.EXTRA_DISCORD_WEBHOOK }} | |
GITHUB_OWNER: ${{ github.repository_owner }} | |
GITHUB_TOKEN: ${{ secrets.PERSONAL_TOKEN }} | |
VERSION: ${{ needs.build.outputs.version }} | |
BRANCH: ${{ needs.build.outputs.branch }} | |
STATUS: ${{ needs.publish.result }} | |
shell: bash | |
run: | | |
export DOCKER_CLI_EXPERIMENTAL=enabled | |
[[ "${STATUS}" == "success" ]] && DIGESTS=$(docker manifest inspect docker.io/${GITHUB_REPOSITORY}:${GITHUB_REF//refs\/heads\//}-${GITHUB_SHA:0:7} | jq -r '.manifests[] | "\(.digest | .[7:19]) \(.platform.os)/\(.platform.architecture)\(.platform.variant // "")"') | |
COMMIT_MESSAGE="$(curl -u "${GITHUB_OWNER}:${GITHUB_TOKEN}" -fsSL --retry 5 "https://api.github.com/repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}" | jq -r .commit.message | head -1)" | |
[[ "${STATUS}" == "success" ]] && COLOR="3066993" | |
CHANGELOG=$(jq -r '.changelog' < VERSION.json) | |
if [[ ${CHANGELOG} != null ]]; then | |
VERSION="[${VERSION:----}](${CHANGELOG})" | |
fi | |
if [[ ! -f "screenshot.png" ]]; then | |
curl -fsSL --retry 5 "https://hotio.dev/img/pullio-background.png" > screenshot.png | |
fi | |
json='{ | |
"embeds": [ | |
{ | |
"title": "'${GITHUB_REPOSITORY}':'${GITHUB_REF//refs\/heads\//}${BRANCH}'", | |
"url": "https://github.com/'${GITHUB_REPOSITORY}'/actions/runs/'${GITHUB_RUN_ID}'", | |
"color": '${COLOR:-15158332}', | |
"fields": [ | |
{ | |
"name": "Commit Message", | |
"value": "```'${COMMIT_MESSAGE//\"/\\\"}'```" | |
}, | |
{ | |
"name": "Commit SHA", | |
"value": "['${GITHUB_SHA:0:7}'](https://github.com/'${GITHUB_REPOSITORY}'/commit/'${GITHUB_SHA}')", | |
"inline": true | |
}, | |
{ | |
"name": "Version", | |
"value": "'${VERSION:----}'", | |
"inline": true | |
}, | |
{ | |
"name": "Digests", | |
"value": "```'"$(echo "${DIGESTS:----}" | tr '\n' '#' | sed 's/#/\\n/g')"'```" | |
} | |
], | |
"footer": { | |
"text": "Powered by GitHub Actions" | |
}, | |
"timestamp": "'$(date -u +'%FT%T.%3NZ')'", | |
"image": { | |
"url": "attachment://screenshot.png" | |
} | |
} | |
] | |
}' | |
curl -fsSL --retry 5 -H "Content-Type: multipart/form-data" -F "[email protected]" -F "payload_json=${json}" "${DISCORD_WEBHOOK}" > /dev/null | |
if [[ -n ${EXTRA_DISCORD_WEBHOOK} ]]; then | |
curl -fsSL --retry 5 -H "Content-Type: multipart/form-data" -F "[email protected]" -F "payload_json=${json}" "${EXTRA_DISCORD_WEBHOOK}" > /dev/null | |
fi |