Skip to content
Draft
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
265 changes: 265 additions & 0 deletions .agents/skills/release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
---
name: release
description: This skill should be used when the user asks to "do a release", "cut a release", "create a patch release", "create a minor release", "release v0.X.Y", or wants to perform the Tekton CLI release process. Guides the user through the full release workflow including prerequisites, running release.sh, and post-release steps (rpm, deb, homebrew, plumbing).
version: 0.1.0
---

# Tekton CLI Release

Guide the user through the complete Tekton CLI release process — from prerequisites through post-release packaging and distribution.

## Purpose

Skill that:

- Validates all prerequisites before starting
- Determines whether this is a minor or patch release
- Guides running `tekton/release.sh`
- Walks through all post-release steps in order
- Tracks progress through the checklist

## Workflow

### Step 1: Determine release type and version

Ask the user for the target release version if not already provided. The version must match `vX.Y.Z` (e.g., `v0.46.0`, `v0.43.3`).

Determine the release type:

- **Minor release** (`Z == 0`, e.g., `v0.46.0`): Creates a new `release-vX.Y.x` branch from `main`.
- **Patch release** (`Z > 0`, e.g., `v0.43.3`): Uses the existing `release-vX.Y.x` branch. All fixes must already be merged into the `.x` branch.

Tell the user which type was detected.

### Step 2: Validate prerequisites

Check each prerequisite and report status. Refer to `references/prerequisites.md` for the full list.

**Automated checks** (run these):

```bash
# Required binaries
for bin in kubectl jq tkn git gh; do
command -v "$bin" >/dev/null 2>&1 && echo "✓ $bin" || echo "✗ $bin missing"
done

# Kubernetes cluster access
kubectl version --short 2>/dev/null && echo "✓ cluster accessible" || echo "✗ no cluster access"

# Tekton installed on cluster
kubectl get pipeline 2>/dev/null && echo "✓ Tekton installed" || echo "✗ Tekton not installed"

# GPG key configured
git config user.signingkey && echo "✓ GPG signing key set" || echo "✗ no GPG signing key"

# GOPATH set and project path correct
echo "GOPATH=$GOPATH"
[[ -d "${GOPATH}/src/github.com/tektoncd/cli" ]] && echo "✓ project at GOPATH path" || echo "✗ project not at \${GOPATH}/src/github.com/tektoncd/cli"

# gh authenticated
gh auth status 2>&1

# Clean working directory
git status --porcelain
```

**Manual checks** (remind the user to verify):

