ci: improve PR deployment workflow and labeling (#3842)

# Description of Changes

- Updated the labeler rules in `.github/labeler-config-srvaroa.yml` to
support optional scope (e.g., `feat(api):`) for all conventional commit
prefixes.
- Added broader matching for API-related PRs by including `swagger` and
`api` keywords in title matching.
- Introduced a new `pr-deployed` label in `.github/labels.yml` to
indicate that a PR has been deployed to a test environment.
- Enhanced the `PR-Demo-Comment-with-react.yml` workflow:
- Replaced `create-github-app-token` with a local `setup-bot` action to
standardize GitHub App auth.
  - Added logic to automatically label deployed PRs with `pr-deployed`.
  - Added cleanup logic for temporary files after workflow execution.
- Improved the `PR-Demo-cleanup.yml` workflow:
- Triggered now on `pull_request_target` instead of `pull_request` for
better permission context.
- Automatically removes the `pr-deployed` label and any bot-generated
deployment comment when a PR is closed.
  - Added proper GitHub App auth handling via `setup-bot`.
- Ensured conditional cleanup only occurs if relevant artifacts are
present.

try:
https://github.com/Stirling-Tools/Stirling-PDF/security/code-scanning/240

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Ludy 2025-07-14 12:57:46 +02:00 committed by GitHub
parent 9e41c625a1
commit 882170ebc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 154 additions and 38 deletions

View File

@ -2,37 +2,46 @@ version: 1
labels: labels:
- label: "Bugfix" - label: "Bugfix"
title: '^fix:.*' title: '^fix(\([^)]*\))?:|^fix:.*'
- label: "enhancement" - label: "enhancement"
title: '^feat:.*' title: '^feat(\([^)]*\))?:|^feat:.*'
- label: "build" - label: "build"
title: '^build:.*' title: '^build(\([^)]*\))?:|^build:.*'
- label: "chore" - label: "chore"
title: '^chore:.*' title: '^chore(\([^)]*\))?:|^chore:.*'
- label: "ci" - label: "ci"
title: '^ci:.*' title: '^ci(\([^)]*\))?:|^ci:.*'
- label: "ci"
title: '^.*\(ci\):.*'
- label: "perf" - label: "perf"
title: '^perf:.*' title: '^perf(\([^)]*\))?:|^perf:.*'
- label: "refactor" - label: "refactor"
title: '^refactor:.*' title: '^refactor(\([^)]*\))?:|^refactor:.*'
- label: "revert" - label: "revert"
title: '^revert:.*' title: '^revert(\([^)]*\))?:|^revert:.*'
- label: "style" - label: "style"
title: '^style:.*' title: '^style(\([^)]*\))?:|^style:.*'
- label: "Documentation" - label: "Documentation"
title: '^docs:.*' title: '^docs(\([^)]*\))?:|^docs:.*'
- label: "dependencies"
title: '^deps(\([^)]*\))?:|^deps:.*'
- label: "dependencies"
title: '^.*\(deps\):.*'
- label: 'API' - label: 'API'
title: '.*openapi.*' title: '.*openapi.*|.*swagger.*|.*api.*'
- label: 'Translation' - label: 'Translation'
files: files:
@ -81,6 +90,7 @@ labels:
- 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java'
- 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/api/.*' - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/api/.*'
- 'stirling-pdf/src/main/java/stirling/software/SPDF/model/api/.*' - 'stirling-pdf/src/main/java/stirling/software/SPDF/model/api/.*'
- 'stirling-pdf/src/main/java/stirling/software/SPDF/service/ApiDocService.java'
- 'proprietary/src/main/java/stirling/software/proprietary/security/controller/api/.*' - 'proprietary/src/main/java/stirling/software/proprietary/security/controller/api/.*'
- 'scripts/png_to_webp.py' - 'scripts/png_to_webp.py'
- 'split_photos.py' - 'split_photos.py'

3
.github/labels.yml vendored
View File

@ -175,3 +175,6 @@
description: "This PR changes 1000+ lines ignoring generated files." description: "This PR changes 1000+ lines ignoring generated files."
- name: "to research" - name: "to research"
color: "FBCA04" color: "FBCA04"
- name: "pr-deployed"
color: "00FF00"
description: "Pull request has been deployed to a test environment"

View File

@ -6,20 +6,18 @@ on:
permissions: permissions:
contents: read contents: read
issues: write # Required for adding reactions to comments pull-requests: read
pull-requests: read # Required for reading PR information
jobs: jobs:
check-comment: check-comment:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
issues: write issues: write
pull-requests: read
if: | if: |
github.event.issue.pull_request && github.event.issue.pull_request &&
( (
contains(github.event.comment.body, 'prdeploy') || contains(github.event.comment.body, 'prdeploy') ||
contains(github.event.comment.body, 'deploypr') contains(github.event.comment.body, 'deploypr')
) )
&& &&
( (
@ -47,10 +45,14 @@ jobs:
with: with:
egress-policy: audit egress-policy: audit
# Generate GitHub App token - name: Checkout PR
- name: Generate GitHub App Token uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
id: setup-bot
uses: ./.github/actions/setup-bot
continue-on-error: true
with: with:
app-id: ${{ secrets.GH_APP_ID }} app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
@ -123,7 +125,7 @@ jobs:
id: add-eyes-reaction id: add-eyes-reaction
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
github-token: ${{ steps.generate-token.outputs.token }} github-token: ${{ steps.setup-bot.outputs.token }}
script: | script: |
console.log(`Adding eyes reaction to comment ID: ${context.payload.comment.id}`); console.log(`Adding eyes reaction to comment ID: ${context.payload.comment.id}`);
try { try {
@ -145,8 +147,8 @@ jobs:
needs: check-comment needs: check-comment
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read
issues: write issues: write
pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
@ -154,9 +156,14 @@ jobs:
with: with:
egress-policy: audit egress-policy: audit
- name: Generate GitHub App Token - name: Checkout PR
id: generate-token uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
id: setup-bot
uses: ./.github/actions/setup-bot
continue-on-error: true
with: with:
app-id: ${{ secrets.GH_APP_ID }} app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
@ -166,7 +173,7 @@ jobs:
with: with:
repository: ${{ needs.check-comment.outputs.pr_repository }} repository: ${{ needs.check-comment.outputs.pr_repository }}
ref: ${{ needs.check-comment.outputs.pr_ref }} ref: ${{ needs.check-comment.outputs.pr_ref }}
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ steps.setup-bot.outputs.token }}
- name: Set up JDK - name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
@ -188,12 +195,6 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Get version number
id: versionNumber
run: |
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
@ -297,7 +298,7 @@ jobs:
if: success() if: success()
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
github-token: ${{ steps.generate-token.outputs.token }} github-token: ${{ steps.setup-bot.outputs.token }}
script: | script: |
console.log(`Adding rocket reaction to comment ID: ${{ needs.check-comment.outputs.comment_id }}`); console.log(`Adding rocket reaction to comment ID: ${{ needs.check-comment.outputs.comment_id }}`);
try { try {
@ -313,11 +314,26 @@ jobs:
console.error(error); console.error(error);
} }
// add label to PR
const prNumber = ${{ needs.check-comment.outputs.pr_number }};
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['pr-deployed']
});
console.log(`Added 'pr-deployed' label to PR #${prNumber}`);
} catch (error) {
console.error(`Failed to add label to PR: ${error.message}`);
console.error(error);
}
- name: Add failure reaction to comment - name: Add failure reaction to comment
if: failure() if: failure()
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
github-token: ${{ steps.generate-token.outputs.token }} github-token: ${{ steps.setup-bot.outputs.token }}
script: | script: |
console.log(`Adding -1 reaction to comment ID: ${{ needs.check-comment.outputs.comment_id }}`); console.log(`Adding -1 reaction to comment ID: ${{ needs.check-comment.outputs.comment_id }}`);
try { try {
@ -337,7 +353,7 @@ jobs:
if: success() if: success()
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with: with:
github-token: ${{ steps.generate-token.outputs.token }} github-token: ${{ steps.setup-bot.outputs.token }}
script: | script: |
const { GITHUB_REPOSITORY } = process.env; const { GITHUB_REPOSITORY } = process.env;
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/'); const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
@ -357,3 +373,11 @@ jobs:
issue_number: prNumber, issue_number: prNumber,
body: commentBody body: commentBody
}); });
- name: Cleanup temporary files
if: always()
run: |
echo "Cleaning up temporary files..."
rm -f ../private.key docker-compose.yml
echo "Cleanup complete."
continue-on-error: true

