Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/auto-pull-request-create.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name: (Auto) Pull Request Create
name: (Automatic) Pull Request Create

on:
push:
branches-ignore:
- master
- main
- release/**
- dependabot/**

permissions:
Expand Down
32 changes: 32 additions & 0 deletions .github/workflows/auto-release-create.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: (Automatic) Release Create

on:
push:
branches:
- master
- main
workflow_dispatch:
inputs:
release_branch:
description: Release branch to publish from (e.g. release/v1.3.0)
required: false
default: ''
type: string
release_version:
description: Explicit release version override (e.g. v1.3.0)
required: false
default: ''
type: string

permissions:
contents: write
pull-requests: read

jobs:
call:
uses: devops-infra/.github/.github/workflows/reusable-auto-release-create.yml@v1
with:
profile: dockerized
release-branch: ${{ inputs.release_branch }}
release-version: ${{ inputs.release_version }}
secrets: inherit
39 changes: 39 additions & 0 deletions .github/workflows/manual-release-branch-prepare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: (Manual) Release Branch Prepare

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
pull-requests: write

jobs:
call:
uses: devops-infra/.github/.github/workflows/reusable-manual-release-branch-prepare.yml@v1
with:
bump-type: ${{ inputs.type }}
explicit-version: ${{ inputs.version }}
build-and-push-only: ${{ inputs.build_only }}
profile: dockerized
secrets: inherit
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Intellij
/.idea/
.idea/
*.iml

# Custom
Expand All @@ -10,3 +10,10 @@
.envrc
.env
.tmp

# Python
build/
dist/
*.egg-info/
*.pyc
__py
177 changes: 11 additions & 166 deletions Taskfile.cicd.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
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
Expand All @@ -29,34 +26,12 @@ tasks:
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
- task: scripts:lint:actionlint

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
- task: scripts:lint:hadolint

lint:shellcheck:
desc: Lint shell scripts with shellcheck
Expand All @@ -66,36 +41,17 @@ tasks:
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
- task: scripts:lint:yamllint

dependency:update:
desc: Update repository dependencies not covered by dependabot
desc: 'No-op: no dedicated dependency updater configured for this profile'
cmds:
- task: scripts:packages:update
- task: scripts:dependency:update

version:set:
desc: Validate version
cmds:
- |
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
- task: scripts:version:set

version:update:patch:
desc: Increment patch version (e.g., 1.2.3 -> 1.2.4)
Expand All @@ -115,135 +71,24 @@ tasks:
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)"

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}"
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" ;;
major) next="v$((major + 1)).0.0" ;;
esac
;;
*)
echo "Unknown type: $bump_type"
exit 1
;;
esac

printf "%s" "$next"
- task: scripts:version:resolve-next

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
- task: scripts:version:tag-release

git:get-pr-template:
desc: Get pull request template
cmds:
- mkdir -p .tmp
- curl -LsS {{.PR_TEMPLATE}} -o .tmp/PULL_REQUEST_TEMPLATE.md
- task: scripts:git:get-pr-template

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"
- task: scripts:git:set-config

version:get:
desc: Get current version
cmds:
- echo "{{.VERSION}}"
- task: scripts:version:get
3 changes: 1 addition & 2 deletions Taskfile.docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ tasks:
docker:cmds:
desc: Show full docker build command
cmds:
- echo -e '{{.DOCKER_BUILD_START}} {{.DOCKER_BUILD_FINISH}}' | {{.SED}} 's/--/ \\\n --/g'
- echo -e '{{.DOCKER_BUILD_START}} {{.DOCKER_BUILD_FINISH}}' | {{.SED}} 's/--/ \\\n+ --/g'

docker:build:
desc: Build Docker image
Expand Down Expand Up @@ -80,7 +80,6 @@ tasks:
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 \
Expand Down
Loading
Loading