Repository: bowtie-json-schema/kotlin-kmp-json-schema-validator
Pull request #1: Add common and harness specific configuration for deployment and publication
Author: login: OptimumCode
Created: 2025-02-24T17:40:27Z | Merged: 2025-03-15T08:16:45Z



Diff:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..8d89552
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,17 @@
+version: 2
+updates:
+  # common configuration
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "weekly"
+  - package-ecosystem: "docker"
+    directory: "/"
+    schedule:
+      interval: "daily"
+
+  # test harnsess configuration
+  - package-ecosystem: "gradle"
+    directory: "/"
+    schedule:
+      interval: "daily"
diff --git a/.github/workflows/build-all.yml b/.github/workflows/build-all.yml
new file mode 100644
index 0000000..d754018
--- /dev/null
+++ b/.github/workflows/build-all.yml
@@ -0,0 +1,121 @@
+name: Build Bowtie Image for all available versions
+
+on:
+  workflow_dispatch:
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+permissions: {}
+
+jobs:
+  versions:
+    runs-on: ubuntu-latest
+    outputs:
+      revisions: ${{ steps.revisions.outputs.value }}
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+          fetch-depth: 0
+          fetch-tags: true
+      - name: Collect available versions
+        id: revisions
+        run: |
+          tags=$(jq -c -n '$ARGS.positional + ["main"]' --args $(git tag --list))
+          echo "value=$(echo $tags | jq -c .)" >> $GITHUB_OUTPUT
+
+  build:
+    needs: versions
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: true
+      matrix:
+        revision: ${{ fromJson(needs.versions.outputs.revisions) }}
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+          ref: ${{ matrix.revision }}
+
+      - name: Compute implementation name
+        id: impl
+        env:
+          GH_REPOSITORY: ${{ github.repository }}
+        run: echo "name=$(echo ${GH_REPOSITORY} | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Install bowtie
+        uses: bowtie-json-schema/bowtie@main
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ steps.impl.outputs.name }}
+          tags: ${{ github.sha }} ${{ matrix.revision == 'main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Smoke Test
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+        run: |
+          bowtie smoke -i "localhost/${IMAGE_WITH_TAG}" --format json
+          bowtie smoke -i "localhost/${IMAGE_WITH_TAG}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Collect current version
+        id: current-version
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+        run: |
+          version=$(bowtie info \
+              --implementation "localhost/${IMAGE_WITH_TAG}" \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+      - name: Print collected version
+        env:
+          CURRENT_VERSION: ${{ steps.current-version.outputs.value }}
+        run: echo "current_version=${CURRENT_VERSION}"
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+
+      - name: Add tag with version to the image
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+          IMAGE_WITH_VERSION: "${{ steps.build_image.outputs.image }}:${{ steps.current-version.outputs.value }}"
+        run: podman tag ${IMAGE_WITH_TAG} ${IMAGE_WITH_VERSION}
+
+      - name: Publish
+        id: push
+        uses: redhat-actions/push-to-registry@v2
+        with:
+          image: ${{ steps.build_image.outputs.image }}
+          tags: ${{ steps.current-version.outputs.value }} ${{ steps.build_image.outputs.tags }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+
+      - name: Generate attestation for images
+        uses: actions/attest-build-provenance@v2
+        with:
+          subject-name: ${{ env.IMAGE_REGISTRY }}/${{ steps.build_image.outputs.image }}
+          subject-digest: ${{ steps.push.outputs.digest }}
+          push-to-registry: true
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..13b8486
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,188 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+permissions: {}
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+
+      - name: Install bowtie
+        uses: bowtie-json-schema/bowtie@main
+
+      - name: Compute implementation name
+        id: impl
+        env:
+          GH_REPOSITORY: ${{ github.repository }}
+        run: echo "name=$(echo ${GH_REPOSITORY} | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        env:
+          IMPL_NAME: ${{ steps.impl.outputs.name }}
+        run: |
+          version=$(bowtie info \
+              --implementation ${IMPL_NAME} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+
+      - name: Install bowtie
+        uses: bowtie-json-schema/bowtie@main
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Smoke Test
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+        run: |
+          bowtie smoke -i "localhost/${IMAGE_WITH_TAG}" --format json
+          bowtie smoke -i "localhost/${IMAGE_WITH_TAG}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Collect current version
+        id: current-version
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+        run: |
+          version=$(bowtie info \
+              --implementation "localhost/${IMAGE_WITH_TAG}" \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+      - name: Print collected versions
+        env:
+          LATEST_VERSION: ${{ needs.meta.outputs.latest-version }}
+          CURRENT_VERSION: ${{ steps.current-version.outputs.value }}
+        run: echo "latest_version=${LATEST_VERSION}; current_version=${CURRENT_VERSION}"
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Add tag with version to the image
+        env:
+          IMAGE_WITH_TAG: ${{ steps.build_image.outputs.image-with-tag }}
+          IMAGE_WITH_VERSION: "${{ steps.build_image.outputs.image }}:${{ steps.current-version.outputs.value }}"
+        run: podman tag ${IMAGE_WITH_TAG} ${IMAGE_WITH_VERSION}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Publish
+        id: push
+        uses: redhat-actions/push-to-registry@v2
+        with:
+          image: ${{ steps.build_image.outputs.image }}
+          tags: ${{ steps.current-version.outputs.value }} ${{ steps.build_image.outputs.tags }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Generate attestation for images
+        uses: actions/attest-build-provenance@v2
+        with:
+          subject-name: ${{ env.IMAGE_REGISTRY }}/${{ steps.build_image.outputs.image }}
+          subject-digest: ${{ steps.push.outputs.digest }}
+          push-to-registry: true
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+  mark-previous-version:
+    needs: [build, meta]
+    runs-on: ubuntu-latest
+
+    if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.build.outputs.current-version != needs.meta.outputs.latest-version
+
+    permissions:
+      contents: write
+
+    env:
+      TAG: v${{ needs.meta.outputs.latest-version }}
+      COMMIT: ${{ github.event.before }}
+      GH_REPOSITORY: ${{ github.repository }}
+
+    steps:
+
+      - name: Create a release for previous implementation version
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: >
+          gh api
+          --method POST
+          -H "Accept: application/vnd.github+json"
+          -H "X-GitHub-Api-Version: 2022-11-28"
+          /repos/${GH_REPOSITORY}/releases
+          -f "tag_name=$TAG"
+          -f "target_commitish=$COMMIT"
+          -f "name=$TAG"
+          -f "body=Automatic release for $TAG"
+          -F "generate_release_notes=true"
+
+
+  automerge:
+    needs: build
+    runs-on: ubuntu-latest
+
+    if: (!cancelled() && github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]')
+
+    permissions:
+      contents: write
+      pull-requests: write
+
+    steps:
+      - name: Automatically merge allowed PRs
+        run: gh pr merge --auto --merge "$PR_URL"
+        env:
+          PR_URL: ${{ github.event.pull_request.html_url }}
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..9ca8d1a
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,31 @@
+repos:
+  # common hooks - should be added to template project
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v5.0.0
+    hooks:
+      - id: check-added-large-files
+      - id: check-ast
+      - id: check-json
+      - id: check-toml
+      - id: check-vcs-permalinks
+      - id: check-yaml
+      - id: debug-statements
+      - id: end-of-file-fixer
+      - id: mixed-line-ending
+        args: [--fix, lf]
+      - id: trailing-whitespace
+  - repo: https://github.com/woodruffw/zizmor-pre-commit
+    rev: v1.4.1
+    hooks:
+    - id: zizmor
+
+  # test harness specific hooks
+  - repo: https://github.com/dustinsand/pre-commit-jvm
+    rev: v0.11.0
+    hooks:
+      - name: ktlint (java/kotlin implementations)
+        id: ktlint
+        args: [--format]
+      - name: detekt (java/kotlin implementations)
+        id: detekt
+        args: ["--build-upon-default-config"]
diff --git a/Dockerfile b/Dockerfile
index 2d16b27..6c0e2c6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM gradle:8.12.1-jdk17 AS builder
+FROM --platform=$BUILDPLATFORM gradle:8.12.1-jdk17 AS builder
 WORKDIR /opt/app
 COPY gradle/libs.versions.toml gradle/
 COPY settings.gradle.kts .
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..36c3214
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2022 Bowtie's Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Bowtie's logo was designed by @PaulWaller with work sponsored by [endjin](https://endjin.com).


Reviews:
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-24T18:01:59Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-25T17:34:22Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-25T18:12:47Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-27T14:16:45Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-27T15:54:44Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-27T16:00:07Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-27T16:07:38Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-27T16:10:25Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-27T20:37:24Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T09:33:59Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T13:58:40Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T15:53:46Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T15:57:06Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T16:41:52Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T14:19:30Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T14:20:33Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T16:17:05Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T16:18:27Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T16:21:44Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T16:46:54Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T17:02:30Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T17:04:02Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T17:05:06Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-10T17:58:00Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T11:12:41Z
user: login: Julian
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T23:40:36Z
user: login: OptimumCode
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T05:17:50Z

Review comments:
diff_hunk: @@ -0,0 +1,17 @@
+version: 2
+updates:
+  # common configuration
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "weekly"
+  - package-ecosystem: "docker"
+    directory: "/"
+    schedule:
+      interval: "daily"
path: .github/dependabot.yml
user: login: OptimumCode
body: note: this part will go into a template project
created_at: 2025-02-24T17:49:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,170 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        description: >
+          A specific version of the implementation you want to build.
+
+          If the implementation has historical version support (i.e. a `matrix-versions.json` file)
+          and your specified version is included in that file then only that version of the implementation
+          will be built and if you don't specify any version over here then all of its versions from that
+          file will be built.
+
+          If no file is found then just the latest version of the implementation will be built.
+        required: false
+        type: string
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  list:
+    runs-on: ubuntu-latest
+    outputs:
+      images: ${{ steps.images-matrix.outputs.images }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Calculate which impages to build
+        id: images-matrix
+        run: |
+          version=${{ inputs.version }}
+          matrix_versions_file="matrix-versions.json"
+          MATRIX="[]"
+          if [ -f "$matrix_versions_file" ]; then
+            versions=$(cat "$matrix_versions_file" | jq -c)
+            if [ -n "$version" ]; then
+              if echo "$versions" | jq -e --arg version "$version" 'index($version) != null' > /dev/null; then
+                MATRIX="[{"version": $version}]"
+              else
+                echo "No such version ('$version') found in the \`matrix-versions.json\` file of $implementation. Please provide a correct version."
+                exit 1
+              fi
+            else
+              MATRIX=$(jq --argjson vers "$versions" '["version": $vers[]}]')
+            fi
+          else
+            MATRIX='[{"version": "latest"}]'
+          fi
+          echo "images=$(echo $MATRIX | jq -c .)" >> $GITHUB_OUTPUT
+
+  build:
+    needs: list
+
+    # Particularly for .NET (which we special case below),
+    # we need a newer buildah than what's in 22.04 (which is buildah 1.23.1)
+    # so that it properly sets TARGETARCH and therefore multi-architecture
+    # container image builds know which architecture we're building for.
+    # See https://github.com/containers/buildah/pull/4295.
+    runs-on: ubuntu-24.04
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        include: ${{ fromJson(needs.list.outputs.images) }}
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+        id: impl
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+        if: (!startsWith(steps.impl.outputs.name, 'dotnet-'))
+        # See https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support/ for why not .NET
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ steps.impl.outputs.name }}
+          tags: ${{ matrix.version }} ${{ github.sha }}
+          archs: amd64, arm64
+          build-args: |
+            ${{ matrix.version && format('IMPLEMENTATION_VERSION={0}', matrix.version) || '' }}
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Smoke Test
+        run: |
+          uvx --from . --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format json
+          uvx --from . --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
path: .github/workflows/build.yml
user: login: OptimumCode
body: question: should we also push the image when PR is merged into the main branch?
created_at: 2025-02-24T17:53:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,27 @@
+repos:
+  # common hooks - should be added to template project
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v5.0.0
+    hooks:
+      - id: check-added-large-files
+      - id: check-ast
+      - id: check-json
+      - id: check-toml
+      - id: check-vcs-permalinks
+      - id: check-yaml
+      - id: debug-statements
+      - id: end-of-file-fixer
+      - id: mixed-line-ending
+        args: [--fix, lf]
+      - id: trailing-whitespace
path: .pre-commit-config.yaml
user: login: OptimumCode
body: note: this part will go into a template project
created_at: 2025-02-24T17:54:15Z
author_association: COLLABORATOR
path: LICENSE
user: login: OptimumCode
body: note: I think it would be fare to add this LICENSE into a template project for test tharnesses
created_at: 2025-02-24T17:54:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: Julian
body: I'll take a closer look at this PR after I finish my teaching for the week (probably on Thursday). I think though this specific file should all hopefully be "obsoleted" -- meaning for future implementation repos, we should have one file which builds the current version, and then one git branch (or possibly tag) for each version of the implementation which we build the image for, and then to build all versions we simply check out each of those branches and run the same workflow on it.

Maybe that is too tersely written, or maybe you want to wait to do that until afterwards and just keep this minimal POC minimal? But just mentioning it in case you have thoughts, hopefully the idea at least seems reasonable!
created_at: 2025-02-25T17:34:21Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: Yes, it looks reasonable to me. Let me just recap what you are saying to make sure we have the same understanding:

- _instead of having `matrix-versions.json` each implementation version will be marked with a tag (or a new branch is created for each version)_ - do we want to automate this? e.g. a PR from dependabot for impl's version update will add a certain label to the PR and once the CI passes it will trigger the creation of a tag\branch
- _the workflow file in the repo should only build the current version_ - we need to figure out how to pass the information about the version into CI to put the right tag... If I am not mistaken, once the test harness image is built we can extract information by sending a `start` command to the impl and in response we get the current version. Maybe we could use that, what do you think?
  Also, we won't be able to use dependabot for those branches\tags. This means no updates for Docker images and other dependencies.  I don't think it is a problem but still worth noticing.
- _we should also have a separate workflow that will go through all tags\branches and rebuild images when required_ - you did not say exactly that but this is how I imagine `we simply check out each of those branches and run the same workflow on it` part. One workflow inside the repo that rebuilds all the images on demand

If my understanding is the same as yours I think it would be better to try implementing that during the POC as well. And you probably can ignore this PR for now, while I change it to meet the above requirements
created_at: 2025-02-25T18:12:47Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: Julian
body: > do we want to automate this? e.g. a PR from dependabot for impl's version update will add a certain label to the PR and once the CI passes it will trigger the creation of a tag\branch

Yes that sound great definitely -- basically we should only ever need to do it for new tags of course, so as long as each time dependabot updates an implementation we tag a new  release automatically with the new version number, then over time all those releases stick around.

> we need to figure out how to pass the information about the version into CI to put the right tag... If I am not mistaken, once the test harness image is built we can extract information by sending a start command to the impl and in response we get the current version. Maybe we could use that, what do you think?

I don't 100% follow this, possibly because I was thinking something even simpler -- the git tag (== release) should be the version of the implementation. So as far as GH Actions is concerned, you get that from looking at the tag in the event that triggers the workflow run. An example is here (in another context, for Bowtie's own release): https://github.com/bowtie-json-schema/bowtie/blob/4027a5138928f7f10cf97800454d87297b252a7c/.github/workflows/ci.yml#L183 basically it's `github.event.ref` (and there's now a newer attribute I think that GH Actions sets which automatically removes the `ref/tags` from the front I think but I forget what it's called)

> we should also have a separate workflow that will go through all tags\branches and rebuild images when required - you did not say exactly that but this is how I imagine we simply check out each of those branches and run the same workflow on it part. One workflow inside the repo that rebuilds all the images on demand

That sounds right yeah, basically loop over all releases, check each one out, build and push

> If my understanding is the same as yours I think it would be better to try implementing that during the POC as well. And you probably can ignore this PR for now, while I change it to meet the above requirements

Other than the second thing sounds like we're on the same page, and yeah thanks a ton again for moving this forward!
created_at: 2025-02-27T14:16:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: > I don't 100% follow this, possibly because I was thinking something even simpler -- the git tag (== release) should be the version of the implementation

Yes, but I was thinking about how to detect changes in impl version automatically and in a unified way. As you said:
> we tag a new release automatically with the new version number

But for each ecosystem, the PRs from dependabot will look a bit differently and it can be problematic to detect when the impl's version is changed. If I am not missing something, each test harness implementation is designed in the way it knows the current impl version and can return it in response to a `start` command from `bowtie`. This would allow us to do the following steps on dependabot's PR updating the harness impl version:

1. request version from the latest test harness image;
2. request version from an image built during PR;
3. compare those versions;
4. if they are different, use the version from the 1st step to create the tag for the current state of the main branch;
5. after that dependabot's PR can be merged into the main branch and a new latest version will be built

As an alternative (I just remembered about that) we could probably use a [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) action. It should return the list of updated dependencies and we can check if the implementation version has changed.

But maybe I am overcomplicating things... If we are okay to do some stuff manually (put a correct tag on a branch) we can use tags as you suggested. But this will be a manual step in any case.

@Julian do you have any thoughts on the above? I think it is worth trying to automate tag creation but not sure which way to choose... I am leaning towards the first option (where bowtie's `start` command is used)

I, probably, can start working on a workflow that iterates over the tags and builds images with the correct versions. We definitely agreed on that :smile:

created_at: 2025-02-27T15:54:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: Julian
body: Ah I see, basically how do we know what the new version is on every dependabot PR, yeah I guess what you're suggesting is one way that does sound reasonable to me to test out!
created_at: 2025-02-27T16:00:07Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: @Julian could you advise how I can use the bowtie to retrieve the version of a particular harness?
Is this the right command?

```bash
$ bowtie info --implementation kotlin-kmp-json-schema-validator --format json
{
  "name": "kmp-json-schema-validator",
  "language": "kotlin",
  "version": "0.4.0",
  "homepage": "https://github.com/OptimumCode/json-schema-validator",
  "issues": "https://github.com/OptimumCode/json-schema-validator/issues",
  "language_version": "2.1.10",
  "os": "Linux",
  "os_version": "5.15.0-113-generic",
  "source": "https://github.com/OptimumCode/json-schema-validator",
  "dialects": [
    "https://json-schema.org/draft/2020-12/schema",
    "https://json-schema.org/draft/2019-09/schema",
    "http://json-schema.org/draft-07/schema#",
    "http://json-schema.org/draft-06/schema#",
    "http://json-schema.org/draft-04/schema#"
  ]
}
```
created_at: 2025-02-27T16:07:38Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: Julian
body: Yep exactly that, `bowtie info --format json`.
created_at: 2025-02-27T16:10:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: I faced a strange behaviour on tag push:
https://github.com/OptimumCode/kotlin-kmp-json-schema-validator/actions/runs/13573603703
GitHub did not allow to push a tag that references a commit where a workflow file was changed... We probably might face this issue in real life. I will try to migrate to this [API call](https://docs.github.com/en/rest/git/refs?apiVersion=2022-11-28#create-a-reference) instead. [Here](https://github.com/orgs/community/discussions/26164#discussioncomment-5416750) people say it works okay.

Please note that the workflow is as simple as it gets: if the version is changed (+ conditions on where the commit was pushed) - create a tag. E.g., I [downgraded the version](https://github.com/OptimumCode/kotlin-kmp-json-schema-validator/compare/prep-ci...test-mark-option?expand=1) and the marking was triggered.


**A test run for the publication** was better ([some changes](https://github.com/OptimumCode/kotlin-kmp-json-schema-validator/compare/prep-ci...test-publication?expand=1) in step's conditions to emulate push to main branch):

https://github.com/OptimumCode/kotlin-kmp-json-schema-validator/actions/runs/13575138196/job/37949466937

I almost did not change the publication flow so it is pretty much the same as in the original bowtie workflow. Looks like everything worked fine:
https://github.com/OptimumCode/kotlin-kmp-json-schema-validator/pkgs/container/kotlin-kmp-json-schema-validator

@Julian what do you think about the current state of the workflow?
created_at: 2025-02-27T20:37:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: > I will try to migrate to this [API call](https://docs.github.com/en/rest/git/refs?apiVersion=2022-11-28#create-a-reference) instead.

Actually, we can probably simply create a GitHub release... We should get the same results as creating a tag
created_at: 2025-02-28T09:33:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: Forgot, that we still need a valid tag to create a release...
I will try to use GitHub API for both actions - will see how it goes
created_at: 2025-02-28T13:58:39Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,168 @@
+name: Rebuild Bowtie Image
path: .github/workflows/build.yml
user: login: OptimumCode
body: Not sure why, but I cannot create a tag in GitHub Workflow without having a `workflows: write` permission... I had to create a personal access token with `contents: write` and `workflows: write` permissions.
Would it be okay to use a PAT token inside the bowite org, @Julian? We can create one and add it to the organization's secrets
created_at: 2025-02-28T15:53:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,186 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Smoke Test
+        run: |
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format json
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Collect current version
+        id: current-version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation "localhost/${{ steps.build_image.outputs.image-with-tag }}" \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+      - name: Print collected versions
+        run: echo "latest_version=${{ needs.meta.outputs.latest-version }}; current_version=${{ steps.current-version.outputs.value }}"
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Add tag with version to the image
+        run: podman tag ${{ steps.build_image.outputs.image-with-tag }} ${{ steps.build_image.outputs.image }}:${{ steps.current-version.outputs.value }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
path: .github/workflows/build.yml
user: login: OptimumCode
body: question: do we want to enable image publication when the workflow is triggered by the `workflow_dispatch` event, @Julian? Right now it will only build an image without publishing it
created_at: 2025-02-28T15:57:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,186 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Smoke Test
+        run: |
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format json
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Collect current version
+        id: current-version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation "localhost/${{ steps.build_image.outputs.image-with-tag }}" \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+      - name: Print collected versions
+        run: echo "latest_version=${{ needs.meta.outputs.latest-version }}; current_version=${{ steps.current-version.outputs.value }}"
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Add tag with version to the image
+        run: podman tag ${{ steps.build_image.outputs.image-with-tag }} ${{ steps.build_image.outputs.image }}:${{ steps.current-version.outputs.value }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
path: .github/workflows/build.yml
user: login: Julian
body: I think no (only push on tag)
created_at: 2025-03-05T16:41:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: Julian
body: Apologies for still being behind in trying to understand some of the issues here in this one -- but can we avoid all the git tag business above if we simply change the container tag here to be the version we get from `bowtie info` directly? I have to assume that somewhere it will automatically track which commit was used to build an image (but even if not we could add an image label for that if need be).

Then we wouldn't need any automatic git tag creation no?
created_at: 2025-03-06T14:19:30Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
path: .github/workflows/build.yml
user: login: Julian
body: I think here we should use Bowtie's GitHub action -- if it need fixing (which it might, as I know you copied this from there probably) then we can fix it -- but probably the reason I didn't use it there in that repo was because I wanted to use the HEAD version of the action, whereas here we do not, we always want the latest Bowtie release to be used for this image's workflow.
created_at: 2025-03-06T14:20:33Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: Thank you, @Julian, for finding the time to do the review!

Not sure if I understand your idea correctly. You are wondering if we could go through the available packages and collect those which has a tag with a version on it. And then take the associated git revision for that version and use it to checkout the sources for that version. Do I get you right? And this is all could be used in [workflow](https://github.com/bowtie-json-schema/kotlin-kmp-json-schema-validator/pull/2) that rebuilds all the versions when required.

If I got everything right, then it can probably work, I think. There is no automatic tracking of the commit from which the image was built (here is what we [get in response](https://docs.github.com/en/rest/packages/packages?apiVersion=2022-11-28#get-a-package-version-for-an-organization--parameters)), but we tag the image with a git hash before publishing it. We can use this tag with git hash, I think. Below is an example of what we get in response for a particular version

```json
{
  "id": 365105767,
  "name": "sha256:537da0fca45c677316d47f27dd1c6d18eba6f56f34b9917d4212f846b7d1d53a",
  "url": "https://api.github.com/users/OptimumCode/packages/container/kotlin-kmp-json-schema-validator/versions/365105767",
  "package_html_url": "https://github.com/users/OptimumCode/packages/container/package/kotlin-kmp-json-schema-validator",
  "created_at": "2025-02-28T17:23:13Z",
  "updated_at": "2025-02-28T17:23:13Z",
  "html_url": "https://github.com/users/OptimumCode/packages/container/kotlin-kmp-json-schema-validator/365105767",
  "metadata": {
    "package_type": "container",
    "container": {
      "tags": [
        "4e8d0c72fd2b1e3bcc18d22d3623749746d3a8d5",
        "latest",
        "0.4.0"
      ]
    }
  }
}
```
created_at: 2025-03-06T16:17:05Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
path: .github/workflows/build.yml
user: login: OptimumCode
body: You are right, I have completely forgotten about the bowtie action. Will use it here
created_at: 2025-03-06T16:18:27Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: And in this case, we will not need a tag creation - **mark-previous-version** job in this workflow (though it might be a bit complicated to find the particular version in a git tree if needed)
created_at: 2025-03-06T16:21:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: Julian
body: Basically I've forgotten why we care / need to tag things! I think the reason I had in mind originally was in order to identify which commits in each harness repo are those relating to a specific implementation version -- specifically, imagine the scenario(s):

implementation has version 1.2.3 and 1.3.4 we want a harness for versions 1.2.3 and 1.3.4
we discover a bug in our *harness* for 1.2.3, and need to go back and fix it, but the implementation version of course does not change

so then we need to checkout and fix the harness at that version and republish the 1.2.3 image

(I have to read your comment more carefully, apologies again for doing this a bit haphazardly I have too many things going on at the moment...)
created_at: 2025-03-06T16:46:54Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: No worries, @Julian)

I think git tags are the best option for this exact case:

- we extract the implementation version using `bowtie info` and this version becomes a git tag and a version of the test harness for that implementation;
- we always know which commit to checkout for each test harness version (the latest one is always a main);
- if we need to modify anything. we can checkout the tag, create a branch, commit changes, and move the tag to point to the new head.

We can use branches instead of tags, If we want to simplify the process of making changes/fixes into test harnesses for previous versions. Just checkout the branch, make changes, push them to the branch, trigger a workflow to rebuild and publish the test harness image
created_at: 2025-03-06T17:02:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: Also, I think I got what was worrying you - you don't see the implementation version in the list of tags when we build the image. This is because we need to have the image to extract the version - this is done a few steps later (I will tag you there)
created_at: 2025-03-06T17:04:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
+          archs: amd64, arm64
+
+      - name: Set DOCKER_HOST so podman-built images are findable
+        run: |
+          systemctl --user enable --now podman.socket
+          sudo loginctl enable-linger $USER
+          podman --remote info
+          echo "DOCKER_HOST=unix://$(podman info --format '{{.Host.RemoteSocket.Path}}')" >> $GITHUB_ENV
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Smoke Test
+        run: |
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format json
+          uvx --from 'bowtie-json-schema' --python 3.13 bowtie smoke -i "localhost/${{ steps.build_image.outputs.image-with-tag }}" --format markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Collect current version
+        id: current-version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation "localhost/${{ steps.build_image.outputs.image-with-tag }}" \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+      - name: Print collected versions
+        run: echo "latest_version=${{ needs.meta.outputs.latest-version }}; current_version=${{ steps.current-version.outputs.value }}"
+
+      - name: Log in to ghcr.io
+        uses: redhat-actions/podman-login@v1
+        with:
+          username: ${{ github.actor }}
+          password: ${{ github.token }}
+          registry: ${{ env.IMAGE_REGISTRY }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+      - name: Add tag with version to the image
+        run: podman tag ${{ steps.build_image.outputs.image-with-tag }} ${{ steps.build_image.outputs.image }}:${{ steps.current-version.outputs.value }}
+        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
path: .github/workflows/build.yml
user: login: OptimumCode
body: @Julian, here we extract the implementation version from the test harness and add this version as a tag on the image
created_at: 2025-03-06T17:05:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: Hi, @Julian. I think we are close to the final state of the workflow. The only thing left is to decide if we keep the job that automatically marks the previous commit with a tag when a new version of implementation is merged into the main branch.
If we want, we might need a PAT token to create a tag (I faced a problem when `workflow: write` permissions were required to create a tag). I am not sure why they were required but GH API and git did not allow creating a tag for a previous commit. It says [here](https://docs.github.com/en/rest/git/refs?apiVersion=2022-11-28#create-a-reference) that either **contents** or **contents and workflows** write permissions are required but providing only **contents** permissions did not work...

Could you please create a secret on org level with permissions `contents: write` and `workflows: write` permissions? We can name `TAG_PAT` for example
created_at: 2025-03-10T17:58:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: I did a few [tests](https://github.com/bowtie-json-schema/kotlin-kmp-json-schema-validator/actions/runs/13786550716/job/38555838307), and it looks like if we use just the release API (no manual tag creation) everything should work with the GH token.

Changes: https://github.com/bowtie-json-schema/kotlin-kmp-json-schema-validator/pull/1/commits/751f7d48e66110e290fcf71187521362ecefed72
created_at: 2025-03-11T11:12:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: Julian
body: Ok so we're good here without me creating the token right? Yay
created_at: 2025-03-11T23:40:36Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,191 @@
+name: Rebuild Bowtie Image
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches-ignore:
+      - "wip*"
+
+env:
+  IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
+
+concurrency:
+  group: images-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  meta:
+    runs-on: ubuntu-latest
+    outputs:
+      latest-version: ${{ steps.version.outputs.value }}
+      implementation-name: ${{ steps.impl.outputs.name }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          enable-cache: true
+
+      - name: Compute implementation name
+        id: impl
+        run: echo "name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+
+      - name: Compute latest implementation version
+        id: version
+        run: |
+          version=$(uvx --from 'bowtie-json-schema' --python 3.13 bowtie info \
+              --implementation ${{ steps.impl.outputs.name }} \
+              --format json | jq -r '.version // empty')
+          echo "value=${version}" >> $GITHUB_OUTPUT
+
+  build:
+    needs: meta
+
+    runs-on: ubuntu-latest
+
+    outputs:
+      current-version: ${{ steps.current-version.outputs.value }}
+
+    permissions:
+      id-token: write
+      contents: read
+      attestations: write
+      packages: write
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Install qemu
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y qemu-user-static
+
+      - name: Build
+        id: build_image
+        uses: redhat-actions/buildah-build@v2
+        with:
+          context: '.'
+          containerfiles: |
+            Dockerfile
+          image: ${{ needs.meta.outputs.implementation-name }}
+          tags: ${{ github.sha }} ${{ github.ref == 'refs/heads/main' && 'latest' || '' }}
path: .github/workflows/build.yml
user: login: OptimumCode
body: Looks like so
created_at: 2025-03-12T05:17:50Z
author_association: COLLABORATOR

PR comments:
user: login: OptimumCode
created_at: 2025-02-24T18:59:10Z
body: Hi, @Julian. Could you please take a look at the changes in the CI workflow?
author_association: COLLABORATOR
user: login: OptimumCode
created_at: 2025-03-03T16:45:28Z
body: Hi, @Julian! I hope you're doing well. Could you please advise if you have a chance to look at workflows this week or next week? 

If you don't have time for this at the moment, I could probably take a look at changes in how bowtie collects known implementations - use GitHub packages API along with traversing the implementations directory. It should be easy to switch to packages API only in the future once all test harnesses are moved out of the main repo.
author_association: COLLABORATOR
user: login: Julian
created_at: 2025-03-11T23:42:02Z
body: I think this lgtm at this point!
author_association: MEMBER
user: login: OptimumCode
created_at: 2025-03-12T07:59:07Z
body: Thank you, @Julian for finding time to review changes!

I think the next step would be merging the changes, moving all to main branch and publishing the first image from that repository (I am not sure if this repo has rights to publish to org packages though - could you please check that @Julian ? I definitely saw an error in one of the runs when it attempted to publish an image)
Once the image is published we can remove the implementation from the bowtie repo.
author_association: COLLABORATOR
user: login: Julian
created_at: 2025-03-12T13:07:52Z
body: We need to make changes in the Bowtie repo from your other PR before we can delete it there right? (e.g. to ensure the doc implementation number is correct, and to ensure that the CLI has the correct full list of implementations by combining the two locations)

But merging certainly sounds good to me -- remind me again (sorry) what's the step going to be to publish an image from this repo? It will happen automatically when we merge? And then automatically going forward when dependabot sends PRs? 

I've just added this repo to the permissions for the package ([here](https://github.com/orgs/bowtie-json-schema/packages/container/kotlin-kmp-json-schema-validator/settings))

Thanks again for all your work!!
author_association: MEMBER
user: login: OptimumCode
created_at: 2025-03-12T16:07:06Z
body: > We need to make changes in the Bowtie repo from your other PR before we can delete it there right?

Yes, you are right. The corresponding changes are done in this PR https://github.com/bowtie-json-schema/bowtie/pull/1867. I tested them locally, and all looked good. But we could add a step in bowtie CI to check the number of implementations collected (until we move all implementations out). What do you think about that @Julian ?

> remind me again (sorry) what's the step going to be to publish an image from this repo? It will happen automatically when we merge?

(all is good :smile: ) No, it will not happen automatically after we merge this PR. The workflow publishes the image only if a commit is pushed into the `main` branch but we are merging in `bowtie-main` - so an automatic push will not be triggered. But once we move `bowtie-main` to `main` and something is pushed into the main branch, the publication will be triggered automatically.

>  And then automatically going forward when dependabot sends PRs?

When this PR is merged into the `main` branch. When PR is created nothing is pushed to the registry
author_association: COLLABORATOR
user: login: Julian
created_at: 2025-03-12T16:13:12Z
body: > But we could add a step in bowtie CI to check the number of implementations collected (until we move all implementations out). What do you think about that @Julian ?

This seems very reasonable! Perhaps as a greater-than-or-equal to check (i.e. that we have at least the current number, on the off chance we add some implementations while we're going through this move).

Ahhhh I didn't notice this was `bowtie-main`, ok great.
author_association: MEMBER