Add script to publish built JS packages to dist repo#2767
Add script to publish built JS packages to dist repo#2767AbanoubGhadban merged 3 commits intoupcoming-v16.3.0from
Conversation
Script builds all packages, copies package.json + lib/ to a separate builds repo (shakacode/react-on-rails-builds), replaces workspace:* references with actual versions, strips devDependencies and build scripts, commits and pushes with a version tag. Usage: ./scripts/publish-to-builds-repo.sh [--dry-run] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of defaulting to 'main', the script now pushes to a branch matching the current react_on_rails branch name. --branch flag still available for override. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| ) | ||
|
|
||
| # Read version from react-on-rails package.json | ||
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) |
There was a problem hiding this comment.
Bug: relative path breaks when script is not run from the monorepo root.
require('./packages/react-on-rails/package.json') resolves relative to the current working directory at script invocation time, not $MONOREPO_ROOT. Running the script from any other directory (e.g. bash scripts/publish-to-builds-repo.sh from /tmp) will silently fail, hit the 2>/dev/null suppression, and exit with the version error.
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) | |
| VERSION=$(node -e "console.log(require('$MONOREPO_ROOT/packages/react-on-rails/package.json').version)") |
| cp -r "$PKG_SRC/lib" "$PKG_DEST/lib" | ||
| else | ||
| echo " WARNING: $PKG_SRC/lib does not exist! Was the build successful?" >&2 | ||
| fi |
There was a problem hiding this comment.
Missing lib/ should abort, not warn-and-continue.
If the build silently failed to produce lib/, the script continues and publishes an empty package to the dist repo. Consumers would get a broken install with no clear error message.
| fi | |
| echo "ERROR: $PKG_SRC/lib does not exist — build failed for $pkg." >&2 | |
| exit 1 |
| PKG_JSON="$DIST_DIR/repo/$pkg/package.json" | ||
| if grep -q '"workspace:\*"' "$PKG_JSON" 2>/dev/null; then | ||
| sed -i "s/\"workspace:\*\"/\"$VERSION\"/g" "$PKG_JSON" | ||
| echo " Fixed $pkg/package.json" | ||
| fi | ||
| done |
There was a problem hiding this comment.
Two issues with the workspace replacement:
-
Incomplete pattern: Only replaces
"workspace:*"but not other pnpm workspace ranges like"workspace:^","workspace:~", or pinned versions like"workspace:1.2.3". If any of those appear in a package.json they'll be published verbatim and cause install failures. -
Fragile tool: Since step 5 already uses
nodeto rewritepackage.json, it's cleaner and safer to do the workspace replacement there too — avoiding the separatesedpass and the need to grep/check first:
// inside the node -e script in step 5:
function replaceWorkspace(deps) {
if (!deps) return;
for (const [k, v] of Object.entries(deps)) {
if (typeof v === 'string' && v.startsWith('workspace:')) deps[k] = VERSION;
}
}
replaceWorkspace(pkg.dependencies);
replaceWorkspace(pkg.peerDependencies);
replaceWorkspace(pkg.optionalDependencies);This handles all workspace range formats and keeps the JSON rewriting in one place.
| node -e " | ||
| const fs = require('fs'); | ||
| const pkg = JSON.parse(fs.readFileSync('$PKG_JSON', 'utf8')); | ||
| if (pkg.scripts) { | ||
| delete pkg.scripts.build; | ||
| delete pkg.scripts['build-watch']; | ||
| delete pkg.scripts.clean; | ||
| delete pkg.scripts.prepare; | ||
| delete pkg.scripts.prepublishOnly; | ||
| delete pkg.scripts['type-check']; | ||
| if (Object.keys(pkg.scripts).length === 0) delete pkg.scripts; | ||
| } | ||
| delete pkg.devDependencies; | ||
| fs.writeFileSync('$PKG_JSON', JSON.stringify(pkg, null, 2) + '\n'); | ||
| " | ||
| echo " Cleaned $pkg/package.json" |
There was a problem hiding this comment.
Shell variable interpolated inside a single-quoted JS string — path injection risk.
'$PKG_JSON' is expanded by bash before Node sees it. If $PKG_JSON ever contained a single quote (e.g., from an unusual mktemp or a future change to the path construction), it would break the JS syntax. The safer pattern is to pass the path as a CLI argument and read it via process.argv:
| node -e " | |
| const fs = require('fs'); | |
| const pkg = JSON.parse(fs.readFileSync('$PKG_JSON', 'utf8')); | |
| if (pkg.scripts) { | |
| delete pkg.scripts.build; | |
| delete pkg.scripts['build-watch']; | |
| delete pkg.scripts.clean; | |
| delete pkg.scripts.prepare; | |
| delete pkg.scripts.prepublishOnly; | |
| delete pkg.scripts['type-check']; | |
| if (Object.keys(pkg.scripts).length === 0) delete pkg.scripts; | |
| } | |
| delete pkg.devDependencies; | |
| fs.writeFileSync('$PKG_JSON', JSON.stringify(pkg, null, 2) + '\n'); | |
| " | |
| echo " Cleaned $pkg/package.json" | |
| node - "$PKG_JSON" << 'NODEEOF' | |
| const fs = require('fs'); | |
| const pkgPath = process.argv[1]; | |
| const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); | |
| if (pkg.scripts) { | |
| delete pkg.scripts.build; | |
| delete pkg.scripts['build-watch']; | |
| delete pkg.scripts.clean; | |
| delete pkg.scripts.prepare; | |
| delete pkg.scripts.prepublishOnly; | |
| delete pkg.scripts['type-check']; | |
| if (Object.keys(pkg.scripts).length === 0) delete pkg.scripts; | |
| } | |
| delete pkg.devDependencies; | |
| fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n'); | |
| NODEEOF |
| find . -not -path './.git/*' -not -path './.git' | sort | ||
| else | ||
| echo "==> Pushing to $DIST_REPO branch $DIST_BRANCH..." | ||
| git push -u origin "$DIST_BRANCH" |
There was a problem hiding this comment.
Push will fail on re-run without guidance.
If the script is re-run for the same version (e.g., to fix a build artifact after a partial publish), the remote branch will have diverged and this push fails with a cryptic "rejected" message. Consider documenting the recovery path in the failure output:
| git push -u origin "$DIST_BRANCH" | |
| git push -u origin "$DIST_BRANCH" || { | |
| echo "" >&2 | |
| echo "ERROR: Push rejected. If you need to overwrite a previous publish of the same version, run:" >&2 | |
| echo " git push --force-with-lease origin $DIST_BRANCH" >&2 | |
| echo "from $DIST_DIR/repo (before it is cleaned up), or delete the remote branch and retry." >&2 | |
| exit 1 | |
| } |
| if git ls-remote "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then | ||
| git clone --branch "$DIST_BRANCH" --depth 1 "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || \ | ||
| git clone "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || { | ||
| # Fresh repo with no commits yet | ||
| git init "$DIST_DIR/repo" | ||
| cd "$DIST_DIR/repo" | ||
| git remote add origin "$DIST_REPO" | ||
| } | ||
| else | ||
| # Branch doesn't exist or repo is empty | ||
| git clone "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || { | ||
| git init "$DIST_DIR/repo" | ||
| cd "$DIST_DIR/repo" | ||
| git remote add origin "$DIST_REPO" | ||
| } | ||
| fi |
There was a problem hiding this comment.
Clone fallback logic is hard to follow and silences real errors.
The triple-fallback ls-remote → clone-with-branch → clone-without-branch → init with &>/dev/null and 2>/dev/null suppression makes it difficult to distinguish auth failures from genuinely empty repos. A few concerns:
- If
git ls-remotefails due to missing SSH key / no network access, the output is silenced and the error only surfaces later (confusingly) whengit pushfails. - The
cd "$DIST_DIR/repo"inside the{...}fallback blocks changes the working directory inside a subshell-like group but actually runs inline — the outercd "$DIST_DIR/repo"on line 108 is redundant in those paths, and harmless, but it obscures control flow.
Consider splitting this into explicit cases with clear error messages, and only suppressing output where it's truly noise (e.g., git checkout when the branch doesn't exist yet).
Greptile SummaryThis PR adds Key issues found:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant Script as publish-to-builds-repo.sh
participant Monorepo as react_on_rails (local)
participant DistRepo as react-on-rails-builds (remote)
Dev->>Script: ./scripts/publish-to-builds-repo.sh [options]
Script->>Monorepo: pnpm build (all packages)
Monorepo-->>Script: lib/ output per package
Script->>Script: mktemp -d (create temp DIST_DIR)
Script->>DistRepo: git ls-remote (check branch)
DistRepo-->>Script: refs (or empty)
alt branch exists
Script->>DistRepo: git clone --branch DIST_BRANCH --depth 1
else branch missing / remote empty
Script->>DistRepo: git clone (full) or git init
end
Script->>Script: git checkout -b DIST_BRANCH (if needed)
Script->>Script: Copy package.json + lib/ + README.md per package
Script->>Script: sed replace workspace:* → VERSION
Script->>Script: node — strip devDependencies & build scripts
Script->>Script: Write top-level README.md
Script->>Script: git add -A && git commit
alt DRY_RUN=false
Script->>DistRepo: git push -u origin DIST_BRANCH
Script->>Script: Check tag existence (git rev-parse)
Script->>DistRepo: git push origin TAG
else DRY_RUN=true
Script->>Script: Print contents (find .)
end
Script->>Script: trap EXIT → rm -rf DIST_DIR
Last reviewed commit: "Default builds repo ..." |
| trap 'rm -rf "$DIST_DIR"' EXIT | ||
|
|
||
| echo "==> Cloning builds repo into $DIST_DIR..." | ||
| if git ls-remote "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then |
There was a problem hiding this comment.
git ls-remote doesn't check branch existence without --exit-code
git ls-remote exits with code 0 even when no refs match — it only fails on network/auth errors. This means the if branch is always taken when the remote is reachable, and the else block on line 99 is essentially dead code.
In practice the fallback inside the if branch (git clone --branch → git clone without --branch) accidentally handles the missing-branch case, but the intent is hidden and error output is silenced. The fix is to add --exit-code:
| if git ls-remote "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then | |
| if git ls-remote --exit-code "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then |
With --exit-code, git ls-remote returns 2 when no matching refs are found, making the condition correctly reflect whether the branch actually exists.
| ) | ||
|
|
||
| # Read version from react-on-rails package.json | ||
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) |
There was a problem hiding this comment.
Relative path in
node -e depends on the caller's working directory
require('./packages/react-on-rails/package.json') resolves relative to the process's current working directory at call time — not relative to the script. If the script is invoked from any directory other than the monorepo root (e.g. bash scripts/publish-to-builds-repo.sh from ~/), node will silently fail (stderr is redirected), $VERSION will be empty, and the script will exit with an error. Use $MONOREPO_ROOT for an absolute path:
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) | |
| VERSION=$(node -e "console.log(require('$MONOREPO_ROOT/packages/react-on-rails/package.json').version)" 2>/dev/null) |
| for pkg in "${PACKAGES[@]}"; do | ||
| PKG_JSON="$DIST_DIR/repo/$pkg/package.json" | ||
| if grep -q '"workspace:\*"' "$PKG_JSON" 2>/dev/null; then | ||
| sed -i "s/\"workspace:\*\"/\"$VERSION\"/g" "$PKG_JSON" |
There was a problem hiding this comment.
sed -i without an empty-string argument fails on macOS (BSD sed)
GNU sed (Linux) accepts sed -i "s/...", but BSD sed (macOS) requires the backup-extension argument immediately after -i, even if it is empty: sed -i '' "s/...". Without it, BSD sed treats the substitute expression as the backup extension and errors out.
A portable one-liner that works on both platforms:
| sed -i "s/\"workspace:\*\"/\"$VERSION\"/g" "$PKG_JSON" | |
| sed -i.bak "s/\"workspace:\*\"/\"$VERSION\"/g" "$PKG_JSON" && rm -f "${PKG_JSON}.bak" |
Alternatively, since node is already used below, the replacement could be folded into the step-5 node script to avoid sed entirely.
| if git rev-parse "$DIST_TAG" &>/dev/null; then | ||
| echo "==> Tag $DIST_TAG already exists, skipping tag creation." | ||
| else | ||
| git tag "$DIST_TAG" | ||
| git push origin "$DIST_TAG" | ||
| echo "==> Tag $DIST_TAG pushed." | ||
| fi |
There was a problem hiding this comment.
Tag existence check is unreliable with a shallow clone
git clone --depth 1 only fetches commits (and tags reachable from those commits) within depth 1. Tags created in a previous run and pointing to older commits won't be present locally, so git rev-parse "$DIST_TAG" will report that the tag doesn't exist even when it already exists on the remote. The subsequent git push origin "$DIST_TAG" will then fail with "tag already exists", and because of set -euo pipefail the script aborts.
Check the remote directly instead:
| if git rev-parse "$DIST_TAG" &>/dev/null; then | |
| echo "==> Tag $DIST_TAG already exists, skipping tag creation." | |
| else | |
| git tag "$DIST_TAG" | |
| git push origin "$DIST_TAG" | |
| echo "==> Tag $DIST_TAG pushed." | |
| fi | |
| if git ls-remote --exit-code origin "refs/tags/$DIST_TAG" &>/dev/null; then | |
| echo "==> Tag $DIST_TAG already exists on remote, skipping tag creation." | |
| else | |
| git tag "$DIST_TAG" | |
| git push origin "$DIST_TAG" | |
| echo "==> Tag $DIST_TAG pushed." | |
| fi |
| SOURCE_SHA=$(cd "$MONOREPO_ROOT" && git rev-parse --short HEAD) | ||
| SOURCE_BRANCH=$(cd "$MONOREPO_ROOT" && git rev-parse --abbrev-ref HEAD) | ||
|
|
||
| git commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" |
There was a problem hiding this comment.
Git user identity not configured — will fail in fresh CI environments
git commit requires user.name and user.email to be configured. In a CI environment that doesn't have a global git config (e.g. a freshly-provisioned runner), this commit will fail with "Please tell me who you are."
Add identity configuration before the commit, or at least guard with a clear error:
| git commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" | |
| git -c user.name="github-actions[bot]" -c user.email="github-actions[bot]@users.noreply.github.com" \ | |
| commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" |
Review SummaryThe overall approach is solid — using a dist repo as a pre-built git dependency target is a clean pattern. The script is well-structured and the dry-run flag is a nice touch. A few issues worth addressing before merging: Bugs
Correctness
Code quality
Minor
|
Previously the script skipped the push entirely when there were no file changes, which meant a new branch name would never be created in the builds repo if the content matched an existing branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| trap 'rm -rf "$DIST_DIR"' EXIT | ||
|
|
||
| echo "==> Cloning builds repo into $DIST_DIR..." | ||
| if git ls-remote "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then |
There was a problem hiding this comment.
Bug: git ls-remote always exits 0 when the remote is reachable, even when the branch doesn't exist. This means the else branch (lines 99–106) is dead code whenever the remote is accessible — the script will always take the if path and attempt git clone --branch, which then fails if the branch doesn't exist.
Fix with --exit-code:
| if git ls-remote "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then | |
| if git ls-remote --exit-code "$DIST_REPO" "refs/heads/$DIST_BRANCH" &>/dev/null; then |
Or pipe to grep:
if git ls-remote "$DIST_REPO" 2>/dev/null | grep -q "refs/heads/$DIST_BRANCH"; then| ) | ||
|
|
||
| # Read version from react-on-rails package.json | ||
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) |
There was a problem hiding this comment.
Bug: relative path depends on the caller's CWD, not $MONOREPO_ROOT.
If the script is invoked from any directory other than the monorepo root (e.g. bash scripts/publish-to-builds-repo.sh from a subdirectory), require('./packages/…') will fail. The error is silently swallowed by 2>/dev/null, yielding an empty $VERSION and the generic "Could not read version" message.
| VERSION=$(node -e "console.log(require('./packages/react-on-rails/package.json').version)" 2>/dev/null) | |
| VERSION=$(node -e "console.log(require('$MONOREPO_ROOT/packages/react-on-rails/package.json').version)" 2>/dev/null) |
| for pkg in "${PACKAGES[@]}"; do | ||
| PKG_JSON="$DIST_DIR/repo/$pkg/package.json" | ||
| if grep -q '"workspace:\*"' "$PKG_JSON" 2>/dev/null; then | ||
| sed -i "s/\"workspace:\*\"/\"$VERSION\"/g" "$PKG_JSON" |
There was a problem hiding this comment.
Two issues here:
1. sed -i is not portable to macOS (BSD sed). GNU sed accepts sed -i "..." but BSD sed requires an explicit backup suffix: sed -i '' "...". This will silently fail or error on developer machines.
2. Only workspace:* is handled. pnpm also supports workspace:^ and workspace:~. If any package ever uses those specifiers, they'll be left unreplaced in the dist package.json.
Consider handling all workspace protocols at once with a more robust replacement, or use the node -e approach already used in step 5 (which avoids the sed portability issue entirely).
Also, if $VERSION ever contains sed metacharacters (/, &, \), the substitution will break. A safer delimiter would be |.
| # Copy lib/ directory | ||
| if [[ -d "$PKG_SRC/lib" ]]; then | ||
| cp -r "$PKG_SRC/lib" "$PKG_DEST/lib" | ||
| else |
There was a problem hiding this comment.
Missing lib/ only warns but allows the script to continue. The dist package would be pushed with a package.json but no compiled output — silently broken for consumers.
This should be a hard failure:
| else | |
| if [[ -d "$PKG_SRC/lib" ]]; then | |
| cp -r "$PKG_SRC/lib" "$PKG_DEST/lib" | |
| else | |
| echo "ERROR: $PKG_SRC/lib does not exist — build may have failed. Aborting." >&2 | |
| exit 1 | |
| fi |
| if git diff --cached --quiet; then | ||
| echo "==> No file changes to commit." | ||
| else | ||
| git commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" |
There was a problem hiding this comment.
git commit will fail in CI environments where user.name/user.email are not configured.
Add a guard or inline config before the commit:
| git commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" | |
| git -c user.name="publish-to-builds-repo" -c user.email="noreply@shakacode.com" \ | |
| commit -m "Build packages $VERSION from $SOURCE_BRANCH ($SOURCE_SHA)" |
Or set them explicitly before the git add:
git config user.email "noreply@shakacode.com"
git config user.name "publish-to-builds-repo"| git push -u origin "$DIST_BRANCH" | ||
|
|
||
| # Create and push tag | ||
| if git rev-parse "$DIST_TAG" &>/dev/null; then |
There was a problem hiding this comment.
git rev-parse "$DIST_TAG" only checks the local clone — not the remote.
With --depth 1, remote tags are not fetched by default. This means the check will always say "tag doesn't exist" and attempt to push, potentially failing with a "tag already exists on remote" error if the script is re-run for the same version.
Fetch remote tags first, or check the remote directly:
if git ls-remote --exit-code --tags origin "$DIST_TAG" &>/dev/null; then
echo "==> Tag $DIST_TAG already exists on remote, skipping tag creation."
else
git tag "$DIST_TAG"
git push origin "$DIST_TAG"
echo "==> Tag $DIST_TAG pushed."
fi| git clone --branch "$DIST_BRANCH" --depth 1 "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || \ | ||
| git clone "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || { | ||
| # Fresh repo with no commits yet | ||
| git init "$DIST_DIR/repo" | ||
| cd "$DIST_DIR/repo" | ||
| git remote add origin "$DIST_REPO" | ||
| } | ||
| else | ||
| # Branch doesn't exist or repo is empty | ||
| git clone "$DIST_REPO" "$DIST_DIR/repo" 2>/dev/null || { | ||
| git init "$DIST_DIR/repo" | ||
| cd "$DIST_DIR/repo" | ||
| git remote add origin "$DIST_REPO" | ||
| } | ||
| fi |
There was a problem hiding this comment.
Silent fallback to git init masks authentication failures.
If git clone fails because of an SSH key problem, wrong permissions, or a network issue, it silently falls through to git init — creating a brand-new local repo. The subsequent git push will then fail with a cryptic "refusing to update checked out branch" or "remote rejected" error, far from the real cause.
Consider removing the 2>/dev/null on clone failures, or at minimum checking whether the failure was "repo not found" vs. another error:
git clone "$DIST_REPO" "$DIST_DIR/repo" || {
if git ls-remote "$DIST_REPO" &>/dev/null; then
# Remote is accessible but empty — init locally
git init "$DIST_DIR/repo"
cd "$DIST_DIR/repo"
git remote add origin "$DIST_REPO"
else
echo "Error: Cannot access $DIST_REPO — check credentials and URL" >&2
exit 1
fi
}|
Good concept. A dedicated publish script for a pre-built dist repo is a clean solution for the no-TypeScript-on-install goal. The structure and dry-run mode are well thought out. See inline comments for specific issues; summary below. Bugs
Reliability
Portability
|
## Summary - Adds `scripts/publish-to-builds-repo.sh` that builds all JS packages and pushes the compiled output to [shakacode/react-on-rails-builds](https://github.com/shakacode/react-on-rails-builds) - The builds repo contains pre-built `package.json` + `lib/` for each package, ready for consumption as pnpm git dependencies — no TypeScript compilation needed during install - The script defaults to pushing to a branch matching the current react_on_rails branch name (overridable with `--branch`) ### What the script does 1. Runs `pnpm build` for all packages 2. Copies `package.json` + `lib/` to the builds repo 3. Replaces `workspace:*` references with the actual version 4. Strips `devDependencies` and build-related scripts 5. Commits, pushes, and tags (e.g., `v16.4.0`) ### Usage ```bash ./scripts/publish-to-builds-repo.sh # build + push + tag ./scripts/publish-to-builds-repo.sh --dry-run # preview without pushing ./scripts/publish-to-builds-repo.sh --tag v1.2.3 # custom tag ./scripts/publish-to-builds-repo.sh --branch main # override branch ``` ### Consumer usage (pnpm) ```json { "react-on-rails": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails", "react-on-rails-pro": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro", "react-on-rails-pro-node-renderer": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro-node-renderer" } ``` ## Test plan - [x] Dry run completes successfully - [x] Real run pushes to `shakacode/react-on-rails-builds` with correct structure - [x] Verified `workspace:*` replaced with actual version in dist `package.json` - [x] Verified `devDependencies` and build scripts stripped - [x] Verified consumer `pnpm install` resolves correct packages in ~30s 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Adds `scripts/publish-to-builds-repo.sh` that builds all JS packages and pushes the compiled output to [shakacode/react-on-rails-builds](https://github.com/shakacode/react-on-rails-builds) - The builds repo contains pre-built `package.json` + `lib/` for each package, ready for consumption as pnpm git dependencies — no TypeScript compilation needed during install - The script defaults to pushing to a branch matching the current react_on_rails branch name (overridable with `--branch`) ### What the script does 1. Runs `pnpm build` for all packages 2. Copies `package.json` + `lib/` to the builds repo 3. Replaces `workspace:*` references with the actual version 4. Strips `devDependencies` and build-related scripts 5. Commits, pushes, and tags (e.g., `v16.4.0`) ### Usage ```bash ./scripts/publish-to-builds-repo.sh # build + push + tag ./scripts/publish-to-builds-repo.sh --dry-run # preview without pushing ./scripts/publish-to-builds-repo.sh --tag v1.2.3 # custom tag ./scripts/publish-to-builds-repo.sh --branch main # override branch ``` ### Consumer usage (pnpm) ```json { "react-on-rails": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails", "react-on-rails-pro": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro", "react-on-rails-pro-node-renderer": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro-node-renderer" } ``` ## Test plan - [x] Dry run completes successfully - [x] Real run pushes to `shakacode/react-on-rails-builds` with correct structure - [x] Verified `workspace:*` replaced with actual version in dist `package.json` - [x] Verified `devDependencies` and build scripts stripped - [x] Verified consumer `pnpm install` resolves correct packages in ~30s 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Adds `scripts/publish-to-builds-repo.sh` that builds all JS packages and pushes the compiled output to [shakacode/react-on-rails-builds](https://github.com/shakacode/react-on-rails-builds) - The builds repo contains pre-built `package.json` + `lib/` for each package, ready for consumption as pnpm git dependencies — no TypeScript compilation needed during install - The script defaults to pushing to a branch matching the current react_on_rails branch name (overridable with `--branch`) ### What the script does 1. Runs `pnpm build` for all packages 2. Copies `package.json` + `lib/` to the builds repo 3. Replaces `workspace:*` references with the actual version 4. Strips `devDependencies` and build-related scripts 5. Commits, pushes, and tags (e.g., `v16.4.0`) ### Usage ```bash ./scripts/publish-to-builds-repo.sh # build + push + tag ./scripts/publish-to-builds-repo.sh --dry-run # preview without pushing ./scripts/publish-to-builds-repo.sh --tag v1.2.3 # custom tag ./scripts/publish-to-builds-repo.sh --branch main # override branch ``` ### Consumer usage (pnpm) ```json { "react-on-rails": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails", "react-on-rails-pro": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro", "react-on-rails-pro-node-renderer": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro-node-renderer" } ``` ## Test plan - [x] Dry run completes successfully - [x] Real run pushes to `shakacode/react-on-rails-builds` with correct structure - [x] Verified `workspace:*` replaced with actual version in dist `package.json` - [x] Verified `devDependencies` and build scripts stripped - [x] Verified consumer `pnpm install` resolves correct packages in ~30s 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Adds `scripts/publish-to-builds-repo.sh` that builds all JS packages and pushes the compiled output to [shakacode/react-on-rails-builds](https://github.com/shakacode/react-on-rails-builds) - The builds repo contains pre-built `package.json` + `lib/` for each package, ready for consumption as pnpm git dependencies — no TypeScript compilation needed during install - The script defaults to pushing to a branch matching the current react_on_rails branch name (overridable with `--branch`) ### What the script does 1. Runs `pnpm build` for all packages 2. Copies `package.json` + `lib/` to the builds repo 3. Replaces `workspace:*` references with the actual version 4. Strips `devDependencies` and build-related scripts 5. Commits, pushes, and tags (e.g., `v16.4.0`) ### Usage ```bash ./scripts/publish-to-builds-repo.sh # build + push + tag ./scripts/publish-to-builds-repo.sh --dry-run # preview without pushing ./scripts/publish-to-builds-repo.sh --tag v1.2.3 # custom tag ./scripts/publish-to-builds-repo.sh --branch main # override branch ``` ### Consumer usage (pnpm) ```json { "react-on-rails": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails", "react-on-rails-pro": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro", "react-on-rails-pro-node-renderer": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro-node-renderer" } ``` ## Test plan - [x] Dry run completes successfully - [x] Real run pushes to `shakacode/react-on-rails-builds` with correct structure - [x] Verified `workspace:*` replaced with actual version in dist `package.json` - [x] Verified `devDependencies` and build scripts stripped - [x] Verified consumer `pnpm install` resolves correct packages in ~30s 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
scripts/publish-to-builds-repo.shthat builds all JS packages and pushes the compiled output to shakacode/react-on-rails-buildspackage.json+lib/for each package, ready for consumption as pnpm git dependencies — no TypeScript compilation needed during install--branch)What the script does
pnpm buildfor all packagespackage.json+lib/to the builds repoworkspace:*references with the actual versiondevDependenciesand build-related scriptsv16.4.0)Usage
Consumer usage (pnpm)
{ "react-on-rails": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails", "react-on-rails-pro": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro", "react-on-rails-pro-node-renderer": "github:shakacode/react-on-rails-builds#v16.4.0&path:react-on-rails-pro-node-renderer" }Test plan
shakacode/react-on-rails-buildswith correct structureworkspace:*replaced with actual version in distpackage.jsondevDependenciesand build scripts strippedpnpm installresolves correct packages in ~30s🤖 Generated with Claude Code