mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-24 21:29:25 +00:00

# Description of Changes This pull request introduces several enhancements and new features, primarily focused on improving API documentation support, expanding backend functionality, and adding new frontend tools. Key changes include the integration of Swagger API documentation, the addition of a new `UIDataController` for backend data handling, and updates to the frontend to include a Swagger UI tool. ### Backend Enhancements: * **Swagger API Documentation Integration**: - Added support for dynamically configuring Swagger servers using the `SWAGGER_SERVER_URL` environment variable in `OpenApiConfig` (`[app/core/src/main/java/stirling/software/SPDF/config/OpenApiConfig.javaR54-L63](diffhunk://#diff-6080fb3dc14efc430c9de1bf9fa4996a23deebc14230dde7788949b2c49cca68R54-L63)`). - Imported necessary Swagger dependencies (`[app/core/src/main/java/stirling/software/SPDF/config/OpenApiConfig.javaR13](diffhunk://#diff-6080fb3dc14efc430c9de1bf9fa4996a23deebc14230dde7788949b2c49cca68R13)`). - Updated `nginx.conf` to proxy Swagger-related requests to the backend (`[docker/frontend/nginx.confR55-R92](diffhunk://#diff-6d35fafb4405bd052c6d5e48bd946bcef7c77552a74e1b902de45e85eee09aceR55-R92)`). * **New `UIDataController`**: - Introduced a new controller (`UIDataController`) to serve React UI data, including endpoints for home data, licenses, pipeline configurations, signature data, and OCR data (`[app/core/src/main/java/stirling/software/SPDF/controller/api/UIDataController.javaR1-R301](diffhunk://#diff-3e7063d4e921c7b9e6eedfcad0e535ba3eff68476dcff5e6f28b00c388cff646R1-R301)`). * **Endpoint Handling**: - Modified `ConfigController` to include explicit parameter naming for better clarity in API requests (`[app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.javaL113-R120](diffhunk://#diff-43d19d45ae547fd79090596c06d58cb0eb7f722ed43eb4da59f9dec39f6def6eL113-R120)`). ### Frontend Enhancements: * **Swagger UI Tool**: - Added a new tool definition (`swagger`) in `useToolManagement.tsx`, with an icon and lazy-loaded component (`[frontend/src/hooks/useToolManagement.tsxR30-R38](diffhunk://#diff-57f8a6b3e75ecaec10ad445b01afe8fccc376af6f8ad4d693c68cf98e8863273R30-R38)`). - Implemented the `SwaggerUI` component to open the Swagger documentation in a new tab (`[frontend/src/tools/SwaggerUI.tsxR1-R18](diffhunk://#diff-ca9bdf83c5d611a5edff10255103d7939895635b33a258dd77db6571da6c4600R1-R18)`). * **Localization Updates**: - Updated English (US and GB) translation files to include Swagger-related strings (`[[1]](diffhunk://#diff-14c707e28788a3a84ed5293ff6689be73d4bca00e155beaf090f9b37c978babbR578-R581)`, `[[2]](diffhunk://#diff-14c707e28788a3a84ed5293ff6689be73d4bca00e155beaf090f9b37c978babbR1528-R1533)`, `[[3]](diffhunk://#diff-e4d543afa388d9eb8a423e45dfebb91641e3558d00848d70b285ebb91c40b249R578-R581)`, `[[4]](diffhunk://#diff-e4d543afa388d9eb8a423e45dfebb91641e3558d00848d70b285ebb91c40b249R1528-R1533)`). ### Workflow Updates: * **Environment Variable Additions**: - Added `SWAGGER_SERVER_URL` to the `PR-Auto-Deploy-V2.yml` and `deploy-on-v2-commit.yml` workflows for configuring Swagger server URLs (`[[1]](diffhunk://#diff-931fcb06ba030420d7044dde06465ad55b4e769a9bd374dcd6a0c76f79a5e30eR320)`, `[[2]](diffhunk://#diff-f8b6ec3c0af9cd2d8dffef6f3def2be6357fe596a606850ca7f5d799e1349069R150)`). <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/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/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] 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/devGuide/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/devGuide/DeveloperGuide.md#6-testing) for more details.
502 lines
20 KiB
YAML
502 lines
20 KiB
YAML
name: Auto PR V2 Deployment
|
||
|
||
on:
|
||
pull_request:
|
||
types: [opened, synchronize, reopened, closed]
|
||
|
||
|
||
permissions:
|
||
contents: read
|
||
issues: write
|
||
pull-requests: write
|
||
|
||
jobs:
|
||
check-pr:
|
||
if: github.event.action != 'closed'
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
should_deploy: ${{ steps.check-conditions.outputs.should_deploy }}
|
||
pr_number: ${{ github.event.number }}
|
||
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
|
||
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
|
||
steps:
|
||
- name: Harden Runner
|
||
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
|
||
with:
|
||
egress-policy: audit
|
||
|
||
- name: Check deployment conditions
|
||
id: check-conditions
|
||
env:
|
||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
|
||
run: |
|
||
echo "PR Title: $PR_TITLE"
|
||
echo "PR Author: $PR_AUTHOR"
|
||
echo "PR Branch: $PR_BRANCH"
|
||
echo "PR Base Branch: ${{ github.event.pull_request.base.ref }}"
|
||
|
||
# Define authorized users
|
||
authorized_users=(
|
||
"Frooodle"
|
||
"sf298"
|
||
"Ludy87"
|
||
"LaserKaspar"
|
||
"sbplat"
|
||
"reecebrowne"
|
||
"DarioGii"
|
||
"ConnorYoh"
|
||
"EthanHealy01"
|
||
)
|
||
|
||
# Check if author is in the authorized list
|
||
is_authorized=false
|
||
for user in "${authorized_users[@]}"; do
|
||
if [[ "$PR_AUTHOR" == "$user" ]]; then
|
||
is_authorized=true
|
||
break
|
||
fi
|
||
done
|
||
|
||
# If PR is targeting V2 and user is authorized, deploy unconditionally
|
||
PR_BASE_BRANCH="${{ github.event.pull_request.base.ref }}"
|
||
if [[ "$PR_BASE_BRANCH" == "V2" && "$is_authorized" == "true" ]]; then
|
||
echo "✅ Deployment forced: PR targets V2 and author is authorized."
|
||
echo "should_deploy=true" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
# Otherwise, continue with original keyword checks
|
||
has_v2_keyword=false
|
||
if [[ "$PR_TITLE" =~ [Vv]2 ]] || [[ "$PR_TITLE" =~ [Vv]ersion.?2 ]] || [[ "$PR_TITLE" =~ [Vv]ersion.?[Tt]wo ]]; then
|
||
has_v2_keyword=true
|
||
fi
|
||
|
||
has_branch_keyword=false
|
||
if [[ "$PR_BRANCH" =~ [Vv]2 ]] || [[ "$PR_BRANCH" =~ [Rr]eact ]]; then
|
||
has_branch_keyword=true
|
||
fi
|
||
|
||
if [[ "$is_authorized" == "true" && ( "$has_v2_keyword" == "true" || "$has_branch_keyword" == "true" ) ]]; then
|
||
echo "✅ Deployment conditions met"
|
||
echo "should_deploy=true" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "❌ Deployment conditions not met"
|
||
echo " - Authorized user: $is_authorized"
|
||
echo " - Has V2 keyword in title: $has_v2_keyword"
|
||
echo " - Has V2/React keyword in branch: $has_branch_keyword"
|
||
echo "should_deploy=false" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Get PR repository and ref
|
||
id: get-pr-info
|
||
if: steps.check-conditions.outputs.should_deploy == 'true'
|
||
run: |
|
||
# For forks, use the full repository name, for internal PRs use the current repo
|
||
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
|
||
repository="${{ github.event.pull_request.head.repo.full_name }}"
|
||
else
|
||
repository="${{ github.repository }}"
|
||
fi
|
||
|
||
echo "repository=$repository" >> $GITHUB_OUTPUT
|
||
echo "ref=${{ github.event.pull_request.head.ref }}" >> $GITHUB_OUTPUT
|
||
|
||
deploy-v2-pr:
|
||
needs: check-pr
|
||
runs-on: ubuntu-latest
|
||
if: needs.check-pr.outputs.should_deploy == 'true'
|
||
# Concurrency control - only one deployment per PR at a time
|
||
concurrency:
|
||
group: v2-deploy-pr-${{ needs.check-pr.outputs.pr_number }}
|
||
cancel-in-progress: true
|
||
permissions:
|
||
contents: read
|
||
issues: write
|
||
pull-requests: write
|
||
|
||
steps:
|
||
- name: Harden Runner
|
||
uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
|
||
with:
|
||
egress-policy: audit
|
||
|
||
- name: Checkout main repository
|
||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||
with:
|
||
repository: ${{ github.repository }}
|
||
ref: main
|
||
|
||
- 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: Add deployment started comment
|
||
id: deployment-started
|
||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||
with:
|
||
github-token: ${{ steps.setup-bot.outputs.token }}
|
||
script: |
|
||
const { owner, repo } = context.repo;
|
||
const prNumber = ${{ needs.check-pr.outputs.pr_number }};
|
||
|
||
// Delete previous V2 deployment comments to avoid clutter
|
||
const { data: comments } = await github.rest.issues.listComments({
|
||
owner,
|
||
repo,
|
||
issue_number: prNumber,
|
||
per_page: 100
|
||
});
|
||
|
||
const v2Comments = comments.filter(comment =>
|
||
comment.body.includes('🚀 **Auto-deploying V2 version**') ||
|
||
comment.body.includes('## 🚀 V2 Auto-Deployment Complete!') ||
|
||
comment.body.includes('❌ **V2 Auto-deployment failed**')
|
||
);
|
||
|
||
for (const comment of v2Comments) {
|
||
console.log(`Deleting old V2 comment: ${comment.id}`);
|
||
await github.rest.issues.deleteComment({
|
||
owner,
|
||
repo,
|
||
comment_id: comment.id
|
||
});
|
||
}
|
||
|
||
// Create new deployment started comment
|
||
const { data: newComment } = await github.rest.issues.createComment({
|
||
owner,
|
||
repo,
|
||
issue_number: prNumber,
|
||
body: `🚀 **Auto-deploying V2 version** for PR #${prNumber}...\n\n_This is an automated deployment triggered by V2/version2 keywords in the PR title or V2/React keywords in the branch name._\n\n⚠️ **Note:** If new commits are pushed during deployment, this build will be cancelled and replaced with the latest version.`
|
||
});
|
||
|
||
return newComment.id;
|
||
|
||
- name: Checkout PR
|
||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||
with:
|
||
repository: ${{ needs.check-pr.outputs.pr_repository }}
|
||
ref: ${{ needs.check-pr.outputs.pr_ref }}
|
||
token: ${{ secrets.GITHUB_TOKEN }}
|
||
fetch-depth: 0 # Fetch full history for commit hash detection
|
||
|
||
|
||
- name: Set up Docker Buildx
|
||
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
|
||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||
with:
|
||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||
password: ${{ secrets.DOCKER_HUB_API }}
|
||
|
||
- name: Get commit hashes for frontend and backend
|
||
id: commit-hashes
|
||
run: |
|
||
# Get last commit that touched the frontend folder, docker/frontend, or docker/compose
|
||
FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "")
|
||
if [ -z "$FRONTEND_HASH" ]; then
|
||
FRONTEND_HASH="no-frontend-changes"
|
||
fi
|
||
|
||
# Get last commit that touched backend code, docker/backend, or docker/compose
|
||
BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "")
|
||
if [ -z "$BACKEND_HASH" ]; then
|
||
BACKEND_HASH="no-backend-changes"
|
||
fi
|
||
|
||
echo "Frontend hash: $FRONTEND_HASH"
|
||
echo "Backend hash: $BACKEND_HASH"
|
||
|
||
echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT
|
||
echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT
|
||
|
||
# Short hashes for tags
|
||
if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then
|
||
echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
if [ "$BACKEND_HASH" = "no-backend-changes" ]; then
|
||
echo "backend_short=no-backend" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Check if frontend image exists
|
||
id: check-frontend
|
||
run: |
|
||
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then
|
||
echo "exists=true" >> $GITHUB_OUTPUT
|
||
echo "Frontend image already exists, skipping build"
|
||
else
|
||
echo "exists=false" >> $GITHUB_OUTPUT
|
||
echo "Frontend image needs to be built"
|
||
fi
|
||
|
||
- name: Check if backend image exists
|
||
id: check-backend
|
||
run: |
|
||
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then
|
||
echo "exists=true" >> $GITHUB_OUTPUT
|
||
echo "Backend image already exists, skipping build"
|
||
else
|
||
echo "exists=false" >> $GITHUB_OUTPUT
|
||
echo "Backend image needs to be built"
|
||
fi
|
||
|
||
- name: Build and push V2 frontend image
|
||
if: steps.check-frontend.outputs.exists == 'false'
|
||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||
with:
|
||
context: .
|
||
file: ./docker/frontend/Dockerfile
|
||
push: true
|
||
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
|
||
build-args: VERSION_TAG=v2-alpha
|
||
platforms: linux/amd64
|
||
|
||
- name: Build and push V2 backend image
|
||
if: steps.check-backend.outputs.exists == 'false'
|
||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||
with:
|
||
context: .
|
||
file: ./docker/backend/Dockerfile
|
||
push: true
|
||
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
|
||
build-args: VERSION_TAG=v2-alpha
|
||
platforms: linux/amd64
|
||
|
||
- name: Set up SSH
|
||
run: |
|
||
mkdir -p ~/.ssh/
|
||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
||
sudo chmod 600 ../private.key
|
||
|
||
- name: Deploy V2 to VPS
|
||
id: deploy
|
||
run: |
|
||
# Use same port strategy as regular PRs - just the PR number
|
||
V2_PORT=${{ needs.check-pr.outputs.pr_number }}
|
||
BACKEND_PORT=$((V2_PORT + 10000)) # Backend on higher port to avoid conflicts
|
||
|
||
# Create docker-compose for V2 with separate frontend and backend
|
||
cat > docker-compose.yml << EOF
|
||
version: '3.3'
|
||
services:
|
||
stirling-pdf-v2-backend:
|
||
container_name: stirling-pdf-v2-backend-pr-${{ needs.check-pr.outputs.pr_number }}
|
||
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
|
||
ports:
|
||
- "${BACKEND_PORT}:8080" # Backend API port
|
||
volumes:
|
||
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/data:/usr/share/tessdata:rw
|
||
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/config:/configs:rw
|
||
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/logs:/logs:rw
|
||
environment:
|
||
DISABLE_ADDITIONAL_FEATURES: "true"
|
||
SECURITY_ENABLELOGIN: "false"
|
||
SYSTEM_DEFAULTLOCALE: en-GB
|
||
UI_APPNAME: "Stirling-PDF V2 PR#${{ needs.check-pr.outputs.pr_number }}"
|
||
UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Frontend/Backend Split Architecture"
|
||
UI_APPNAMENAVBAR: "V2 PR#${{ needs.check-pr.outputs.pr_number }}"
|
||
SYSTEM_MAXFILESIZE: "100"
|
||
METRICS_ENABLED: "true"
|
||
SYSTEM_GOOGLEVISIBILITY: "false"
|
||
SWAGGER_SERVER_URL: "http://${{ secrets.VPS_HOST }}:${V2_PORT}"
|
||
restart: on-failure:5
|
||
|
||
stirling-pdf-v2-frontend:
|
||
container_name: stirling-pdf-v2-frontend-pr-${{ needs.check-pr.outputs.pr_number }}
|
||
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
|
||
ports:
|
||
- "${V2_PORT}:80" # Frontend port (same as regular PRs)
|
||
environment:
|
||
VITE_API_BASE_URL: "http://${{ secrets.VPS_HOST }}:${BACKEND_PORT}"
|
||
depends_on:
|
||
- stirling-pdf-v2-backend
|
||
restart: on-failure:5
|
||
EOF
|
||
|
||
# Deploy to VPS
|
||
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose-v2.yml
|
||
|
||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << ENDSSH
|
||
# Create V2 PR-specific directories
|
||
mkdir -p /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/{data,config,logs}
|
||
|
||
# Move docker-compose file to correct location
|
||
mv /tmp/docker-compose-v2.yml /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/docker-compose.yml
|
||
|
||
# Stop any existing container and clean up
|
||
cd /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}
|
||
docker-compose down --remove-orphans 2>/dev/null || true
|
||
|
||
# Start the new container
|
||
docker-compose pull
|
||
docker-compose up -d
|
||
|
||
# Clean up unused Docker resources to save space
|
||
docker system prune -af --volumes
|
||
|
||
# Clean up old backend/frontend images (older than 2 weeks)
|
||
docker image prune -af --filter "until=336h" --filter "label!=keep=true"
|
||
ENDSSH
|
||
|
||
# Set port for output
|
||
echo "v2_port=${V2_PORT}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Post V2 deployment URL to PR
|
||
if: success()
|
||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||
with:
|
||
github-token: ${{ steps.setup-bot.outputs.token }}
|
||
script: |
|
||
const { owner, repo } = context.repo;
|
||
const prNumber = ${{ needs.check-pr.outputs.pr_number }};
|
||
const v2Port = ${{ steps.deploy.outputs.v2_port }};
|
||
|
||
// Delete the "deploying..." comment since we're posting the final result
|
||
const deploymentStartedId = ${{ steps.deployment-started.outputs.result }};
|
||
if (deploymentStartedId) {
|
||
console.log(`Deleting deployment started comment: ${deploymentStartedId}`);
|
||
try {
|
||
await github.rest.issues.deleteComment({
|
||
owner,
|
||
repo,
|
||
comment_id: deploymentStartedId
|
||
});
|
||
} catch (error) {
|
||
console.log(`Could not delete deployment started comment: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${v2Port}`;
|
||
|
||
const commentBody = `## 🚀 V2 Auto-Deployment Complete!\n\n` +
|
||
`Your V2 PR with the new frontend/backend split architecture has been deployed!\n\n` +
|
||
`🔗 **V2 Test URL:** [${deploymentUrl}](${deploymentUrl})\n\n` +
|
||
`_This deployment will be automatically cleaned up when the PR is closed._\n\n` +
|
||
`🔄 **Auto-deployed** because PR title or branch name contains V2/version2/React keywords.`;
|
||
|
||
await github.rest.issues.createComment({
|
||
owner,
|
||
repo,
|
||
issue_number: prNumber,
|
||
body: commentBody
|
||
});
|
||
|
||
cleanup-v2-deployment:
|
||
if: github.event.action == 'closed'
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
issues: write
|
||
pull-requests: write
|
||
|
||
steps:
|
||
- name: Harden Runner
|
||
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
|
||
with:
|
||
egress-policy: audit
|
||
|
||
- name: Checkout repository
|
||
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: Clean up V2 deployment comments
|
||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||
with:
|
||
github-token: ${{ steps.setup-bot.outputs.token }}
|
||
script: |
|
||
const { owner, repo } = context.repo;
|
||
const prNumber = ${{ github.event.pull_request.number }};
|
||
|
||
// Find and delete V2 deployment comments
|
||
const { data: comments } = await github.rest.issues.listComments({
|
||
owner,
|
||
repo,
|
||
issue_number: prNumber
|
||
});
|
||
|
||
const v2Comments = comments.filter(c =>
|
||
c.body?.includes("## 🚀 V2 Auto-Deployment Complete!") &&
|
||
c.user?.type === "Bot"
|
||
);
|
||
|
||
for (const comment of v2Comments) {
|
||
await github.rest.issues.deleteComment({
|
||
owner,
|
||
repo,
|
||
comment_id: comment.id
|
||
});
|
||
console.log(`Deleted V2 deployment comment (ID: ${comment.id})`);
|
||
}
|
||
|
||
- name: Set up SSH
|
||
run: |
|
||
mkdir -p ~/.ssh/
|
||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
||
sudo chmod 600 ../private.key
|
||
|
||
- name: Cleanup V2 deployment
|
||
run: |
|
||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||
if [ -d "/stirling/V2-PR-${{ github.event.pull_request.number }}" ]; then
|
||
echo "Found V2 PR directory, proceeding with cleanup..."
|
||
|
||
# Stop and remove V2 containers
|
||
cd /stirling/V2-PR-${{ github.event.pull_request.number }}
|
||
docker-compose down || true
|
||
|
||
# Go back to root before removal
|
||
cd /
|
||
|
||
# Remove V2 PR-specific directories
|
||
rm -rf /stirling/V2-PR-${{ github.event.pull_request.number }}
|
||
|
||
# Clean up V2 containers by name (in case compose cleanup missed them)
|
||
docker rm -f stirling-pdf-v2-frontend-pr-${{ github.event.pull_request.number }} || true
|
||
docker rm -f stirling-pdf-v2-backend-pr-${{ github.event.pull_request.number }} || true
|
||
|
||
echo "V2 cleanup completed"
|
||
else
|
||
echo "V2 PR directory not found, nothing to clean up"
|
||
fi
|
||
|
||
# Clean up old unused images (older than 2 weeks) but keep recent ones for reuse
|
||
docker image prune -af --filter "until=336h" --filter "label!=keep=true"
|
||
|
||
# Note: We don't remove the commit-based images since they can be reused across PRs
|
||
# Only remove PR-specific containers and directories
|
||
ENDSSH
|
||
|
||
- name: Cleanup temporary files
|
||
if: always()
|
||
run: |
|
||
rm -f ../private.key
|
||
continue-on-error: true
|
||
|