Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d11d2ab
Initial commit
dabrign Mar 7, 2025
e79a58c
feat: bootstrap
Mar 7, 2025
22fa591
chore: working on it
Apr 18, 2025
36d832d
chore: better logging
Apr 18, 2025
da3c788
feat! opus try
Fuochi Feb 10, 2026
f960349
chore: claudio cleaning
Fuochi Feb 28, 2026
d558a45
chore: claudio fmt and lint
Fuochi Feb 28, 2026
6da9844
ci: install k3d for E2E tests, optimize pipeline parallelism and caching
Fuochi Feb 28, 2026
1532fcd
ci: remove --no-lb from E2E k3d cluster (needed for port mapping)
Fuochi Feb 28, 2026
f4ba4e9
ci: set imagePullPolicy to IfNotPresent in deployment manifest
Fuochi Feb 28, 2026
3ab48bf
ci: increase Sonarr CR wait timeout to 360s to avoid race with operat…
Fuochi Feb 28, 2026
a53ea88
fix: controller field mapping, quality profile population, E2E test data
Fuochi Feb 28, 2026
ae54680
feat: add CI/CD workflow for release management and multi-arch image …
Fuochi Feb 28, 2026
546cb74
refactor: streamline Makefile for improved testing and E2E workflows
Fuochi Feb 28, 2026
a2241db
feat: add workflow to generate and publish CRDs and documentation on …
Fuochi Feb 28, 2026
fff04f0
chore: update inconsistent doc
Fuochi Mar 13, 2026
eafa7ff
fix: clean up unused code
Fuochi Mar 13, 2026
210d227
fix: missing release please manifest
Fuochi Mar 13, 2026
29da9f9
feat: integrate DevOpsArrBOT for token management and update git conf…
Fuochi Mar 13, 2026
53ba386
feat: move to helm release
Fuochi May 31, 2026
3b22a6b
refactor: simplify error messages in integration tests and improve co…
Fuochi May 31, 2026
c0202fe
ci: fix integration test matrix and shellcheck warnings
Fuochi Jul 30, 2026
565eef5
chore: merge initial main into bootstrap branch
Fuochi Jul 30, 2026
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
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/.github
/target
/tests
/docs
/deploy
.vscode
.cursorrules
.idea
Dockerfile
.dockerignore
.gitignore
Makefile
README.md
AI_PLAN.md
LICENSE
release-please-config.json
.release-please-manifest.json
277 changes: 277 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
name: Release

on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write
packages: write
id-token: write # required for cosign keyless signing

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# OCI repository for the operator chart. Note: the GHCR namespace must
# already exist as a package; first push will create it.
CHART_OCI_REPO: oci://ghcr.io/${{ github.repository_owner }}/charts

jobs:
# ============================================
# Release Please - Multi-Package Version Management
#
# Two linked packages:
# - `.` (rust crate / operator binary)
# - `charts/sonarr-operator` (helm chart)
# Versions are kept in lockstep by the `linked-versions` plugin.
# ============================================
release-please:
name: Release Please
runs-on: ubuntu-latest
outputs:
# Operator (root) package outputs
operator_released: ${{ steps.release.outputs['.--release_created'] }}
operator_tag: ${{ steps.release.outputs['.--tag_name'] }}
operator_version: ${{ steps.release.outputs['.--version'] }}
# Chart package outputs
chart_released: ${{
steps.release.outputs['charts/sonarr-operator--release_created']
}}
chart_tag: ${{ steps.release.outputs['charts/sonarr-operator--tag_name'] }}
chart_version: ${{ steps.release.outputs['charts/sonarr-operator--version'] }}
steps:
- name: DevOpsArrBOT token
id: DevOpsArrBOT
uses: getsentry/action-github-app-token@v3
with:
app_id: '305652'
private_key: ${{ secrets.DEVOPSARRBOT_PRIVATE_KEY }}

- name: Set DevOpsArrBOT config
run: |
git config --global user.name "devopsarr[bot]"
git config --global user.email "127950054+devopsarr[bot]@users.noreply.github.com"

- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.DevOpsArrBOT.outputs.token }}

- name: Release Please
id: release
uses: googleapis/release-please-action@v4
with:
token: ${{ steps.DevOpsArrBOT.outputs.token }}

# ============================================
# Build, Push & Sign Multi-arch Operator Image
# ============================================
build-and-push:
name: Build & Push Multi-arch Image
runs-on: ubuntu-latest
needs: release-please
if: ${{ needs.release-please.outputs.operator_released == 'true' }}
permissions:
contents: read
packages: write
id-token: write
steps:
- uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Install cosign
uses: sigstore/cosign-installer@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern=v{{version}},value=${{ needs.release-please.outputs.operator_version }}
type=semver,pattern=v{{major}}.{{minor}},value=${{ needs.release-please.outputs.operator_version }}
type=semver,pattern=v{{major}},value=${{ needs.release-please.outputs.operator_version }}
type=raw,value=latest

- name: Build and push multi-arch Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Sign the image (keyless)
env:
COSIGN_EXPERIMENTAL: "true"
DIGEST: ${{ steps.build.outputs.digest }}
TAGS: ${{ steps.meta.outputs.tags }}
run: |
for tag in $TAGS; do
cosign sign --yes "${tag}@${DIGEST}"
done

