1717
1818permissions :
1919 contents : read
20+ pull-requests : write
2021
2122jobs :
2223 build :
2324 runs-on : ubuntu-latest
2425 env :
2526 CLOUDFLARE_TOKEN : ${{ secrets.CLOUDFLARE_TOKEN || secrets.CF_API_TOKEN }}
2627 CLOUDFLARE_ACCOUNT_ID : ${{ secrets.CLOUDFLARE_ACCOUNT_ID || secrets.CF_ACCOUNT_ID }}
28+ CF_PAGES_PROJECT_NAME : ${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || 'codenameone' }}
29+ CF_PAGES_PRODUCTION_BRANCH : ${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }}
2730 steps :
2831 - name : Check out repository
2932 uses : actions/checkout@v4
@@ -141,10 +144,13 @@ jobs:
141144 - name : Validate internal links and images
142145 uses : lycheeverse/lychee-action@v2
143146 with :
147+ lycheeVersion : latest
148+ workingDirectory : docs/website
144149 args : >-
145150 --offline
146151 --no-progress
147- docs/website/public/**/*.html
152+ --root-dir public
153+ public/**/*.html
148154
149155 - name : Reject absolute codenameone.com links
150156 run : |
@@ -196,6 +202,148 @@ jobs:
196202 path : docs/website/public
197203 if-no-files-found : error
198204
205+ - name : Check Cloudflare preview deploy credentials
206+ if : ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN == '' }}
207+ run : |
208+ echo "::warning::Skipping Cloudflare Pages preview deploy because no API token secret is configured. Set CLOUDFLARE_TOKEN (preferred) or CF_API_TOKEN."
209+
210+ - name : Deploy PR preview to Cloudflare Pages
211+ id : cf_preview
212+ if : ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN != '' }}
213+ env :
214+ CLOUDFLARE_API_TOKEN : ${{ env.CLOUDFLARE_TOKEN }}
215+ PREVIEW_BRANCH : pr-${{ github.event.pull_request.number }}-website-preview
216+ run : |
217+ set -euo pipefail
218+ deploy_output="$(npx --yes wrangler@4 pages deploy docs/website/public \
219+ --project-name "${CF_PAGES_PROJECT_NAME}" \
220+ --branch "${PREVIEW_BRANCH}" 2>&1)"
221+ echo "${deploy_output}"
222+ preview_url="$(printf '%s\n' "${deploy_output}" | grep -Eo 'https://[A-Za-z0-9._-]+\.pages\.dev' | tail -n1 || true)"
223+ if [ -z "${preview_url}" ]; then
224+ echo "Could not determine Cloudflare preview URL from deploy output." >&2
225+ exit 1
226+ fi
227+ echo "preview_url=${preview_url}" >> "${GITHUB_OUTPUT}"
228+ echo "preview_branch=${PREVIEW_BRANCH}" >> "${GITHUB_OUTPUT}"
229+
230+ - name : Publish Cloudflare preview link in CI summary
231+ if : ${{ steps.cf_preview.outputs.preview_url != '' }}
232+ run : |
233+ {
234+ echo "## Cloudflare Preview"
235+ echo
236+ echo "- URL: ${{ steps.cf_preview.outputs.preview_url }}"
237+ echo "- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\`"
238+ } >> "${GITHUB_STEP_SUMMARY}"
239+
240+ - name : Comment Cloudflare preview link on PR
241+ if : ${{ github.event_name == 'pull_request' && steps.cf_preview.outputs.preview_url != '' }}
242+ uses : actions/github-script@v7
243+ with :
244+ script : |
245+ const marker = '<!-- cn1-cloudflare-preview -->';
246+ const body = [
247+ marker,
248+ '## Cloudflare Preview',
249+ '',
250+ `- URL: ${{ steps.cf_preview.outputs.preview_url }}`,
251+ `- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\``,
252+ ].join('\n');
253+
254+ const { owner, repo } = context.repo;
255+ const issue_number = context.issue.number;
256+ const comments = await github.paginate(github.rest.issues.listComments, {
257+ owner,
258+ repo,
259+ issue_number,
260+ per_page: 100,
261+ });
262+ const existing = comments.find((comment) =>
263+ comment.user?.type === 'Bot' && comment.body?.includes(marker)
264+ );
265+
266+ if (existing) {
267+ await github.rest.issues.updateComment({
268+ owner,
269+ repo,
270+ comment_id: existing.id,
271+ body,
272+ });
273+ } else {
274+ await github.rest.issues.createComment({
275+ owner,
276+ repo,
277+ issue_number,
278+ body,
279+ });
280+ }
281+
282+ - name : Prune older Cloudflare preview deployments for this PR branch
283+ if : ${{ steps.cf_preview.outputs.preview_url != '' }}
284+ env :
285+ CLOUDFLARE_API_TOKEN : ${{ env.CLOUDFLARE_TOKEN }}
286+ PREVIEW_BRANCH : ${{ steps.cf_preview.outputs.preview_branch }}
287+ PREVIEW_URL : ${{ steps.cf_preview.outputs.preview_url }}
288+ run : |
289+ set -euo pipefail
290+ api_base="https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}/deployments"
291+ tmp_json="$(mktemp)"
292+ curl -sS \
293+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
294+ -H "Content-Type: application/json" \
295+ "${api_base}" > "${tmp_json}"
296+
297+ cat > /tmp/cf_preview_cleanup.py <<'PY'
298+ import json
299+ import sys
300+
301+ path, preview_branch, preview_url = sys.argv[1:]
302+ data = json.load(open(path, encoding="utf-8"))
303+ result = data.get("result", []) or []
304+
305+ def aliases_of(dep):
306+ aliases = dep.get("aliases") or []
307+ out = []
308+ for a in aliases:
309+ if isinstance(a, str):
310+ out.append(a)
311+ elif isinstance(a, dict):
312+ v = a.get("url")
313+ if isinstance(v, str):
314+ out.append(v)
315+ return out
316+
317+ def branch_of(dep):
318+ trig = dep.get("deployment_trigger") or {}
319+ meta = trig.get("metadata") or {}
320+ return meta.get("branch")
321+
322+ current_id = None
323+ for dep in result:
324+ if preview_url in aliases_of(dep):
325+ current_id = dep.get("id")
326+ break
327+
328+ for dep in result:
329+ dep_id = dep.get("id")
330+ if not dep_id or dep_id == current_id:
331+ continue
332+ if branch_of(dep) == preview_branch:
333+ print(dep_id)
334+ PY
335+
336+ python3 /tmp/cf_preview_cleanup.py "${tmp_json}" "${PREVIEW_BRANCH}" "${PREVIEW_URL}" > /tmp/cf_deployments_to_delete.txt
337+
338+ while IFS= read -r dep_id; do
339+ [ -z "${dep_id}" ] && continue
340+ echo "Deleting old preview deployment: ${dep_id}"
341+ curl -sS -X DELETE \
342+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
343+ -H "Content-Type: application/json" \
344+ "${api_base}/${dep_id}" >/dev/null
345+ done < /tmp/cf_deployments_to_delete.txt
346+
199347 - name : Check Cloudflare deploy credentials
200348 if : ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master') && env.CLOUDFLARE_TOKEN == '' }}
201349 run : |
@@ -214,5 +362,5 @@ jobs:
214362 accountId : ${{ env.CLOUDFLARE_ACCOUNT_ID }}
215363 command : >-
216364 pages deploy docs/website/public
217- --project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CLOUDFLARE_PAGES_PROJECT_NAME || secrets. CF_PAGES_PROJECT_NAME || 'codenameone' }}
218- --branch=${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || secrets.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }}
365+ --project-name=${{ env. CF_PAGES_PROJECT_NAME }}
366+ --branch=${{ env.CF_PAGES_PRODUCTION_BRANCH }}
0 commit comments