diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 6a5e4aad..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,14 +0,0 @@ -on: - workflow_dispatch: - workflow_call: - -jobs: - build: - uses: flmorg/universal-workflows-testing/.github/workflows/dotnet.build.app.yml@main - with: - dockerRepository: flaminel/cleanuperr - githubContext: ${{ toJSON(github) }} - outputName: cleanuperr - selfContained: false - baseImage: 9.0-bookworm-slim - secrets: inherit \ No newline at end of file diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml new file mode 100644 index 00000000..0816a111 --- /dev/null +++ b/.github/workflows/build_docker.yml @@ -0,0 +1,125 @@ +name: Build Docker Images + +on: + push: + tags: + - "v*.*.*" + pull_request: + paths: + - 'code/**' + workflow_dispatch: + workflow_call: + +jobs: + build_app: + runs-on: ubuntu-latest + steps: + + - name: Set github context + timeout-minutes: 1 + run: | + echo 'githubRepository=${{ github.repository }}' >> $GITHUB_ENV + echo 'githubSha=${{ github.sha }}' >> $GITHUB_ENV + echo 'githubRef=${{ github.ref }}' >> $GITHUB_ENV + echo 'githubHeadRef=${{ github.head_ref }}' >> $GITHUB_ENV + + - name: Initialize build info + timeout-minutes: 1 + run: | + githubHeadRef=${{ env.githubHeadRef }} + latestDockerTag="" + versionDockerTag="" + version="0.0.1" + + if [[ "$githubRef" =~ ^"refs/tags/" ]]; then + branch=${githubRef##*/} + latestDockerTag="latest" + versionDockerTag=${branch#v} + version=${branch#v} + else + # Determine if this run is for the main branch or another branch + if [[ -z "$githubHeadRef" ]]; then + # Main branch + githubRef=${{ env.githubRef }} + branch=${githubRef##*/} + versionDockerTag="$branch" + else + # Pull request + branch=$githubHeadRef + versionDockerTag="$branch" + fi + fi + + githubTags="" + + if [ -n "$latestDockerTag" ]; then + githubTags="$githubTags,ghcr.io/cleanuparr:$latestDockerTag" + fi + + if [ -n "$versionDockerTag" ]; then + githubTags="$githubTags,ghcr.io/cleanuparr:$versionDockerTag" + fi + + # set env vars + echo "branch=$branch" >> $GITHUB_ENV + echo "githubTags=$githubTags" >> $GITHUB_ENV + echo "versionDockerTag=$versionDockerTag" >> $GITHUB_ENV + echo "version=$version" >> $GITHUB_ENV + + - name: Get vault secrets + uses: hashicorp/vault-action@v2 + with: + url: ${{ secrets.VAULT_HOST }} + method: approle + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: + secrets/data/docker username | DOCKER_USERNAME; + secrets/data/docker password | DOCKER_PASSWORD; + secrets/data/github repo_readonly_pat | REPO_READONLY_PAT; + secrets/data/github packages_pat | PACKAGES_PAT + + - name: Checkout target repository + uses: actions/checkout@v4 + timeout-minutes: 1 + with: + repository: ${{ env.githubRepository }} + ref: ${{ env.branch }} + token: ${{ env.REPO_READONLY_PAT }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + timeout-minutes: 5 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push docker image + timeout-minutes: 15 + uses: docker/build-push-action@v6 + with: + context: ${{ github.workspace }}/code + file: ${{ github.workspace }}/code/Dockerfile + provenance: false + labels: | + commit=sha-${{ env.githubSha }} + version=${{ env.versionDockerTag }} + build-args: | + VERSION=${{ env.version }} + PACKAGES_USERNAME=${{ env.PACKAGES_USERNAME }} + PACKAGES_PAT=${{ env.PACKAGES_PAT }} + outputs: | + type=image + platforms: | + linux/amd64 + linux/arm64 + push: true + tags: | + ${{ env.githubTags }} \ No newline at end of file diff --git a/.github/workflows/build_executable.yml b/.github/workflows/build_executable.yml new file mode 100644 index 00000000..52b07f56 --- /dev/null +++ b/.github/workflows/build_executable.yml @@ -0,0 +1,124 @@ +name: Build Executables + +on: + push: + tags: + - "v*.*.*" + +jobs: + release: + uses: flmorg/universal-workflows/.github/workflows/dotnet.release.yml@main + with: + githubContext: ${{ toJSON(github) }} + secrets: inherit + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: Gate + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + run: | + echo "This is not a tag event. Pipeline finished." + exit + + - name: Set variables + run: | + repoFullName=${{ fromJSON(inputs.githubContext).repository }} + ref=${{ fromJSON(inputs.githubContext).ref }} + releaseVersion=${ref##refs/tags/} + appVersion=${releaseVersion#v} + + echo 'githubRepository=${{ github.repository }}' >> $GITHUB_ENV + echo "githubRepositoryName=${repoFullName#*/}" >> $GITHUB_ENV + echo "releaseVersion=$releaseVersion" >> $GITHUB_ENV + echo "appVersion=$appVersion" >> $GITHUB_ENV + + - name: Get vault secrets + uses: hashicorp/vault-action@v2 + with: + url: ${{ secrets.VAULT_HOST }} + method: approle + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: + secrets/data/github repo_readonly_pat | REPO_READONLY_PAT; + secrets/data/github packages_pat | PACKAGES_PAT + + - name: Checkout target repository + uses: actions/checkout@v4 + timeout-minutes: 1 + with: + repository: ${{ env.githubRepository }} + ref: main + token: ${{ env.REPO_READONLY_PAT }} + + - name: Setup dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Install dependencies + run: | + dotnet nuget add source --username Flaminel --password ${{ secrets.PACKAGES_PAT }} --store-password-in-clear-text --name flmorg https://nuget.pkg.github.com/flmorg/index.json + dotnet restore code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj + + - name: Build win-x64 + run: dotnet publish code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj -c Release --runtime win-x64 --self-contained -o artifacts/${{ env.githubRepositoryName }}-win-amd64 /p:PublishSingleFile=true /p:Version=${{ env.appVersion }} + + - name: Build linux-x64 + run: dotnet publish code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj -c Release --runtime linux-x64 --self-contained -o artifacts/${{ env.githubRepositoryName }}-linux-amd64 /p:PublishSingleFile=true /p:Version=${{ env.appVersion }} + + - name: Build linux-arm64 + run: dotnet publish code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj -c Release --runtime linux-arm64 --self-contained -o artifacts/${{ env.githubRepositoryName }}-linux-arm64 /p:PublishSingleFile=true /p:Version=${{ env.appVersion }} + + - name: Build osx-x64 + run: dotnet publish code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj -c Release --runtime osx-x64 --self-contained -o artifacts/${{ env.githubRepositoryName }}-osx-amd64 /p:PublishSingleFile=true /p:Version=${{ env.appVersion }} + + - name: Build osx-arm64 + run: dotnet publish code/${{ inputs.executableName }}/${{ inputs.executableName }}.csproj -c Release --runtime osx-arm64 --self-contained -o artifacts/${{ env.githubRepositoryName }}-osx-arm64 /p:PublishSingleFile=true /p:Version=${{ env.appVersion }} + + - name: Zip win-x64 + run: | + cd ./artifacts + zip ./${{ env.githubRepositoryName }}-win-amd64.zip ./${{ env.githubRepositoryName }}-win-amd64/${{ env.githubRepositoryName }}.exe ./${{ env.githubRepositoryName }}-win-amd64/appsettings.json + + - name: Zip linux-x64 + run: | + cd ./artifacts + zip ./${{ env.githubRepositoryName }}-linux-amd64.zip ./${{ env.githubRepositoryName }}-linux-amd64/${{ env.githubRepositoryName }} ./${{ env.githubRepositoryName }}-linux-amd64/appsettings.json + + - name: Zip linux-arm64 + run: | + cd ./artifacts + zip ./${{ env.githubRepositoryName }}-linux-arm64.zip ./${{ env.githubRepositoryName }}-linux-arm64/${{ env.githubRepositoryName }} ./${{ env.githubRepositoryName }}-linux-arm64/appsettings.json + + - name: Zip osx-x64 + run: | + cd ./artifacts + zip ./${{ env.githubRepositoryName }}-osx-amd64.zip ./${{ env.githubRepositoryName }}-osx-amd64/${{ env.githubRepositoryName }} ./${{ env.githubRepositoryName }}-osx-amd64/appsettings.json + + - name: Zip osx-arm64 + run: | + cd ./artifacts + zip ./${{ env.githubRepositoryName }}-osx-arm64.zip ./${{ env.githubRepositoryName }}-osx-arm64/${{ env.githubRepositoryName }} ./${{ env.githubRepositoryName }}-osx-arm64/appsettings.json + + - name: Release + id: release + uses: softprops/action-gh-release@v2 + with: + name: ${{ env.releaseVersion }} + tag_name: ${{ env.releaseVersion }} + repository: ${{ env.githubRepository }} + token: ${{ env.REPO_READONLY_PAT }} + make_latest: true + fail_on_unmatched_files: true + target_commitish: main + generate_release_notes: true + files: | + ./artifacts/${{ env.githubRepositoryName }}-win-amd64.zip + ./artifacts/${{ env.githubRepositoryName }}-linux-amd64.zip + ./artifacts/${{ env.githubRepositoryName }}-linux-arm64.zip + ./artifacts/${{ env.githubRepositoryName }}-osx-amd64.zip + ./artifacts/${{ env.githubRepositoryName }}-osx-arm64.zip \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 2c632ff2..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,19 +0,0 @@ -on: - workflow_call: - workflow_dispatch: - push: - paths: - - 'chart/**' - branches: [ main ] - -jobs: - deploy: - uses: flmorg/universal-workflows/.github/workflows/chart.install.yml@main - with: - githubContext: ${{ toJSON(github) }} - chartRepo: oci://ghcr.io/flmorg - chartName: universal-chart - version: ^1.0.0 - valuesPath: chart/values.yaml - releaseName: main - secrets: inherit \ No newline at end of file diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml deleted file mode 100644 index 640e9382..00000000 --- a/.github/workflows/pipeline.yml +++ /dev/null @@ -1,20 +0,0 @@ -on: - push: - tags: - - "v*.*.*" - # paths: - # - 'code/**' - # branches: [ main ] - pull_request: - paths: - - 'code/**' - -jobs: - build: - uses: flmorg/cleanuperr/.github/workflows/build.yml@main - secrets: inherit - - # deploy: - # needs: [ build ] - # uses: flmorg/cleanuperr/.github/workflows/deploy.yml@main - # secrets: inherit \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 37b246d3..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,11 +0,0 @@ -on: - push: - tags: - - "v*.*.*" - -jobs: - release: - uses: flmorg/universal-workflows/.github/workflows/dotnet.release.yml@main - with: - githubContext: ${{ toJSON(github) }} - secrets: inherit \ No newline at end of file diff --git a/chart/values.yaml b/chart/values.yaml deleted file mode 100644 index 73787c41..00000000 --- a/chart/values.yaml +++ /dev/null @@ -1,162 +0,0 @@ -deployment: - replicas: 1 - strategy: - type: RollingUpdate - maxSurge: 1 - maxUnavailable: 0 - containers: - - name: qbit - image: - repository: ghcr.io/flmorg/cleanuperr - tag: latest - env: - - name: DRY_RUN - value: "false" - - - name: LOGGING__LOGLEVEL - value: Verbose - - name: LOGGING__FILE__ENABLED - value: "true" - - name: LOGGING__FILE__PATH - value: /var/logs - - name: LOGGING__ENHANCED - value: "true" - - - name: TRIGGERS__QUEUECLEANER - value: 0 0/5 * * * ? - - name: TRIGGERS__CONTENTBLOCKER - value: 0 0/5 * * * ? - - - name: QUEUECLEANER__ENABLED - value: "true" - - name: QUEUECLEANER__RUNSEQUENTIALLY - value: "true" - - name: QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES - value: "3" - - name: QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE - value: "false" - - name: QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE - value: "false" - - name: QUEUECLEANER__STALLED_MAX_STRIKES - value: "3" - - name: QUEUECLEANER__STALLED_IGNORE_PRIVATE - value: "false" - - name: QUEUECLEANER__STALLED_DELETE_PRIVATE - value: "false" - - - name: CONTENTBLOCKER__ENABLED - value: "true" - - name: CONTENTBLOCKER__IGNORE_PRIVATE - value: "true" - - name: CONTENTBLOCKER__DELETE_PRIVATE - value: "false" - - - name: DOWNLOADCLEANER__ENABLED - value: "false" - - - name: DOWNLOAD_CLIENT - value: qbittorrent - - name: QBITTORRENT__URL - value: http://service.qbittorrent-videos.svc.cluster.local - - - name: SONARR__ENABLED - value: "true" - - name: SONARR__SEARCHTYPE - value: Episode - - name: SONARR__BLOCK__TYPE - value: blacklist - - name: SONARR__BLOCK__PATH - value: https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist - - name: SONARR__INSTANCES__0__URL - value: http://service.sonarr-low-res.svc.cluster.local - - name: SONARR__INSTANCES__1__URL - value: http://service.sonarr-high-res.svc.cluster.local - - - name: RADARR__ENABLED - value: "true" - - name: RADARR__BLOCK__TYPE - value: blacklist - - name: RADARR__BLOCK__PATH - value: https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist - - name: RADARR__INSTANCES__0__URL - value: http://service.radarr-low-res.svc.cluster.local - - name: RADARR__INSTANCES__1__URL - value: http://service.radarr-high-res.svc.cluster.local - - - name: NOTIFIARR__ON_IMPORT_FAILED_STRIKE - value: "true" - - name: NOTIFIARR__ON_STALLED_STRIKE - value: "true" - - name: NOTIFIARR__ON_QUEUE_ITEM_DELETED - value: "true" - - name: NOTIFIARR__ON_DOWNLOAD_CLEANED - value: "true" - - name: NOTIFIARR__CHANNEL_ID - value: "1340708411259748413" - envFromSecret: - - secretName: qbit-auth - envs: - - name: QBITTORRENT__USERNAME - key: QBIT_USER - - name: QBITTORRENT__PASSWORD - key: QBIT_PASS - - secretName: sonarr-auth - envs: - - name: SONARR__INSTANCES__0__APIKEY - key: SNRL_API_KEY - - name: SONARR__INSTANCES__1__APIKEY - key: SNRH_API_KEY - - secretName: radarr-auth - envs: - - name: RADARR__INSTANCES__0__APIKEY - key: RDRL_API_KEY - - name: RADARR__INSTANCES__1__APIKEY - key: RDRH_API_KEY - - secretName: notifiarr-auth - envs: - - name: NOTIFIARR__API_KEY - key: API_KEY - resources: - requests: - cpu: 0m - memory: 0Mi - limits: - cpu: 1000m - memory: 1000Mi - volumeMounts: - - name: storage - mountPath: /var/logs - subPath: cleanuperr/logs - volumes: - - name: storage - type: pvc - typeName: storage-pvc - -pvcs: - - name: storage-pvc - storageClassName: local-path-persistent - accessModes: - - ReadWriteOnce - size: 1Gi - volumeMode: Filesystem - -vaultSecrets: - - name: qbit-auth - path: secrets/qbittorrent - templates: - QBIT_USER: "{% .Secrets.username %}" - QBIT_PASS: "{% .Secrets.password %}" - - name: radarr-auth - path: secrets/radarr - templates: - RDRL_API_KEY: "{% .Secrets.low_api_key %}" - RDRH_API_KEY: "{% .Secrets.high_api_key %}" - - name: sonarr-auth - path: secrets/sonarr - templates: - SNRL_API_KEY: "{% .Secrets.low_api_key %}" - SNRH_API_KEY: "{% .Secrets.high_api_key %}" - - name: notifiarr-auth - path: secrets/notifiarr - templates: - API_KEY: "{% .Secrets.passthrough_api_key %}" \ No newline at end of file diff --git a/code/Dockerfile b/code/Dockerfile new file mode 100644 index 00000000..cc48e8c4 --- /dev/null +++ b/code/Dockerfile @@ -0,0 +1,30 @@ +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS build +ARG TARGETARCH +ARG VERSION=0.0.1 +ARG PACKAGES_USERNAME +ARG PACKAGES_PAT + +WORKDIR /app +EXPOSE 11011 +COPY . ./ + +RUN dotnet nuget add source --username ${PACKAGES_USERNAME} --password ${PACKAGES_PAT} --store-password-in-clear-text --name Cleanuparr https://nuget.pkg.github.com/flmorg/index.json + +RUN dotnet publish ./Executable/Executable.csproj \ + -a $TARGETARCH \ + -c Release \ + -o /app/publish \ + /p:Version=${VERSION} \ + /p:PublishSingleFile=true + +FROM mcr.microsoft.com/dotnet/aspnet:9.0-bookworm-slim + +RUN apt-get update && apt-get install -y tzdata && rm -rf /var/lib/apt/lists/* +ENV TZ=Etc/UTC + +# Fix FileSystemWatcher in Docker: https://github.com/dotnet/dotnet-docker/issues/3546 +ENV DOTNET_USE_POLLING_FILE_WATCHER=true + +WORKDIR /app +COPY --from=build /app/publish . +ENTRYPOINT ["./cleanuparr"] \ No newline at end of file diff --git a/code/Executable/Executable.csproj b/code/Executable/Executable.csproj index b7462bfc..1b65fa70 100644 --- a/code/Executable/Executable.csproj +++ b/code/Executable/Executable.csproj @@ -1,7 +1,7 @@ - cleanuperr + cleanuparr net9.0 0.0.1 enable