.github/workflows/on-tag.yml
name: Build & deploy on git tag push
env:
APP: invoicer
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
# Capture groups in $TAG_FMT:
# \1 => TAG vX.Y.Z+build<N>
# \2 => VERSION vX.Y.Z
# \3 => ignore (captures dot, and last number-group in version)
# \4 => BUILD N
TAG_FMT: '^refs/tags/((v(.?[0-9]+){3})\+build([0-9]+))$'
on:
push:
tags: [ '*' ]
jobs:
build:
name: Build invoicer
runs-on: ubuntu-18.04
strategy:
matrix:
arch:
- amd64
- arm32v6
- arm32v7
- arm64v8
env:
QEMU_VERSION: v4.2.0
DOCKER_BUILDKIT: 1
steps:
- uses: actions/checkout@v2
- name: Setup environment
run: |
if ! echo "$GITHUB_REF" | grep -qE "$TAG_FMT"; then
echo "ERR: TAG must be in format: vX.Y.Z+build<N>"
exit 1
fi
VERSION="$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\2|")"
DIR="$(echo "${VERSION#v}" | cut -d. -f-2)"
if ! grep -q "^ARG VERSION=$VERSION$" "$DIR/Dockerfile"; then
echo "ERR: $DIR/Dockerfile must contain VERSION=$VERSION"
exit 1
fi
echo ::set-env name=DIR::"$DIR"
echo ::set-env name=TAG::"$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\1|")"
echo ::set-env name=BUILD::"$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\4|")"
# GOARCH => arm|arm64
# GOARM => 6|7
- name: Setup Go environment
if: matrix.arch != 'amd64'
env:
ARCH: ${{ matrix.arch }}
run: |
GOARCH="${ARCH%32v?}"
echo ::set-env name=GOARCH::"${GOARCH%v8}"
echo ::set-env name=GOARM::"$(echo "$ARCH" | sed -En 's|^arm32v([6-7])$|\1|p')"
- name: Print ENV VARs set above
run: |
printf " APP: %s\n" "$APP"
printf " ARCH: %s\n" "${{ matrix.arch }}"
printf " TAG: %s\n" "$TAG"
printf " DIR: %s\n" "$DIR"
printf " BUILD: %s\n" "$BUILD"
printf " GOARCH: %s\n" "$GOARCH"
printf " GOARM: %s\n" "$GOARM"
- name: Build ${{ env.APP }}
run: >
docker build --no-cache .
--build-arg "ARCH=$ARCH"
--build-arg "GOARCH=$GOARCH"
--build-arg "GOARM=$GOARM"
--label "arch=${{ matrix.arch }}"
--label "commit=${{ github.sha }}"
--label "git-tag=$TAG"
--label "guilty=${{ github.actor }}"
--label "repo-url=${{ github.repositoryUrl }}"
--tag "$APP"
- name: Show built image details
run: docker images "$APP"
- name: Register self-compiled qemu
if: matrix.arch != 'amd64'
env:
ARCH: ${{ matrix.arch }}
run: docker run --rm --privileged "meedamian/simple-qemu:$QEMU_VERSION-${ARCH%32v6}" -p yes
- name: Run sanity checks
env:
DIR: /usr/local/bin
run: |
run() {
ENTRYPOINT="${1:-$APP}"; shift;
ARGS=${*:-"--version"}
printf "\n$ %s %s\n" "$ENTRYPOINT" "$ARGS"
docker run --rm --entrypoint "$ENTRYPOINT" "$APP" $ARGS
printf "\n"
}
docker inspect "$APP" | jq '.'
printf "\n"
run invoicer
run uname -a
run cat /etc/os-release
run sha256sum "$DIR/invoicer"
docker run --rm --entrypoint=sh -u=root "$APP" -c "apk add --no-cache file && file $DIR/invoicer"
- name: Save image to a .tgz file
run: |
mkdir -p images/
docker tag "$APP" "$APP:${{ matrix.arch }}"
docker save "$APP:${{ matrix.arch }}" | gzip > "images/docker-$APP-$TAG-${{ matrix.arch }}.tgz"
- name: Print sha256sum of built image
run: sha256sum images/*
- name: Upload docker image as build artifact
uses: actions/upload-artifact@v1.0.0
with:
name: docker-images
path: images/
- name: Extract binary from the built image
run: |
mkdir -p binaries/
ID=$(docker create "$APP:${{ matrix.arch }}")
docker cp "$ID:/usr/local/bin/invoicer" binaries/
docker rm "$ID"
gzip -S "-$TAG-${{ matrix.arch }}.gz" "binaries/$APP"
- name: Print sha256sum of extracted binaries
run: sha256sum binaries/*
- name: Upload raw binaries as build artifacts
uses: actions/upload-artifact@v1.0.0
with:
name: binaries
path: binaries/
deploy:
name: Deploy to Docker Hub & Github Releases. Only after successful build.
runs-on: ubuntu-18.04
needs: build
env:
DOCKER_CLI_EXPERIMENTAL: enabled
steps:
- name: Setup environment
run: |
echo ::set-env name=SLUG::"$(echo ${GITHUB_REPOSITORY,,} | sed 's/docker-//')"
echo ::set-env name=TAG::"$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\1|")"
echo ::set-env name=VERSION::"$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\2|")"
echo ::set-env name=BUILD::"$(echo "$GITHUB_REF" | sed -E "s|$TAG_FMT|\4|")"
- name: Print just set ENV VARs
run: |
printf " APP: %s\n" "$APP"
printf " TAG: %s\n" "$TAG"
printf " SLUG: %s\n" "$SLUG"
printf "VERSION: %s\n" "$VERSION"
printf " BUILD: %s\n" "$BUILD"
- name: Download all build artifacts
uses: actions/download-artifact@v1.0.0
with:
name: docker-images
- name: Print sha256sum of downloaded images
run: sha256sum docker-images/*
- name: Load images locally
run: find docker-images -exec docker load -i "{}" \;
# `invoicer:arm64` -> `lncm/invoicer:v0.6.0-arm64[+build<N>]`
- name: Version-tag all images
run: |
for arch in $(docker images ${APP} --format "{{.Tag}}"); do
docker tag "$APP:$arch" "$SLUG:$VERSION-$arch-build$BUILD"
docker tag "$APP:$arch" "$SLUG:$VERSION-$arch"
done
- name: List all tagged images
run: docker images "$SLUG"
- name: Login to Docker Hub
env:
DOCKER_USER: meedamian
run: |
echo "Logging in as ${DOCKER_USER}…"
echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u="$DOCKER_USER" --password-stdin
- name: Push all images
run: docker images "$SLUG" --format "{{.Repository}}:{{.Tag}}" | xargs -I % docker push %
- name: Get convenience Docker tag suggestions
id: tags
uses: meeDamian/tag-suggestions@v1.0.3
- name: Create :X.Y.Z manifest
run: ./scripts/ci-create-manifest.sh "$SLUG" "$VERSION"
- name: Create :X.Y manifest
if: steps.tags.outputs.minor != ''
run: ./scripts/ci-create-manifest.sh "$SLUG" "$VERSION" "${{ steps.tags.outputs.minor }}"
- name: Create :X manifest
if: steps.tags.outputs.major != ''
run: ./scripts/ci-create-manifest.sh "$SLUG" "$VERSION" "${{ steps.tags.outputs.major }}"
- name: Create :latest manifest
if: steps.tags.outputs.latest != ''
run: ./scripts/ci-create-manifest.sh "$SLUG" "$VERSION" "${{ steps.tags.outputs.latest }}"
- name: List all tagged images
run: docker images "$SLUG"
- name: Download binaries from build artifacts
uses: actions/download-artifact@v1.0.0
with:
name: binaries
- name: Print checksums of everything
run: sha256sum binaries/* docker-images/*
- name: Upload binaries to Github Release
uses: meeDamian/github-release@v1.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ env.VERSION }}
prerelease: true
gzip: false
files: >
docker-images/*
binaries/*