Skip to content

Publish standalone CLI bundles to Apps CDN and install from the CDN latest alias - #3835

Merged
bcotrim merged 13 commits into
trunkfrom
stu-1780-upload-cli-bundles-to-cdn
Jun 18, 2026
Merged

Publish standalone CLI bundles to Apps CDN and install from the CDN latest alias#3835
bcotrim merged 13 commits into
trunkfrom
stu-1780-upload-cli-bundles-to-cdn

Conversation

@bcotrim

@bcotrim bcotrim commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

AI helped map the existing Apps CDN / Fastlane / Buildkite release flow, design the CLI upload to mirror the established PHP CLI binary path, switch the installers to the CDN latest alias, and verify the work locally (Ruby + YAML syntax, the fastlane helper tests, a studio_cli_cdn_builds/upload dry-run harness, an end-to-end install.sh behavior harness, and a real throwaway upload against the production CDN). All changes were reviewed and validated before pushing.

Proposed Changes

Makes the standalone Studio CLI available to users without the desktop app, kept current automatically.

  • Every Studio build now publishes the standalone CLI bundles to the Apps CDN (under the WordPress.com Studio CLI product), for nightly/dev, beta, and stable alike. The bundles track the app build exactly — same version and visibility — so stable bundles become public at publish time just like the app, and there's no separate step to run.
  • The curl installers download straight from the CDN's versionless latest alias, so no bespoke redirect service is needed. STUDIO_CLI_VERSION pins a specific version, and STUDIO_CLI_URL is retained as a bypass for local builds and mirrors. Both paths rely on HTTPS plus a staged-extraction guard (a corrupt download fails at tar -xzf before touching an existing install); the bundle's SHA-256 is still recorded as CDN build metadata.
  • Bundles are published as studio-cli-<platform>-<arch>.tgz (gzipped tar) for all six platform/arch targets.

Trade-off / remaining dependency: the install.sh / install.ps1 scripts themselves still need public hosting for the curl … | bash / irm … | iex entry points (the CDN serves uploaded builds, not arbitrary scripts) — a separate WordPress.com-side task. Until that lands, the CLI is installable via the direct CDN URL or STUDIO_CLI_URL.

Testing Instructions

Fastlane (dry run, no remote side effects):

npm run cli:bundle -- darwin arm64          # build a bundle (repeat per platform/arch)
DRY_RUN=true bundle exec fastlane publish_studio_cli_binaries version:"v1.11.0"

Confirm it lists the six platform/arch uploads with the right product, platform labels, version, and sha. Existing helper tests still pass: bash .buildkite/commands/run-fastlane-tests.sh.

Real CDN upload (verified): a throwaway 0.0.1 / Internal build was uploaded to the production WordPress.com Studio CLI product via the same media/new endpoint the lane posts to — confirming the upload path works and that the .tgz file type is accepted (see Notes).

Installer — STUDIO_CLI_URL bypass:

STUDIO_CLI_HOME="$(mktemp -d)" STUDIO_CLI_URL="$PWD/standalone-bundles" bash scripts/standalone/install.sh

Installer — default CDN mode: with bundles published, a fresh install resolves
https://appscdn.wordpress.com/downloads/wordpress-com-studio-cli/<slug>/latest/full-install
(e.g. mac-silicon), and STUDIO_CLI_VERSION=v1.11.0 pins that version.

Windows: install.ps1 mirrors the same logic (win32 → windows-x64 / windows-arm64). It was validated structurally but needs a real Windows run to confirm (no pwsh locally).

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors? — N/A (changes are Fastlane/Ruby, Buildkite YAML, PowerShell/shell installers, and docs; no app code).

Notes for reviewers

  • Bundles are .tgz, not .tar.gz. The Apps CDN's upload validation (WordPress wp_check_filetype_and_ext) rejects the .tar.gz double extension — even though gz is allow-listed — while .tgz (same gzip bytes, single extension, already on the CDN's accepted-mime list) uploads cleanly. tar -xzf handles both identically, so the installers and extraction logic are unchanged.
  • macOS quarantine: install.sh clears com.apple.quarantine from the extracted files. The bundled .node modules are unsigned, so a browser-downloaded bundle would otherwise be Gatekeeper-blocked ("library load disallowed by system policy"). The curl … | bash path isn't quarantined, so this is defensive for manual / MDM-managed installs. (Signing + notarizing the macOS bundle is a possible future hardening, tracked separately.)
  • Cross-arch bundles are safe within an OS (so the existing CI matrix runners are fine): the CLI uses no-fsevents chokidar, fs-ext-extra-prebuilt ships both arches per-OS, and the target Node binary is downloaded per arch. Only cross-OS needs a native runner, which the matrix already provides.
  • Stable bundles flip to public automatically because their CDN post IDs ride the draft GitHub release through the existing create_draft_github_releasemake_cdn_builds_public path — no change to that logic.
@bcotrim
bcotrim requested review from a team and fredrikekelund June 16, 2026 16:32
@bcotrim
bcotrim marked this pull request as ready for review June 16, 2026 16:32
@bcotrim
bcotrim requested a review from a team as a code owner June 16, 2026 16:32
@wpmobilebot

wpmobilebot commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing 0f0e844 vs trunk

app-size

Metric trunk 0f0e844 Diff Change
App Size (Mac) 2357.83 MB 2357.83 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk 0f0e844 Diff Change
load 1067 ms 1056 ms 11 ms ⚪ 0.0%

site-startup