# ============================================
# Publish & Sign Operator Helm Chart (OCI)
# ============================================
publish-chart:
name: Publish Helm Chart
runs-on: ubuntu-latest
needs: [ release-please, build-and-push ]
# `always() && ...` lets the chart publish even if build-and-push was
# skipped (chart-only release), but blocks publish if image build failed.
if: ${{ always() && needs.release-please.outputs.chart_released == 'true' &&
(needs.build-and-push.result == 'success' ||
needs.build-and-push.result == 'skipped') }}
permissions:
contents: write
packages: write
id-token: write
steps:
- name: DevOpsArrBOT token
id: DevOpsArrBOT
uses: getsentry/action-github-app-token@v3
with:
app_id: '305652'
private_key: ${{ secrets.DEVOPSARRBOT_PRIVATE_KEY }}

- uses: actions/checkout@v4
with:
# Pull the tagged release commit so Chart.yaml has the right version.
ref: ${{ needs.release-please.outputs.chart_tag }}
token: ${{ steps.DevOpsArrBOT.outputs.token }}

- uses: azure/setup-helm@v4
- uses: sigstore/cosign-installer@v3

- name: Log in to GHCR for Helm
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | \
helm registry login ${{ env.REGISTRY }} \
-u "${{ github.actor }}" --password-stdin

- name: Package chart
id: package
run: |
helm package charts/sonarr-operator -d dist/
pkg=$(ls dist/sonarr-operator-*.tgz)
echo "path=${pkg}" >> "$GITHUB_OUTPUT"
echo "name=$(basename "${pkg}")" >> "$GITHUB_OUTPUT"

- name: Push chart to GHCR
id: push
run: |
out=$(helm push "${{ steps.package.outputs.path }}" "${{ env.CHART_OCI_REPO }}" 2>&1)
echo "$out"
digest=$(echo "$out" | awk '/Digest:/ {print $2}')
echo "digest=${digest}" >> "$GITHUB_OUTPUT"

- name: Sign chart (keyless)
env:
COSIGN_EXPERIMENTAL: "true"
run: |
cosign sign --yes \
"${{ env.REGISTRY }}/${{ github.repository_owner }}/charts/sonarr-operator@${{ steps.push.outputs.digest }}"

- name: Attach chart tarball to GH release
env:
GITHUB_TOKEN: ${{ steps.DevOpsArrBOT.outputs.token }}
run: |
gh release upload ${{ needs.release-please.outputs.chart_tag }} \
"${{ steps.package.outputs.path }}"

# ============================================
# Regenerate Docs & CRDs and Attach to Release
#
# Runs on operator release: regenerates the helm-templated CRDs in the
# chart (source of truth), derives the plain CRDs + docs from them,
# commits chart + docs back, and attaches plain CRDs to the GH release
# for users who don't use Helm.
# ============================================
publish-docs:
name: Publish Docs & CRDs
runs-on: ubuntu-latest
needs: release-please
if: ${{ needs.release-please.outputs.operator_released == 'true' }}
permissions:
contents: write
steps:
- name: DevOpsArrBOT token
id: DevOpsArrBOT
uses: getsentry/action-github-app-token@v3
with:
app_id: '305652'
private_key: ${{ secrets.DEVOPSARRBOT_PRIVATE_KEY }}

- uses: actions/checkout@v4
with:
ref: main
token: ${{ steps.DevOpsArrBOT.outputs.token }}

- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2

- uses: actions/setup-go@v5
with:
go-version: '1.22'

- uses: azure/setup-helm@v4

- name: Generate helm-templated CRDs into the chart
run: |
rm -f charts/sonarr-operator/templates/crds/*.yaml
cargo run --bin crdgen -- --split charts/sonarr-operator/templates/crds --helm

- name: Render plain CRDs (for docs and release asset)
run: |
mkdir -p artifacts/crds
helm template sonarr-operator charts/sonarr-operator \
--namespace sonarr-operator-system \
--set crds.install=true \
--set crds.keep=false \
--show-only 'templates/crds/*.yaml' \
> artifacts/crds/all.yaml

- name: Generate documentation
run: |
go install fybrik.io/crdoc@latest
mkdir -p docs/api
crdoc --resources artifacts/crds --output docs/api/crd-reference.md

- name: Commit and push docs
run: |
git config user.name "devopsarr[bot]"
git config user.email "127950054+devopsarr[bot]@users.noreply.github.com"
git add charts/sonarr-operator/templates/crds/ docs/api/
if git diff --cached --quiet; then
echo "No documentation changes to commit"
else
git commit -m "docs: update CRDs and documentation for ${{ needs.release-please.outputs.operator_tag }}"
git push
fi

- name: Attach CRDs to release
env:
GITHUB_TOKEN: ${{ steps.DevOpsArrBOT.outputs.token }}
run: |
cp artifacts/crds/all.yaml crds.yaml
tar czf crds.tar.gz -C artifacts/crds .
gh release upload ${{ needs.release-please.outputs.operator_tag }} crds.tar.gz crds.yaml
Loading
Loading