From 2ff37ce97a33c0fd4f7600abe5b46d27f03c5e44 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Tue, 12 Sep 2023 19:11:46 +0200
Subject: [PATCH] chore: bring back docker image releases

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/release.yml | 88 +++++++++++++++++++++++++++++++++--
 1 file changed, 83 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 30fa9f19..d949097c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -45,11 +45,16 @@ env:
   POETRY_VERSION: "1.4.1"
 
 jobs:
-  release:
+  release-PyPI:
+    name: "Release: PyPI & GitHub"
     # https://github.community/t/how-do-i-specify-job-dependency-running-in-another-workflow/16482
     # limit this to being run on regular commits, not the commits that semantic-release will create
     # but also allow manual workflow dispatch
     if: "!contains(github.event.head_commit.message, 'chore(release):')"
+    outputs:
+      released: ${{ steps.release.outputs.released }}
+      version:  ${{ steps.release.outputs.version }}
+      tag:      ${{ steps.release.outputs.tag }}
     runs-on: ubuntu-latest
     permissions:
       # NOTE: this enables trusted publishing.
@@ -63,7 +68,6 @@ jobs:
         uses: actions/checkout@v3
         with:
           fetch-depth: 0
-
       - name: Setup python
         # see https://github.com/actions/setup-python
         uses: actions/setup-python@v4
@@ -82,7 +86,6 @@ jobs:
         run: poetry install --no-root
       - name: View poetry version
         run: poetry --version
-
       - name: Python Semantic Release
         id: release
         # see https://python-semantic-release.readthedocs.io/en/latest/automatic-releases/github-actions.html
@@ -93,14 +96,12 @@ jobs:
           force: ${{ github.event.inputs.release_force }}
           prerelease: ${{ github.event.inputs.prerelease }}
           prerelease_token: ${{ github.event.inputs.prerelease_token }}
-
       - name: Publish package distributions to PyPI
         if: steps.release.outputs.released == 'true'
         # see https://github.com/pypa/gh-action-pypi-publish
         uses: pypa/gh-action-pypi-publish@release/v1
         with:
           password: ${{ secrets.PYPI_TOKEN }}
-
       - name: Publish package distributions to GitHub Releases
         if: steps.release.outputs.released == 'true'
         # see https://github.com/python-semantic-release/upload-to-gh-release
@@ -108,3 +109,80 @@ jobs:
         with:
           github_token: ${{ secrets.GITHUB_TOKEN }}
           tag: ${{ steps.release.outputs.tag }}
+  release-DockerHub:
+    name: "Release: DockerHub"
+    needs:
+      - release-PyPI
+    if: |
+      !failure() && !cancelled() &&
+      needs.release-PyPI.result == 'success' &&
+      needs.release-PyPI.outputs.released &&
+      needs.release-PyPI.outputs.version &&
+      needs.release-PyPI.outputs.tag
+    runs-on: ubuntu-latest
+    env:
+      VERSION: ${{ needs.release-PyPI.outputs.version }}
+      ARTIFACT_DOCKER_SBOM: 'docker-image-bom'
+      DOCKER_REPO: cyclonedx/cyclonedx-python
+    steps:
+      - name: Checkout code (${{ env.TAG }})
+        # see https://github.com/actions/checkout
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ needs.release-PyPI.outputs.tag }}
+      - name: setup dirs
+        run: |
+          mkdir "$REPORTS_DIR"
+          mkdir "$DIST_DIR"
+      - name: Fetch python dist artifact
+        # see https://github.com/actions/download-artifact
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.DIST_ARTIFACT }}
+          path: ${{ env.DIST_DIR }}/
+      - name: Build Docker Image (${{ env.VERSION }})
+        run: >
+          docker build -f Dockerfile
+          --build-arg "VERSION=$VERSION"
+          -t "$DOCKER_REPO:$VERSION"
+          -t "$DOCKER_REPO:latest"
+          .
+      - name: Build own SBoM (XML)
+        run: >
+          docker run --rm "$DOCKER_REPO:$VERSION"
+          --environment
+          --format=xml
+          --output=-
+          > "$REPORTS_DIR/$ARTIFACT_DOCKER_SBOM.bom.xml"
+      - name: Build own SBoM (JSON)
+        run: >
+          docker run --rm "$DOCKER_REPO:$VERSION"
+          --environment
+          --format=json
+          --output=-
+          > "$REPORTS_DIR/$ARTIFACT_DOCKER_SBOM.bom.json"
+      - name: Artifact reports
+        if: ${{ ! cancelled() }}
+        # see https://github.com/actions/upload-artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.ARTIFACT_DOCKER_SBOM }}
+          path: ${{ env.REPORTS_DIR }}/*.bom.*
+          if-no-files-found: error
+      # publish AFTER the boms were build, as the bom-generation is kind of a test if the image works
+      - name: Publish Docker Image(s)
+        run: |
+          docker login --username "$DOCKERHUB_USERNAME" --password "$DOCKERHUB_TOKEN"
+          docker push "$DOCKER_REPO:$VERSION"
+          docker push "$DOCKER_REPO:latest"
+        env:
+          DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
+          DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
+      # TODO: publish all files in $REPORTS_DIR as release assets - see https://github.com/actions/upload-release-asset
+      - name: Destroy Docker image
+        # run regardless of outcome
+        if: ${{ always() }}
+        run: >
+          docker rmi -f
+          "$DOCKER_REPO:$VERSION"
+          "$DOCKER_REPO:latest"
