Skip to content

Forge API v2 migration + GitHub-built static binaries - #2

Open
ngunyimacharia wants to merge 16 commits into
mainfrom
feat/forge-api-v2-migration
Open

Forge API v2 migration + GitHub-built static binaries#2
ngunyimacharia wants to merge 16 commits into
mainfrom
feat/forge-api-v2-migration

Conversation

@ngunyimacharia

@ngunyimacharia ngunyimacharia commented Jul 27, 2026

Copy link
Copy Markdown
Member

Summary

Migrates forge-previewer from the deprecated Forge API v1 to API v2 using laravel/forge-sdk ^4.1, upgrades the application stack, and replaces the committed PHAR with self-contained release binaries built by GitHub Actions.

Implements docs/specs/2026-07-27-forge-api-v2-migration-design.md.

Changes

Upstream sync

  • Merge the two missing commits from ryangjchandler/forge-previewer: commit composer.lock and remove InspireCommand.
  • Preserve this fork's --timeout option and config('app.timeout') default.
  • Commit composer.lock going forward.

Runtime and dependency upgrades

  • Require PHP 8.5, Laravel Zero 12.1, Forge SDK 4.1, Termwind 2.4, Pest 4.7, and Mockery 1.6.12.
  • Migrate the bootstrap to Laravel Zero's fluent application builder.
  • Update the PHPUnit configuration and test scaffolding.
  • Rename HandlesOutput::fail() to bail() to avoid a collision with Illuminate\Console\Command::fail().

Forge API v2 migration

  • Scope every Forge API call to an organization using the new --org option or FORGE_ORG environment variable.
  • Use lazy pagination for list endpoints so every page is scanned.
  • Update site creation, deployment scripts, environment updates, deployments, commands, and resource deletion for Forge SDK v4.
  • Create and delete certificates per domain, using dns-01 for wildcard domains and http-01 otherwise.
  • Fix database-user deletion so it deletes the user rather than the stale database variable.
  • Change the default PHP version from php81 to php84.
  • Write CI output to $GITHUB_OUTPUT instead of using the deprecated ::set-output command.

Forge API v2 does not accept DNS-provider credentials when creating certificates. The existing --route-53-key and --route-53-secret options remain for CLI compatibility, but credentials must now be configured in Forge for the dns-01 challenge.

CI and distribution

  • Run Pest on PHP 8.5 for pushes and pull requests.
  • Build a PHAR and then a static musl binary when a v* tag is pushed.
  • Smoke-test the binary natively and in Ubuntu 20.04 before attaching binaries and checksums to the GitHub release.
  • Stop committing builds/forge-previewer and use the source entry script for Composer installations.
  • Document binary and source installation, organization configuration, wildcard certificates, and current CI examples.

Verification

  • ./forge-previewer list
  • ./forge-previewer deploy --help
  • ./forge-previewer destroy --help
  • Missing-organization error handling
  • Pest test suite: 3 tests passed
  • composer validate
  • Workflow YAML validation
  • Reflection check for all 24 Forge SDK methods used by the application

The static-binary release pipeline requires a real v* tag, and a live deploy/destroy test requires Forge credentials. Both remain gated by their respective external prerequisites.

@ngunyimacharia
ngunyimacharia force-pushed the feat/forge-api-v2-migration branch from 1a60477 to 7c46dad Compare July 27, 2026 15:21
ngunyimacharia and others added 2 commits July 28, 2026 13:12
app('git.version') shells out to git at boot; inside a PHAR the cwd is a phar:// path so proc_open fails and the packaged binary cannot start. Bake the tag in as a literal at build time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Box's requirements checker rejects the embedded PHP without iconv (required by symfony/polyfill-mbstring). Add it to the static-php-cli extension set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ngunyimacharia

Copy link
Copy Markdown
Member Author

Release pipeline verified end-to-end via v1.0.0-beta.1 (tag → release.yml, all 3 jobs green, both smoke tests incl. ubuntu:20.04, assets published + checksums verified, binary runs standalone reporting v1.0.0-beta.1).

The beta run caught two bugs that would have shipped a non-booting binary — both fixed here:

  • fix(ci): stamp release version…app('git.version') ran git describe at boot with cwd = phar://…, crashing proc_open.
  • fix(ci): add iconv extension… — Box's requirements checker rejected the embedded PHP without iconv (needed by symfony/polyfill-mbstring).

Still outstanding (needs real credentials): a live-Forge deploydestroy against a test org/server.

ngunyimacharia and others added 8 commits July 28, 2026 14:55
…ation errors

Forge API v2 validation requires www_redirect_type (the OpenAPI schema marked it optional, but the live API rejects createSite without it) — default to 'none' for preview subdomains. Also catch Laravel\Forge\Exceptions\ValidationException in both commands and print the field-level errors instead of the opaque 'The given data failed to pass validation.'

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ested error bag

Forge API v2 requires letsencrypt.key_type on createCertificate (default ecdsa). Also fix bailValidation: the SDK passes the full {message, errors} body, so flatten the nested errors bag recursively instead of interpolating arrays into strings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anaged databases)

Servers using an external database return 404 on database/schemas and database/users. safelyIterate() treats a NotFoundException on a list endpoint as empty so destroy still cleans up the remaining resources and deletes the site.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…olerate cert conflicts

If createSite returns a 'domain has already been added' 422 (e.g. a prior partial/failed create that our site scan missed), look the site up and continue provisioning (setup-command, env, cert, deploy) instead of aborting and leaving it half-configured. Also tolerate a ValidationException on createCertificate (a reused site may already have one). Extract flattenValidationMessages into HandlesOutput.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rovisioning

Forge returns a 422 ('recently created, wait 60s') when updating the .env of a just-created site. Retry the read-modify-write (bounded by --timeout) until provisioning completes, for both the --edit-env and database env-injection paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enabling push_to_deploy in createSite makes Forge auto-deploy the instant the repo finishes cloning — before the deployment script and environment are configured — running Forge's default script and racing/blocking our own deployment. Create the site with push_to_deploy=false, run the explicit deployment (correct script + env), then enable push-to-deploy so future pushes still auto-deploy (skipped when --no-quick-deploy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ wedges)

forge-previewer always runs a deployment immediately after creating the site, which installs dependencies. Asking Forge to also install them during creation is redundant and runs an uncontrollable parallel composer install that, on servers hitting composer's download race, wedges and blocks our deployment. The deployment (with its serialized composer + shared-env restore) is the single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Site creation (repo clone + directory setup) is async. createDeployment was firing before the site directory existed, so the deploy script's first command (cd <site dir>) failed instantly (2s). Poll the site until SiteStatus leaves creating/installing before running setup/cert/deploy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants