zmk-docker/.github/workflows/containers.yml
innovaker 70e225f229 feat: add integration tests
Runs a set of tests before the candidate image can be pushed.  The tests aim to cover all common use cases.

It was not possible to run the tests as a separate set of jobs because `actions/upload-artifact` and `actions/download-artifact` are too slow.  Moreover, a separate set of jobs would create a bottleneck because some architectures complete their docker builds faster than others.

The custom docker shell may require maintenance if GitHub change the underlying runner environment in the future.  It doesn't (yet?) support multi-line run commands.

PR: #46
2021-05-20 14:31:37 +01:00

280 lines
12 KiB
YAML

name: Containers
env:
zephyr-version: 2.4.0
zephyr-sdk-version: 0.11.4
run-unit-tests: ${{ secrets.RUN_UNIT_TESTS != null }}
cache-repository-name: zmk-docker-cache
docker-hub-credentials: ${{ secrets.DOCKER_HUB_USERNAME != null && secrets.DOCKER_HUB_TOKEN != null }}
ghcr-credentials: ${{ secrets.GHCR_USERNAME != null && secrets.GHCR_TOKEN != null }}
docker-hub-namespace: ${{ secrets.DOCKER_HUB_NAMESPACE || github.repository_owner }}
ghcr-namespace: ${{ github.repository_owner }}
zmk-repository: ${{ secrets.ZMK_REPOSITORY || 'zmkfirmware/zmk' }}
zmk-ref: ${{ secrets.ZMK_REF || 'main' }}
on:
push:
pull_request:
workflow_dispatch:
concurrency: ${{ github.workflow }}
jobs:
architectures:
runs-on: ubuntu-latest
outputs:
json: ${{ steps.import.outputs.json }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Import from architectures.yml
id: import
shell: python
run: |
import yaml, json
with open('architectures.yml', 'r') as file:
architectures = yaml.safe_load(file)
print('::set-output name=json::' + json.dumps(architectures))
tags:
runs-on: ubuntu-latest
outputs:
candidate: ${{ steps.definitions.outputs.candidate }}
versions: ${{ steps.definitions.outputs.versions }}
major-minor: ${{ steps.definitions.outputs.major-minor }}
latest: ${{ steps.definitions.outputs.latest }}
release-trigger: ${{ steps.definitions.outputs.release-trigger }}
steps:
- name: Definitions
id: definitions
env:
SHA: ${{ github.sha }}
ZEPHYR_VERSION: ${{ env.zephyr-version }}
ZEPHYR_SDK_VERSION: ${{ env.zephyr-sdk-version }}
run: |
CANDIDATE=${SHA}
VERSIONS=${ZEPHYR_VERSION}-${ZEPHYR_SDK_VERSION}
MAJOR=$(echo ${ZEPHYR_VERSION} | cut -d'.' -f 1)
MINOR=$(echo ${ZEPHYR_VERSION} | cut -d'.' -f 2)
MAJOR_MINOR=${MAJOR}.${MINOR}
LATEST=${MAJOR_MINOR}
RELEASE_TRIGGER=${ZEPHYR_VERSION}-${ZEPHYR_SDK_VERSION}
echo ::set-output name=candidate::${CANDIDATE}
echo ::set-output name=versions::${VERSIONS}
echo ::set-output name=major-minor::${MAJOR_MINOR}
echo ::set-output name=latest::${LATEST}
echo ::set-output name=release-trigger::${RELEASE_TRIGGER}
candidates:
needs:
- architectures
- tags
if: ${{ !startsWith(github.ref, 'refs/tags') }}
runs-on: ubuntu-latest
env:
docker-args: --rm --workdir /github/workspace -v /var/run/docker.sock:/var/run/docker.sock -v /home/runner/work/_temp:/home/runner/work/_temp -v /home/runner/work/_temp/_github_home:/github/home -v /home/runner/work/_temp/_github_workflow:/github/workflow -v /home/runner/work/_temp/_runner_file_commands:/github/file_commands -v ${{ github.workspace }}:/github/workspace
defaults:
run:
shell: /usr/bin/docker exec candidate /bin/bash {0}
strategy:
max-parallel: 1 # takes advantage of caching between jobs
matrix:
architecture: ${{ fromJSON(needs.architectures.outputs.json) }}
target: # ordered from biggest to smallest to take advantage of the registry cache
- dev
- build
include:
- architecture: arm
board: nice_nano
shield: qaz
steps:
- name: Login to Docker Hub
id: docker-hub-login
if: ${{ env.docker-hub-credentials == 'true' }}
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Login to GitHub Container Registry
id: ghcr-login
if: ${{ env.ghcr-credentials == 'true' }}
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Define repository
id: repository
shell: bash
run: echo ::set-output name=name::zmk-${{ matrix.target }}-${{ matrix.architecture }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and load candidate image
id: build-push
uses: docker/build-push-action@v2
with:
target: ${{ matrix.target }}
build-args: |
ZEPHYR_VERSION=${{ env.zephyr-version }}
ARCHITECTURE=${{ matrix.architecture }}
ZEPHYR_SDK_VERSION=${{ env.zephyr-sdk-version }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
tags: |
docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
cache-from: type=registry,ref=docker.io/${{ env.docker-hub-namespace }}/${{ env.cache-repository-name }}:dev
cache-to: ${{ (steps.docker-hub-login.outcome == 'success') && (matrix.target == 'dev') && format('type=registry,ref=docker.io/{0}/{1}:{2},mode=max', env.docker-hub-namespace, env.cache-repository-name, 'dev') || null }}
load: true
- name: Create and run container from candidate image
shell: bash
run: docker run -d -it --name candidate ${{ env.docker-args }} docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
- name: Checkout ZMK
uses: actions/checkout@v2
with:
repository: ${{ env.zmk-repository }}
ref: ${{ env.zmk-ref }}
- name: Cache Zephyr modules
uses: actions/cache@v2
env:
cache-name: zephyr-modules
with:
path: |
modules/
tools/
zephyr/
bootloader/
key: ${{ runner.os }}/${{ env.cache-name }}/${{ hashFiles('app/west.yml') }}
restore-keys: |
${{ runner.os }}/${{ env.cache-name }}/
- name: Test diff
run: diff --version
- name: Test west init
run: west init -l app
- name: Test west update
run: west update
- name: Test west zephyr-export
run: west zephyr-export
- name: Test board/shield (west build)
if: ${{ matrix.board != null }}
run: west build -s app -b ${{ matrix.board }} -- ${{ matrix.shield != null && format('-DSHIELD={0}', matrix.shield) || null }}
- name: Test RAM report (west build)
run: west build -t ram_report
- name: Test ROM report (west build)
run: west build -t rom_report
- name: Test west test (single)
run: west test tests/none/normal
- name: Test west test (full)
if: ${{ env.run-unit-tests == 'true' }}
run: west test
- name: Test clean (west build)
run: west build -t clean
- name: Test clang-format
if: ${{ matrix.target == 'dev' }}
run: clang-format --version
- name: Test node
if: ${{ matrix.target == 'dev' }}
run: node --version
- name: Test docs ci
if: ${{ matrix.target == 'dev' }}
run: cd docs && npm ci
- name: Test docs lint
if: ${{ matrix.target == 'dev' }}
run: cd docs && npm run lint
- name: Test docs prettier check
if: ${{ matrix.target == 'dev' }}
run: cd docs && npm run prettier:check
- name: Test docs start (webpack-dev-server)
if: ${{ matrix.target == 'dev' }}
run: cd docs && timeout -s SIGINT 20 npm run start &
- run: sleep 15
if: ${{ matrix.target == 'dev' }}
- name: Test docs wget (webpack-dev-server)
if: ${{ matrix.target == 'dev' }}
run: wget http://localhost:3000
- run: sleep 10
if: ${{ matrix.target == 'dev' }}
- name: Test docs build (webpack)
if: ${{ matrix.target == 'dev' }}
run: cd docs && npm run build
- name: Test docs serve (webpack)
if: ${{ matrix.target == 'dev' }}
run: cd docs && timeout -s SIGINT 10 npm run serve &
- run: sleep 5
if: ${{ matrix.target == 'dev' }}
- name: Test docs wget (webpack)
if: ${{ matrix.target == 'dev' }}
run: wget http://localhost:3000
- name: Test ssh
if: ${{ matrix.target == 'dev' }}
run: ssh -V
- name: Stop container
shell: bash
run: docker stop candidate
- name: Push candidate image to the registry
if: ${{ steps.docker-hub-login.outcome == 'success' }}
shell: bash
run: |
docker image push docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
releases:
needs:
- architectures
- tags
if: ${{ github.ref == format('refs/tags/{0}', needs.tags.outputs.release-trigger) }}
runs-on: ubuntu-latest
strategy:
matrix:
architecture: ${{ fromJSON(needs.architectures.outputs.json) }}
target:
- build
- dev
steps:
- name: Login to GitHub Container Registry
id: ghcr-login
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Login to Docker Hub
id: docker-hub-login
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Repository name
id: repository
run: echo ::set-output name=name::zmk-${{ matrix.target }}-${{ matrix.architecture }}
- name: Release (pull candidate, tag, push)
run: |
docker pull docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
docker tag docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }} docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.versions }}
docker tag docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }} docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.latest }}
docker tag docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }} ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
docker tag docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }} ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.versions }}
docker tag docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }} ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.latest }}
docker push docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
docker push docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.versions }}
docker push docker.io/${{ env.docker-hub-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.latest }}
docker push ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.candidate }}
docker push ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.versions }}
docker push ghcr.io/${{ env.ghcr-namespace }}/${{ steps.repository.outputs.name }}:${{ needs.tags.outputs.latest }}
git-tag:
needs:
- tags
- releases
if: ${{ startsWith(github.ref, 'refs/tags') }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
if: ${{ github.ref == format('refs/tags/{0}', needs.tags.outputs.release-trigger) }}
- name: Tag
if: ${{ github.ref == format('refs/tags/{0}', needs.tags.outputs.release-trigger) }}
env:
TAG: ${{ needs.tags.outputs.major-minor }}
run: |
git tag ${TAG}
git push -f origin ${TAG}