- Member of [CLI maintainers team](https://github.com/orgs/tektoncd/teams/cli-maintainers)
- GitHub personal access token with `admin:org, read:packages, repo, write:packages` scopes
- Access to [copr repository](https://copr.fedorainfracloud.org/coprs/chmouel/tektoncd-cli/) (for RPM)
- Member of [launchpad team](https://launchpad.net/~tektoncd) with GPG key uploaded (for DEB)

If any automated check fails, stop and help resolve it before proceeding.

**CRITICAL**: The working directory must be clean (no uncommitted changes). If `git status --porcelain` returns output, tell the user to stash or commit changes first.

### Step 3: Patch release — verify fixes are merged

**Skip this step for minor releases.**

For patch releases, verify the release branch exists and contains the expected fixes:

```bash
RELEASE_BRANCH="release-v${VERSION%.*}.x"
git fetch -a --tags upstream
git ls-remote --exit-code upstream "refs/heads/${RELEASE_BRANCH}"
```

Show recent commits on the release branch so the user can confirm the right fixes are included:

```bash
git log --oneline upstream/${RELEASE_BRANCH} -20
```

Ask: **"Are all the fixes for this patch release merged into `${RELEASE_BRANCH}`? (y/n)"**

Do not proceed until confirmed.

### Step 4: Run the release script

**CRITICAL**: This step requires the user to run the command themselves since `release.sh` is interactive (it may prompt for a GitHub token).

Tell the user to run:

```bash
cd ${GOPATH}/src/github.com/tektoncd/cli
./tekton/release.sh vX.Y.Z
```

Explain what the script does:

1. Fetches tags and determines previous release tag
2. For minor releases: creates `release-vX.Y.x` branch from `main`
3. For patch releases: checks out existing `release-vX.Y.x` branch
4. Generates a changelog from commits between previous tag and HEAD
5. Updates the `VERSION` file, commits, and creates a signed tag
6. Pushes the tag and release branch to `upstream`
7. Installs Tekton catalog tasks on the cluster
8. Applies the release pipeline and triggers it
9. Streams pipeline logs via `tkn`

Tell the user: **"Run the release script and let me know when it completes successfully, or if you hit any errors."**

Wait for the user to report back before continuing.

### Step 5: Mark release as published on GitHub

After the release pipeline completes, the GitHub release will be in pre-release state.

```bash
gh release view vX.Y.Z --json isDraft,isPrerelease,tagName
```

Tell the user to:

1. Go to https://github.com/tektoncd/cli/releases/tag/vX.Y.Z
2. Edit the release
3. Change it from pre-release to released (uncheck "Set as a pre-release")
4. Publish the release

**IMPORTANT**: This must be done before building the RPM package.

Ask the user to confirm the release is published before proceeding.

### Step 6: Generate release notes

Invoke the `release-notes` skill to generate and publish release notes for the tag. Tell the user:

**"Let's generate the release notes. You can run `/release-notes vX.Y.Z` or I can generate them now."**

### Step 7: Build RPM package

Guide the user through building the RPM package per `tekton/rpmbuild/README.md`.

**Prerequisites** (remind user):

- Access to [copr repository](https://copr.fedorainfracloud.org/coprs/chmouel/tektoncd-cli/)
- Copr API config at `~/.config/copr` (get from https://copr.fedorainfracloud.org/api/)
- Change `username` field in copr config to `chmouel`

**Steps**:

```bash
# Create copr secret if not exists
kubectl -n release get secret copr-cli-config || \
kubectl -n release create secret generic copr-cli-config --from-file=copr=${HOME}/.config/copr

# Ensure git-clone task is installed
tkn -n release task list | grep git-clone || tkn -n release hub install task git-clone

# Create and run the RPM build
kubectl -n release apply -f tekton/rpmbuild/rpmbuild.yml
kubectl -n release create -f tekton/rpmbuild/rpmbuild-run.yml

# Watch logs
tkn -n release pipelinerun logs rpmbuild-pipelinerun -f
```

Tell the user this may take time if the copr builder is busy.

### Step 8: Build Debian package

Guide the user through building the DEB package per `tekton/debbuild/README.md`. This can start while the RPM is building.

**Prerequisites** (remind user):

- Member of [launchpad team](https://launchpad.net/~tektoncd)
- GPG key uploaded to launchpad profile
- Set `GPG_KEY` environment variable to GPG key user ID

**Steps**:

```bash
export GPG_KEY=<user-gpg-key-id>
cd tekton/debbuild
./run.sh
```

The build uploads to https://launchpad.net/~tektoncd/+archive/ubuntu/cli/+packages — user can check build logs there.

**Known issue**: If the build fails with `build flag -mod=vendor only valid when using modules`, edit `tekton/debbuild/control/rules` and append `GO111MODULE=on` at the build line. If re-pushing after a failed build, increment the release version in `tekton/debbuild/container/buildpackage.sh`.

### Step 9: Homebrew update

Tell the user:

- Homebrew Core has a GitHub Action that automatically bumps the formula every ~3 hours
- Check that a PR like [this example](https://github.com/Homebrew/homebrew-core/pull/171551) is created and merged
- Alternatively, manually update [homebrew-core](https://github.com/Homebrew/homebrew-core) for `tektoncd-cli` formula

### Step 10: Update plumbing repo (optional)

**This step is optional.** Mention it to the user but do not block on it.

Tell the user they can optionally update the `tkn` version in the [tektoncd/plumbing](https://github.com/tektoncd/plumbing/) repo:

1. **test-runner image**: Update `ARG TKN_VERSION=<NEW_VERSION>` in [test-runner Dockerfile](https://github.com/tektoncd/plumbing/blob/main/tekton/images/test-runner/Dockerfile)
2. **tkn image**: Update `ARG TKN_VERSION=<NEW_VERSION>` in [tkn Dockerfile](https://github.com/tektoncd/plumbing/blob/main/tekton/images/tkn/Dockerfile)

### Step 11: Update Arch Linux

Tell the user to go to https://archlinux.org/packages/extra/x86_64/tekton-cli/flag/ and notify packagers that a new version is available, leaving the release URL and their email address.

### Step 12: Update README version

Remind the user to update version numbers in the main `README.md` via a PR to `main`.

## Progress Tracking

After each step, confirm with the user before moving on. Use a checklist format:

```text
Release vX.Y.Z Progress:
[✓] 1. Release type determined (minor/patch)
[✓] 2. Prerequisites validated
[✓] 3. Fixes verified (patch only)
[✓] 4. release.sh completed
[ ] 5. GitHub release published
[ ] 6. Release notes generated
[ ] 7. RPM package built
[ ] 8. DEB package built
[ ] 9. Homebrew updated
[ ] 10. Plumbing repo updated (optional)
[ ] 11. Arch Linux notified
[ ] 12. README version updated
```

## Error Handling

| Scenario | Action |
| --- | --- |
| Binary missing | Tell user how to install it |
| No cluster access | Tell user to configure kubeconfig |
| Tekton not installed | Link to Tekton Pipelines install docs |
| No GPG key | Link to GitHub GPG setup guide |
| Dirty working directory | Tell user to stash or commit |
| Release branch missing (patch) | Error — fixes need to be merged first |
| release.sh fails | Help debug based on error output |
| RPM build fails | Check copr builder status and logs |
| DEB build fails | Check launchpad build logs, suggest GO111MODULE fix |
| GitHub release not found | Script may not have pushed; check tags |

## User Confirmation Requirements

**CRITICAL**: Never run `release.sh` directly — it is interactive and must be run by the user. Always confirm after each major step before proceeding. Never push tags or branches without the user having explicitly run the release script.
55 changes: 55 additions & 0 deletions .agents/skills/release/references/prerequisites.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Release Prerequisites Reference

## Required Tools

| Tool | Purpose | Install |
| --- | --- | --- |
| `kubectl` | Kubernetes cluster access | https://kubernetes.io/docs/tasks/tools/ |
| `jq` | JSON processing in release script | `brew install jq` / `dnf install jq` |
| `tkn` | Tekton CLI (for pipeline management) | https://tekton.dev/docs/cli/ |
| `git` | Version control, tagging, branching | System package manager |
| `gh` | GitHub CLI (for release notes, auth) | https://cli.github.com/ |

## Access Requirements

| Requirement | How to get it |
| --- | --- |
| CLI maintainers team | Request access via [tektoncd/cli OWNERS](https://github.com/tektoncd/cli/blob/main/OWNERS) |
| GitHub PAT (`admin:org, read:packages, repo, write:packages`) | https://github.com/settings/tokens |
| GPG signing key in git | https://help.github.com/en/github/authenticating-to-github/managing-commit-signature-verification |
| Kubernetes cluster with Tekton | minikube, GKE, or any cluster with `kubectl get pipeline` working |
| Copr admin access (RPM) | Request at https://copr.fedorainfracloud.org/coprs/chmouel/tektoncd-cli/permissions/ |
| Launchpad team (DEB) | Join at https://launchpad.net/~tektoncd/+join and upload GPG key to profile |

## Environment

| Variable | Required | Purpose |
| --- | --- | --- |
| `GOPATH` | Yes | release.sh uses `${GOPATH}/src/github.com/tektoncd/cli` |
| `PUSH_REMOTE` | No | Override push remote for testing (default: `upstream`) |
| `GPG_KEY` | For DEB builds | GPG key user ID for signing Debian packages |

## Release Branch Convention

Release branches follow `release-vX.Y.x`:

- `release-v0.46.x` for the v0.46 release line
- `release-v0.43.x` for the v0.43 release line

### Minor release (e.g., v0.46.0)

- Script creates `release-vX.Y.x` from `main`
- No prior branch expected

### Patch release (e.g., v0.43.3)

- Branch `release-vX.Y.x` must already exist
- All fixes must be merged into the `.x` branch before running the release
- Script detects the branch exists and checks it out

## Previous Tag Detection

The release script auto-detects the previous tag for changelog generation:

- **Patch release**: Finds the latest `vX.Y.*` tag within the same minor version (e.g., for `v0.43.3`, finds `v0.43.2`)
- **Minor release**: Finds the latest `vX.Y.Z` tag across all versions (e.g., for `v0.46.0`, finds `v0.45.0`)
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,7 @@ For complex workflows, use these repo-local skills:
- **Release notes**: Gather PRs between tags, categorize, output formatted
markdown, optionally update GitHub release. Trigger: "create release note",
"generate release notes", "release changelog"
- **Release**: Full CLI release workflow for minor and patch releases. Validates
prerequisites, guides running release.sh, and walks through post-release
steps (RPM, DEB, Homebrew, plumbing). Trigger: "do a release",
"cut a release", "create a patch release", "release vX.Y.Z"
3 changes: 1 addition & 2 deletions tekton/release-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ spec:
- name: github-token-secret-key
value: $(params.github-token-secret-key)
- name: image
# TODO: update the goreleaser image to latest once go v1.25.6 is supported in latest goreleaser image
value: goreleaser/goreleaser:v2.18.0-ae4debbe-nightly
value: goreleaser/goreleaser:v2.17.1
- name: flags
value: --timeout=60m
workspaces:
Expand Down
31 changes: 15 additions & 16 deletions tekton/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,21 @@ kubectl get pipeline 2>/dev/null >/dev/null || {
RELEASE_BRANCH="release-${RELEASE_VERSION%.*}.x"

git fetch -a --tags ${UPSTREAM_REMOTE} >/dev/null
lasttag=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -v "^${RELEASE_VERSION}$" | head -1)
[[ -z ${lasttag} ]] && { echo "no previous release tag found for ${RELEASE_VERSION}"; exit 1; }

git ls-remote --exit-code ${UPSTREAM_REMOTE} refs/heads/${RELEASE_BRANCH} >/dev/null 2>&1 && {
echo "Patch release detected: ${RELEASE_BRANCH} exists on ${UPSTREAM_REMOTE}, previous tag ${lasttag}"
patch_release=true
} || {
echo "New release detected: creating ${RELEASE_BRANCH} from ${DEFAULT_BRANCH}, previous tag ${lasttag}"
}
} || true

if [[ -n ${patch_release} ]];then
version_prefix="${RELEASE_VERSION%.*}"
prev_tag=$(git tag --sort=-v:refname -l "${version_prefix}.*" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -v "^${RELEASE_VERSION}$" | head -1)
[[ -z ${prev_tag} ]] && { echo "no previous patch release tag found for ${version_prefix}"; exit 1; }
echo "Patch release detected: ${RELEASE_BRANCH} exists on ${UPSTREAM_REMOTE}, previous tag ${prev_tag}"
else
prev_tag=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -v "^${RELEASE_VERSION}$" | head -1)
[[ -z ${prev_tag} ]] && { echo "no previous release tag found for ${RELEASE_VERSION}"; exit 1; }
echo "New minor release detected: creating ${RELEASE_BRANCH} from ${DEFAULT_BRANCH}, previous tag ${prev_tag}"
fi

cd ${GOPATH}/src/github.com/tektoncd/cli

Expand Down Expand Up @@ -77,16 +83,9 @@ fi
git cherry-pick 052b0b4ce989fe9aee01027e67e61538b48e1179 >/dev/null
}

if [[ -n ${patch_release} ]];then
version_prefix="${RELEASE_VERSION%.*}"
prev_tag=$(git tag --sort=-v:refname -l "${version_prefix}.*" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -v "^${RELEASE_VERSION}$" | head -1)
[[ -z ${prev_tag} ]] && { echo "no previous patch release tag found for ${version_prefix}"; exit 1; }
else
prev_tag=${lasttag}
fi
COMMITS=$(git log --reverse --no-merges \
--pretty=format:'%H' HEAD \
--since "$(git log --pretty=format:%cd -1 ${prev_tag})")
COMMITS=$(git log --reverse --no-merges --pretty=format:'%H' ${prev_tag}..HEAD)

echo "Creating changelog for ${RELEASE_VERSION} from ${prev_tag}..HEAD"

changelog=""
for c in ${COMMITS};do
Expand Down
Loading