Skip to content

Publish from CI ​

A game kept in a Git repository can publish itself: each push to main updates the site, with no one at the keyboard. The CI runs the same command as on your PC, with --json: it never asks a question, and it ends with the game's link and the build report.

Before you start ​

  1. Publish the game once from a terminal (first deploy) if you can, to answer its questions. A first deploy in CI takes the defaults; give it the site name with a rwk.json in the game folder, or the site-name input (--name on the command line), or it is made from the folder's name. Access protection is set up through the API when the token has the Access permissions and the account already has a Zero Trust team.
  2. Create a Cloudflare API token with the permissions the toolkit needs, for the one account, and save it in the CI's secrets as CLOUDFLARE_API_TOKEN. Add CLOUDFLARE_ACCOUNT_ID if the token reaches several accounts (or put --account <ID> on the command line).
  3. Put the game in the repository, in a folder such as game/ (the one with index.html and js/). Large pictures and sounds fit better in Git LFS.

The settings stay in your Cloudflare account, as for a deploy from your PC: change them with config on your PC. Feature settings apply at once; the others (include, exclude…) with the next CI run. To keep the site name and the files to leave out in the repository instead, next to the game, use a rwk.json: the pull request check (analyze) then counts the same files as the deploy.

GitHub Actions ​

.github/workflows/publish.yml in the game's repository:

yaml
name: Publish the game
on:
  push:
    branches: [main]
    paths: ["game/**"]
  workflow_dispatch:

# One publish at a time; a newer push waits for the one running.
concurrency: publish-game
permissions:
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    # A fork has no secrets: never publish from one.
    if: ${{ !github.event.repository.fork }}
    steps:
      - uses: actions/checkout@v5
        with:
          lfs: true # if the game uses Git LFS
      - id: rwk
        uses: Kokoroou/rpgmaker-web-toolkit@v0.4.0 # a release tag: v0.4.0 or later
        with:
          game-folder: game
          cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
      - run: echo "Published at $URL"
        env:
          URL: ${{ steps.rwk.outputs.url }}

The action installs Node.js and the toolkit at the tag you pin, then publishes the folder. Pin a release tag rather than main, and move it up when you want a newer toolkit. The run's page shows a summary: the link, the number of files and the warnings.

InputDefault
game-folder.The game folder, from the repository's root. For upgrade, the game's link or site name
commanddeployOr analyze, saves import, upgrade
site-namedeploy: the site name of a first deploy. A published game must already have it
cloudflare-api-tokenRequired, except for analyze
cloudflare-account-idWhen the token reaches several accounts: the one to publish to (its ID or name, see Several Cloudflare accounts)
node-version22
Output
urlThe game's link
siteThe site name
warningsHow many warnings the run had
resultThe whole result as JSON (see below)

Do not publish on pull_request: a pull request would replace the live site. Check it instead, as below.

Check pull requests without publishing ​

deploy --dry-run (or analyze) analyzes the game and counts its files against the free plan limits, with no Cloudflare token and nothing published. It fails the job when the build would not deploy (too many files, or a creator who does not allow publishing) and lists the warnings, so it suits pull_request:

yaml
on:
  pull_request:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Kokoroou/rpgmaker-web-toolkit@v0.4.0 # a release that has `analyze` (after v0.4.0)
        with:
          command: analyze
          game-folder: game

No cloudflare-api-token is needed, so a pull request from a fork can run it too.

Or from the shell: node cli/index.js deploy ./game --dry-run --json. The result has "dryRun": true and the build report (see Commands). It uses the first-deploy defaults, so a game with exclude patterns saved in R2 may count more files than its real deploy.

GitLab CI ​

.gitlab-ci.yml, with CLOUDFLARE_API_TOKEN as a masked CI/CD variable:

yaml
publish-game:
  image: node:22
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes: ["game/**/*"]
  variables:
    RWK_REF: v0.4.0 # a release tag: v0.4.0 or later
  script:
    - curl -fsSL "https://raw.githubusercontent.com/Kokoroou/rpgmaker-web-toolkit/$RWK_REF/run.sh" | bash -s -- deploy "$CI_PROJECT_DIR/game" --json > rwk-result.json
  artifacts:
    when: always
    paths: [rwk-result.json]

Any other CI ​

Anything with Node.js 22 or newer, curl and tar runs the same line as GitLab, with CLOUDFLARE_API_TOKEN (and maybe CLOUDFLARE_ACCOUNT_ID) in the environment:

sh
curl -fsSL https://raw.githubusercontent.com/Kokoroou/rpgmaker-web-toolkit/v0.4.0/run.sh | bash -s -- deploy ./game --json > rwk-result.json

From a clone of the toolkit: node cli/index.js deploy ./game --json after npm ci.

The result ​

The log always goes to stderr. With --json, stdout holds one JSON object:

json
{
  "schema": 1,
  "ok": true,
  "command": "deploy",
  "site": "my-game",
  "url": "https://my-game.alice.workers.dev",
  "locked": false,
  "build": { "files": 1834, "bytes": 412301204, "r2Files": 2, "r2Uploaded": 0 },
  "next": ["On a phone: open the link → browser menu → “Add to Home Screen” to play fullscreen."],
  "warnings": ["3 audio file(s) have no .m4a version: …"]
}

A failed run has "ok": false, error, hint (what to try, or null) and exitCode instead: 1 for a failure (Cloudflare, wrangler, a file), 2 for a question only a person can answer, 64 for a wrong command line. schema changes only when a field is removed or changes meaning. In GitHub Actions the toolkit also writes ok, site, url and warnings as step outputs and the summary, with or without --json, and shows each warning (and the error of a failed run) as an annotation on the run's page and on the pull request.

Good to know ​

  • Each run uploads only the files that changed, as on your PC; the free plan limits still apply.
  • The game folder in the checkout is never changed. The toolkit never prints the token; keep it in the CI's secrets, never in the repository.
  • Unattended, a deploy does not upload the save/ folder (saves import does) and never deletes the old Worker after a rename: run those from a terminal.

PolyForm Noncommercial License 1.0.0, plus any use by game creators for their own games. For games you own, played by you.
Screenshots: GameDev: The Beginning by yancharkin, CC BY-SA 4.0 (credits). Not affiliated with Cloudflare or RPG Maker.