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).