@@ -57,30 +57,74 @@ jobs:
5757 - '.github/workflows/**'
5858 - '.github/actions/**'
5959
60- # Post preview links immediately (no waiting for other jobs)
61- preview-links :
60+ # Coolify's preview switch is all-or-nothing: enabled, it deploys every open PR. We leave it
61+ # disabled and create a preview per PR from the Coolify UI, and this job keeps the ones that
62+ # exist up to date. Coolify's deploy API only accepts a pull request that already has a preview,
63+ # so a PR without one is a no-op. Instance identifiers come from repository variables; a fork or
64+ # an unconfigured instance simply skips.
65+ preview :
6266 name : " Preview / Coolify"
6367 runs-on : ubuntu-latest
64- if : github.event_name == 'pull_request'
68+ if : github.event_name == 'pull_request' && vars.COOLIFY_URL != '' && vars.COOLIFY_APP_UUID != ''
6569 permissions :
6670 statuses : write
67- timeout-minutes : 1
71+ timeout-minutes : 2
72+ env :
73+ COOLIFY_URL : ${{ vars.COOLIFY_URL }}
74+ COOLIFY_APP_UUID : ${{ vars.COOLIFY_APP_UUID }}
75+ COOLIFY_PROJECT_UUID : ${{ vars.COOLIFY_PROJECT_UUID }}
76+ COOLIFY_ENVIRONMENT_UUID : ${{ vars.COOLIFY_ENVIRONMENT_UUID }}
6877 steps :
69- - name : Post Coolify preview link
78+ - name : Link the preview deployments page on the PR
79+ if : vars.COOLIFY_PROJECT_UUID != '' && vars.COOLIFY_ENVIRONMENT_UUID != ''
7080 uses : actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
7181 with :
7282 script : |
73- const sha = context.payload.pull_request.head.sha ;
83+ const { COOLIFY_URL, COOLIFY_PROJECT_UUID, COOLIFY_ENVIRONMENT_UUID, COOLIFY_APP_UUID } = process.env ;
7484 await github.rest.repos.createCommitStatus({
7585 owner: context.repo.owner,
7686 repo: context.repo.repo,
77- sha: sha,
87+ sha: context.payload.pull_request.head. sha,
7888 state: 'success',
79- target_url: 'https://coolify.hephaestus.aet.cit.tum.de/ project/lc8sows0ok8g880sg4o4o84w /environment/ek8o8800g4wks84c8w8wcckc /application/wg44k0ccsoscsgcco8swc4ks /preview-deployments' ,
89+ target_url: `${COOLIFY_URL}/ project/${COOLIFY_PROJECT_UUID} /environment/${COOLIFY_ENVIRONMENT_UUID} /application/${COOLIFY_APP_UUID} /preview-deployments` ,
8090 description: 'Click Details to view Coolify preview deployments',
81- context: 'Preview / Coolify'
91+ context: 'Preview / Coolify',
8292 });
8393
94+ # Forks are skipped deliberately: a preview runs with the instance's real credentials.
95+ - name : Update this PR's preview deployment, if it has one
96+ if : github.event.action == 'synchronize' && github.event.pull_request.head.repo.full_name == github.repository
97+ env :
98+ COOLIFY_TOKEN : ${{ secrets.COOLIFY_API_TOKEN }}
99+ PR_NUMBER : ${{ github.event.pull_request.number }}
100+ run : |
101+ set -euo pipefail
102+
103+ if [ -z "${COOLIFY_TOKEN}" ]; then
104+ echo "::notice::COOLIFY_API_TOKEN is not configured; skipping preview update."
105+ exit 0
106+ fi
107+
108+ body=$(mktemp)
109+ status=$(curl -sS -o "${body}" -w '%{http_code}' -X POST \
110+ -H "Authorization: Bearer ${COOLIFY_TOKEN}" \
111+ -H 'Accept: application/json' \
112+ --retry 3 --retry-connrefused --max-time 30 \
113+ "${COOLIFY_URL}/api/v1/deploy?uuid=${COOLIFY_APP_UUID}&pr=${PR_NUMBER}")
114+
115+ if [ "${status}" -ge 400 ]; then
116+ echo "::error::Coolify returned HTTP ${status}: $(cat "${body}")"
117+ exit 1
118+ fi
119+
120+ deployment=$(jq -r '.deployments[0].deployment_uuid // empty' "${body}")
121+ if [ -z "${deployment}" ]; then
122+ echo "::notice::PR #${PR_NUMBER} has no preview deployment ($(jq -r '.deployments[0].message // "no deployment queued"' "${body}"))."
123+ exit 0
124+ fi
125+
126+ echo "::notice::Queued Coolify deployment ${deployment} for PR #${PR_NUMBER}."
127+
84128 Quality :
85129 uses : ./.github/workflows/ci-quality-gates.yml
86130 needs : [detect-changes]
0 commit comments