Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d47b71b
feat(ci): migrate CI/CD from Azure Pipelines to GitHub Actions (#18)
Starosdev Mar 18, 2026
ba7a8a8
fix(ci): use self-hosted SonarQube instead of SonarCloud (#18)
Starosdev Mar 18, 2026
e0a17c4
fix(ci): separate Discord webhook ID from channel ID (#18)
Starosdev Mar 18, 2026
bf20f0d
Merge feature/RAD-18-github-actions-ci into develop
Starosdev Mar 18, 2026
7a27db3
fix(ci): resolve actionlint errors in workflow (#18)
Starosdev Mar 19, 2026
cd606ad
fix(ci): allow workflow changes to trigger CI (#18)
Starosdev Mar 19, 2026
f3953cb
fix(ci): resolve build failures from first CI run (#18)
Starosdev Mar 19, 2026
4efebc2
fix(ci): resolve test reporter, webpack, and SonarQube issues (#18)
Starosdev Mar 19, 2026
ea5db0d
fix: resolve lint errors in frontend test files (#18)
Starosdev Mar 19, 2026
dda5e10
fix(ci): exclude test files from webpack/tsc, fix SonarScanner args (…
Starosdev Mar 19, 2026
1fc11ba
fix(ci): handle missing net8.0-windows output, exclude tests from ESL…
Starosdev Mar 19, 2026
1d8f150
fix(ci): fix installer and sentry source map upload (#18)
Starosdev Mar 19, 2026
46322c4
fix(ci): add checkout to sentry job for set-commits (#18)
Starosdev Mar 19, 2026
290f806
feat(ci): update Sentry config for Starosdev fork (#21)
Starosdev Mar 21, 2026
7f3b6ac
Merge branch 'feature/RAD-21-update-sentry-config' into develop
Starosdev Mar 21, 2026
ac7a380
fix(host): use ordinal comparison for Uri pattern matching (#22)
Starosdev Mar 21, 2026
fa06a5b
fix(host): use ordinal comparison for remaining EndsWith calls (#22)
Starosdev Mar 21, 2026
6b8b4da
Merge branch 'fix/RAD-22-turkish-locale-crash' into develop
Starosdev Mar 21, 2026
001635e
fix(http): serve intermediate CA certificates from PFX on Linux (#23)
Starosdev Mar 21, 2026
cb79f30
Merge branch 'fix/RAD-23-kestrel-intermediate-ca' into develop
Starosdev Mar 21, 2026
ae5b47f
fix(ci): update Inno Setup to 6.4.2 and add curl error handling
Starosdev Mar 21, 2026
1fa77d5
Merge branch 'master' into develop
Starosdev Mar 21, 2026
414207b
fix(ci): use Chocolatey for Inno Setup, fix Sentry set-commits
Starosdev Mar 21, 2026
f3a17f6
fix(ci): use pre-installed Inno Setup on Windows runner
Starosdev Mar 21, 2026
f799c4b
Merge branch 'master' into develop
Starosdev Mar 21, 2026
d6769a7
feat(docker): add Dockerfile for container builds
Starosdev Mar 22, 2026
825a463
feat(ci): add Gitleaks secret scanning workflow
Starosdev Mar 22, 2026
b8f04cd
feat(ci): add GitHub Release job for develop and master builds
Starosdev Mar 22, 2026
620ad07
feat(ci): add stale branch cleanup workflow
Starosdev Mar 22, 2026
e843212
feat(ci): add Docker build and push to GHCR
Starosdev Mar 22, 2026
3c1fb1a
feat(ci): update Discord notification, clean up Inno Setup env vars
Starosdev Mar 22, 2026
4bcef63
chore: add docs/plans/ to gitignore
Starosdev Mar 22, 2026
8d6fa04
Merge branch 'feature/RAD-release-pipeline' into develop
Starosdev Mar 22, 2026
e1be92a
fix(docker): handle existing GID/UID in base image
Starosdev Mar 22, 2026
efd743b
fix(ci): drop arm/v7 from Docker builds (no Noble base image)
Starosdev Mar 22, 2026
9077094
fix(ci): add --amend flag to docker manifest create
Starosdev Mar 22, 2026
3ae0993
fix(ci): use buildx imagetools for multi-arch manifest creation
Starosdev Mar 22, 2026
2591eb7
fix(ci): update GHCR image namespace to staros-labs
Starosdev Apr 30, 2026
0fd0785
[OPS] v1.0.0 — standardize develop and master workflow
Starosdev May 9, 2026
9407929
[OPS] v1.0.1 — bump MailKit to patched release for CI
Starosdev May 9, 2026
ccdf8d0
fix(ci): patch MailKit vuln and harden secret scan
Starosdev May 9, 2026
f2b4b81
fix(merge): resolve develop/master conflicts in .gitignore and AGENTS.md
Starosdev May 9, 2026
565a764
fix(ci): make release tag creation idempotent
Starosdev May 10, 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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!radarr/
204 changes: 201 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ env:
MAJOR_VERSION: '6.1.1'
DOTNET_VERSION: '8.0.405'
NODE_VERSION: '20.19.0'
INNO_VERSION: '6.4.2'

jobs:
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -282,6 +281,192 @@ jobs:
name: packages
path: _archives/

# ---------------------------------------------------------------------------
# Release: create GitHub Release with package assets
# ---------------------------------------------------------------------------
release:
runs-on: ubuntu-24.04
needs: [packages, installer, setup]
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master')
permissions:
contents: write
env:
RADARR_VERSION: ${{ needs.setup.outputs.radarr_version }}
BRANCH_NAME: ${{ needs.setup.outputs.branch_name }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Download packages
uses: actions/download-artifact@v4
with:
name: packages
path: _release/

- name: Download installer
uses: actions/download-artifact@v4
with:
name: windows-installer
path: _release/

- name: Generate checksums
working-directory: _release
run: |
sha256sum * > sha256sums.txt
cat sha256sums.txt

- name: Determine release type
id: release-type
run: |
if [ "${{ github.ref }}" = "refs/heads/master" ]; then
echo "prerelease=false" >> "$GITHUB_OUTPUT"
echo "tag=v${RADARR_VERSION}" >> "$GITHUB_OUTPUT"
else
echo "prerelease=true" >> "$GITHUB_OUTPUT"
echo "tag=v${RADARR_VERSION}-nightly" >> "$GITHUB_OUTPUT"
fi

- name: Create git tag
env:
TAG: ${{ steps.release-type.outputs.tag }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -d "${TAG}" 2>/dev/null || true
git push origin ":refs/tags/${TAG}" 2>/dev/null || true
git tag -a "${TAG}" -m "Release ${TAG}"
git push origin "${TAG}"

- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.release-type.outputs.tag }}
PRERELEASE: ${{ steps.release-type.outputs.prerelease }}
run: |
RELEASE_ARGS=(
"${TAG}"
--repo Starosdev/Radarr
--title "Radarr v${RADARR_VERSION}"
--generate-notes
)

if [ "${PRERELEASE}" = "true" ]; then
RELEASE_ARGS+=(--prerelease)
else
RELEASE_ARGS+=(--latest)
fi

gh release create "${RELEASE_ARGS[@]}" _release/*

# ---------------------------------------------------------------------------
# Docker: build and push per-arch images to GHCR
# ---------------------------------------------------------------------------
docker:
runs-on: ubuntu-24.04
needs: [packages, setup]
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master')
permissions:
contents: read
packages: write
env:
RADARR_VERSION: ${{ needs.setup.outputs.radarr_version }}
BUILDNAME: ${{ needs.setup.outputs.branch_name }}.${{ needs.setup.outputs.radarr_version }}
REGISTRY: ghcr.io
IMAGE_NAME: staros-labs/radarr
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
archive_rid: linux-core-x64
- platform: linux/arm64
archive_rid: linux-core-arm64
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Download packages
uses: actions/download-artifact@v4
with:
name: packages
path: _archives/

- name: Extract package for platform
run: |
mkdir -p radarr
tar xzf _archives/Radarr.${BUILDNAME}.${{ matrix.archive_rid }}.tar.gz -C radarr/

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ matrix.platform }}

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

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: ${{ matrix.platform }}
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.RADARR_VERSION }}-${{ matrix.archive_rid }}
labels: |
org.opencontainers.image.title=Radarr
org.opencontainers.image.version=${{ env.RADARR_VERSION }}
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
cache-from: type=gha,scope=${{ matrix.archive_rid }}
cache-to: type=gha,mode=max,scope=${{ matrix.archive_rid }}

# ---------------------------------------------------------------------------
# Docker Manifest: combine per-arch images into multi-arch manifest
# ---------------------------------------------------------------------------
docker-manifest:
runs-on: ubuntu-24.04
needs: [docker, setup]
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master')
permissions:
packages: write
env:
RADARR_VERSION: ${{ needs.setup.outputs.radarr_version }}
REGISTRY: ghcr.io
IMAGE_NAME: staros-labs/radarr
steps:
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

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

- name: Create and push manifests
run: |
VERSION_TAG="${REGISTRY}/${IMAGE_NAME}:${RADARR_VERSION}"
BRANCH_TAG="${REGISTRY}/${IMAGE_NAME}:${{ github.ref == 'refs/heads/master' && 'latest' || 'develop' }}"

docker buildx imagetools create -t "${VERSION_TAG}" \
"${REGISTRY}/${IMAGE_NAME}:${RADARR_VERSION}-linux-core-x64" \
"${REGISTRY}/${IMAGE_NAME}:${RADARR_VERSION}-linux-core-arm64"

docker buildx imagetools create -t "${BRANCH_TAG}" \
"${REGISTRY}/${IMAGE_NAME}:${RADARR_VERSION}-linux-core-x64" \
"${REGISTRY}/${IMAGE_NAME}:${RADARR_VERSION}-linux-core-arm64"

# ---------------------------------------------------------------------------
# Lint
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -694,7 +879,6 @@ jobs:
env:
RADARRVERSION: ${{ needs.setup.outputs.radarr_version }}
MAJORVERSION: '6.1.1'
INNOVERSION: '6.4.2'
BUILD_SOURCEBRANCHNAME: ${{ needs.setup.outputs.branch_name }}
BUILDNAME: ${{ needs.setup.outputs.branch_name }}.${{ needs.setup.outputs.radarr_version }}
steps:
Expand Down Expand Up @@ -947,6 +1131,8 @@ jobs:
- integration-docker
- integration-postgres
- installer
- release
- docker-manifest
- sentry
- sonarqube-frontend
- sonarqube-backend
Expand All @@ -972,6 +1158,18 @@ jobs:

RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"

RELEASE_URL="${{ github.server_url }}/${{ github.repository }}/releases/tag/v${RADARR_VERSION}${{ github.ref == 'refs/heads/develop' && '-nightly' || '' }}"

RELEASE_FIELD=""
if [ "${{ needs.release.result }}" = "success" ]; then
RELEASE_FIELD=",{\"name\": \"Release\", \"value\": \"[v${RADARR_VERSION}](${RELEASE_URL})\", \"inline\": true}"
fi

DOCKER_FIELD=""
if [ "${{ needs.docker-manifest.result }}" = "success" ]; then
DOCKER_FIELD=",{\"name\": \"Docker\", \"value\": \"ghcr.io/starosdev/radarr:${RADARR_VERSION}\", \"inline\": true}"
fi

# Only send if webhook is configured
if [ -n "$DISCORD_WEBHOOK_KEY" ] && [ -n "$DISCORD_WEBHOOK_ID" ]; then
curl -s -H "Content-Type: application/json" \
Expand All @@ -984,7 +1182,7 @@ jobs:
\"color\": ${COLOR},
\"fields\": [
{\"name\": \"Branch\", \"value\": \"${BRANCH_NAME}\", \"inline\": true},
{\"name\": \"Version\", \"value\": \"${RADARR_VERSION}\", \"inline\": true}
{\"name\": \"Version\", \"value\": \"${RADARR_VERSION}\", \"inline\": true}${RELEASE_FIELD}${DOCKER_FIELD}
]
}]
}" \
Expand Down
138 changes: 138 additions & 0 deletions .github/workflows/cleanup-branches.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: Cleanup Stale Branches

on:
schedule:
- cron: '0 3 * * 0' # Weekly on Sunday at 3 AM UTC
workflow_dispatch:

permissions:
contents: write

jobs:
cleanup:
name: Delete Stale Merged Branches
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Configure Git
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"

- name: Fetch All Branches
run: git fetch --all --prune

- name: Find and Delete Stale Branches
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "=================================================="
echo "Stale Branch Cleanup - $(date)"
echo "=================================================="
echo ""

PROTECTED_BRANCHES="master develop"
DELETED_COUNT=0
KEPT_COUNT=0

echo "Scanning for stale branches (merged >30 days ago)..."
echo ""

for branch in $(git branch -r | grep -v '\->' | grep -v 'HEAD' | sed 's/origin\///'); do
skip=false
for protected in $PROTECTED_BRANCHES; do
if [ "$branch" = "$protected" ]; then
skip=true
break
fi
done

if [ "$skip" = true ]; then
continue
fi

merged_to_develop=$(git branch -r --merged origin/develop | grep -cxF " origin/$branch" || echo "0")
merged_to_master=$(git branch -r --merged origin/master | grep -cxF " origin/$branch" || echo "0")

# Check GitHub API for squash-merged PRs
if [ "$merged_to_develop" = "0" ] && [ "$merged_to_master" = "0" ]; then
pr_merged=$(gh pr list --repo "${{ github.repository }}" --head "$branch" --state merged --json number --jq 'length' 2>/dev/null || echo "0")
if [ "$pr_merged" != "0" ] && [ "$pr_merged" != "" ]; then
pr_base=$(gh pr list --repo "${{ github.repository }}" --head "$branch" --state merged --json baseRefName --jq '.[0].baseRefName' 2>/dev/null || echo "")
if [ "$pr_base" = "develop" ]; then
merged_to_develop="1"
elif [ "$pr_base" = "master" ]; then
merged_to_master="1"
else
merged_to_develop="1"
fi
fi
fi

if [ "$merged_to_develop" = "0" ] && [ "$merged_to_master" = "0" ]; then
KEPT_COUNT=$((KEPT_COUNT + 1))
continue
fi

LAST_COMMIT_DATE=$(git log -1 --format="%ci" "origin/$branch" 2>/dev/null || echo "1970-01-01")
LAST_COMMIT_EPOCH=$(date -d "$LAST_COMMIT_DATE" +%s 2>/dev/null || echo "0")
CURRENT_EPOCH=$(date +%s)
DAYS_OLD=$(( (CURRENT_EPOCH - LAST_COMMIT_EPOCH) / 86400 ))

if [ "$DAYS_OLD" -gt 30 ]; then
merged_to=""
[ "$merged_to_develop" != "0" ] && merged_to="develop"
if [ "$merged_to_master" != "0" ]; then
[ -n "$merged_to" ] && merged_to="$merged_to and master" || merged_to="master"
fi

echo " Deleting: $branch"
echo " Last commit: $DAYS_OLD days ago"
echo " Merged to: $merged_to"

git push origin --delete "$branch" 2>&1 | sed 's/^/ /' || {
echo " WARNING: Failed to delete $branch"
}

DELETED_COUNT=$((DELETED_COUNT + 1))
echo ""
else
KEPT_COUNT=$((KEPT_COUNT + 1))
fi
done

echo ""
echo "=================================================="
echo "Cleanup Summary"
echo "=================================================="
echo "Deleted branches: $DELETED_COUNT"
echo "Kept branches: $KEPT_COUNT"
echo "Protected branches: $PROTECTED_BRANCHES"

- name: List Remaining Feature Branches
run: |
echo ""
echo "=================================================="
echo "Remaining Feature/Development Branches"
echo "=================================================="

PATTERN='feature/|fix/|hotfix/'
REMAINING=$(git branch -r | grep -E "$PATTERN" | grep -v 'origin/master' | grep -v 'origin/develop' | sed 's/origin\///' | wc -l)

if [ "$REMAINING" -gt 0 ]; then
echo "Found $REMAINING active feature branches:"
echo ""
git branch -r | grep -E "$PATTERN" | grep -v 'origin/master' | grep -v 'origin/develop' | sed 's/origin\///' | while read branch; do
LAST_COMMIT=$(git log -1 --format="%ci" "origin/$branch" 2>/dev/null | cut -d' ' -f1)
AUTHOR=$(git log -1 --format="%an" "origin/$branch" 2>/dev/null)
echo " $branch"
echo " Last commit: $LAST_COMMIT by $AUTHOR"
done
else
echo "No active feature branches remaining."
fi
Loading
Loading