feat(ci): gitops image-update PR workflow for home-kubernetes #39
94
.gitea/workflows/gitops-update.yaml
Normal file
94
.gitea/workflows/gitops-update.yaml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
name: GitOps image update
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Auto-fires when "Build and Push" completes successfully (tag push).
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Build and Push"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
# Manual trigger for dry-runs and one-off bumps.
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Git tag to deploy (without the -go suffix, e.g. 0.37)"
|
||||||
|
required: true
|
||||||
|
dry_run:
|
||||||
|
description: "Dry run — print diff, do not open a PR"
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
uh_cli_version:
|
||||||
|
description: "uh-cli version override (e.g. v0.2.0). Defaults to v0.1.0."
|
||||||
|
required: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
TEA_VERSION: "0.9.2"
|
||||||
|
# Resolved priority: manual input → repo/org variable → hardcoded default.
|
||||||
|
UH_CLI_VERSION: ${{ inputs.uh_cli_version || vars.UH_CLI_VERSION || 'v0.1.0' }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
gitops-pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip if triggered by workflow_run that did not succeed.
|
||||||
|
if: >
|
||||||
|
github.event_name == 'workflow_dispatch' ||
|
||||||
|
github.event.workflow_run.conclusion == 'success'
|
||||||
|
container:
|
||||||
|
image: ubuntu:latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITOPS_TOKEN }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install git, curl, ca-certificates
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y --no-install-recommends git curl ca-certificates
|
||||||
|
|
||||||
|
- name: Install tea
|
||||||
|
run: |
|
||||||
|
curl -fsSL \
|
||||||
|
"https://gitea.com/gitea/tea/releases/download/v${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64" \
|
||||||
|
-o /usr/local/bin/tea
|
||||||
|
chmod +x /usr/local/bin/tea
|
||||||
|
|
||||||
|
- name: Install uh-cli
|
||||||
|
run: |
|
||||||
|
curl -fsSL \
|
||||||
|
"https://gitea.home.hrajfrisbee.cz/kacerr/uh-cli/releases/download/${UH_CLI_VERSION}/uh-cli-${UH_CLI_VERSION}-linux-amd64" \
|
||||||
|
-o /usr/local/bin/uh-cli
|
||||||
|
chmod +x /usr/local/bin/uh-cli
|
||||||
|
|
||||||
|
- name: Resolve image tag
|
||||||
|
id: resolve
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
GIT_TAG="${{ inputs.tag }}"
|
||||||
|
else
|
||||||
|
# workflow_run: use the ref name of the triggering workflow (the pushed git tag).
|
||||||
|
GIT_TAG="${{ github.event.workflow_run.head_branch }}"
|
||||||
|
fi
|
||||||
|
IMAGE="gitea.home.hrajfrisbee.cz/${{ github.repository }}:${GIT_TAG}-go"
|
||||||
|
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Resolved image: ${IMAGE}"
|
||||||
|
|
||||||
|
- name: Configure git identity
|
||||||
|
run: |
|
||||||
|
git config --global user.name "uh-cli bot"
|
||||||
|
git config --global user.email "bot@hrajfrisbee.cz"
|
||||||
|
|
||||||
|
- name: Authenticate tea
|
||||||
|
run: |
|
||||||
|
tea login add \
|
||||||
|
--name ci \
|
||||||
|
--url https://gitea.home.hrajfrisbee.cz \
|
||||||
|
--token "$GITEA_TOKEN"
|
||||||
|
|
||||||
|
- name: Open image-update PR (or dry run)
|
||||||
|
run: |
|
||||||
|
uh-cli -v gitops deployment update \
|
||||||
|
--deployment-name fuj-management \
|
||||||
|
--deployment-namespace fuj \
|
||||||
|
--set-image "${{ steps.resolve.outputs.image }}" \
|
||||||
|
--git-repo "https://kacerr:${GITEA_TOKEN}@gitea.home.hrajfrisbee.cz/kacerr/home-kubernetes" \
|
||||||
|
--git-path gitops/home-kubernetes \
|
||||||
|
${{ (github.event_name == 'workflow_dispatch' && inputs.dry_run == 'true') && '--dry-run' || '' }}
|
||||||
112
docs/plans/2026-06-12-1927-gitops-pr-action.md
Normal file
112
docs/plans/2026-06-12-1927-gitops-pr-action.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Plan: Gitea Action to open a gitops image-update PR for fuj-management
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The Go image of this app is built and pushed by the `build-go` job in
|
||||||
|
[.gitea/workflows/build.yaml](.gitea/workflows/build.yaml), tagged
|
||||||
|
`gitea.home.hrajfrisbee.cz/kacerr/fuj-management:<git-tag>-go` (e.g. `0.37-go`).
|
||||||
|
|
||||||
|
Kubernetes manifests live in a **separate** repo,
|
||||||
|
`gitea.home.hrajfrisbee.cz/kacerr/home-kubernetes`. Today, bumping the image in
|
||||||
|
the `fuj-management` Deployment (namespace `fuj`) is a manual edit there.
|
||||||
|
|
||||||
|
We want CI to automate that bump: when a new Go image is built, open a PR against
|
||||||
|
`home-kubernetes` that swaps the image to the freshly built tag — using the
|
||||||
|
`uh-cli gitops deployment update` command. The user reviews/merges that PR in
|
||||||
|
Gitea (matching the existing branch-per-change, merge-in-browser workflow).
|
||||||
|
|
||||||
|
Decisions confirmed with the user:
|
||||||
|
- **Separate workflow file** (not a job inside build.yaml).
|
||||||
|
- **New `GITOPS_TOKEN` secret** for home-kubernetes write + PR access.
|
||||||
|
- **uh-cli version pinned with a default, overridable via env/var/input.**
|
||||||
|
|
||||||
|
## How uh-cli works (from `/Users/jan.novak/srv/go/uh-cli/docs/`)
|
||||||
|
|
||||||
|
- `uh-cli gitops deployment update` clones `--git-repo`, walks `--git-path`
|
||||||
|
recursively for a `kind: Deployment` whose `metadata.name`/`namespace` match,
|
||||||
|
edits the first container image surgically, commits on a new branch
|
||||||
|
`gitops/update-<name>-<timestamp>`, pushes, and **opens the PR itself** via
|
||||||
|
`tea pr create`. PR base is always `main`; title/body are hardcoded (no flags).
|
||||||
|
- Requires on PATH: `git` and `tea` (tea only for the PR flow; `--force` skips it).
|
||||||
|
- Auth: token embedded in the `--git-repo` URL (`https://user:TOKEN@host/...`);
|
||||||
|
`tea login add` for PR creation; git identity via `git config`/env vars.
|
||||||
|
- `--dry-run` prints the unified diff and makes no git changes. Global `-v`
|
||||||
|
(placed **before** the subcommand) enables debug logging on stderr.
|
||||||
|
- Release binaries are named `uh-cli-<version>-linux-amd64` (version includes the
|
||||||
|
`v`), attached to the Gitea release. Latest tag today is **`v0.1.0`**.
|
||||||
|
|
||||||
|
## Change: new workflow `.gitea/workflows/gitops-update.yaml`
|
||||||
|
|
||||||
|
Triggers:
|
||||||
|
- `workflow_run` on `workflows: ["Build and Push"]`, `types: [completed]`, gated
|
||||||
|
to `conclusion == 'success'` — auto-fires after the image build succeeds.
|
||||||
|
- `workflow_dispatch` with inputs: `tag` (git tag without the `-go` suffix, e.g.
|
||||||
|
`0.37`), `dry_run` (boolean, default false), `uh_cli_version` (optional override).
|
||||||
|
|
||||||
|
Single job `gitops-pr`, `runs-on: ubuntu-latest`, in a `container: ubuntu:latest`
|
||||||
|
for a hermetic install (matches the uh-cli CI doc pattern). Steps:
|
||||||
|
|
||||||
|
1. **Install git, curl, ca-certificates, tea** — apt-get + download tea
|
||||||
|
`0.9.2` from `gitea.com/gitea/tea/releases/...` to `/usr/local/bin/tea`.
|
||||||
|
2. **Install uh-cli** — download
|
||||||
|
`https://gitea.home.hrajfrisbee.cz/kacerr/uh-cli/releases/download/${UH_CLI_VERSION}/uh-cli-${UH_CLI_VERSION}-linux-amd64`
|
||||||
|
to `/usr/local/bin/uh-cli`.
|
||||||
|
`UH_CLI_VERSION: ${{ inputs.uh_cli_version || vars.UH_CLI_VERSION || 'v0.1.0' }}`.
|
||||||
|
3. **Resolve image tag** — if `workflow_dispatch`, use `inputs.tag`; else use
|
||||||
|
`github.event.workflow_run.head_branch` (the pushed tag name). Output
|
||||||
|
`gitea.home.hrajfrisbee.cz/${{ github.repository }}:<tag>-go`.
|
||||||
|
4. **Configure git identity** — `git config --global user.name/email` for the bot.
|
||||||
|
5. **Authenticate tea** — `tea login add --name ci --url https://gitea.home.hrajfrisbee.cz --token "$GITEA_TOKEN"`.
|
||||||
|
6. **Open image-update PR** — run, with `--dry-run` appended only when the
|
||||||
|
dispatch `dry_run` input is true:
|
||||||
|
```
|
||||||
|
uh-cli -v gitops deployment update \
|
||||||
|
--deployment-name fuj-management \
|
||||||
|
--deployment-namespace fuj \
|
||||||
|
--set-image "<resolved image>" \
|
||||||
|
--git-repo "https://fuj-gitops-bot:${GITEA_TOKEN}@gitea.home.hrajfrisbee.cz/kacerr/home-kubernetes" \
|
||||||
|
--git-path gitops/home-kubernetes
|
||||||
|
```
|
||||||
|
|
||||||
|
`GITEA_TOKEN` is sourced from `secrets.GITOPS_TOKEN` at job level.
|
||||||
|
|
||||||
|
Job-level guard: `if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}`.
|
||||||
|
|
||||||
|
## Prerequisites (user must set up in Gitea — call out in handoff)
|
||||||
|
|
||||||
|
1. **Create `GITOPS_TOKEN` secret** in the `fuj-management` repo: a Gitea token
|
||||||
|
for a user (`fuj-gitops-bot` or `kacerr`) that has **write + pull-request**
|
||||||
|
access to `kacerr/home-kubernetes`. The username in the `--git-repo` URL must
|
||||||
|
match that token's owner (adjust `fuj-gitops-bot` if using `kacerr`).
|
||||||
|
2. **uh-cli `v0.1.0` release assets must exist** (the `uh-cli-v0.1.0-linux-amd64`
|
||||||
|
binary attached to the release). If not yet published, cut that release in the
|
||||||
|
uh-cli repo first, or set `UH_CLI_VERSION` to a published tag.
|
||||||
|
3. **Confirm the manifest path**: `--git-path gitops/home-kubernetes` must contain
|
||||||
|
the `fuj-management` Deployment; `--deployment-namespace fuj` disambiguates.
|
||||||
|
Cannot verify from this repo — verify against home-kubernetes (narrow the path
|
||||||
|
if uh-cli reports an ambiguity error).
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- **New**: `.gitea/workflows/gitops-update.yaml` (the workflow above).
|
||||||
|
- After it works: prepend a `CHANGELOG.md` entry; save this plan to
|
||||||
|
`docs/plans/<ts>-gitops-pr-action.md` per CLAUDE.md convention.
|
||||||
|
|
||||||
|
## Branching
|
||||||
|
|
||||||
|
Feature work → branch `feat/gitops-pr-action` off `main`, commit with the
|
||||||
|
`Co-Authored-By` trailer, push with `-u`, open the MR with
|
||||||
|
`tea pr create --base main --head feat/gitops-pr-action`. Do not merge from CLI.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
1. **Dry run (manual)**: trigger `gitops-update.yaml` via workflow_dispatch with
|
||||||
|
`tag=0.37`, `dry_run=true`. Confirm logs show the unified diff (image line
|
||||||
|
`…:0.37-go`) and `-v` debug milestones; **no PR** is created.
|
||||||
|
2. **Real run (manual)**: re-trigger with `dry_run=false`. Confirm a PR appears in
|
||||||
|
`home-kubernetes` against `main` with the image bump, and the PR URL is printed.
|
||||||
|
3. **Auto-trigger**: push a new git tag to fuj-management → `Build and Push`
|
||||||
|
completes → `gitops-update` fires via `workflow_run` and opens the PR.
|
||||||
|
(Note: `workflow_run`/`head_branch` behavior depends on this Gitea/act_runner
|
||||||
|
version; if it doesn't fire, manual `workflow_dispatch` is the fallback and the
|
||||||
|
plan still delivers the core capability.)
|
||||||
Reference in New Issue
Block a user