Metric trunk 0f0e844 Diff Change
siteCreation 6509 ms 6492 ms 17 ms ⚪ 0.0%
siteStartup 6977 ms 6990 ms +13 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not knowledgeable about Fastlane to the point about providing detailed feedback about the Fastfile implementation, but this LGTM 👍

bundle exec fastlane notarize_binary

echo "--- :package: Building standalone CLI bundle"
npm run cli:bundle -- darwin {{matrix}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably won't optimize anything beyond the micro level, and we can leave it as is for this PR, but we should already have the Node.js binary at this point, so we might want to consider not re-downloading it.

Comment thread fastlane/Fastfile Outdated
# builds_to_upload routes their post IDs through create_draft_github_release, so
# publish_release flips them to External exactly like the app builds. Skipped when no
# bundles are present (e.g. a local app-only distribute run that didn't build them).
if Dir.exist?(STANDALONE_BUNDLES_FOLDER)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why fail gracefully here? If we're committing to publishing the standalone CLI, then it seems like we might want a hard failure if the build artifacts are missing

Comment thread scripts/standalone/install.sh Outdated
Comment on lines 135 to 146
# The CDN exposes the SHA-256 only as build metadata, not as a downloadable
# sidecar, so checksum verification applies to STUDIO_CLI_URL sources (which do
# ship one). The CDN path relies on HTTPS for transport integrity plus the
# staging-extraction guard below.
if [ "$HAS_SHA256_SIDECAR" = "1" ]; then
download "${BUNDLE_URL}.sha256" "$TMP_BUNDLE.sha256"
echo "Verifying checksum..."
if ! verify_checksum "$TMP_BUNDLE" "$TMP_BUNDLE.sha256"; then
echo "Error: checksum verification failed. Aborting; existing install left untouched." >&2
exit 1
fi
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, [ "$HAS_SHA256_SIDECAR" = "1" ] is effectively only true in a dry run or local testing context. Is it really still worth keeping..?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends Studio’s release/distribution flow so the standalone Studio CLI bundles are published to the WordPress.com Apps CDN for every build (dev/nightly, beta, stable), and updates the curl/PowerShell installers to install from the CDN latest (or a pinned STUDIO_CLI_VERSION) instead of a custom releases host.

Changes:

  • Update standalone installers (install.sh / install.ps1) to resolve bundles via Apps CDN latest (or STUDIO_CLI_VERSION), while keeping STUDIO_CLI_URL as an override.
  • Add Fastlane support to upload the 6 standalone CLI bundles to the Apps CDN and fold their post IDs into the existing release visibility-flip flow.
  • Build and persist standalone CLI bundle artifacts in Buildkite (macOS/Linux steps, Windows via build-for-windows.ps1) and document the updated release process.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/standalone/install.sh Switch default install source to Apps CDN latest/version pin, keep STUDIO_CLI_URL override.
scripts/standalone/install.ps1 Same as install.sh, for Windows PowerShell installs.
scripts/create-standalone-bundle.ts Rename bundle output to .tgz (and corresponding .sha256).
fastlane/Fastfile Add Apps CDN upload lane + helper to publish CLI bundles and include them in release distribution.
docs/release-process.md Document the new Apps CDN publishing flow and installer resolution behavior.
.buildkite/release-build-and-distribute.yml Build/upload CLI bundle artifacts in release pipeline and download them for publishing.
.buildkite/pipeline.yml Build/upload CLI bundle artifacts in dev pipeline and download them for distribution.
.buildkite/commands/build-for-windows.ps1 Build the standalone CLI bundle during Windows builds.
Comments suppressed due to low confidence (1)

scripts/standalone/install.ps1:92

  • Checksum verification was removed entirely. Since the bundle build still generates a .sha256 sidecar, it would be good to keep checksum validation when STUDIO_CLI_URL points at a local directory or mirror that provides *.sha256, before extracting into the staging directory.
        $TmpBundle = Join-Path $StagingDir $BundleName

        Write-Host "Downloading Studio CLI..."
        Get-Bundle -Url $BundleUrl -Dest $TmpBundle

        Write-Host "Installing to $InstallDir..."
        $ExtractDir = Join-Path $StagingDir "extracted"
        New-Item -ItemType Directory -Path $ExtractDir -Force | Out-Null
        # Use the Windows-provided BSD tar explicitly: a GNU tar earlier on PATH
        # (e.g. Git Bash) would misread "C:" in the archive path as a remote host.
        & "$env:SystemRoot\System32\tar.exe" -xzf $TmpBundle -C $ExtractDir
        if ($LASTEXITCODE -ne 0) {
            throw "Failed to extract $BundleName (tar exited with $LASTEXITCODE)"
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/standalone/install.sh
Comment thread .buildkite/pipeline.yml Outdated
Comment thread .buildkite/pipeline.yml
Comment thread .buildkite/release-build-and-distribute.yml Outdated
Comment thread .buildkite/release-build-and-distribute.yml
@bcotrim
bcotrim merged commit 58820b8 into trunk Jun 18, 2026
21 checks passed
@bcotrim
bcotrim deleted the stu-1780-upload-cli-bundles-to-cdn branch June 18, 2026 21:09
@iangmaia

Copy link
Copy Markdown
Contributor

@bcotrim one follow-up concern now that this landed: create-standalone-bundle.ts downloads a target-arch Node binary, but cli:package builds/copies node_modules for the runner arch.
The Buildkite matrices publish x64 + arm64 bundles from OS queues without target-arch npm install settings or an extracted-bundle smoke test.

I wonder if it is worth it to add a follow-up that either builds each bundle on native OS/arch runners or extracts the generated .tgz and runs the bundled studio --help on the target arch before upload?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

5 participants