diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 356e8e4..674ae98 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ name: Build on: push: branches: [ main ] - tags: [ 'v*' ] pull_request: branches: [ main ] @@ -12,10 +11,6 @@ env: GHCR_REGISTRY: ghcr.io GHCR_IMAGE_REPO: ${{ format('{0}/{1}', 'ghcr.io', github.repository) }} - # Quay configuration - QUAY_REGISTRY: quay.io - QUAY_IMAGE_REPO: quay.io/aipcc-cicd/claudio - jobs: build-and-upload: name: Build and Upload Images @@ -34,11 +29,7 @@ jobs: - name: Set image repo and tag based on event run: | - if [[ "${{ github.ref_type }}" == "tag" ]]; then - # Tag events: build for Quay - echo "IMAGE_REPO=${{ env.QUAY_IMAGE_REPO }}" >> $GITHUB_ENV - echo "IMAGE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV - elif [[ "${{ github.event_name }}" == "pull_request" ]]; then + if [[ "${{ github.event_name }}" == "pull_request" ]]; then # PRs: build for GHCR with pr-X tag echo "IMAGE_REPO=${{ env.GHCR_IMAGE_REPO }}" >> $GITHUB_ENV echo "IMAGE_TAG=pr-${{ github.event.number }}" >> $GITHUB_ENV @@ -126,54 +117,3 @@ jobs: make oci-manifest-build make oci-manifest-push - push-quay: - name: Push to Quay (tag release) - if: startsWith(github.ref, 'refs/tags/v') - needs: build-and-upload - runs-on: ubuntu-24.04 - permissions: - contents: read - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Download claudio images - uses: actions/download-artifact@v8 - with: - pattern: claudio-* - - - name: Log in to Quay Container Registry - uses: docker/login-action@v4 - with: - registry: ${{ env.QUAY_REGISTRY }} - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_PASSWORD }} - - - name: Load and push images to Quay - env: - IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }} - IMAGE_TAG: ${{ github.ref_name }} - run: | - make oci-load - make oci-push-arch - make oci-manifest-build - make oci-manifest-push - - create-release: - name: Create GitHub Release - if: startsWith(github.ref, 'refs/tags/v') - needs: push-quay - runs-on: ubuntu-24.04 - permissions: - contents: write - - steps: - - name: Create release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh release create "${{ github.ref_name }}" \ - --repo "${{ github.repository }}" \ - --title "${{ github.ref_name }}" \ - --generate-notes diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..521ab88 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,159 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. v0.8.0)' + required: true + type: string + skills_ref: + description: 'claudio-skills tag to pin (e.g. v0.5.5)' + required: true + type: string + +permissions: {} + +env: + QUAY_REGISTRY: quay.io + QUAY_IMAGE_REPO: quay.io/aipcc-cicd/claudio + +jobs: + authorize: + name: Authorize + runs-on: ubuntu-24.04 + environment: release + steps: + - name: Verify team membership + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + ACTOR: ${{ github.actor }} + run: | + gh api "orgs/aipcc-cicd/teams/aipcc-productization/memberships/${ACTOR}" --silent \ + || (echo "::error::${ACTOR} is not a member of aipcc-cicd/aipcc-productization" && exit 1) + + - name: Validate inputs + env: + INPUT_VERSION: ${{ inputs.version }} + INPUT_SKILLS_REF: ${{ inputs.skills_ref }} + run: | + if [[ ! "${INPUT_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then + echo "::error::Invalid version '${INPUT_VERSION}'. Expected format: v0.8.0 or v0.8.0-rc1" + exit 1 + fi + if [[ ! "${INPUT_SKILLS_REF}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then + echo "::error::Invalid skills_ref '${INPUT_SKILLS_REF}'. Expected format: v0.5.5 or v0.5.5-rc1" + exit 1 + fi + + - name: Check release does not exist + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + INPUT_VERSION: ${{ inputs.version }} + run: | + if gh release view "${INPUT_VERSION}" &>/dev/null; then + echo "::error::Release ${INPUT_VERSION} already exists" + exit 1 + fi + + build-and-upload: + name: Build Images + needs: authorize + runs-on: ${{ matrix.runner }} + permissions: + contents: read + strategy: + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Build image (${{ matrix.arch }}) + env: + VERSION: ${{ inputs.version }} + CS_REF_TYPE: tag + CS_REF: ${{ inputs.skills_ref }} + IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }} + IMAGE_TAG: ${{ inputs.version }} + IMAGE_NAME: ${{ env.QUAY_IMAGE_REPO }}:${{ inputs.version }}-${{ matrix.arch }} + ARTIFACT_NAME: claudio-${{ matrix.arch }} + run: | + make oci-build + make oci-save + + - name: Upload image artifact + uses: actions/upload-artifact@v7 + with: + name: claudio-${{ matrix.arch }} + path: claudio-${{ matrix.arch }}.tar + + push-quay: + name: Push to Quay + needs: build-and-upload + runs-on: ubuntu-24.04 + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Download claudio images + uses: actions/download-artifact@v8 + with: + pattern: claudio-* + + - name: Log in to Quay Container Registry + uses: docker/login-action@v4 + with: + registry: ${{ env.QUAY_REGISTRY }} + username: ${{ secrets.QUAY_USERNAME }} + password: ${{ secrets.QUAY_PASSWORD }} + + - name: Load and push images to Quay + env: + IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }} + IMAGE_TAG: ${{ inputs.version }} + run: | + make oci-load + make oci-push-arch + make oci-manifest-build + make oci-manifest-push + + - name: Tag and push as latest + env: + IMAGE_REPO: ${{ env.QUAY_IMAGE_REPO }} + IMAGE_TAG: latest + IMAGE_SOURCE_TAG: ${{ inputs.version }} + run: | + make oci-manifest-build + make oci-manifest-push + + create-release: + name: Create GitHub Release + needs: push-quay + runs-on: ubuntu-24.04 + permissions: + contents: write + + steps: + - name: Create release and tag + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_VERSION: ${{ inputs.version }} + run: | + gh release create "$RELEASE_VERSION" \ + --repo "${{ github.repository }}" \ + --target "${{ github.sha }}" \ + --title "$RELEASE_VERSION" \ + --generate-notes diff --git a/Containerfile b/Containerfile index d6c5782..82aa3fd 100644 --- a/Containerfile +++ b/Containerfile @@ -85,12 +85,10 @@ ARG CS_REF_TYPE ARG CS_REF ARG CS_CACHE_KEY RUN echo "cs-cache-key: ${CS_CACHE_KEY}" \ - && if [ "${CS_REF_TYPE}" = "branch" ]; then \ - claude plugin marketplace add aipcc-cicd/claudio-skills#${CS_REF}; \ - elif [ "${CS_REF_TYPE}" != "pr" ]; then \ - claude plugin marketplace add aipcc-cicd/claudio-skills@v${CS_REF}; \ + && if [ "${CS_REF_TYPE}" = "pr" ]; then \ + claude plugin marketplace add /home/claudio/claudio-skills; \ else \ - claude plugin marketplace add /home/claudio/claudio-skills; \ + claude plugin marketplace add aipcc-cicd/claudio-skills@${CS_REF}; \ fi; \ claude plugin install --scope user claudio-plugin; \ pt-manager.sh diff --git a/Makefile b/Makefile index 3605914..42dc553 100644 --- a/Makefile +++ b/Makefile @@ -15,28 +15,23 @@ # # SPDX-License-Identifier: Apache-2.0 -VERSION ?= 0.6.1 +VERSION ?= dev CONTAINER_MANAGER ?= podman # Image configuration IMAGE_REPO ?= quay.io/aipcc-cicd/claudio -IMAGE_TAG ?= v${VERSION} +IMAGE_TAG ?= ${VERSION} IMAGE_NAME ?= $(IMAGE_REPO):$(IMAGE_TAG) IMAGE_SOURCE_TAG ?= $(IMAGE_TAG) # Artifact naming ARTIFACT_NAME ?= claudio -# Claudio skills -# -# CS_REF_TYPE can be branch, tag, or pr -# Example when we create a tag version for claudio -CS_REF_TYPE ?= tag -CS_REF ?= 0.5.3 +# Claudio skills — ref type (branch, tag, or pr) and ref value. +# Override via env vars for release builds: CS_REF_TYPE=tag CS_REF=v0.5.5 +CS_REF_TYPE ?= branch +CS_REF ?= main CS_REPO ?= https://github.com/aipcc-cicd/claudio-skills.git -# For CS PR 41 -# CS_REF_TYPE = pr -# CS_REF = 41 # Resolve the remote HEAD SHA for the skills ref so the build cache # invalidates automatically when the PR/branch gets new commits. CS_CACHE_KEY_CMD = $(if $(filter pr,$(CS_REF_TYPE)), \ @@ -78,8 +73,3 @@ oci-tag: oci-push: ${CONTAINER_MANAGER} push $(IMAGE_NAME) -# Integrations -.PHONY: integrations-update - -integrations-update: - sed -e 's%%$(IMAGE_NAME)%g' integrations/gitlab-ci/template/claudio.yml > integrations/gitlab-ci/claudio.yml diff --git a/README.md b/README.md index 2deb1d8..dc77088 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ Available targets: - `oci-tag` - Tag existing image with new tag - `oci-manifest-build` - Create multi-arch manifest from arch-tagged images - `oci-manifest-push` - Push manifest to registry -- `integrations-update` - Regenerate CI templates with current image version ## Claudio Skills Reference @@ -68,7 +67,7 @@ When developing changes to claudio-skills that affect a downstream image (e.g. a ```bash CS_REF_TYPE=pr CS_REF=9 make oci-build ``` - This produces a local image tagged `quay.io/aipcc-cicd/claudio:v1.0.0-dev`. + This produces a local image tagged `quay.io/aipcc-cicd/claudio:dev`. 3. In the downstream repo, point the `FROM` line at that local image (or tag it to match the expected base tag) and build: ```bash # In aipcc-claudio @@ -153,7 +152,7 @@ The `.claudio` template uses the claudio image directly as the job container. Yo Available variables: - `CLAUDIO_PROMPT` (required) — the prompt to run -- `CLAUDIO_IMAGE` — override the claudio image (default: current release version) +- `CLAUDIO_IMAGE` — override the claudio image (default: `quay.io/aipcc-cicd/claudio:latest`) - `CLAUDIO_EXTRA_ARGS` — extra arguments passed to claudio - `CLAUDIO_STREAM` — set to `1` to enable human-readable streaming output in the job log - `CLAUDIO_LOG_FILE` — write a plain-text log (no ANSI codes) to this path (streaming mode only) @@ -173,6 +172,22 @@ my-claudio-job: CLAUDIO_PROMPT: "Do something useful" ``` -The template is generated from `integrations/gitlab-ci/template/claudio.yml`. When preparing a release, run `make integrations-update` to regenerate the template with the current version, then commit the result. - Downstream projects can extend this template to add their own secret management. + +## Releasing + +Releases are fully automated via GitHub Actions — no manual commits or version bumps needed. + +1. Go to **Actions** → **Release** → **Run workflow** +2. Enter the version (e.g. `v0.8.0`) and the claudio-skills tag to pin (e.g. `v0.5.5`) +3. Click **Run workflow** + +The workflow builds multi-arch images, pushes to Quay (`quay.io/aipcc-cicd/claudio:v0.8.0`), creates a git tag, and publishes a GitHub Release with auto-generated notes. + +### Patch releases + +If you need to patch an older release: + +1. Create a release branch from the tag: `git checkout -b release-0.7 v0.7.0` +2. Cherry-pick the fix(es) and push the branch: `git push origin release-0.7` +3. Run the release workflow, selecting the release branch as the target diff --git a/integrations/gitlab-ci/claudio.yml b/integrations/gitlab-ci/claudio.yml index bdc1be5..d7c8571 100644 --- a/integrations/gitlab-ci/claudio.yml +++ b/integrations/gitlab-ci/claudio.yml @@ -14,7 +14,7 @@ # CLAUDIO_PROMPT: "Analyze the latest MRs and report to Slack" # # Optional variables to override: -# CLAUDIO_IMAGE - claudio container image (default: quay.io/aipcc-cicd/claudio:) +# CLAUDIO_IMAGE - claudio container image (default: quay.io/aipcc-cicd/claudio:latest) # CLAUDIO_EXTRA_ARGS - Extra arguments passed to claudio # @@ -23,7 +23,7 @@ name: ${CLAUDIO_IMAGE} entrypoint: [""] variables: - CLAUDIO_IMAGE: "quay.io/aipcc-cicd/claudio:v0.5.0-dev" + CLAUDIO_IMAGE: "quay.io/aipcc-cicd/claudio:latest" CLAUDIO_EXTRA_ARGS: "" script: - | diff --git a/integrations/gitlab-ci/template/claudio.yml b/integrations/gitlab-ci/template/claudio.yml deleted file mode 100644 index c0deb2a..0000000 --- a/integrations/gitlab-ci/template/claudio.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Reusable GitLab CI template for running claudio jobs. -# -# Include this template in your project's .gitlab-ci.yml: -# -# include: -# - project: 'aipcc-cicd/claudio' -# file: 'integrations/gitlab-ci/claudio.yml' -# -# Then define a job that extends .claudio: -# -# my-claudio-job: -# extends: .claudio -# variables: -# CLAUDIO_PROMPT: "Analyze the latest MRs and report to Slack" -# -# Optional variables to override: -# CLAUDIO_IMAGE - claudio container image (default: quay.io/aipcc-cicd/claudio:) -# CLAUDIO_EXTRA_ARGS - Extra arguments passed to claudio -# - -.claudio: - image: - name: ${CLAUDIO_IMAGE} - entrypoint: [""] - variables: - CLAUDIO_IMAGE: "" - CLAUDIO_EXTRA_ARGS: "" - script: - - | - if [ -z "${CLAUDIO_PROMPT}" ]; then - echo "ERROR: CLAUDIO_PROMPT variable is not set" >&2 - exit 1 - fi - - printf "=== PROMPT ===\n%s\n" "${CLAUDIO_PROMPT}" - entrypoint.sh -p "${CLAUDIO_PROMPT}" ${CLAUDIO_EXTRA_ARGS} diff --git a/renovate.json b/renovate.json index 05061da..bd1e17b 100644 --- a/renovate.json +++ b/renovate.json @@ -30,20 +30,6 @@ "datasourceTemplate": "docker", "depNameTemplate": "google/cloud-sdk", "autoReplaceStringTemplate": "ENV GCLOUD_V {{newVersion}}" - }, - { - "customType": "regex", - "description": "Update Claudio Skills version", - "managerFilePatterns": [ - "Makefile" - ], - "matchStrings": [ - "CS_REF\\s+\\?=\\s+(?\\d+\\.\\d+\\.\\d+)" - ], - "datasourceTemplate": "github-releases", - "depNameTemplate": "aipcc-cicd/claudio-skills", - "extractVersionTemplate": "^v?(?\\d+\\.\\d+\\.\\d+)$", - "autoReplaceStringTemplate": "CS_REF ?= {{newValue}}" } ], "packageRules": []