diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b06f9ad..868d397 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,21 +1,19 @@ -name: Build / Test / Push +name: Build image on: - push: - branches: - - '**' - workflow_dispatch: - -env: - BUILD_SUFFIX: -build-${{ github.run_id }}_${{ github.run_attempt }} - DOCKER_METADATA_SET_OUTPUT_ENV: 'true' + workflow_call: + outputs: + image: + description: ID of the image created by the workflow run + value: ${{ jobs.merge.outputs.image }} jobs: build: runs-on: ${{ matrix.runner }} outputs: - build-image-arm: ${{ steps.gen-output.outputs.image-arm64 }} - build-image-x64: ${{ steps.gen-output.outputs.image-x64 }} + image-digest-arm: ${{ steps.gen-output.outputs.image-digest-arm64 }} + image-digest-x64: ${{ steps.gen-output.outputs.image-digest-x64 }} + build-tag: ${{ steps.build-meta.outputs.tags }} strategy: fail-fast: false matrix: @@ -41,7 +39,7 @@ jobs: uses: docker/metadata-action@v5 with: images: ghcr.io/${{ github.repository }} - tags: type=sha,suffix=${{ env.BUILD_SUFFIX }} + tags: type=sha,suffix=-build-${{ github.run_id }}_${{ github.run_attempt }} # Build cache is shared among all builds of the same architecture - id: cache-meta @@ -71,17 +69,18 @@ jobs: - id: gen-output name: Write arch-specific image digest to outputs run: | - echo "image-${RUNNER_ARCH,,}=${{ steps.get-registry.outputs.registry }}@${{ steps.build.outputs.digest }}" | tee -a "$GITHUB_OUTPUT" + echo "image-digest-${RUNNER_ARCH,,}=${{ steps.get-registry.outputs.registry }}@${{ steps.build.outputs.digest }}" | tee -a "$GITHUB_OUTPUT" merge: + name: create multi-platform image + needs: build runs-on: ubuntu-24.04 - needs: - - build env: - DOCKER_APP_IMAGE_ARM64: ${{ needs.build.outputs.build-image-arm }} - DOCKER_APP_IMAGE_X64: ${{ needs.build.outputs.build-image-x64 }} + DOCKER_APP_IMAGE: ${{ needs.build.outputs.build-tag }} + DOCKER_APP_IMAGE_DIGEST_ARM64: ${{ needs.build.outputs.image-digest-arm }} + DOCKER_APP_IMAGE_DIGEST_X64: ${{ needs.build.outputs.image-digest-x64 }} outputs: - build-image: ${{ steps.meta.outputs.tags }} + image: ${{ needs.build.outputs.build-tag }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -96,77 +95,8 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=sha,suffix=-build-${{ github.run_id }}_${{ github.run_attempt }} - - name: Push the multi-platform image run: | docker buildx imagetools create \ - --tag "$DOCKER_METADATA_OUTPUT_TAGS" \ - "$DOCKER_APP_IMAGE_ARM64" "$DOCKER_APP_IMAGE_X64" - - test: - runs-on: ubuntu-24.04 - needs: - - merge - env: - COMPOSE_FILE: docker-compose.yml:docker-compose.ci.yml - DOCKER_APP_IMAGE: ${{ needs.merge.outputs.build-image }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Compose - uses: docker/setup-compose-action@v1 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Run the test script - run: | - docker compose run --rm --user root app chown -R avplayer:avplayer artifacts - docker compose up --detach --wait - docker compose exec app bin/test - - push: - runs-on: ubuntu-24.04 - needs: - - merge - - test - env: - DOCKER_APP_IMAGE: ${{ needs.merge.outputs.build-image }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Produce permanent image tags - id: branch-meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=sha - type=ref,event=branch - type=raw,value=latest,enable={{is_default_branch}} - - - name: Retag and push the image - run: | - docker pull "$DOCKER_APP_IMAGE" - echo "$DOCKER_METADATA_OUTPUT_TAGS" | tr ' ' '\n' | xargs -n1 docker tag "$DOCKER_APP_IMAGE" - docker push --all-tags "$(echo "$DOCKER_APP_IMAGE" | cut -f1 -d:)" + --tag "$DOCKER_APP_IMAGE" \ + "$DOCKER_APP_IMAGE_DIGEST_ARM64" "$DOCKER_APP_IMAGE_DIGEST_X64" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cb05aa6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: Build / Test / Tag + +on: + push: + branches: + - '**' + tags: + - '**' + +jobs: + meta: + name: Determine image permatags + uses: ./.github/workflows/meta.yml + + build: + name: Build the image + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + uses: ./.github/workflows/build.yml + + test: + name: Test built image + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + needs: build + uses: ./.github/workflows/test.yml + with: + image: ${{ needs.build.outputs.image }} + + tag: + name: Tag/push tested image + needs: [build, test, meta] + uses: ./.github/workflows/tag.yml + with: + image: ${{ needs.build.outputs.image || needs.meta.outputs.base-tag }} + tags: ${{ needs.meta.outputs.permatags }} diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml new file mode 100644 index 0000000..34c33b4 --- /dev/null +++ b/.github/workflows/meta.yml @@ -0,0 +1,42 @@ +name: Extract image metadata + +on: + workflow_call: + outputs: + base-tag: + description: SHA-based tag for the built ref (org/repo:sha-1234567) + value: ${{ jobs.meta.outputs.base-tag }} + permatags: + description: Space-separated list of all tags to apply to the ref + value: ${{ jobs.meta.outputs.permatags }} + +jobs: + meta: + runs-on: ubuntu-24.04 + outputs: + base-tag: ${{ steps.base-tag.outputs.tags }} + permatags: ${{ steps.permatags.outputs.tags }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - id: base-tag + name: Determine base tag (for git-tag builds) + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: type=sha + + - id: permatags + name: Determine permatags + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=sha + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=ref,event=tag + type=semver,event=tag,pattern={{major}} + type=semver,event=tag,pattern={{major}}.{{minor}} + type=semver,event=tag,pattern={{version}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index d6564d0..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Push Release Tags - -on: - push: - tags: - - '**' - workflow_dispatch: - -env: - DOCKER_METADATA_SET_OUTPUT_ENV: 'true' - -jobs: - retag: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Determine the sha-based image tag to retag - id: get-base-image - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - tags: type=sha - - - name: Verify that the image was previously built - env: - BASE_IMAGE: ${{ steps.get-base-image.outputs.tags }} - run: | - docker pull "$BASE_IMAGE" - - - name: Produce release tags - id: tag-meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository }} - flavor: latest=false - tags: | - type=ref,event=tag - type=semver,pattern={{major}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{version}} - - - name: Retag the pulled image - env: - BASE_IMAGE: ${{ steps.get-base-image.outputs.tags }} - run: | - echo "$DOCKER_METADATA_OUTPUT_TAGS" | tr ' ' '\n' | xargs -n1 docker tag "$BASE_IMAGE" - docker push --all-tags "$(echo "$BASE_IMAGE" | cut -f1 -d:)" diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 0000000..0db5ccb --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,34 @@ +name: Tag Docker image + +on: + workflow_call: + inputs: + # Image to be retagged. This must exist in the registry. + image: + type: string + + # Space-separated list of fully qualified image tags (including registry address) + # Format matches the output of `docker/metadata-action`. + tags: + type: string + +env: + DOCKER_APP_IMAGE: ${{ inputs.image }} + DOCKER_METADATA_OUTPUT_TAGS: ${{ inputs.tags }} + +jobs: + tag: + runs-on: ubuntu-24.04 + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Apply tags to the image + run: | + docker pull "$DOCKER_APP_IMAGE" + echo "$DOCKER_METADATA_OUTPUT_TAGS" | tr ' ' '\n' | xargs -n1 docker tag "$DOCKER_APP_IMAGE" + docker push --all-tags "$(echo "$DOCKER_APP_IMAGE" | cut -f1 -d:)" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..385b4a4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: Test Docker image + +on: + workflow_call: + inputs: + image: + type: string + +env: + COMPOSE_FILE: docker-compose.yml:docker-compose.ci.yml + DOCKER_APP_IMAGE: ${{ inputs.image }} + +jobs: + test: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Compose + uses: docker/setup-compose-action@v1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Run the test script + run: | + docker compose run --rm --user root app chown -R avplayer:avplayer artifacts + docker compose up --detach --wait + docker compose exec app bin/test