From 5c69bae076b80e25ba68e77330ce16724868ae58 Mon Sep 17 00:00:00 2001 From: Christoph Date: Sat, 28 Mar 2026 10:46:10 +0100 Subject: [PATCH 1/8] refactor: migrate to Taskfile and centralized reusable workflows Co-Authored-By: Claude Opus 4.6 --- .github/workflows/CRON.yml | 23 -- .github/workflows/PUSH-MASTER.yml | 41 --- .github/workflows/PUSH-OTHER.yml | 117 ------- .../workflows/auto-create-pull-request.yml | 21 ++ .github/workflows/cron-check-dependencies.yml | 19 ++ .../workflows/manual-sync-common-files.yml | 26 ++ .github/workflows/manual-update-version.yml | 39 +++ .version | 1 + Makefile | 53 --- Taskfile.cicd.yml | 305 ++++++++++++++++++ Taskfile.docker.yml | 104 ++++++ Taskfile.scripts.yml | 191 +++++++++++ Taskfile.variables.yml | 67 ++++ Taskfile.yml | 24 ++ 14 files changed, 797 insertions(+), 234 deletions(-) delete mode 100644 .github/workflows/CRON.yml delete mode 100644 .github/workflows/PUSH-MASTER.yml delete mode 100644 .github/workflows/PUSH-OTHER.yml create mode 100644 .github/workflows/auto-create-pull-request.yml create mode 100644 .github/workflows/cron-check-dependencies.yml create mode 100644 .github/workflows/manual-sync-common-files.yml create mode 100644 .github/workflows/manual-update-version.yml create mode 100644 .version delete mode 100644 Makefile create mode 100644 Taskfile.cicd.yml create mode 100644 Taskfile.docker.yml create mode 100644 Taskfile.scripts.yml create mode 100644 Taskfile.variables.yml create mode 100644 Taskfile.yml diff --git a/.github/workflows/CRON.yml b/.github/workflows/CRON.yml deleted file mode 100644 index 192d813..0000000 --- a/.github/workflows/CRON.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Weekly build - -on: - schedule: - # Run every week at 5.00 AM UTC - - cron: "0 5 */7 * *" - -jobs: - build_and_push: - name: Build and push images - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Build Docker image and push to registry - env: - DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TERM: xterm-256color - run: make build diff --git a/.github/workflows/PUSH-MASTER.yml b/.github/workflows/PUSH-MASTER.yml deleted file mode 100644 index 529bf37..0000000 --- a/.github/workflows/PUSH-MASTER.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Push to master - -on: - push: - branches: - - master - -jobs: - lint: - name: Run linters - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Docker Lint - uses: luke142367/Docker-Lint-Action@v1.1.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Haskell Dockerfile Linter (Hadolint) - uses: brpaz/hadolint-action@v1.5.0 - with: - dockerfile: Dockerfile - - build_and_push: - name: Build and push images - needs: lint - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Build Docker image and push to registry - env: - DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TERM: xterm-256color - run: make build push diff --git a/.github/workflows/PUSH-OTHER.yml b/.github/workflows/PUSH-OTHER.yml deleted file mode 100644 index 2f98654..0000000 --- a/.github/workflows/PUSH-OTHER.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Push to other branches - -on: - push: - branches-ignore: - - master - - release/* - -jobs: - lint: - name: Run linters - if: "!startsWith(github.ref, 'refs/heads/dependabot')" - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Docker Lint - uses: luke142367/Docker-Lint-Action@v1.1.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Haskell Dockerfile Linter (Hadolint) - uses: brpaz/hadolint-action@v1.5.0 - with: - dockerfile: Dockerfile - - build: - name: Build image - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Build Docker image - env: - TERM: xterm-256color - run: make build - - pull_request: - name: Create Pull Request - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Download Pull Request template - shell: bash - run: | - mkdir -p .tmp - curl -LsS https://raw.githubusercontent.com/devops-infra/.github/master/PULL_REQUEST_TEMPLATE.md -o .tmp/PULL_REQUEST_TEMPLATE.md - - - name: Create pull request - bugfix (conditional) - if: startsWith(github.ref, 'refs/heads/bugfix') - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - label: bugfix - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true - - - name: Create pull request - dependency (conditional) - if: startsWith(github.ref, 'refs/heads/dependency') - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - label: dependency - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true - - - name: Create pull request - documentation (conditional) - if: startsWith(github.ref, 'refs/heads/documentation') - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - label: documentation - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true - - - name: Create pull request - feature (conditional) - if: startsWith(github.ref, 'refs/heads/feature') - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - label: feature - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true - - - name: Create pull request - test (conditional) - if: startsWith(github.ref, 'refs/heads/test') - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - reviewer: ${{ github.actor }} - label: test - template: .tmp/PULL_REQUEST_TEMPLATE.md - draft: true - get_diff: true - - - name: Create pull request - other (conditional) - if: "!startsWith(github.ref, 'refs/heads/bugfix') && !startsWith(github.ref, 'refs/heads/dependabot') && !startsWith(github.ref, 'refs/heads/dependency') && !startsWith(github.ref, 'refs/heads/documentation') && !startsWith(github.ref, 'refs/heads/feature') && !startsWith(github.ref, 'refs/heads/test')" - uses: devops-infra/action-pull-request@v1.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - assignee: ${{ github.actor }} - label: feature - template: .tmp/PULL_REQUEST_TEMPLATE.md - get_diff: true diff --git a/.github/workflows/auto-create-pull-request.yml b/.github/workflows/auto-create-pull-request.yml new file mode 100644 index 0000000..a0cfed7 --- /dev/null +++ b/.github/workflows/auto-create-pull-request.yml @@ -0,0 +1,21 @@ +name: (Auto) Create Pull Request + +on: + push: + branches-ignore: + - master + - main + - dependabot/** + +permissions: + contents: read + packages: write + pull-requests: write + +jobs: + call: + uses: devops-infra/.github/.github/workflows/reusable-auto-create-pull-request.yml@v1 + with: + profile: dockerized + secrets: + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} diff --git a/.github/workflows/cron-check-dependencies.yml b/.github/workflows/cron-check-dependencies.yml new file mode 100644 index 0000000..95e2a25 --- /dev/null +++ b/.github/workflows/cron-check-dependencies.yml @@ -0,0 +1,19 @@ +name: (Cron) Weekly repository health + +on: + schedule: + - cron: 0 5 * * 1 + workflow_dispatch: + +permissions: + contents: read + issues: write + pull-requests: read + +jobs: + call: + uses: devops-infra/.github/.github/workflows/reusable-cron-check-dependencies.yml@v1 + with: + profile: dockerized + secrets: + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} diff --git a/.github/workflows/manual-sync-common-files.yml b/.github/workflows/manual-sync-common-files.yml new file mode 100644 index 0000000..7523759 --- /dev/null +++ b/.github/workflows/manual-sync-common-files.yml @@ -0,0 +1,26 @@ +name: (Manual) Sync Common Files + +on: + workflow_dispatch: + inputs: + type: + description: File type to sync + required: true + default: all + type: choice + options: + - all + - configs + - ignores + - taskfiles + +permissions: + contents: write + pull-requests: write + +jobs: + call: + uses: devops-infra/.github/.github/workflows/reusable-manual-sync-common-files.yml@v1 + with: + sync-type: ${{ inputs.type }} + template-profile: dockerized diff --git a/.github/workflows/manual-update-version.yml b/.github/workflows/manual-update-version.yml new file mode 100644 index 0000000..a2b6b19 --- /dev/null +++ b/.github/workflows/manual-update-version.yml @@ -0,0 +1,39 @@ +name: (Manual) Update Version + +on: + workflow_dispatch: + inputs: + type: + description: Bump type + required: false + default: patch + type: choice + options: + - patch + - minor + - major + - set + version: + description: Explicit version when type="set" (e.g., v1.2.3) + required: false + default: '' + build_only: + description: Build and push artifacts without version bump + required: false + default: false + type: boolean + +permissions: + contents: write + packages: write + +jobs: + call: + uses: devops-infra/.github/.github/workflows/reusable-manual-update-version.yml@v1 + with: + bump-type: ${{ inputs.type }} + explicit-version: ${{ inputs.version }} + build-and-push-only: ${{ inputs.build_only }} + profile: dockerized + secrets: + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} diff --git a/.version b/.version new file mode 100644 index 0000000..b82608c --- /dev/null +++ b/.version @@ -0,0 +1 @@ +v0.1.0 diff --git a/Makefile b/Makefile deleted file mode 100644 index 8d044a0..0000000 --- a/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -.PHONY: phony -phony: help - -# Provide version -VERSION=0.1.0 - -# GitHub Actions bogus variables -GITHUB_REF ?= refs/heads/null -GITHUB_SHA ?= aabbccddeeff - -# Other variables and constants -CURRENT_BRANCH := $(shell echo $(GITHUB_REF) | sed 's/refs\/heads\///') -GITHUB_SHORT_SHA := $(shell echo $(GITHUB_SHA) | cut -c1-7) -DOCKER_USER_ID := christophshyper -DOCKER_ORG_NAME := devopsinfra -DOCKER_IMAGE := docker-simple-runner -DOCKER_NAME := $(DOCKER_ORG_NAME)/$(DOCKER_IMAGE) -BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") - -# Some cosmetics -SHELL := bash -TXT_RED := $(shell tput setaf 1) -TXT_GREEN := $(shell tput setaf 2) -TXT_YELLOW := $(shell tput setaf 3) -TXT_RESET := $(shell tput sgr0) -define NL - - -endef - -# Main actions -.PHONY: help check build build-plain build-aws build-gcp build-azure push - -help: ## Display help prompt - $(info Available options:) - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(TXT_YELLOW)%-25s $(TXT_RESET) %s\n", $$1, $$2}' - -build: ## Build Docker images - $(info $(NL)$(TXT_GREEN)Building Docker image:$(TXT_YELLOW) $(DOCKER_NAME):$(VERSION)$(TXT_RESET)) - @docker build \ - --build-arg VCS_REF=$(GITHUB_SHORT_SHA) \ - --build-arg BUILD_DATE=$(BUILD_DATE) \ - --file=Dockerfile \ - --tag=$(DOCKER_NAME):$(VERSION) . - -push: ## Push to DockerHub - $(info $(NL)$(TXT_GREEN) == STARTING DEPLOYMENT == $(TXT_RESET)) - $(info $(NL)$(TXT_GREEN)Logging to DockerHub$(TXT_RESET)) - @echo $(DOCKER_TOKEN) | docker login -u $(DOCKER_USER_ID) --password-stdin - $(info $(NL)$(TXT_GREEN)Pushing image:$(TXT_YELLOW) $(DOCKER_NAME):$(VERSION)$(TXT_RESET)) - @docker tag $(DOCKER_NAME):$(VERSION) $(DOCKER_NAME):latest - @docker push $(DOCKER_NAME):$(VERSION) - @docker push $(DOCKER_NAME):latest diff --git a/Taskfile.cicd.yml b/Taskfile.cicd.yml new file mode 100644 index 0000000..cc89bd3 --- /dev/null +++ b/Taskfile.cicd.yml @@ -0,0 +1,305 @@ +version: '3' + +silent: true + +vars: + PR_TEMPLATE: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/PULL_REQUEST_TEMPLATE.md + CONFIGS_BASE_URL: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/templates/dockerized/configs + TASKFILES_BASE_URL: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/templates/dockerized/taskfiles + +tasks: + pre-commit: + desc: Run all pre-commit hooks + cmds: + - pre-commit run --all-files + + pre-commit:install: + desc: Install pre-commit hooks + cmds: + - pre-commit install + + lint: + desc: Run all linters (Dockerfile, shell scripts, workflows, YAML) + cmds: + - task: lint:actionlint + - task: lint:hadolint + - task: lint:shellcheck + - task: lint:yamllint + + lint:actionlint: + desc: Lint GitHub Actions workflows with actionlint + cmds: + - | + echo "▶️ Running actionlint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work rhysd/actionlint:latest -color + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ actionlint passed" + else + echo "❌ actionlint failed" + exit $rc + fi + + lint:hadolint: + desc: Lint Dockerfile with hadolint + cmds: + - | + echo "▶️ Running hadolint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work hadolint/hadolint:latest-debian < Dockerfile + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ hadolint passed" + else + echo "❌ hadolint failed" + exit $rc + fi + + lint:shellcheck: + desc: Lint shell scripts with shellcheck + cmds: + - | + echo "▶️ Running shellcheck..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work koalaman/shellcheck:stable -x -S style entrypoint.sh + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ shellcheck passed" + else + echo "❌ shellcheck failed" + exit $rc + fi + + lint:yamllint: + desc: Lint YAML files with yamllint + cmds: + - | + echo "▶️ Running yamllint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work cytopia/yamllint -c .yamllint.yml . + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ yamllint passed" + else + echo "❌ yamllint failed" + exit $rc + fi + + version:get: + desc: Get current version + cmds: + - echo "{{.VERSION}}" + + version:set: + desc: Update version in README.md and action.yml + cmds: + - | + # check if VERSION if different than VERSION_FROM_ACTION_YML + if [ "{{.VERSION}}" = "{{.VERSION_FROM_ACTION_YML}}" ]; then + echo "❌ ERROR: VERSION is same as VERSION_FROM_ACTION_YML ({{.VERSION}})" + exit 1 + fi + - echo Updating full version from {{.VERSION_FROM_ACTION_YML}} to {{.VERSION}} + - echo Updating minor version from {{.MINOR_FROM_ACTION_YML}} to {{.VERSION_MINOR}} + - echo Updating major version from {{.MAJOR_FROM_ACTION_YML}} to {{.VERSION_MAJOR}} + - "{{.SED}} -i 's#{{.DOCKER_NAME}}:{{.VERSION_FROM_ACTION_YML}}#{{.DOCKER_NAME}}:{{.VERSION}}#g' action.yml" + - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.VERSION_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION}}#g' README.md" + - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.VERSION_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION}}#g' README.md" + - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.MINOR_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION_MINOR}}#g' README.md" + - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.MINOR_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION_MINOR}}#g' README.md" + - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.MAJOR_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION_MAJOR}}#g' README.md" + - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.MAJOR_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION_MAJOR}}#g' README.md" + + version:update:patch: + desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) + cmds: + - task version:set VERSION=v{{.MAJOR}}.{{.MINOR}}.{{.NEXT_PATCH}} + + version:update:minor: + desc: Increment minor version (e.g., 1.2.3 -> 1.3.0) + cmds: + - task version:set VERSION=v{{.MAJOR}}.{{.NEXT_MINOR}}.0 + + version:update:major: + desc: Increment major version (e.g., 1.2.3 -> 2.0.0) + cmds: + - task version:set VERSION=v{{.NEXT_MAJOR}}.0.0 + + version:resolve-next: + desc: Resolve next version from bump type and profile + cmds: + - | + set -eu + bump_type="${BUMP_TYPE:-patch}" + input_version="${INPUT_VERSION:-}" + + normalize_version() { + candidate="${1#v}" + if ! printf "%s" "${candidate}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then + return 1 + fi + printf "v%s" "${candidate}" + } + + current="$(task version:get 2>/dev/null || true)" + if [ -z "$current" ] && [ -f .version ]; then + current="$(tr -d '\n' < .version)" + fi + + case "$bump_type" in + set) + [ -n "$input_version" ] || { echo "Missing version for type=set"; exit 1; } + next="$(normalize_version "$input_version")" || { + echo "Invalid explicit version: $input_version. Expected vX.Y.Z or X.Y.Z" + exit 1 + } + ;; + patch|minor|major) + [ -n "$current" ] || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } + current="$(normalize_version "$current")" || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } + no_v="${current#v}" + IFS='.' read -r major minor patch <<< "$no_v" + case "$bump_type" in + patch) next="v${major}.${minor}.$((patch + 1))" ;; + minor) next="v${major}.$((minor + 1)).0" ;; + major) next="v$((major + 1)).0.0" ;; + esac + ;; + *) + echo "Unknown type: $bump_type" + exit 1 + ;; + esac + + printf "%s" "$next" > .version + + version:tag-release: + desc: Create set of git tags + cmds: + - | + set -eu + if (set -o | grep -q pipefail) 2>/dev/null; then set -o pipefail; fi + + REMOTE='origin' + FULL='{{.VERSION_FULL}}' + MINOR='{{.VERSION_MINOR}}' + MAJOR='{{.VERSION_MAJOR}}' + + # Validate vX.Y.Z + if ! printf "%s" "$FULL" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "❌ ERROR: VERSION '$FULL' must match vX.Y.Z" >&2 + exit 1 + fi + + tag_sha() { git rev-parse "refs/tags/$1" 2>/dev/null || true; } + remote_tag_sha() { git ls-remote --tags "$REMOTE" "refs/tags/$1" 2>/dev/null | awk '{print $1}' || true; } + + echo "ℹ️ INFO: Tags - Full: $FULL | Minor: $MINOR | Major: $MAJOR" + + # Full tag: must NOT exist on remote; fail fast if it does + full_remote_sha="$(remote_tag_sha "$FULL")" + if [ -n "$full_remote_sha" ]; then + echo "❌ ERROR: Full tag '$FULL' already exists on remote; aborting" >&2 + exit 1 + fi + + # Create full tag locally (if missing) and push + if git rev-parse --quiet --verify "refs/tags/$FULL" >/dev/null 2>&1; then + echo "ℹ️ INFO: Full tag '$FULL' exists locally but not on remote; pushing" + else + echo "ℹ️ INFO: Creating full tag '$FULL'" + git tag --annotate "$FULL" --message "$FULL" + fi + git push "$REMOTE" "refs/tags/$FULL" + echo "✅ OK: Pushed full tag '$FULL'" + + # Minor tag: create or update + git tag --force --annotate "$MINOR" --message "$FULL" + minor_local_sha="$(tag_sha "$MINOR")" + minor_remote_sha="$(remote_tag_sha "$MINOR")" + if [ -z "$minor_remote_sha" ]; then + git push "$REMOTE" "refs/tags/$MINOR" + echo "✅ OK: Created and pushed minor tag '$MINOR' -> $minor_local_sha" + else + if [ "$minor_local_sha" != "$minor_remote_sha" ]; then + echo "⚠️ WARN: Updating remote minor tag '$MINOR' to $minor_local_sha (was $minor_remote_sha)" + git push --force "$REMOTE" "refs/tags/$MINOR" + else + echo "ℹ️ INFO: Minor tag '$MINOR' already up-to-date" + fi + fi + + # Major tag: create or update + git tag --force --annotate "$MAJOR" --message "$FULL" + major_local_sha="$(tag_sha "$MAJOR")" + major_remote_sha="$(remote_tag_sha "$MAJOR")" + if [ -z "$major_remote_sha" ]; then + git push "$REMOTE" "refs/tags/$MAJOR" + echo "✅ OK: Created and pushed major tag '$MAJOR' -> $major_local_sha" + else + if [ "$major_local_sha" != "$major_remote_sha" ]; then + echo "⚠️ WARN: Updating remote major tag '$MAJOR' to $major_local_sha (was $major_remote_sha)" + git push --force "$REMOTE" "refs/tags/$MAJOR" + else + echo "ℹ️ INFO: Major tag '$MAJOR' already up-to-date" + fi + fi + + git:get-pr-template: + desc: Get pull request template + cmds: + - mkdir -p .tmp + - curl -LsS {{.PR_TEMPLATE}} -o .tmp/PULL_REQUEST_TEMPLATE.md + + git:set-config: + desc: Set git user config + cmds: + - git config user.name "github-actions[bot]" + - git config user.email "github-actions[bot]@users.noreply.github.com" + + sync:all: + desc: Sync all common files + cmds: + - task sync:configs + - task sync:ignores + - task sync:taskfiles + + sync:configs: + desc: Sync configuration files with devops-infra/.github + cmds: + - | + echo "▶️ Syncing configuration files from devops-infra/.github..." + curl -sL {{.CONFIGS_BASE_URL}}/.editorconfig -o ./.editorconfig + curl -sL {{.CONFIGS_BASE_URL}}/.hadolint.yaml -o ./.hadolint.yaml + curl -sL {{.CONFIGS_BASE_URL}}/.pre-commit-config.yaml -o ./.pre-commit-config.yaml + curl -sL {{.CONFIGS_BASE_URL}}/.shellcheckrc -o ./.shellcheckrc + curl -sL {{.CONFIGS_BASE_URL}}/.yamllint.yml -o ./.yamllint.yml + git add .editorconfig .hadolint.yaml .pre-commit-config.yaml .shellcheckrc .yamllint.yml + echo "✅ Synced configuration files" + + sync:ignores: + desc: Sync ignore files with devops-infra/.github + cmds: + - | + echo "▶️ Syncing ignore files from devops-infra/.github..." + curl -sL {{.CONFIGS_BASE_URL}}/.gitignore -o ./.gitignore + curl -sL {{.CONFIGS_BASE_URL}}/.dockerignore -o ./.dockerignore + git add .gitignore .dockerignore + echo "✅ Synced ignore files" + + sync:taskfiles: + desc: Sync Taskfiles with devops-infra/.github + cmds: + - | + echo "▶️ Syncing Taskfiles from devops-infra/.github..." + curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.yml -o ./Taskfile.yml + curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.cicd.yml -o ./Taskfile.cicd.yml + curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.docker.yml -o ./Taskfile.docker.yml + curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.variables.yml -o ./Taskfile.variables.yml + git add Taskfile*.yml + echo "✅ Synced Taskfiles" diff --git a/Taskfile.docker.yml b/Taskfile.docker.yml new file mode 100644 index 0000000..9b66a81 --- /dev/null +++ b/Taskfile.docker.yml @@ -0,0 +1,104 @@ +version: '3' + +silent: true + +tasks: + docker:login: + desc: Login to hub.docker.com and ghcr.io + cmds: + - echo "Logging into Docker Hub as {{.DOCKER_USERNAME}}" + - echo "${DOCKER_TOKEN}" | docker login -u "{{.DOCKER_USERNAME}}" --password-stdin + - echo "Logging into GHCR as {{.GITHUB_USERNAME}}" + - echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "{{.GITHUB_USERNAME}}" --password-stdin + + docker:cmds: + desc: Show full docker build command + cmds: + - echo -e '{{.DOCKER_BUILD_START}} {{.DOCKER_BUILD_FINISH}}' | {{.SED}} 's/--/ \\\n --/g' + + docker:build: + desc: Build Docker image + cmds: + - docker buildx create --use + - '{{.DOCKER_BUILD_START}} {{.DOCKER_BUILD_FINISH}}' + + docker:build:inspect: + desc: Inspect built Docker image + cmds: + - | + image_inspect_out=$(docker image inspect {{.DOCKER_NAME}}:{{.VERSION_FULL}}{{.VERSION_SUFFIX}} | jq -r) + echo -e "\nℹ️ Docker image inspect:" + echo "$image_inspect_out" | jq + + docker:push: + desc: Build and push Docker images + deps: + - task: docker:login + cmds: + - docker buildx create --use + - '{{.DOCKER_BUILD_START}} --push {{.DOCKER_BUILD_FINISH}}' + + docker:push:inspect: + desc: Inspect built Docker image + cmds: + - | + set -eu + image="{{.DOCKER_NAME}}:{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + + echo -e "\nℹ️ Trying local image inspect: $image" + set +e + image_inspect_out=$(docker image inspect "$image" 2>/dev/null || true) + rc=$? + set -e + + # Validate that docker inspect returned a non-empty array with an Id + has_local=0 + if [ "$rc" -eq 0 ] && [ -n "$image_inspect_out" ]; then + if echo "$image_inspect_out" | jq -e 'type=="array" and (length > 0) and \ + (.[0].Id != null and .[0].Id != "")' >/dev/null 2>&1; then + has_local=1 + fi + fi + + if [ "$has_local" -eq 1 ]; then + echo -e "\n✅ Local image found. Docker image inspect:" + echo "$image_inspect_out" | jq + image_sha=$(echo "$image_inspect_out" | jq -r '.[0].Id // empty') + if [ -n "$image_sha" ]; then + echo -e "\nℹ️ Docker manifest inspect (local):" + docker manifest inspect "${image}@${image_sha}" | jq || true + fi + exit 0 + fi + + echo -e "\nℹ️ Local image not found or inspect returned empty; inspecting remote with buildx imagetools..." + set +e + raw=$(docker buildx imagetools inspect --raw "$image" 2>/dev/null || true) + set -e + + if [ -z "$raw" ]; then + echo "❌ Failed to inspect remote image with buildx imagetools: $image" + exit 1 + fi + + echo -e "\n✅ Remote manifest/index (raw):" + echo "$raw" | jq + + echo -e "\nℹ️ Attempting to pull and inspect per-platform manifests:" + echo "$raw" | jq -r '.manifests[]?.digest' | while IFS= read -r digest; do + if [ -z "$digest" ] || [ "$digest" = "null" ]; then + continue + fi + ref="${image%@*}@${digest}" + echo -e "\nℹ️ Pulling $ref (may fail for some registries)..." + set +e + docker pull "$ref" >/dev/null 2>&1 || true + pulled_rc=$? + set -e + if [ "$pulled_rc" -eq 0 ]; then + echo "ℹ️ Inspecting pulled image $ref" + docker image inspect "$ref" | jq || true + else + echo "⚠️ Could not pull $ref; skipping image inspect" + fi + done diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml new file mode 100644 index 0000000..b39a3a7 --- /dev/null +++ b/Taskfile.scripts.yml @@ -0,0 +1,191 @@ +version: '3' + +silent: true + +tasks: + help: + desc: Detailed help + cmds: + - | + echo "Tasks:" + task --list + echo DOCKER_BUILDKIT={{.DOCKER_BUILDKIT}} TERM={{.TERM}} + + lint:actionlint: + desc: Lint GitHub Actions workflows with actionlint + cmds: + - | + echo "▶️ Running actionlint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work rhysd/actionlint:latest -color + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ actionlint passed" + else + echo "❌ actionlint failed" + exit $rc + fi + + lint:hadolint: + desc: Lint Dockerfile with hadolint + cmds: + - | + echo "▶️ Running hadolint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work hadolint/hadolint:latest-debian < Dockerfile + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ hadolint passed" + else + echo "❌ hadolint failed" + exit $rc + fi + + lint:shellcheck: + desc: Lint shell scripts with shellcheck + cmds: + - | + echo "▶️ Running shellcheck..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work koalaman/shellcheck:stable -x -S style show-versions.sh + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ shellcheck passed" + else + echo "❌ shellcheck failed" + exit $rc + fi + + lint:yamllint: + desc: Lint YAML files with yamllint + cmds: + - | + echo "▶️ Running yamllint..." + set +e + docker run --rm -i -v "$PWD:/work" -w /work cytopia/yamllint -c .yamllint.yml . + rc=$? + set -e + if [ "$rc" -eq 0 ]; then + echo "✅ yamllint passed" + else + echo "❌ yamllint failed" + exit $rc + fi + + git:get-pr-template: + desc: Get pull request template + cmds: + - mkdir -p .tmp + - curl -LsS https://raw.githubusercontent.com/devops-infra/.github/master/PULL_REQUEST_TEMPLATE.md -o .tmp/PULL_REQUEST_TEMPLATE.md + + git:set-config: + desc: Set git user config + cmds: + - git config user.name "github-actions[bot]" + - git config user.email "github-actions[bot]@users.noreply.github.com" + + version:get: + desc: Get current version + cmds: + - echo "{{.VERSION}}" + + version:set: + desc: Update .version file + cmds: + - | + if [ -z "{{.VERSION}}" ]; then + echo "❌ ERROR: VERSION is empty" + exit 1 + fi + - echo "{{.VERSION}}" > .version + + version:update:patch: + desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) + cmds: + - task version:set VERSION=v{{.MAJOR}}.{{.MINOR}}.{{.NEXT_PATCH}} + + version:update:minor: + desc: Increment minor version (e.g., 1.2.3 -> 1.3.0) + cmds: + - task version:set VERSION=v{{.MAJOR}}.{{.NEXT_MINOR}}.0 + + version:update:major: + desc: Increment major version (e.g., 1.2.3 -> 2.0.0) + cmds: + - task version:set VERSION=v{{.NEXT_MAJOR}}.0.0 + + version:tag-release: + desc: Create set of git tags + cmds: + - | + set -eu + if (set -o | grep -q pipefail) 2>/dev/null; then set -o pipefail; fi + + REMOTE='origin' + FULL='{{.VERSION_FULL}}' + MINOR='{{.VERSION_MINOR}}' + MAJOR='{{.VERSION_MAJOR}}' + + # Validate vX.Y.Z + if ! printf "%s" "$FULL" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "❌ ERROR: VERSION '$FULL' must match vX.Y.Z" >&2 + exit 1 + fi + + tag_sha() { git rev-parse "refs/tags/$1" 2>/dev/null || true; } + remote_tag_sha() { git ls-remote --tags "$REMOTE" "refs/tags/$1" 2>/dev/null | awk '{print $1}' || true; } + + echo "ℹ️ INFO: Tags - Full: $FULL | Minor: $MINOR | Major: $MAJOR" + + # Full tag: must NOT exist on remote; fail fast if it does + full_remote_sha="$(remote_tag_sha "$FULL")" + if [ -n "$full_remote_sha" ]; then + echo "❌ ERROR: Full tag '$FULL' already exists on remote; aborting" >&2 + exit 1 + fi + + # Create full tag locally (if missing) and push + if git rev-parse --quiet --verify "refs/tags/$FULL" >/dev/null 2>&1; then + echo "ℹ️ INFO: Full tag '$FULL' exists locally but not on remote; pushing" + else + echo "ℹ️ INFO: Creating full tag '$FULL'" + git tag --annotate "$FULL" --message "$FULL" + fi + git push "$REMOTE" "refs/tags/$FULL" + echo "✅ OK: Pushed full tag '$FULL'" + + # Minor tag: create or update + git tag --force --annotate "$MINOR" --message "$FULL" + minor_local_sha="$(tag_sha "$MINOR")" + minor_remote_sha="$(remote_tag_sha "$MINOR")" + if [ -z "$minor_remote_sha" ]; then + git push "$REMOTE" "refs/tags/$MINOR" + echo "✅ OK: Created and pushed minor tag '$MINOR' -> $minor_local_sha" + else + if [ "$minor_local_sha" != "$minor_remote_sha" ]; then + echo "⚠️ WARN: Updating remote minor tag '$MINOR' to $minor_local_sha (was $minor_remote_sha)" + git push --force "$REMOTE" "refs/tags/$MINOR" + else + echo "ℹ️ INFO: Minor tag '$MINOR' already up-to-date" + fi + fi + + # Major tag: create or update + git tag --force --annotate "$MAJOR" --message "$FULL" + major_local_sha="$(tag_sha "$MAJOR")" + major_remote_sha="$(remote_tag_sha "$MAJOR")" + if [ -z "$major_remote_sha" ]; then + git push "$REMOTE" "refs/tags/$MAJOR" + echo "✅ OK: Created and pushed major tag '$MAJOR' -> $major_local_sha" + else + if [ "$major_local_sha" != "$major_remote_sha" ]; then + echo "⚠️ WARN: Updating remote major tag '$MAJOR' to $major_local_sha (was $major_remote_sha)" + git push --force "$REMOTE" "refs/tags/$MAJOR" + else + echo "ℹ️ INFO: Major tag '$MAJOR' already up-to-date" + fi + fi + diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml new file mode 100644 index 0000000..fe0471e --- /dev/null +++ b/Taskfile.variables.yml @@ -0,0 +1,67 @@ +version: '3' + +silent: true + +env: + DOCKER_BUILDKIT: '1' + TERM: xterm-256color + +vars: + # System context + SED: + sh: | + if [ "$(uname -s)" = "Darwin" ]; then + if command -v gsed >/dev/null 2>&1; then + echo gsed + else + if command -v brew >/dev/null 2>&1; then + # Quietly ensure gnu-sed is installed + brew list gnu-sed >/dev/null 2>&1 || { + HOMEBREW_NO_ENV_HINTS=1 HOMEBREW_NO_ANALYTICS=1 brew update >/dev/null 2>&1 || true + HOMEBREW_NO_ENV_HINTS=1 HOMEBREW_NO_ANALYTICS=1 brew install gnu-sed >/dev/null 2>&1 + } + echo gsed + else + echo sed + fi + fi + else + echo sed + fi + PROJECT_DIR_NAME: + sh: basename "$PWD" + VERSION_FILE: .version + VERSION_FROM_FILE: + sh: | + if [ ! -f "{{.VERSION_FILE}}" ]; then + echo "" + else + tr -d '\n' < "{{.VERSION_FILE}}" + fi + VERSION_OVERRIDE: + sh: echo "__TAKEN_FROM_FILE__" + VERSION: + sh: | + if [ "${VERSION_OVERRIDE}" = "__TAKEN_FROM_FILE__" ]; then + echo "{{.VERSION_FROM_FILE}}" + else + echo "${VERSION_OVERRIDE}" + fi + VERSION_NO_V: + sh: v="{{.VERSION}}"; echo "${v#v}" + MAJOR: + sh: echo "{{.VERSION_NO_V}}" | awk -F\. '{print $1}' + MINOR: + sh: echo "{{.VERSION_NO_V}}" | awk -F\. '{print $2}' + PATCH: + sh: echo "{{.VERSION_NO_V}}" | awk -F\. '{print $3}' + VERSION_MAJOR: v{{.MAJOR}} + VERSION_MINOR: v{{.MAJOR}}.{{.MINOR}} + VERSION_FULL: v{{.MAJOR}}.{{.MINOR}}.{{.PATCH}} + NEXT_PATCH: + sh: echo $(( {{.PATCH}} + 1 )) + NEXT_MINOR: + sh: echo $(( {{.MINOR}} + 1 )) + NEXT_MAJOR: + sh: echo $(( {{.MAJOR}} + 1 )) + diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..03c95c1 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,24 @@ +version: '3' + +silent: true + +includes: + variables: ./Taskfile.variables.yml + scripts: ./Taskfile.scripts.yml + docker: + taskfile: ./Taskfile.docker.yml + flatten: true + cicd: + taskfile: ./Taskfile.cicd.yml + flatten: true + +tasks: + default: + desc: List tasks + cmds: + - task help + + help: + desc: Detailed help + cmds: + - task: scripts:help From 8674228074ef0ee5325157b449db8f350a18073a Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:30:20 +0100 Subject: [PATCH 2/8] fix: fall back to latest git tag when .version file is missing VERSION variable now resolves from git tags when VERSION_FROM_FILE is empty, so version:resolve-next works on fresh checkouts without a committed .version file. Co-Authored-By: Claude Opus 4.6 --- Taskfile.variables.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml index fe0471e..25e4f29 100644 --- a/Taskfile.variables.yml +++ b/Taskfile.variables.yml @@ -43,7 +43,12 @@ vars: VERSION: sh: | if [ "${VERSION_OVERRIDE}" = "__TAKEN_FROM_FILE__" ]; then - echo "{{.VERSION_FROM_FILE}}" + from_file="{{.VERSION_FROM_FILE}}" + if [ -n "$from_file" ]; then + echo "$from_file" + else + git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 + fi else echo "${VERSION_OVERRIDE}" fi From a94a92ca7c7203afbf01102a0537885593f7c640 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:30:20 +0100 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20remove=20.version=20file=20=E2=80=94?= =?UTF-8?q?=20version=20resolved=20from=20git=20tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VERSION now falls back to latest git tag when .version is absent, making the file unnecessary. Co-Authored-By: Claude Opus 4.6 --- .version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .version diff --git a/.version b/.version deleted file mode 100644 index b82608c..0000000 --- a/.version +++ /dev/null @@ -1 +0,0 @@ -v0.1.0 From 3442c4c63c5c6e39ce4a0472c37ad858dfcd5ee5 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 16:01:33 +0100 Subject: [PATCH 4/8] refactor and fix --- Taskfile.cicd.yml | 5 +---- Taskfile.scripts.yml | 4 +--- Taskfile.variables.yml | 22 +++++----------------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/Taskfile.cicd.yml b/Taskfile.cicd.yml index cc89bd3..891baae 100644 --- a/Taskfile.cicd.yml +++ b/Taskfile.cicd.yml @@ -147,9 +147,6 @@ tasks: } current="$(task version:get 2>/dev/null || true)" - if [ -z "$current" ] && [ -f .version ]; then - current="$(tr -d '\n' < .version)" - fi case "$bump_type" in set) @@ -176,7 +173,7 @@ tasks: ;; esac - printf "%s" "$next" > .version + printf "%s" "$next" version:tag-release: desc: Create set of git tags diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml index b39a3a7..b57cfb0 100644 --- a/Taskfile.scripts.yml +++ b/Taskfile.scripts.yml @@ -93,15 +93,13 @@ tasks: - echo "{{.VERSION}}" version:set: - desc: Update .version file + desc: Validate version cmds: - | if [ -z "{{.VERSION}}" ]; then echo "❌ ERROR: VERSION is empty" exit 1 fi - - echo "{{.VERSION}}" > .version - version:update:patch: desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) cmds: diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml index 25e4f29..5000734 100644 --- a/Taskfile.variables.yml +++ b/Taskfile.variables.yml @@ -30,27 +30,15 @@ vars: fi PROJECT_DIR_NAME: sh: basename "$PWD" - VERSION_FILE: .version - VERSION_FROM_FILE: - sh: | - if [ ! -f "{{.VERSION_FILE}}" ]; then - echo "" - else - tr -d '\n' < "{{.VERSION_FILE}}" - fi VERSION_OVERRIDE: - sh: echo "__TAKEN_FROM_FILE__" + sh: echo "${VERSION_OVERRIDE:-}" VERSION: sh: | - if [ "${VERSION_OVERRIDE}" = "__TAKEN_FROM_FILE__" ]; then - from_file="{{.VERSION_FROM_FILE}}" - if [ -n "$from_file" ]; then - echo "$from_file" - else - git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 - fi + override="{{.VERSION_OVERRIDE}}" + if [ -n "$override" ]; then + echo "$override" else - echo "${VERSION_OVERRIDE}" + git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 fi VERSION_NO_V: sh: v="{{.VERSION}}"; echo "${v#v}" From f7d3ba3f61cd7fc571ccb0e78025b991749a5133 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 16:24:22 +0100 Subject: [PATCH 5/8] Updated baseline sync files and reusable workflow callers --- .dockerignore | 3 +- .editorconfig | 9 ++++ .../workflows/auto-create-pull-request.yml | 3 +- .github/workflows/cron-check-dependencies.yml | 4 +- .../workflows/manual-sync-common-files.yml | 1 + .github/workflows/manual-update-version.yml | 4 +- .gitignore | 8 ++- .hadolint.yaml | 24 +++++++++ .pre-commit-config.yaml | 46 +++++++++++++++++ .shellcheckrc | 5 ++ .yamllint.yml | 24 +++++++++ Taskfile.cicd.yml | 49 +++++++++---------- Taskfile.variables.yml | 8 ++- 13 files changed, 150 insertions(+), 38 deletions(-) create mode 100644 .editorconfig create mode 100644 .hadolint.yaml create mode 100644 .pre-commit-config.yaml create mode 100644 .shellcheckrc create mode 100644 .yamllint.yml diff --git a/.dockerignore b/.dockerignore index a5551df..05f50d1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,7 +2,6 @@ * # Include +!Dockerfile !LICENSE !README.md -!show-versions.sh -!pip diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..99580d0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.github/workflows/auto-create-pull-request.yml b/.github/workflows/auto-create-pull-request.yml index a0cfed7..8102c39 100644 --- a/.github/workflows/auto-create-pull-request.yml +++ b/.github/workflows/auto-create-pull-request.yml @@ -17,5 +17,4 @@ jobs: uses: devops-infra/.github/.github/workflows/reusable-auto-create-pull-request.yml@v1 with: profile: dockerized - secrets: - DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + secrets: inherit diff --git a/.github/workflows/cron-check-dependencies.yml b/.github/workflows/cron-check-dependencies.yml index 95e2a25..a1aef97 100644 --- a/.github/workflows/cron-check-dependencies.yml +++ b/.github/workflows/cron-check-dependencies.yml @@ -9,11 +9,11 @@ permissions: contents: read issues: write pull-requests: read + packages: write jobs: call: uses: devops-infra/.github/.github/workflows/reusable-cron-check-dependencies.yml@v1 with: profile: dockerized - secrets: - DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + secrets: inherit diff --git a/.github/workflows/manual-sync-common-files.yml b/.github/workflows/manual-sync-common-files.yml index 7523759..8699220 100644 --- a/.github/workflows/manual-sync-common-files.yml +++ b/.github/workflows/manual-sync-common-files.yml @@ -24,3 +24,4 @@ jobs: with: sync-type: ${{ inputs.type }} template-profile: dockerized + secrets: inherit diff --git a/.github/workflows/manual-update-version.yml b/.github/workflows/manual-update-version.yml index a2b6b19..8d43eea 100644 --- a/.github/workflows/manual-update-version.yml +++ b/.github/workflows/manual-update-version.yml @@ -26,6 +26,7 @@ on: permissions: contents: write packages: write + pull-requests: write jobs: call: @@ -35,5 +36,4 @@ jobs: explicit-version: ${{ inputs.version }} build-and-push-only: ${{ inputs.build_only }} profile: dockerized - secrets: - DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + secrets: inherit diff --git a/.gitignore b/.gitignore index 894c62d..274f060 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ # Intellij -.idea/ +/.idea/ *.iml # Custom +.DS_Store .tmp/ +.venv +.venv/ +.envrc +.env +.tmp diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000..7c16a46 --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,24 @@ +failure-threshold: error +format: tty +strict-labels: false +no-color: false +no-fail: false +disable-ignore-pragma: false +trustedRegistries: + - docker.io + - ghcr.io + +# ignored: [string] +# label-schema: +# author: text +# contact: email +# created: rfc3339 +# version: semver +# documentation: url +# git-revision: hash +# license: spdx +# override: +# error: [string] +# warning: [string] +# info: [string] +# style: [string] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..113778a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,46 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-illegal-windows-names + - id: check-json + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-xml + - id: check-yaml + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: mixed-line-ending + args: [--fix=lf] + - id: no-commit-to-branch + args: [--branch, master, --branch, main] + - id: pretty-format-json + args: [--autofix] + - id: trailing-whitespace + - repo: local + hooks: + - id: actionlint + name: actionlint + entry: bash -lc 'docker run --rm -v "$PWD:/work" -w /work rhysd/actionlint:latest -color' + language: system + pass_filenames: false + - id: hadolint + name: hadolint + entry: bash -lc 'docker run --rm -v "$PWD:/work" -w /work hadolint/hadolint:latest-debian "$@"' -- + language: system + files: '(^|/)Dockerfile(\..*)?$' + - id: shellcheck + name: shellcheck + entry: bash -lc 'docker run --rm -v "$PWD:/work" -w /work koalaman/shellcheck:stable -x -S style "$@"' -- + language: system + files: '\.sh$' + - id: yamllint + name: yamllint + entry: bash -lc 'docker run --rm -v "$PWD:/work" -w /work cytopia/yamllint -c .yamllint.yml "$@"' -- + language: system + files: '\.(yml|yaml)$' diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..c05574a --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,5 @@ +# shellcheck configuration +shell=bash +check-sourced=true +external-sources=true +source-path=SCRIPTDIR diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..fb0e11a --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,24 @@ +extends: default +rules: + empty-lines: + max: 2 + max-end: 1 + document-end: + present: false + document-start: + present: false + indentation: + spaces: 2 + indent-sequences: true + check-multi-line-strings: false + line-length: + max: 220 + allow-non-breakable-inline-mappings: true + new-line-at-end-of-file: enable + new-lines: + type: unix + quoted-strings: disable + trailing-spaces: {} + truthy: + allowed-values: ['true', 'false', 'yes', 'no'] + check-keys: false diff --git a/Taskfile.cicd.yml b/Taskfile.cicd.yml index 891baae..9dd4008 100644 --- a/Taskfile.cicd.yml +++ b/Taskfile.cicd.yml @@ -96,25 +96,17 @@ tasks: - echo "{{.VERSION}}" version:set: - desc: Update version in README.md and action.yml + desc: Validate version cmds: - | - # check if VERSION if different than VERSION_FROM_ACTION_YML - if [ "{{.VERSION}}" = "{{.VERSION_FROM_ACTION_YML}}" ]; then - echo "❌ ERROR: VERSION is same as VERSION_FROM_ACTION_YML ({{.VERSION}})" + if [ -z "{{.VERSION}}" ]; then + echo "❌ ERROR: VERSION is empty" + exit 1 + fi + if ! echo "{{.VERSION}}" | grep -Eq '^v?[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "❌ ERROR: VERSION '{{.VERSION}}' is not a valid semantic version (expected vX.Y.Z or X.Y.Z)" exit 1 fi - - echo Updating full version from {{.VERSION_FROM_ACTION_YML}} to {{.VERSION}} - - echo Updating minor version from {{.MINOR_FROM_ACTION_YML}} to {{.VERSION_MINOR}} - - echo Updating major version from {{.MAJOR_FROM_ACTION_YML}} to {{.VERSION_MAJOR}} - - "{{.SED}} -i 's#{{.DOCKER_NAME}}:{{.VERSION_FROM_ACTION_YML}}#{{.DOCKER_NAME}}:{{.VERSION}}#g' action.yml" - - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.VERSION_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION}}#g' README.md" - - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.VERSION_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION}}#g' README.md" - - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.MINOR_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION_MINOR}}#g' README.md" - - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.MINOR_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION_MINOR}}#g' README.md" - - "{{.SED}} -i 's#{{.DOCKER_NAME}}@{{.MAJOR_FROM_ACTION_YML}}#{{.DOCKER_NAME}}@{{.VERSION_MAJOR}}#g' README.md" - - "{{.SED}} -i 's#{{.GITHUB_NAME}}@{{.MAJOR_FROM_ACTION_YML}}#{{.GITHUB_NAME}}@{{.VERSION_MAJOR}}#g' README.md" - version:update:patch: desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) cmds: @@ -160,7 +152,9 @@ tasks: [ -n "$current" ] || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } current="$(normalize_version "$current")" || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } no_v="${current#v}" - IFS='.' read -r major minor patch <<< "$no_v" + major="$(printf "%s" "$no_v" | awk -F. '{print $1}')" + minor="$(printf "%s" "$no_v" | awk -F. '{print $2}')" + patch="$(printf "%s" "$no_v" | awk -F. '{print $3}')" case "$bump_type" in patch) next="v${major}.${minor}.$((patch + 1))" ;; minor) next="v${major}.$((minor + 1)).0" ;; @@ -271,11 +265,11 @@ tasks: cmds: - | echo "▶️ Syncing configuration files from devops-infra/.github..." - curl -sL {{.CONFIGS_BASE_URL}}/.editorconfig -o ./.editorconfig - curl -sL {{.CONFIGS_BASE_URL}}/.hadolint.yaml -o ./.hadolint.yaml - curl -sL {{.CONFIGS_BASE_URL}}/.pre-commit-config.yaml -o ./.pre-commit-config.yaml - curl -sL {{.CONFIGS_BASE_URL}}/.shellcheckrc -o ./.shellcheckrc - curl -sL {{.CONFIGS_BASE_URL}}/.yamllint.yml -o ./.yamllint.yml + curl -fsSL {{.CONFIGS_BASE_URL}}/.editorconfig -o ./.editorconfig + curl -fsSL {{.CONFIGS_BASE_URL}}/.hadolint.yaml -o ./.hadolint.yaml + curl -fsSL {{.CONFIGS_BASE_URL}}/.pre-commit-config.yaml -o ./.pre-commit-config.yaml + curl -fsSL {{.CONFIGS_BASE_URL}}/.shellcheckrc -o ./.shellcheckrc + curl -fsSL {{.CONFIGS_BASE_URL}}/.yamllint.yml -o ./.yamllint.yml git add .editorconfig .hadolint.yaml .pre-commit-config.yaml .shellcheckrc .yamllint.yml echo "✅ Synced configuration files" @@ -284,8 +278,8 @@ tasks: cmds: - | echo "▶️ Syncing ignore files from devops-infra/.github..." - curl -sL {{.CONFIGS_BASE_URL}}/.gitignore -o ./.gitignore - curl -sL {{.CONFIGS_BASE_URL}}/.dockerignore -o ./.dockerignore + curl -fsSL {{.CONFIGS_BASE_URL}}/.gitignore -o ./.gitignore + curl -fsSL {{.CONFIGS_BASE_URL}}/.dockerignore -o ./.dockerignore git add .gitignore .dockerignore echo "✅ Synced ignore files" @@ -294,9 +288,10 @@ tasks: cmds: - | echo "▶️ Syncing Taskfiles from devops-infra/.github..." - curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.yml -o ./Taskfile.yml - curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.cicd.yml -o ./Taskfile.cicd.yml - curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.docker.yml -o ./Taskfile.docker.yml - curl -sL {{.TASKFILES_BASE_URL}}/Taskfile.variables.yml -o ./Taskfile.variables.yml + curl -fsSL {{.TASKFILES_BASE_URL}}/Taskfile.yml -o ./Taskfile.yml + curl -fsSL {{.TASKFILES_BASE_URL}}/Taskfile.cicd.yml -o ./Taskfile.cicd.yml + curl -fsSL {{.TASKFILES_BASE_URL}}/Taskfile.scripts.yml -o ./Taskfile.scripts.yml + curl -fsSL {{.TASKFILES_BASE_URL}}/Taskfile.docker.yml -o ./Taskfile.docker.yml + curl -fsSL {{.TASKFILES_BASE_URL}}/Taskfile.variables.yml -o ./Taskfile.variables.yml git add Taskfile*.yml echo "✅ Synced Taskfiles" diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml index 5000734..a9d555f 100644 --- a/Taskfile.variables.yml +++ b/Taskfile.variables.yml @@ -38,7 +38,12 @@ vars: if [ -n "$override" ]; then echo "$override" else - git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 + latest_tag="$(git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)" + if [ -n "$latest_tag" ]; then + echo "$latest_tag" + else + echo "v0.0.0" + fi fi VERSION_NO_V: sh: v="{{.VERSION}}"; echo "${v#v}" @@ -57,4 +62,3 @@ vars: sh: echo $(( {{.MINOR}} + 1 )) NEXT_MAJOR: sh: echo $(( {{.MAJOR}} + 1 )) - From 140368d774f0d422bf2005472446ca14e136f7a3 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 17:55:30 +0100 Subject: [PATCH 6/8] Fixed lint and script defaults for dockerized tasks --- .github/dependabot.yml | 3 ++- Taskfile.cicd.yml | 13 +------------ Taskfile.scripts.yml | 7 +++++-- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a624fb8..e78e16f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,6 +16,7 @@ updates: labels: - automatic + # Enable version updates for pip - package-ecosystem: "pip" directory: "/" @@ -24,4 +25,4 @@ updates: assignees: - "ChristophShyper" labels: - - automatic \ No newline at end of file + - automatic diff --git a/Taskfile.cicd.yml b/Taskfile.cicd.yml index 9dd4008..7071bb2 100644 --- a/Taskfile.cicd.yml +++ b/Taskfile.cicd.yml @@ -61,18 +61,7 @@ tasks: lint:shellcheck: desc: Lint shell scripts with shellcheck cmds: - - | - echo "▶️ Running shellcheck..." - set +e - docker run --rm -i -v "$PWD:/work" -w /work koalaman/shellcheck:stable -x -S style entrypoint.sh - rc=$? - set -e - if [ "$rc" -eq 0 ]; then - echo "✅ shellcheck passed" - else - echo "❌ shellcheck failed" - exit $rc - fi + - task: scripts:lint:shellcheck lint:yamllint: desc: Lint YAML files with yamllint diff --git a/Taskfile.scripts.yml b/Taskfile.scripts.yml index b57cfb0..b183f7d 100644 --- a/Taskfile.scripts.yml +++ b/Taskfile.scripts.yml @@ -79,7 +79,7 @@ tasks: desc: Get pull request template cmds: - mkdir -p .tmp - - curl -LsS https://raw.githubusercontent.com/devops-infra/.github/master/PULL_REQUEST_TEMPLATE.md -o .tmp/PULL_REQUEST_TEMPLATE.md + - curl -LsS https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/PULL_REQUEST_TEMPLATE.md -o .tmp/PULL_REQUEST_TEMPLATE.md git:set-config: desc: Set git user config @@ -100,6 +100,10 @@ tasks: echo "❌ ERROR: VERSION is empty" exit 1 fi + if ! echo "{{.VERSION}}" | grep -Eq '^v?[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "❌ ERROR: VERSION '{{.VERSION}}' is not a valid semantic version (expected vX.Y.Z or X.Y.Z)" + exit 1 + fi version:update:patch: desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) cmds: @@ -186,4 +190,3 @@ tasks: echo "ℹ️ INFO: Major tag '$MAJOR' already up-to-date" fi fi - From e8a27353ec631157c6379877e9c9577d66d2c149 Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:11:48 +0100 Subject: [PATCH 7/8] Fixed dockerized Taskfile variables for Docker login defaults --- Taskfile.variables.yml | 164 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/Taskfile.variables.yml b/Taskfile.variables.yml index a9d555f..8cb7b72 100644 --- a/Taskfile.variables.yml +++ b/Taskfile.variables.yml @@ -30,6 +30,58 @@ vars: fi PROJECT_DIR_NAME: sh: basename "$PWD" + + # Container metadata + DOCKER_IMAGE: '{{.DOCKER_IMAGE | default .PROJECT_DIR_NAME}}' + GITHUB_REPO: '{{.GITHUB_REPO | default .PROJECT_DIR_NAME}}' + DOCKER_ORG_NAME: '{{.DOCKER_ORG_NAME | default "devopsinfra"}}' + GITHUB_ORG_NAME: '{{.GITHUB_ORG_NAME | default "devops-infra"}}' + DOCKER_USERNAME: '{{.DOCKER_USERNAME | default "christophshyper"}}' + GITHUB_USERNAME: '{{.GITHUB_USERNAME | default "ChristophShyper"}}' + DOCKER_NAME: '{{.DOCKER_ORG_NAME}}/{{.DOCKER_IMAGE}}' + GITHUB_NAME: '{{.GITHUB_ORG_NAME}}/{{.GITHUB_REPO}}' + GHRC_NAME: ghcr.io/{{.GITHUB_ORG_NAME}}/{{.GITHUB_REPO}} + DEFAULT_BRANCH: master + VERSION_FROM_ACTION_YML: + sh: 'grep "image: docker://{{.DOCKER_NAME}}:" action.yml 2>/dev/null | cut -d ":" -f 4' + AUTHOR_FROM_ACTION_YML: + sh: | + grep -e "^author:" action.yml 2>/dev/null | head -1 | awk -F": " '{print $2}' + NAME_FROM_ACTION_YML: + sh: | + grep -e "^name:" action.yml 2>/dev/null | head -1 | awk -F": " '{print $2}' + DESCRIPTION_FROM_ACTION_YML: + sh: | + grep -e "^description:" action.yml 2>/dev/null | head -1 | awk -F": " '{print $2}' + LABEL_AUTHOR: '{{.LABEL_AUTHOR | default .AUTHOR_FROM_ACTION_YML}}' + LABEL_NAME: '{{.LABEL_NAME | default .NAME_FROM_ACTION_YML}}' + LABEL_DESCRIPTION: '{{.LABEL_DESCRIPTION | default .DESCRIPTION_FROM_ACTION_YML}}' + LABEL_REPO_URL: '{{ default (printf "https://github.com/%s/%s" .GITHUB_ORG_NAME .DOCKER_IMAGE) .LABEL_REPO_URL }}' + LABEL_DOCS_URL: >- + {{ default (printf "https://github.com/%s/%s/blob/%s/README.md" .GITHUB_ORG_NAME .DOCKER_IMAGE + .DEFAULT_BRANCH) .LABEL_DOCS_URL }} + LABEL_HOMEPAGE: '{{.LABEL_HOMEPAGE | default "https://shyper.pro"}}' + LABEL_VENDOR: '{{.LABEL_VENDOR | default "DevOps-Infra"}}' + LABEL_LICENSE: '{{.LABEL_LICENSE | default "MIT"}}' + + # Build context + CONTEXT: '{{.CONTEXT | default "."}}' + DOCKERFILE: '{{.DOCKERFILE | default "Dockerfile"}}' + PLATFORMS: '{{.PLATFORMS | default "linux/amd64,linux/arm64"}}' + BUILD_DATE: + sh: date -u +"%Y-%m-%dT%H:%M:%SZ" + LAST_RELEASE: + sh: | + curl --silent "https://api.github.com/repos/{{.GITHUB_ORG_NAME}}/{{.GITHUB_REPO}}/releases/latest" | \ + grep '"tag_name":' | \ + {{.SED}} -E 's/.*"([^"]+)".*/\1/' + VERSION_SUFFIX: + sh: | + if [ "${VERSION_SUFFIX+x}" = "x" ]; then + printf "%s" "${VERSION_SUFFIX}" + else + printf "%s" "-test" + fi VERSION_OVERRIDE: sh: echo "${VERSION_OVERRIDE:-}" VERSION: @@ -38,11 +90,13 @@ vars: if [ -n "$override" ]; then echo "$override" else - latest_tag="$(git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)" - if [ -n "$latest_tag" ]; then - echo "$latest_tag" + tag="$(git tag --sort=-v:refname 2>/dev/null | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)" + if [ -n "$tag" ]; then + echo "$tag" + elif [ -n "{{.VERSION_FROM_ACTION_YML}}" ]; then + echo "{{.VERSION_FROM_ACTION_YML}}" else - echo "v0.0.0" + echo "{{.LAST_RELEASE}}" fi fi VERSION_NO_V: @@ -62,3 +116,105 @@ vars: sh: echo $(( {{.MINOR}} + 1 )) NEXT_MAJOR: sh: echo $(( {{.MAJOR}} + 1 )) + MAJOR_FROM_ACTION_YML: + sh: echo "{{.VERSION_FROM_ACTION_YML}}" | awk -F\. '{print $1}' + MINOR_FROM_ACTION_YML: + sh: echo "{{.VERSION_FROM_ACTION_YML}}" | awk -F\. '{print $1"."$2}' + + # Git metadata + GIT_SHA: + sh: git rev-parse HEAD 2>/dev/null || echo 0000000000000000000000000000000000000000 + GIT_SHORT_SHA: + sh: git rev-parse --short HEAD 2>/dev/null || echo 0000000 + GIT_BRANCH: + sh: | + if [ -n "${GITHUB_REF:-}" ]; then + echo "${GITHUB_REF#refs/heads/}" + else + git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown" + fi + + # Labels for http://label-schema.org/rc1/#build-time-labels + # And for https://github.com/opencontainers/image-spec/blob/master/annotations.md + ANNOTATIONS: >- + --annotation index:org.label-schema.schema-version="1.0" + --annotation index:org.label-schema.build-date="{{.BUILD_DATE}}" + --annotation index:org.label-schema.name="{{.LABEL_NAME}}" + --annotation index:org.label-schema.description="{{.LABEL_DESCRIPTION}}" + --annotation index:org.label-schema.usage="{{.LABEL_DOCS_URL}}" + --annotation index:org.label-schema.url="{{.LABEL_HOMEPAGE}}" + --annotation index:org.label-schema.vcs-url="{{.LABEL_REPO_URL}}" + --annotation index:org.label-schema.vcs-ref="{{.GIT_SHA}}" + --annotation index:org.label-schema.vendor="{{.LABEL_VENDOR}}" + --annotation index:org.label-schema.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --annotation index:org.opencontainers.image.created="{{.BUILD_DATE}}" + --annotation index:org.opencontainers.image.authors="{{.LABEL_AUTHOR}}" + --annotation index:org.opencontainers.image.url="{{.LABEL_HOMEPAGE}}" + --annotation index:org.opencontainers.image.documentation="{{.LABEL_DOCS_URL}}" + --annotation index:org.opencontainers.image.source="{{.LABEL_REPO_URL}}" + --annotation index:org.opencontainers.image.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --annotation index:org.opencontainers.image.revision="{{.GIT_SHA}}" + --annotation index:org.opencontainers.image.vendor="{{.LABEL_VENDOR}}" + --annotation index:org.opencontainers.image.licenses="{{.LABEL_LICENSE}}" + --annotation index:org.opencontainers.image.title="{{.LABEL_NAME}}" + --annotation index:org.opencontainers.image.description="{{.LABEL_DESCRIPTION}}" + --annotation manifest:org.label-schema.schema-version="1.0" + --annotation manifest:org.label-schema.build-date="{{.BUILD_DATE}}" + --annotation manifest:org.label-schema.name="{{.LABEL_NAME}}" + --annotation manifest:org.label-schema.description="{{.LABEL_DESCRIPTION}}" + --annotation manifest:org.label-schema.usage="{{.LABEL_DOCS_URL}}" + --annotation manifest:org.label-schema.url="{{.LABEL_HOMEPAGE}}" + --annotation manifest:org.label-schema.vcs-url="{{.LABEL_REPO_URL}}" + --annotation manifest:org.label-schema.vcs-ref="{{.GIT_SHA}}" + --annotation manifest:org.label-schema.vendor="{{.LABEL_VENDOR}}" + --annotation manifest:org.label-schema.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --annotation manifest:org.opencontainers.image.created="{{.BUILD_DATE}}" + --annotation manifest:org.opencontainers.image.authors="{{.LABEL_AUTHOR}}" + --annotation manifest:org.opencontainers.image.url="{{.LABEL_HOMEPAGE}}" + --annotation manifest:org.opencontainers.image.documentation="{{.LABEL_DOCS_URL}}" + --annotation manifest:org.opencontainers.image.source="{{.LABEL_REPO_URL}}" + --annotation manifest:org.opencontainers.image.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --annotation manifest:org.opencontainers.image.revision="{{.GIT_SHA}}" + --annotation manifest:org.opencontainers.image.vendor="{{.LABEL_VENDOR}}" + --annotation manifest:org.opencontainers.image.licenses="{{.LABEL_LICENSE}}" + --annotation manifest:org.opencontainers.image.title="{{.LABEL_NAME}}" + --annotation manifest:org.opencontainers.image.description="{{.LABEL_DESCRIPTION}}" + LABELS: >- + --label org.label-schema.schema-version="1.0" + --label org.label-schema.build-date="{{.BUILD_DATE}}" + --label org.label-schema.name="{{.LABEL_NAME}}" + --label org.label-schema.description="{{.LABEL_DESCRIPTION}}" + --label org.label-schema.usage="{{.LABEL_DOCS_URL}}" + --label org.label-schema.url="{{.LABEL_HOMEPAGE}}" + --label org.label-schema.vcs-url="{{.LABEL_REPO_URL}}" + --label org.label-schema.vcs-ref="{{.GIT_SHA}}" + --label org.label-schema.vendor="{{.LABEL_VENDOR}}" + --label org.label-schema.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --label org.opencontainers.image.created="{{.BUILD_DATE}}" + --label org.opencontainers.image.authors="{{.LABEL_AUTHOR}}" + --label org.opencontainers.image.url="{{.LABEL_HOMEPAGE}}" + --label org.opencontainers.image.documentation="{{.LABEL_DOCS_URL}}" + --label org.opencontainers.image.source="{{.LABEL_REPO_URL}}" + --label org.opencontainers.image.version="{{.VERSION_FULL}}{{.VERSION_SUFFIX}}" + --label org.opencontainers.image.revision="{{.GIT_SHA}}" + --label org.opencontainers.image.vendor="{{.LABEL_VENDOR}}" + --label org.opencontainers.image.licenses="{{.LABEL_LICENSE}}" + --label org.opencontainers.image.title="{{.LABEL_NAME}}" + --label org.opencontainers.image.description="{{.LABEL_DESCRIPTION}}" + TAGS: >- + --tag {{.DOCKER_NAME}}:{{.VERSION_FULL}}{{.VERSION_SUFFIX}} + --tag {{.DOCKER_NAME}}:{{.VERSION_MINOR}}{{.VERSION_SUFFIX}} + --tag {{.DOCKER_NAME}}:{{.VERSION_MAJOR}}{{.VERSION_SUFFIX}} + --tag {{.DOCKER_NAME}}:latest{{.VERSION_SUFFIX}} + --tag {{.GHRC_NAME}}:{{.VERSION_FULL}}{{.VERSION_SUFFIX}} + --tag {{.GHRC_NAME}}:{{.VERSION_MINOR}}{{.VERSION_SUFFIX}} + --tag {{.GHRC_NAME}}:{{.VERSION_MAJOR}}{{.VERSION_SUFFIX}} + --tag {{.GHRC_NAME}}:latest{{.VERSION_SUFFIX}} + DOCKER_BUILD_START: + sh: | + if docker buildx version >/dev/null 2>&1; then + echo "docker buildx build --platform {{.PLATFORMS}}" + else + echo "docker build" + fi + DOCKER_BUILD_FINISH: '{{.ANNOTATIONS}} {{.LABELS}} {{.TAGS}} --file={{.DOCKERFILE}} .' From 72cba20742e152708624918e891d0495bff95a8e Mon Sep 17 00:00:00 2001 From: ChristophShyper <45788587+ChristophShyper@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:28:37 +0100 Subject: [PATCH 8/8] Updated .dockerignore to match dockerized template --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index 05f50d1..d59c4e2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,5 @@ !Dockerfile !LICENSE !README.md +!show-versions.sh +!pip