diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml
index f6af195e..2d0848b1 100644
--- a/.github/workflows/build-docker.yml
+++ b/.github/workflows/build-docker.yml
@@ -150,6 +150,7 @@ jobs:
repository: ${{ github.repository }}
ref: ${{ needs.prepare.outputs.branch }}
token: ${{ env.REPO_READONLY_PAT }}
+ persist-credentials: false
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
diff --git a/.github/workflows/build-executable.yml b/.github/workflows/build-executable.yml
index ae671cf1..f2ad3f17 100644
--- a/.github/workflows/build-executable.yml
+++ b/.github/workflows/build-executable.yml
@@ -72,6 +72,7 @@ jobs:
repository: ${{ env.githubRepository }}
ref: ${{ github.ref_name }}
token: ${{ env.REPO_READONLY_PAT }}
+ persist-credentials: false
- name: Setup dotnet
uses: actions/setup-dotnet@v5
diff --git a/.github/workflows/build-frontend.yml b/.github/workflows/build-frontend.yml
index 6c720b5d..547ab501 100644
--- a/.github/workflows/build-frontend.yml
+++ b/.github/workflows/build-frontend.yml
@@ -30,6 +30,7 @@ jobs:
repository: ${{ github.repository }}
ref: ${{ inputs.ref || github.ref_name }}
token: ${{ env.REPO_READONLY_PAT }}
+ persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
diff --git a/.github/workflows/build-macos-installer.yml b/.github/workflows/build-macos-installer.yml
index 1a863427..01d42e68 100644
--- a/.github/workflows/build-macos-installer.yml
+++ b/.github/workflows/build-macos-installer.yml
@@ -76,6 +76,7 @@ jobs:
ref: ${{ github.ref_name }}
token: ${{ env.REPO_READONLY_PAT }}
fetch-depth: 0
+ persist-credentials: false
- name: Download frontend artifact
uses: actions/download-artifact@v4
diff --git a/.github/workflows/build-windows-installer.yml b/.github/workflows/build-windows-installer.yml
index 61eea5c0..6b1fcbf4 100644
--- a/.github/workflows/build-windows-installer.yml
+++ b/.github/workflows/build-windows-installer.yml
@@ -65,6 +65,7 @@ jobs:
repository: ${{ env.githubRepository }}
ref: ${{ inputs.ref || github.ref_name }}
token: ${{ env.REPO_READONLY_PAT }}
+ persist-credentials: false
- name: Download frontend artifact
uses: actions/download-artifact@v4
diff --git a/.github/workflows/cloudflare-pages-blocklists.yml b/.github/workflows/cloudflare-pages-blocklists.yml
index e1293c1d..7a6c27de 100644
--- a/.github/workflows/cloudflare-pages-blocklists.yml
+++ b/.github/workflows/cloudflare-pages-blocklists.yml
@@ -20,6 +20,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Create directory for static files
run: |
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index bbe99c03..0f95332d 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -20,6 +20,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Dependency Review
uses: actions/dependency-review-action@v4
diff --git a/.github/workflows/docs-preview-cleanup.yml b/.github/workflows/docs-preview-cleanup.yml
new file mode 100644
index 00000000..5926502f
--- /dev/null
+++ b/.github/workflows/docs-preview-cleanup.yml
@@ -0,0 +1,53 @@
+name: Docs Preview Cleanup
+
+on:
+ pull_request:
+ types: [closed]
+ paths:
+ - 'docs/**'
+
+permissions:
+ contents: read
+
+jobs:
+ cleanup:
+ runs-on: ubuntu-latest
+ # Skip fork PRs
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ env:
+ CF_API_TOKEN: ${{ secrets.CLOUDFLARE_PAGES_TOKEN }}
+ PROJECT: cleanuparr-docs
+ BRANCH: pull-${{ github.event.pull_request.number }}
+ steps:
+ - name: Delete preview deployments for this PR
+ run: |
+ set -euo pipefail
+ api="https://api.cloudflare.com/client/v4"
+ auth="Authorization: Bearer $CF_API_TOKEN"
+
+ account_id=$(curl -fsS -H "$auth" "$api/accounts" | jq -r '.result[0].id')
+ echo "Account $account_id, tearing down branch $BRANCH"
+
+ ids=""
+ page=1
+ while :; do
+ resp=$(curl -fsS -H "$auth" \
+ "$api/accounts/$account_id/pages/projects/$PROJECT/deployments?page=$page&per_page=25")
+ count=$(echo "$resp" | jq '.result | length')
+ [ "$count" -eq 0 ] && break
+
+ page_ids=$(echo "$resp" | jq -r --arg b "$BRANCH" \
+ '.result[] | select(.deployment_trigger.metadata.branch == $b) | .id')
+ ids="$ids $page_ids"
+ page=$((page + 1))
+ done
+
+ deleted=0
+ for id in $ids; do
+ echo "Deleting deployment $id"
+ curl -fsS -X DELETE -H "$auth" \
+ "$api/accounts/$account_id/pages/projects/$PROJECT/deployments/$id?force=true" >/dev/null
+ deleted=$((deleted + 1))
+ done
+
+ echo "Deleted $deleted deployment(s) for $BRANCH"
diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml
new file mode 100644
index 00000000..15df6475
--- /dev/null
+++ b/.github/workflows/docs-preview.yml
@@ -0,0 +1,84 @@
+name: Docs Preview
+
+on:
+ pull_request:
+ paths:
+ - 'docs/**'
+
+concurrency:
+ group: docs-preview-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ preview:
+ runs-on: ubuntu-latest
+ # Skip fork PRs
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 26.x
+ cache: yarn
+ cache-dependency-path: docs/yarn.lock
+
+ - name: Install dependencies
+ working-directory: docs
+ run: yarn install --frozen-lockfile
+
+ - name: Build Docusaurus
+ working-directory: docs
+ run: yarn build
+
+ - name: Deploy preview to Cloudflare Pages
+ uses: cloudflare/wrangler-action@v3
+ with:
+ apiToken: ${{ secrets.CLOUDFLARE_PAGES_TOKEN }}
+ workingDirectory: docs
+ command: pages deploy build --project-name=cleanuparr-docs --branch=pull-${{ github.event.pull_request.number }}
+
+ - name: Comment preview URL
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const url = `https://pull-${context.issue.number}.cleanuparr-docs.pages.dev`;
+ const marker = '';
+ const body = [
+ marker,
+ `Docs preview for \`${context.payload.pull_request.head.ref}\` (\`${context.payload.pull_request.head.sha.substring(0, 7)}\`):`,
+ ``,
+ `${url}/docs`
+ ].join('\n');
+
+ const comments = await github.paginate(github.rest.issues.listComments, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ per_page: 100
+ });
+ const existing = comments.find(c => c.body.includes(marker));
+
+ if (existing) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existing.id,
+ body
+ });
+ } else {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body
+ });
+ }
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index c75103f3..a29e43c9 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -10,10 +10,7 @@ permissions:
id-token: write
jobs:
- deploy:
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
+ publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -21,6 +18,7 @@ jobs:
with:
fetch-depth: 0
ref: main
+ persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
@@ -37,12 +35,39 @@ jobs:
working-directory: docs
run: yarn build
+ - name: Publish to org site
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ personal_token: ${{ secrets.DOCS_DEPLOY_TOKEN }}
+ external_repository: Cleanuparr/Cleanuparr.github.io
+ publish_branch: gh-pages
+ publish_dir: docs/build
+
+ redirect:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build redirect stub
+ run: |
+ mkdir redirect
+ cat > redirect/404.html <<'EOF'
+
+
+
+ EOF
+ cp redirect/404.html redirect/index.html
+
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
- path: docs/build
+ path: redirect
retention-days: 1
- - name: Deploy to GitHub Pages
+ - name: Deploy redirect to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v4
\ No newline at end of file
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 812e3b20..edd8f92d 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -43,6 +43,8 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
timeout-minutes: 1
+ with:
+ persist-credentials: false
- name: Get vault secrets
uses: hashicorp/vault-action@v2
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 10a024c3..e3128800 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -47,6 +47,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Get version info
id: version
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d44f0696..3bb41dec 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -27,6 +27,8 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
timeout-minutes: 1
+ with:
+ persist-credentials: false
- name: Setup .NET
uses: actions/setup-dotnet@v5
diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts
index 39a875a2..7090a124 100644
--- a/docs/docusaurus.config.ts
+++ b/docs/docusaurus.config.ts
@@ -8,10 +8,10 @@ const config: Config = {
favicon: 'img/favicon.ico',
url: 'https://cleanuparr.github.io',
- baseUrl: '/Cleanuparr/',
+ baseUrl: '/',
organizationName: 'Cleanuparr',
- projectName: 'Cleanuparr',
+ projectName: 'Cleanuparr.github.io',
onBrokenLinks: 'throw',