From 5adb83113667f9e1c1f9934aae89893530f00a5f Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Fri, 27 Sep 2024 16:30:02 -0400 Subject: [PATCH] Add multi-runner WIP tests to ACT Would like to move to this to improve build time on GH Actions but its not working yet. Will also be good when GH Runners release arm nodes publicly. --- .dockerignore | 3 +- .github/act/.actrc | 4 +- .github/act/.env.example | 6 +- .github/act/README.md | 24 ++- .github/act/actTagPreEvent.json | 4 +- .github/act/docker-bake.hcl | 30 ++++ .github/act/multiRunnerBakeTest.yml | 233 ++++++++++++++++++++++++++++ .github/act/multiRunnerTest.yml | 195 +++++++++++++++++++++++ .gitignore | 1 + 9 files changed, 493 insertions(+), 7 deletions(-) create mode 100644 .github/act/docker-bake.hcl create mode 100644 .github/act/multiRunnerBakeTest.yml create mode 100644 .github/act/multiRunnerTest.yml diff --git a/.dockerignore b/.dockerignore index d48b3b9d..75f7f374 100644 --- a/.dockerignore +++ b/.dockerignore @@ -24,4 +24,5 @@ docsite/.cache-loader build *.secrets .devcontainer -.vscode \ No newline at end of file +.vscode +**/act/* \ No newline at end of file diff --git a/.github/act/.actrc b/.github/act/.actrc index 5bb06149..8815f9de 100644 --- a/.github/act/.actrc +++ b/.github/act/.actrc @@ -1,3 +1,5 @@ --directory ../../ --env-file .github/act/.env ---secret-file .github/act/.secrets \ No newline at end of file +--secret-file .github/act/.secrets +--artifact-server-path out +#--action-offline-mode \ No newline at end of file diff --git a/.github/act/.env.example b/.github/act/.env.example index 080e7f0f..4506c1c8 100644 --- a/.github/act/.env.example +++ b/.github/act/.env.example @@ -1 +1,5 @@ -NO_DOCKER_BUILD=true \ No newline at end of file +NO_DOCKER_BUILD=true +#https://github.com/nektos/act/issues/329#issuecomment-1905955589 +ACTIONS_RUNTIME_URL=http://YOUR_HOST_IP:8082/ +ACTIONS_RUNTIME_TOKEN=foo +ACTIONS_CACHE_URL=http://YOUR_HOST_IP:8082/ \ No newline at end of file diff --git a/.github/act/README.md b/.github/act/README.md index a1aa03b5..152ae9cb 100644 --- a/.github/act/README.md +++ b/.github/act/README.md @@ -1,8 +1,16 @@ -Testing GH Actions with [ACT] +Testing GH Actions with ACT Need to have credentials in a [`.secrets` file](https://nektosact.com/usage/index.html#secrets), copy and rename [`.secrets.example`](./secrets.example) to `.secrets`, then fill out blank fields. Required for docker/metadata-action to read...something. Fails with `Parameter token or opts.auth is required` if they are not supplied. -An ENV file can also be made by copy and renaming [`.env.example`](./env.example). Set `NO_DOCKER_BUILD=true` if you only want to test APP_VERSION and docker tags output. +An ENV file can also be made by copy and renaming [`.env.example`](./env.example). Set `NO_DOCKER_BUILD=true` if you only want to test APP_VERSION and docker tags output. + +If running a full docker build for multi-runner workflows you will need to create an [artifact server](https://github.com/nektos/act/issues/329#issuecomment-1905955589) for ACT to work: + + +```shell +docker pull ghcr.io/jefuller/artifact-server:latest +docker run -d --name artifact-server -p 8082:8080 --add-host host.docker.internal:host-gateway -e AUTH_KEY=foo ghcr.io/jefuller/artifact-server:latest +``` Run the following **from this directory** to make use of `.actrc` and proper working directoy. @@ -25,3 +33,15 @@ act -W '.github/act/actTest.yml' -e '.github/act/actTagEvent.json' ```shell act -W '.github/act/actTest.yml' -e '.github/act/actTagPreEvent.json' ``` + +### Test Multi-Runner Push (WIP) + +```shell +act -W '.github/act/multiRunnerTest.yml' -e '.github/act/actBranchEvent.json' +``` + +### Test Multi-Runner Bake Push (WIP) + +```shell +act -W '.github/act/multiRunnerBakeTest.yml' -e '.github/act/actBranchEvent.json' +``` \ No newline at end of file diff --git a/.github/act/actTagPreEvent.json b/.github/act/actTagPreEvent.json index adf853f1..e17c2c3b 100644 --- a/.github/act/actTagPreEvent.json +++ b/.github/act/actTagPreEvent.json @@ -1,6 +1,6 @@ { - "ref": "refs/tags/0.8.5-rc1", - "ref_name": "0.8.5-rc1", + "ref": "refs/tags/0.8.5-gh-runner", + "ref_name": "0.8.5-gh-runner", "before": "0000000000000000000000000000000000000000", "after": "005dae76ab51799d3d55112738e301cb1af0dafd", "sha": "005dae76ab51799d3d55112738e301cb1af0dafd", diff --git a/.github/act/docker-bake.hcl b/.github/act/docker-bake.hcl new file mode 100644 index 00000000..ff974c9c --- /dev/null +++ b/.github/act/docker-bake.hcl @@ -0,0 +1,30 @@ +variable "DEFAULT_TAG" { + default = "multi-scrobbler:local" +} + +// Special target: https://github.com/docker/metadata-action#bake-definition +target "docker-metadata-action" { + tags = ["${DEFAULT_TAG}"] +} + +// Default target if none specified +group "default" { + targets = ["image-local"] +} + +target "image" { + inherits = ["docker-metadata-action"] +} + +target "image-local" { + inherits = ["image"] + output = ["type=docker"] +} + +target "image-all" { + inherits = ["image"] + platforms = [ + "linux/amd64", + "linux/arm64" + ] +} diff --git a/.github/act/multiRunnerBakeTest.yml b/.github/act/multiRunnerBakeTest.yml new file mode 100644 index 00000000..3bd9fbd4 --- /dev/null +++ b/.github/act/multiRunnerBakeTest.yml @@ -0,0 +1,233 @@ +# Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#with-bake (https://github.com/docker/build-push-action/issues/671#issuecomment-1609106171) +# with example from here https://github.com/crazy-max/docker-linguist/blob/master/.github/workflows/build.yml that uses caching +# +# may have to use this to enable pushing to multiple registries? https://github.com/docker/build-push-action/discussions/1067#discussioncomment-8677682 + +name: build + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - 'master' + tags: + - '*.*.*' + paths-ignore: + - 'README.md' + - '.github/**' + - 'flatpak/**' + +env: + DOCKERHUB_SLUG: foxxmd/multi-scrobbler + GHCR_SLUG: ghcr.io/foxxmd/multi-scrobbler + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.platforms.outputs.matrix }} + steps: + - + name: Checkout + uses: actions/checkout@v4 + + - name: Set short git commit SHA + id: appvars + # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7 + # short sha available under env.COMMIT_SHORT_SHA + run: | + calculatedSha=$(git rev-parse --short HEAD) + branchName=$(git rev-parse --abbrev-ref HEAD) + echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV + echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV + + - name: Get App Version + id: appversion + env: + # use release instead of tags once version is correctly parsed + #APP_VERSION: ${{ github.event.release.tag_name }} + + # https://github.com/actions/runner/issues/409#issuecomment-752775072 + # https://stackoverflow.com/a/69919067/1469797 + APP_VERSION: ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }} + run: | + echo appversion=$APP_VERSION >>${GITHUB_OUTPUT} + + - + name: Create matrix + id: platforms + run: | + echo "matrix=$(docker buildx bake --file ./docker-bake.hcl image-all --print | jq -cr '.target."image-all".platforms')" >>${GITHUB_OUTPUT} + - + name: Show matrix + run: | + echo ${{ steps.platforms.outputs.matrix }} + - + name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_SLUG }} + ${{ env.GHCR_SLUG }} + tags: | + type=edge + + # maybe re-enable branch-named tags in the futures + #type=ref,event=branch,enable=${{ !endsWith(github.ref, 'master') }} + + # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries + type=match,pattern=\d.\d.\d$,priority=901 + + # tag all semver (include pre-release) + type=semver,pattern={{version}} + labels: | + org.opencontainers.image.title=Multi-Scrobbler + org.opencontainers.image.description=Scrobble from many sources to many clients + org.opencontainers.image.vendor=FoxxMD + - + name: Rename meta bake definition file + run: | + mv "${{ steps.meta.outputs.bake-file }}" "/tmp/bake-meta.json" + - + name: Upload meta bake definition + uses: actions/upload-artifact@v3 + with: + name: bake-meta + path: /tmp/bake-meta.json + if-no-files-found: error + retention-days: 1 + + build: + runs-on: ubuntu-latest + needs: + - prepare + strategy: + fail-fast: false + matrix: + platform: ${{ fromJson(needs.prepare.outputs.matrix) }} + steps: + - + name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - + name: Checkout + uses: actions/checkout@v4 + - + name: Test App Version Transfer + run: | + echo "App Version in Build ${{ needs.prepare.appversion.outputs.appversion }}" + - + name: Download meta bake definition + uses: actions/download-artifact@v3 + with: + name: bake-meta + path: /tmp + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + buildkitd-flags: "--debug" + - + name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - + name: Login to GHCR + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Build + id: bake + uses: docker/bake-action@v5 + with: + files: | + ./.github/act/docker-bake.hcl + /tmp/bake-meta.json + targets: image + set: | + *.args.APP_BUILD_VERSION=${{ needs.prepare.appversion.outputs.appversion }} + *.tags= + *.platform=${{ matrix.platform }} + *.cache-from=type=gha,scope=build-${{ env.PLATFORM_PAIR }} + *.cache-to=type=gha,scope=build-${{ env.PLATFORM_PAIR }} + *.output=type=image,"name=${{ env.DOCKERHUB_SLUG }},${{ env.GHCR_SLUG }}",push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + - + name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ fromJSON(steps.bake.outputs.metadata).image['containerimage.digest'] }}" + touch "/tmp/digests/${digest#sha256:}" + - + name: Upload digest + uses: actions/upload-artifact@v3 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + needs: + - build + steps: + - + name: Download meta bake definition + uses: actions/download-artifact@v3 + with: + name: bake-meta + path: /tmp + - + name: Download digests + uses: actions/download-artifact@v3 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - + name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.DOCKERHUB_SLUG }}")) | "-t " + .) | join(" ")' /tmp/bake-meta.json) \ + $(printf '${{ env.DOCKERHUB_SLUG }}@sha256:%s ' *) + docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.GHCR_SLUG }}")) | "-t " + .) | join(" ")' /tmp/bake-meta.json) \ + $(printf '${{ env.GHCR_SLUG }}@sha256:%s ' *) + - + name: Inspect image + run: | + tag=$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' /tmp/bake-meta.json) + docker buildx imagetools inspect ${{ env.DOCKERHUB_SLUG }}:${tag} + docker buildx imagetools inspect ${{ env.GHCR_SLUG }}:${tag} diff --git a/.github/act/multiRunnerTest.yml b/.github/act/multiRunnerTest.yml new file mode 100644 index 00000000..552da892 --- /dev/null +++ b/.github/act/multiRunnerTest.yml @@ -0,0 +1,195 @@ +# Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners + +name: build + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - 'master' + tags: + - '*.*.*' + paths-ignore: + - 'README.md' + - '.github/**' + - 'flatpak/**' + +env: + DOCKERHUB_SLUG: foxxmd/multi-scrobbler + GHCR_SLUG: ghcr.io/foxxmd/multi-scrobbler + +jobs: + build: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Set short git commit SHA + id: appvars + # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7 + # short sha available under env.COMMIT_SHORT_SHA + run: | + calculatedSha=$(git rev-parse --short HEAD) + branchName=$(git rev-parse --abbrev-ref HEAD) + echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV + echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV + + - name: Get App Version + id: appversion + env: + # use release instead of tags once version is correctly parsed + #APP_VERSION: ${{ github.event.release.tag_name }} + + # https://github.com/actions/runner/issues/409#issuecomment-752775072 + # https://stackoverflow.com/a/69919067/1469797 + APP_VERSION: ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }} + run: | + echo appversion=$APP_VERSION >>${GITHUB_OUTPUT} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_SLUG }} + ${{ env.GHCR_SLUG }} + labels: | + org.opencontainers.image.title=Multi-Scrobbler + org.opencontainers.image.description=Scrobble from many sources to many clients + org.opencontainers.image.vendor=FoxxMD + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + # https://github.com/docker/build-push-action/issues/671#issuecomment-1619353328 + # for caching + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + build-args: | + APP_BUILD_VERSION=${{steps.appversion.outputs.appversion}} + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + #tags: ${{ steps.meta.outputs.tags }} + outputs: type=image,"name=${{ env.DOCKERHUB_SLUG }},${{ env.GHCR_SLUG }}",push-by-digest=true,name-canonical=true,push=true + #cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }} + #cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }} + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_SLUG }} + ${{ env.GHCR_SLUG }} + # generate Docker tags based on the following events/attributes + # https://github.com/docker/metadata-action/issues/247#issuecomment-1511259674 for NOT is default branch, eventually + tags: | + type=edge + + # maybe re-enable branch-named tags in the futures + #type=ref,event=branch,enable=${{ !endsWith(github.ref, 'master') }} + + # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries + type=match,pattern=\d.\d.\d$,priority=901 + + # tag all semver (include pre-release) + type=semver,pattern={{version}} + # flavor: | + # latest=false + labels: | + org.opencontainers.image.title=Multi-Scrobbler + org.opencontainers.image.description=Scrobble from many sources to many clients + org.opencontainers.image.vendor=FoxxMD + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("${{ env.DOCKERHUB_SLUG }}")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKERHUB_SLUG }}@sha256:%s ' *) + docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("${{ env.GHCR_SLUG }}")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.GHCR_SLUG }}@sha256:%s ' *) + + # - name: Inspect image + # run: | + # docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ead98818..3c305f50 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,4 @@ flatpak/generated-sources.json build !setupProxy.js **/generated-sources.* +.github/act/out \ No newline at end of file