Skip to content

Run Flutter widget code on Codename One #11488

Run Flutter widget code on Codename One

Run Flutter widget code on Codename One #11488

Workflow file for this run

name: Build Hugo Website
on:
pull_request:
paths:
- 'docs/website/**'
- 'docs/developer-guide/**'
- 'scripts/cn1playground/**'
- 'scripts/initializr/**'
- 'scripts/website/**'
- 'scripts/skindesigner/**'
# The Initializr/playground/skindesigner JS bundles are built from
# JavaScriptPort sources and the ParparVM translator at workflow
# time, so a change in either also needs to redeploy the website.
# Without these paths a JS-port bug fix (e.g. dialog rendering
# in be3bc6dcd) sits in the branch with no Cloudflare preview
# refresh until an unrelated docs change happens to trigger
# the workflow.
- 'Ports/JavaScriptPort/**'
- 'vm/ByteCodeTranslator/**'
- 'vm/JavaAPI/**'
- 'CodenameOne/src/**'
# The other root build_javadocs.sh generates from, and the other one
# check-guide-links.py indexes. Without it, deleting a linked CLDC type
# merges unvalidated and the next scheduled build is where it surfaces.
- 'Ports/CLDC11/src/**'
# The developer guide this site renders includes a build hint table that is
# generated rather than committed, so a change to the catalog or to the
# renderer changes the published page without touching docs/. The
# annotations it is also rendered from are covered by CodenameOne/src/**
# above. Same gap codex reported on developer-guide-docs.yml; this is the
# other workflow that renders the table.
- 'maven/build-hint-catalog/**'
- 'maven/build-hint-tools/**'
- 'scripts/gen-build-hint-table.sh'
# The Hugo build embeds JavaDocs produced by this script, so a change
# to how the docs are generated must redeploy the website too.
- '.github/scripts/build_javadocs.sh'
# The doclet that renders the API pages themselves. It is outside the
# maven reactor and built only by this workflow, so nothing else would
# catch a change to it.
- 'maven/javadoc-hugo-doclet/**'
- '.github/workflows/website-docs.yml'
push:
branches: [main, master]
paths:
- 'docs/website/**'
- 'docs/developer-guide/**'
- 'scripts/cn1playground/**'
- 'scripts/initializr/**'
- 'scripts/website/**'
- 'scripts/skindesigner/**'
- 'Ports/JavaScriptPort/**'
- 'vm/ByteCodeTranslator/**'
- 'vm/JavaAPI/**'
- 'CodenameOne/src/**'
# The other root build_javadocs.sh generates from, and the other one
# check-guide-links.py indexes. Without it, deleting a linked CLDC type
# merges unvalidated and the next scheduled build is where it surfaces.
- 'Ports/CLDC11/src/**'
# As above: the build hint table is generated, not committed.
- 'maven/build-hint-catalog/**'
- 'maven/build-hint-tools/**'
- 'scripts/gen-build-hint-table.sh'
# The Hugo build embeds JavaDocs produced by this script, so a change
# to how the docs are generated must redeploy the website too.
- '.github/scripts/build_javadocs.sh'
# The doclet that renders the API pages themselves. It is outside the
# maven reactor and built only by this workflow, so nothing else would
# catch a change to it.
- 'maven/javadoc-hugo-doclet/**'
- '.github/workflows/website-docs.yml'
workflow_dispatch:
inputs:
deploy_production:
description: 'Deploy this master build to production'
required: false
default: false
type: boolean
# Daily production rebuild so future-dated blog posts (the daily release
# follow-ups) publish on their own date with no manual push. Production
# builds keep HUGO_BUILD_FUTURE=false, so a post only appears once its date
# has arrived (UTC; hugo.toml sets no timeZone). Runs at 00:15 UTC; GitHub
# may delay scheduled runs under load, but the post still surfaces same-day.
schedule:
- cron: '15 0 * * *'
permissions:
contents: read
pull-requests: write
jobs:
build:
runs-on: ubuntu-latest
# A ceiling, because there was not one: this job hung in apt and ran for six
# hours before GitHub's own limit stopped it.
timeout-minutes: 90
env:
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN || secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || secrets.CF_ACCOUNT_ID }}
CF_PAGES_PROJECT_NAME: ${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || 'codenameone' }}
CF_PAGES_PRODUCTION_BRANCH: ${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }}
WRANGLER_VERSION: '4.129.0'
# `npx` installs Wrangler on a clean runner. An unavailable npm audit
# endpoint must not keep that install alive while the Worker test waits
# for a process that has not actually started yet.
npm_config_audit: 'false'
npm_config_fund: 'false'
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
extended: true
- name: Set up Java 8 for Initializr build
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '8'
# Restored once for the whole job, and saved with whatever the later Java 25 steps
# pulled as well -- both use the same ~/.m2. Without it every run of this workflow
# re-fetched the world from Maven Central, which answered one of them with HTTP 429
# and failed the build on the pom rather than on anything in the change. Every other
# Java workflow here already caches this way.
cache: 'maven'
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
- name: Prepare Wrangler
timeout-minutes: 6
run: |
set -euo pipefail
for attempt in 1 2 3; do
if timeout 90s npx --yes "wrangler@${WRANGLER_VERSION}" --version; then
exit 0
fi
echo "::warning::Wrangler bootstrap attempt ${attempt} failed; retrying"
done
exit 1
- name: Install Asciidoctor tooling
run: |
set -euo pipefail
gem install --no-document asciidoctor rouge
- name: Download latest OTA skins
run: |
set -euo pipefail
scripts/website/fetch_ota_skins.sh
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check redirect rule ordering
run: python3 scripts/website/test_redirect_order.py
- name: Test developer guide chapter generation
run: ruby scripts/website/test_generate_developer_guide.rb
- name: Test developer guide PDF redirect resolver
run: scripts/website/test_update_developer_guide_redirect.sh
- name: Update developer guide PDF redirect
run: |
set -euo pipefail
scripts/website/update_developer_guide_redirect.sh
env:
GITHUB_TOKEN: ${{ github.token }}
# The Initializr/Playground/Skin Designer JavaScript bundles are built by
# scripts/website/build.sh through xvfb-run: the Codename One Maven
# plugin's CSS/theme compile instantiates JavaSEPort, which needs a
# display on the headless runner. (xvfb formerly also served the Skin
# Designer screenshot generation step, which has been removed -- the
# screenshots are now committed under docs/developer-guide/img/skin-designer.)
- name: Set up xvfb for headless JavaScript bundle builds
run: |
set -euo pipefail
bash scripts/ci/apt-get-update.sh
sudo apt-get install -y --no-install-recommends xvfb
- name: Set up Java 25 for website build
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '25'
- name: Build website
run: |
set -euo pipefail
scripts/website/build.sh
env:
WEBSITE_INCLUDE_JAVADOCS: "true"
WEBSITE_INCLUDE_DEVGUIDE: "true"
WEBSITE_INCLUDE_INITIALIZR: "true"
WEBSITE_INCLUDE_PLAYGROUND: "true"
# The Initializr's JavaScript app is built with the local ParparVM
# target, whose builder lives in the repo (8.0-SNAPSHOT) plugin rather
# than the pinned release. Bootstrap the local snapshot artifacts so
# the initializr (and the other site apps) build against repo HEAD.
WEBSITE_BOOTSTRAP_CN1_SNAPSHOTS: "true"
# Resolve the latest persisted master result for each port before
# Hugo writes the static status table. Checked-in reports remain the
# fallback if the data branch is temporarily unavailable.
WEBSITE_REFRESH_PORT_STATUS: "true"
# PR previews build with future-dated posts visible so reviewers
# can read posts staged for later in the week. Production deploys
# (push to master) keep the default so future posts only appear
# on their actual date.
HUGO_BUILD_FUTURE: ${{ github.event_name == 'pull_request' && 'true' || 'false' }}
- name: Validate API reference output
run: |
set -euo pipefail
test -f docs/website/public/javadoc/index.html
# Pages are published at the directory URL, because Cloudflare Pages
# will not serve a .html one: see check-javadoc-urls.sh.
test -f docs/website/public/javadoc/com/codename1/ui/Component/index.html
test -f docs/website/public/javadoc/com/codename1/ui/package-summary/index.html
test -f docs/website/public/javadoc-search.json
# The fragment encoding is the compatibility surface, so assert one of
# the awkward spellings rather than only that the page exists. This is
# a canary for the parity gate rather than a duplicate of it: the gate
# compares two trees, and a gate that ends up comparing nothing reports
# nothing missing.
#
# Quotes are optional because the site is built with --minify and the
# minifier drops them wherever HTML allows: this page really does carry
# id=createImage(byte[],int,int) with no quotes at all.
grep -Eq 'id="?createImage\(byte\[\],int,int\)"?' \
docs/website/public/javadoc/com/codename1/ui/Image/index.html
# The old integration copied the standard doclet's tree into static/
# and scoped its stylesheet with a script. Nothing should reintroduce
# either: they are what broke dark mode.
test ! -e docs/website/static/javadoc
test ! -e docs/website/assets/js/cn1-javadoc.js
- name: Validate API URLs on the Pages runtime
run: |
set -euo pipefail
# Asks the server rather than the filesystem. Everything else was green
# on a build where clicking any class left the site: Pages redirects
# /x.html to /x before an asset is considered, so the page published at
# the extension was one nobody could reach.
scripts/website/check-javadoc-urls.sh docs/website/public 8789
- name: Validate Port Status page output
run: |
set -euo pipefail
node scripts/website/validate_port_status.mjs docs/website/public
- name: Validate comparison page claims
run: |
set -euo pipefail
node scripts/website/validate_compare_page.mjs docs/website/public
- name: Validate Initializr page output
run: |
set -euo pipefail
test -f docs/website/public/initializr/index.html
- name: Validate Playground page output
run: |
set -euo pipefail
test -f docs/website/public/playground/index.html
- name: Validate Initializr JS bundle output
run: |
set -euo pipefail
test -f docs/website/public/initializr-app/index.html
grep -Fq 'downloadProject' docs/website/public/initializr-app/translated_app.js
grep -Fq 'cn1-initializr-project-downloaded' \
docs/website/public/initializr-app/com_codename1_initializr_WebsiteThemeNative.js
grep -Fq 'cn1-initializr-project-downloaded' docs/website/public/initializr/index.html
node docs/website/scripts/test-initializr-download-bridge.mjs \
docs/website/public/initializr-app/com_codename1_initializr_WebsiteThemeNative.js
- name: Validate website conversion telemetry
run: |
set -euo pipefail
node docs/website/scripts/test-signup-funnel.mjs docs/website/public
node docs/website/scripts/test-cn1-crisp-events.mjs
- name: Validate Playground JS bundle output
run: test -f docs/website/public/playground-app/index.html
- name: Validate redirects against local Pages runtime
run: |
set -euo pipefail
PORT=8788
cd docs/website
npx --yes "wrangler@${WRANGLER_VERSION}" pages dev public \
--port "${PORT}" \
--ip 127.0.0.1 \
--compatibility-date=2026-02-18 > /tmp/wrangler-pages-dev.log 2>&1 &
WRANGLER_PID=$!
cleanup() {
kill "${WRANGLER_PID}" >/dev/null 2>&1 || true
}
trap cleanup EXIT
print_log_on_error() {
echo "wrangler pages dev log (tail):" >&2
tail -n 200 /tmp/wrangler-pages-dev.log >&2 || true
}
trap print_log_on_error ERR
for i in $(seq 1 60); do
if curl -sSf "http://127.0.0.1:${PORT}/" >/dev/null; then
break
fi
sleep 1
done
if ! curl -sSf "http://127.0.0.1:${PORT}/" >/dev/null; then
echo "wrangler pages dev did not become ready on port ${PORT}" >&2
exit 1
fi
cd ../..
python3 scripts/website/test_redirects.py \
--base-url "http://127.0.0.1:${PORT}" \
--redirects-file docs/website/public/_redirects \
--skip-auto-cases
- name: Validate internal links and images
uses: lycheeverse/lychee-action@v2
with:
# Pin to v0.23.0. lychee v0.24.0 renamed its release assets
# from `lychee-<arch>-unknown-linux-gnu.tar.gz` to
# `lychee-lychee-v0.24.0-<arch>-unknown-linux-gnu.tar.gz`,
# and `lychee-action@v2` still constructs the old URL, so
# `lycheeVersion: latest` 404s and breaks this job with
# curl exit code 22. Bump once the action catches up.
lycheeVersion: v0.23.0
workingDirectory: docs/website
args: >-
--offline
--no-progress
--root-dir public
public/**/*.html
# The developer guide links into this site, so a page renamed, deleted or
# re-slugged here breaks the guide. The check lives in THIS workflow rather
# than in developer-guide-docs.yml because it is the route data that
# changed: widening that workflow's paths to docs/website/** would run the
# full guide build -- maven install, demo build, screenshot generation --
# on every blog post the daily publisher pushes, to run one Python script.
# This job already triggers on docs/website/**, and the check needs nothing
# but a checkout.
- name: Check developer guide links against the routes this site serves
run: python3 scripts/developer-guide/check-guide-links.py
- name: Reject absolute codenameone.com links
run: |
set -euo pipefail
report="docs/website/reports/disallowed-codenameone-links.txt"
mkdir -p "$(dirname "$report")"
rg -n --no-heading -S '\]\((https?:)?//(www\.)?codenameone\.com([/:?#)]|$)|<https?://(www\.)?codenameone\.com([/:?#>]|$)|(href|src)=["'"'"']https?://(www\.)?codenameone\.com([/:?#]|$)' \
docs/website/content docs/website/layouts docs/website/static > "$report" || true
if [ -s "$report" ]; then
echo "Disallowed absolute codenameone.com links found (use relative URLs or non-www subdomains):" >&2
sed -n '1,200p' "$report" >&2
exit 1
fi
- name: Upload codenameone link policy report
if: ${{ always() }}
uses: actions/upload-artifact@v7
with:
name: codenameone-link-policy-report
path: docs/website/reports/disallowed-codenameone-links.txt
if-no-files-found: ignore
- name: Validate OTA skin output
run: |
set -euo pipefail
test -f docs/website/public/OTA/Skins.xml
- name: Validate developer guide redirect output
run: |
set -euo pipefail
test -f docs/website/public/_redirects
test -f docs/website/public/developer-guide/index.html
python3 scripts/website/check_developer_guide.py docs/website/public
grep -Eq '^/files/developer-guide\.pdf https://github\.com/codenameone/CodenameOne/releases/download/.+/developer-guide\.pdf 302$' docs/website/public/_redirects
grep -Eq '^/manual /developer-guide/ 301$' docs/website/public/_redirects
grep -Eq '^/manual/ /developer-guide/ 301$' docs/website/public/_redirects
grep -Eq '^/developer-guide /developer-guide/ 301$' docs/website/public/_redirects
- name: Validate RSS output and alias
run: |
set -euo pipefail
test -f docs/website/public/blog/index.xml
test ! -f docs/website/public/index.xml
grep -Eq '^/feed\.xml /blog/index\.xml 302$' docs/website/public/_redirects
- name: Upload built site artifact
uses: actions/upload-artifact@v7
with:
name: website-preview
path: docs/website/public
if-no-files-found: error
- name: Check Cloudflare preview deploy credentials
if: ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN == '' }}
run: |
echo "::warning::Skipping Cloudflare Pages preview deploy because no API token secret is configured. Set CLOUDFLARE_TOKEN (preferred) or CF_API_TOKEN."
- name: Deploy PR preview to Cloudflare Pages
id: cf_preview
if: ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN != '' }}
env:
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_TOKEN }}
PREVIEW_BRANCH: pr-${{ github.event.pull_request.number }}-website-preview
run: |
set -uo pipefail
# Stream wrangler output to the job log (via tee) while still
# capturing it so we can pull the *.pages.dev preview URL out. The
# previous `deploy_output=$(... 2>&1)` form hid every line — when
# wrangler died without any stdout we had nothing to debug with.
# -e is intentionally off for the wrangler invocation so we can
# report its exit status explicitly instead of exiting opaquely.
deploy_log="$(mktemp)"
npx --yes "wrangler@${WRANGLER_VERSION}" pages deploy docs/website/public \
--project-name "${CF_PAGES_PROJECT_NAME}" \
--branch "${PREVIEW_BRANCH}" 2>&1 | tee "${deploy_log}"
wrangler_status="${PIPESTATUS[0]}"
if [ "${wrangler_status}" -ne 0 ]; then
echo "wrangler pages deploy exited with status ${wrangler_status}" >&2
exit "${wrangler_status}"
fi
deployment_url="$(grep 'Deployment complete!' "${deploy_log}" | grep -Eo 'https://[A-Za-z0-9._-]+\.pages\.dev' | tail -n1 || true)"
preview_url="$(grep 'Deployment alias URL:' "${deploy_log}" | grep -Eo 'https://[A-Za-z0-9._-]+\.pages\.dev' | tail -n1 || true)"
if [ -z "${deployment_url}" ]; then
echo "wrangler reported success but printed no immutable deployment URL." >&2
exit 1
fi
if [ -z "${preview_url}" ]; then
# Cloudflare does not always echo "Deployment alias URL", even though the branch
# alias is created either way -- one deploy of this branch printed it and the next
# did not. The upload, the alias and the deployment had all succeeded, so failing
# here reported a working preview as a broken build.
#
# The alias is derived from the branch name, and PREVIEW_BRANCH is built from a PR
# number so it is always lowercase, hyphenated and well inside the 28-character
# limit Cloudflare truncates at -- no sanitising to replicate. Rebuild it, and only
# accept it if it actually serves.
candidate="https://${PREVIEW_BRANCH}.${CF_PAGES_PROJECT_NAME}.pages.dev"
if curl -fsS -o /dev/null --max-time 30 "${candidate}"; then
preview_url="${candidate}"
echo "No alias line in the deploy output; recovered it from the branch name: ${preview_url}"
else
preview_url="${deployment_url}"
echo "::warning::No alias line in the deploy output and ${candidate} did not respond; using the immutable deployment URL as the preview link."
fi
fi
echo "deployment_url=${deployment_url}" >> "${GITHUB_OUTPUT}"
echo "preview_url=${preview_url}" >> "${GITHUB_OUTPUT}"
echo "preview_branch=${PREVIEW_BRANCH}" >> "${GITHUB_OUTPUT}"
- name: Validate deployed comparison page
if: ${{ steps.cf_preview.outputs.deployment_url != '' }}
run: |
set -euo pipefail
deployed_compare="$(mktemp)"
curl --fail --silent --show-error \
--retry 6 \
--retry-delay 2 \
--retry-all-errors \
"${{ steps.cf_preview.outputs.deployment_url }}/compare/" \
--output "${deployed_compare}"
node scripts/website/validate_compare_page.mjs "${deployed_compare}"
- name: Publish Cloudflare preview link in CI summary
if: ${{ steps.cf_preview.outputs.preview_url != '' }}
run: |
{
echo "## Cloudflare Preview"
echo
echo "- URL: ${{ steps.cf_preview.outputs.preview_url }}"
echo "- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\`"
} >> "${GITHUB_STEP_SUMMARY}"
- name: Comment Cloudflare preview link on PR
if: ${{ github.event_name == 'pull_request' && steps.cf_preview.outputs.preview_url != '' }}
uses: actions/github-script@v9
with:
script: |
const marker = '<!-- cn1-cloudflare-preview -->';
const body = [
marker,
'## Cloudflare Preview',
'',
`- URL: ${{ steps.cf_preview.outputs.preview_url }}`,
`- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\``,
].join('\n');
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
});
const existing = comments.find((comment) =>
comment.user?.type === 'Bot' && comment.body?.includes(marker)
);
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
- name: Prune older Cloudflare preview deployments for this PR branch
if: ${{ steps.cf_preview.outputs.preview_url != '' }}
env:
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_TOKEN }}
PREVIEW_BRANCH: ${{ steps.cf_preview.outputs.preview_branch }}
DEPLOYMENT_URL: ${{ steps.cf_preview.outputs.deployment_url }}
run: |
set -euo pipefail
api_base="https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}/deployments"
tmp_json="$(mktemp)"
curl -sS \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
"${api_base}" > "${tmp_json}"
cat > /tmp/cf_preview_cleanup.py <<'PY'
import json
import sys
path, preview_branch, deployment_url = sys.argv[1:]
data = json.load(open(path, encoding="utf-8"))
result = data.get("result", []) or []
def normalized(value):
return (value or "").rstrip("/")
def branch_of(dep):
trig = dep.get("deployment_trigger") or {}
meta = trig.get("metadata") or {}
return meta.get("branch")
current_id = None
for dep in result:
if normalized(dep.get("url")) == normalized(deployment_url):
current_id = dep.get("id")
break
if not current_id:
raise SystemExit(
f"Could not identify current Cloudflare deployment for {deployment_url}; refusing to prune"
)
for dep in result:
dep_id = dep.get("id")
if not dep_id or dep_id == current_id:
continue
if branch_of(dep) == preview_branch:
print(dep_id)
PY
python3 /tmp/cf_preview_cleanup.py "${tmp_json}" "${PREVIEW_BRANCH}" "${DEPLOYMENT_URL}" > /tmp/cf_deployments_to_delete.txt
while IFS= read -r dep_id; do
[ -z "${dep_id}" ] && continue
echo "Deleting old preview deployment: ${dep_id}"
curl -sS -X DELETE \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
"${api_base}/${dep_id}" >/dev/null
done < /tmp/cf_deployments_to_delete.txt
- name: Check Cloudflare deploy credentials
if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master')) || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.deploy_production && (github.ref_name == 'main' || github.ref_name == 'master'))) && env.CLOUDFLARE_TOKEN == '' }}
run: |
echo "::warning::Skipping Cloudflare Pages deploy because no API token secret is configured. Set CLOUDFLARE_TOKEN (preferred) or CF_API_TOKEN."
- name: Deploy to Cloudflare Pages
if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master')) || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.deploy_production && (github.ref_name == 'main' || github.ref_name == 'master'))) && env.CLOUDFLARE_TOKEN != '' }}
uses: cloudflare/wrangler-action@v3
env:
# Keep these env vars explicit so Wrangler can authenticate in non-interactive CI.
CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.CLOUDFLARE_ACCOUNT_ID }}
with:
# Also pass through action inputs for compatibility with wrangler-action versions.
apiToken: ${{ env.CLOUDFLARE_TOKEN }}
accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }}
command: >-
pages deploy docs/website/public
--project-name=${{ env.CF_PAGES_PROJECT_NAME }}
--branch=${{ env.CF_PAGES_PRODUCTION_BRANCH }}
# touched to retrigger Hugo workflow (path filter matches this file)