Add CI workflow that packs tarballs and installer artifacts#11
Conversation
Builds standalone tarballs (linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64) via `oclif pack tarballs` on workflow_dispatch and on `v*` tag pushes, and uploads them as a workflow artifact. Tarballs bundle Node so users without Node installed can run the CLI. Publishing to GitHub Releases / npm is intentionally deferred to a follow-up so we can verify the artifact build first. Also guards the `prepare` script: `oclif pack` runs an internal `npm install --production` that triggered the previous unconditional `tsc -b` even though TypeScript is a devDependency. The new guard runs the build only when tsc is present, preserving the install-from-git build path while letting the production install inside oclif pack succeed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The |
Installs nsis (Windows installer) and bomutils + xar (macOS package tooling) on the runner, then runs `oclif pack macos` and `oclif pack win` after the existing tarball pack. Uploads everything under a single `bitmovin-cli-installers` artifact. The installers are unsigned for now — they build and run, but macOS Gatekeeper and Windows SmartScreen will warn users until we add Apple Developer ID notarization and Authenticode signing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ubuntu 24.04 dropped both `xar` and `bomutils` from its package repos, so building a `.pkg` on a Linux runner without source-building those tools is no longer feasible. Move the macOS package build to a `macos-latest` runner that has native `pkgbuild` / `productbuild`, and keep tarballs + Windows `.exe` (NSIS) on the Linux runner. Outputs split across two artifacts: `bitmovin-cli-tarballs-and-windows` and `bitmovin-cli-macos`. Public repo, so macOS runner minutes are free. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`oclif pack macos` requires `oclif.macos.identifier` in package.json to set the macOS package identifier. Use the reverse-DNS form `com.bitmovin.cli`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`oclif pack win` defaults to building x64, x86 and arm64 .exe installers in parallel — each ~200 MB — which pushed the Linux artifact bundle to 1.2 GB. Restrict to win32-x64 to match the tarball target list and bring the artifact back under ~500 MB. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Workflow artifacts are always zip-wrapped by GitHub, which makes
.pkg/.exe download-and-run unfriendly. Add a third job that runs
after both pack jobs, downloads their artifacts, and creates a
draft GitHub Release with each installer file (tarballs, .exe, .pkg)
as its own asset.
Draft releases are invisible to anyone without write access. After
verifying the assets, a maintainer publishes via the Releases UI
("Publish release" button); the tag stays the same, only the
visibility flips. Workflow artifacts are kept too for shorter-term
inspection (auto-expire in 30 days).
The release job is gated on tag pushes (`startsWith(github.ref,
'refs/tags/v')`), so workflow_dispatch runs still produce artifacts
without trying to create a release object.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When upload-artifact gets multiple `path:` entries with a common prefix (`dist/`), it preserves any path components below that prefix. So `dist/*.tar.gz` lands at the artifact root but `dist/win32/*.exe` lands under `win32/` inside the artifact. Update the release glob to match the actual download layout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Two things on this expanded version:
|
Two changes in response to PR feedback: 1. Revert the draft-release job. Restore the original PR scope of "build artifacts only, defer publishing." Tarballs, .pkg, and .exe continue to upload as workflow artifacts (zip-wrapped, internal testing only). GitHub Release publishing will land in a follow-up that also addresses code signing — shipping unsigned installers through a Release surfaces Gatekeeper / SmartScreen warnings that undercut the "no Node required" promise. 2. Make `prepare` fail loud when build is actually needed. The previous shim `if [ -x ./node_modules/.bin/tsc ]; then tsc -b; fi` silently no-op'd whenever tsc was missing, hiding broken-state installs. New form `[ -d dist ] || tsc -b` only skips when dist already exists (oclif pack's tmp workspace, npm install from a shipped tarball) and otherwise runs `tsc -b` — which fails loud if tsc isn't available. The three install paths still work: - `npm install <git-url>`: dist absent, devDeps present → builds - `npm install` from npm tarball: dist already shipped → skip - `oclif pack` tmp `npm install --production`: dist copied → skip Considered Lukas's suggestion of skipping lifecycle scripts at the oclif invocation level instead — oclif v4 doesn't expose a knob for this in `pack`, so the dist-presence guard remains the cleanest available fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an "Import Developer ID Installer cert into temp keychain" step to the pack-macos job that decodes a P12 from the APPLE_INSTALLER_CERT_P12_BASE64 / APPLE_INSTALLER_CERT_PASSWORD secrets, imports it into a per-job temp keychain (random unlock password, 6h timeout), and authorizes productsign / productbuild against the imported identity. oclif.macos.sign in package.json is set to the cert's full Common Name; oclif's pack:macos invokes productsign with that identity at the end of pkg build. Resulting .pkg passes pkgutil --check-signature and Gatekeeper installer trust. Notarization is not wired yet — that needs a Developer ID Application codesign of bundled Mach-O binaries plus xcrun notarytool against an App Store Connect API key. Without notarization, Gatekeeper still shows the standard "from an identified developer" allow flow on first install. Notarization will follow. The workflow will fail at the import step until both APPLE_INSTALLER_CERT_* secrets are configured on the repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
oclif passes the sign string straight to a /bin/sh -c invocation
without quoting, so any shell-special characters break it. The
common name has spaces, a colon, and the team-id parens — pkgbuild
on the runner died with `syntax error near unexpected token '('`.
pkgbuild --sign accepts either the CN or the certificate's SHA-1
hash (per `man pkgbuild`). Switching to the hex-only SHA-1 sidesteps
oclif's quoting bug entirely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lukaskroepfl
left a comment
There was a problem hiding this comment.
All three points addressed cleanly:
- Release job reverted — back to artifact-only, matches the staged plan in the original PR description.
prepareshim —[ -d dist ] || tsc -bis the right shape. Whendist/is missing it runstsc -band fails loud if tsc isn't there; whendist/already exists (theoclif packtemp-workspace case) it short-circuits without trying to build. Preserves the install-from-git path while letting the production install succeed.- macOS .pkg is signed with Developer ID Installer (SHA1 fingerprint to disambiguate).
Two small follow-ups, neither blocking:
- CHANGELOG drift: the entry still says "Installers are unsigned. Code signing… will follow" but the .pkg is now signed in this PR. Worth tightening to "macOS .pkg is signed with Developer ID Installer; notarization and Windows Authenticode will follow."
- Notarization is the other half of the Gatekeeper story. Signing alone doesn't satisfy
spctl --assessfor downloaded .pkg's; users will still hit "Apple cannot check this for malicious software" unless they right-click → Open or you notarize. Worth queueing as the next signing follow-up.
Approving on the artifact-only scope.
pkgbuild was hanging for 10+ minutes in pack-macos with no diagnostic output, and a `gh run cancel` finally produced `Terminate orphan process: pid (12617) (pkgbuild)`. Root cause: the key was imported with -T productsign/productbuild only, so pkgbuild itself wasn't on the trust list and was blocking on a non-existent auth dialog when reaching for the signing key. Adding -T /usr/bin/pkgbuild and -T /usr/bin/codesign closes the gap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
oclif's pack:macos calls productsign but doesn't fail loud if the signature ends up unverifiable — we'd discover that only when a user tries to install. Run pkgutil --check-signature on each produced .pkg in the macOS job; non-zero exit fails the job. Catches missing or corrupt signatures, untrusted cert chains, and other signature defects before the artifact ships. spctl --assess deliberately not added here — without notarization it would fail on every signed-but-unnotarized .pkg. Will land together with the notarization step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…flow # Conflicts: # CHANGELOG.md
Summary
Adds
.github/workflows/pack.yml— onworkflow_dispatchandv*tag pushes, builds:linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64(.tar.gz + .tar.xz, bundled Node 20).pkginstallers fordarwin-x64anddarwin-arm64(built on amacos-latestrunner using nativepkgbuild— Ubuntu 24.04 dropped bothxarandbomutilsfrom its repos).exeinstaller (NSIS) forwin32-x64All artifacts upload as workflow artifacts under two names —
bitmovin-cli-tarballs-and-windowsandbitmovin-cli-macos. 30-day retention. Internal testing only: zip-wrapped (GitHub limitation) and unsigned. Code signing + GitHub Release publishing + npm publishing will land in subsequent PRs.Guards the
preparescript with a dist-presence check:[ -d dist ] || tsc -b.oclif packruns an internalnpm install --productionin a temp workspace, which previously triggered an unconditionaltsc -beven though TypeScript is a devDependency. The new form runs the build only whendist/is missing — fails loud iftscis then unavailable, silently skips whendist/is already present (oclif's tmp workspace, npm install from the shipped tarball).Test plan
v0.0.0-pack-test.xtag — both jobs greenbin/bitmovin --version/--help/config show --jsonall work with bundled Node 20 + correct secret masking.Out of scope (follow-ups)
v*tag push. Bundle with Bump lodash from 4.17.23 to 4.18.1 #1.NPM_TOKENsecret. README install instructions..deb—oclif pack deb, straightforward addition..exeis 303 MB; LZMA/SOLID compression should bring it down significantly.stable,beta) viaoclif upload.bitmovin/homebrew-tap).npm publish --tag nextfor-rc/-betatags.🤖 Generated with Claude Code