View File

@ -1,7 +1,7 @@
name: PR Deployment cleanup name: PR Deployment cleanup
on: on:
pull_request: pull_request_target:
types: [opened, synchronize, reopened, closed] types: [opened, synchronize, reopened, closed]
permissions: permissions:
@ -13,11 +13,11 @@ env:
jobs: jobs:
cleanup: cleanup:
if: github.event.action == 'closed'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write
pull-requests: write pull-requests: write
if: github.event.action == 'closed' issues: write
steps: steps:
- name: Harden Runner - name: Harden Runner
@ -25,13 +25,84 @@ jobs:
with: with:
egress-policy: audit egress-policy: audit
- name: Checkout PR
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
id: setup-bot
uses: ./.github/actions/setup-bot
continue-on-error: true
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Remove 'pr-deployed' label if present
id: remove-label-comment
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const prNumber = ${{ github.event.pull_request.number }};
const owner = context.repo.owner;
const repo = context.repo.repo;
// Hole alle Labels auf dem PR
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: prNumber
});
const hasLabel = labels.some(label => label.name === 'pr-deployed');
if (hasLabel) {
console.log("Label 'pr-deployed' found. Removing...");
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: 'pr-deployed'
});
} else {
console.log("Label 'pr-deployed' not found. Nothing to do.");
}
// Find existing comment
const comments = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber
});
const deploymentComments = comments.data.filter(c =>
c.body?.includes("## 🚀 PR Test Deployment") &&
c.user?.type === "Bot"
);
if (deploymentComments.length > 0) {
for (const comment of deploymentComments) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id
});
console.log(`Deleted deployment comment (ID: ${comment.id})`);
}
} else {
console.log("No matching deployment comments found.");
}
core.setOutput('present', hasLabel || deploymentComment ? 'true' : 'false');
- name: Set up SSH - name: Set up SSH
if: steps.remove-label-comment.outputs.present == 'true'
run: | run: |
mkdir -p ~/.ssh/ mkdir -p ~/.ssh/
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
sudo chmod 600 ../private.key sudo chmod 600 ../private.key
- name: Cleanup PR deployment - name: Cleanup PR deployment
if: steps.remove-label-comment.outputs.present == 'true'
id: cleanup id: cleanup
run: | run: |
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH' ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
@ -57,3 +128,11 @@ jobs:
echo "NO_CLEANUP_NEEDED" echo "NO_CLEANUP_NEEDED"
fi fi
ENDSSH ENDSSH
- name: Cleanup temporary files
if: always()
run: |
echo "Cleaning up temporary files..."
rm -f ../private.key
echo "Cleanup complete."
continue-on-error: true