LibreChat/.github/workflows/gitnexus-cleanup-pr.yml
Marco Beretta 9e6d677751
⚙️ ci: Bump GitHub Actions to Node.js 24 Runtimes (#14689)
* ci: bump GitHub Actions to Node.js 24 runtimes

Clear Node 20 deprecation warnings on runners by moving workflow
actions to majors that declare node24 (checkout, cache, setup-node,
artifacts, Docker buildx/build-push/qemu/login, github-script,
setup-go, Azure login/helm, create-pull-request, axe-linter).

* fix: release leader lock via ioredis on Redis Cluster

@keyv/redis EVAL can surface unhandled MOVED redirects on cluster,
so resign() logged failure and left LeadingServerUUID set. Use ioredis
for leader election SET NX / GET / Lua (same pattern as principals and
concurrency locks) so cluster redirects are retried and resignation
clears the lock.
2026-08-07 11:25:29 -04:00

91 lines
3.3 KiB
YAML

# Removes a PR's GitNexus index from the droplet when the PR is closed
# (merged or not). The deploy workflow also prunes stale folders as a
# safety net, but this gives us immediate cleanup without waiting for
# the next deploy trigger.
name: GitNexus Cleanup PR
on:
pull_request:
types: [closed]
permissions:
contents: read
actions: read
concurrency:
group: gitnexus-cleanup-pr-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
cleanup:
# Skip fork PRs entirely. GitHub withholds repository secrets from
# pull_request events originating on forks, so an SSH deploy job run
# from a fork close would fail noisily. The deploy workflow's stale-
# folder pruning step catches any fork-contributor indexes that
# actually made it onto the droplet.
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
# Skip the SSH round-trip entirely when no index artifact was ever
# built for this PR (docs-only PRs, paths-ignored PRs, PRs closed
# before indexing finished, etc). Eliminates ~95% of no-op SSH
# sessions on a busy repo.
- name: Check for index artifact
id: check
uses: actions/github-script@v8
with:
script: |
const { data } = await github.rest.actions.listArtifactsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
name: `gitnexus-index-pr-${context.payload.pull_request.number}`,
per_page: 1,
});
const hasArtifact = data.total_count > 0;
core.info(`Artifact exists: ${hasArtifact}`);
core.setOutput('has_artifact', hasArtifact ? 'true' : 'false');
- name: Setup SSH
if: steps.check.outputs.has_artifact == 'true'
env:
SSH_KEY: ${{ secrets.GITNEXUS_DO_SSH_KEY }}
KNOWN_HOST: ${{ secrets.GITNEXUS_DO_KNOWN_HOST }}
run: |
set -e
mkdir -p ~/.ssh
chmod 700 ~/.ssh
printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
if [ -z "$KNOWN_HOST" ]; then
echo "::error::GITNEXUS_DO_KNOWN_HOST secret is empty"
exit 1
fi
printf '%s\n' "$KNOWN_HOST" > ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
- name: Remove PR index from droplet
if: steps.check.outputs.has_artifact == 'true'
env:
SSH_USER: ${{ secrets.GITNEXUS_DO_USER }}
SSH_HOST: ${{ secrets.GITNEXUS_DO_HOST }}
PR_NUM: ${{ github.event.pull_request.number }}
run: |
ssh -i ~/.ssh/deploy_key "$SSH_USER@$SSH_HOST" PR_NUM="$PR_NUM" bash <<'REMOTE'
set -e
TARGET="/opt/gitnexus/indexes/LibreChat-pr-$PR_NUM"
if [ -d "$TARGET" ]; then
echo "Removing $TARGET"
rm -rf "$TARGET"
cd /opt/gitnexus
docker compose up -d --force-recreate gitnexus
echo "GitNexus restarted without PR #$PR_NUM"
else
echo "No index to clean up for PR #$PR_NUM (artifact existed but droplet folder did not)"
fi
REMOTE
- name: Cleanup SSH key
if: always()
run: rm -f ~/.ssh/deploy_key