Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ jobs:
done
ls -la release-assets/

- name: Stage binaries for npm package
run: |
install -Dm755 release-assets/gale-aarch64-apple-darwin npm/bin/aarch64-apple-darwin/gale
install -Dm755 release-assets/gale-x86_64-apple-darwin npm/bin/x86_64-apple-darwin/gale
install -Dm755 release-assets/gale-aarch64-unknown-linux-gnu npm/bin/aarch64-unknown-linux-gnu/gale
install -Dm755 release-assets/gale-x86_64-unknown-linux-gnu npm/bin/x86_64-unknown-linux-gnu/gale
chmod +x npm/bin/gale
find npm/bin -maxdepth 3 -type f -print

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
Expand Down
44 changes: 23 additions & 21 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
# Publishing Gale to npm

Gale is distributed on npm as `@lyricalstring/gale`. The package uses a postinstall
script that downloads the correct precompiled binary from GitHub Releases.
Gale is distributed on npm as `@lyricalstring/gale`. The package includes
precompiled binaries for supported platforms in the npm tarball, so install does
not run a lifecycle script or download executables from GitHub Releases.

## Package layout

```
npm/
package.json @lyricalstring/gale — main package
install.js Postinstall script (downloads platform binary from GitHub Releases)
bin/gale Placeholder script (replaced by real binary on install)
bin/gale POSIX launcher that selects the current platform binary
bin/<target>/ Precompiled platform binaries
README.md npm page README
```

When a user runs `npm install @lyricalstring/gale`, the postinstall script
(`install.js`) detects the platform and downloads the matching binary from the
GitHub Release matching the package version.
When a user runs `npm install @lyricalstring/gale`, package managers unpack the
launcher and the platform binaries directly from the npm tarball. Running
`gale` executes `bin/gale`, which selects the matching native binary.

Supported platforms: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`.

## Prerequisites

- npm account with publish access to the `@lyricalstring` scope
- GitHub Release with precompiled binaries for the target version
- Precompiled binaries for every supported platform

## Release process

Expand All @@ -39,14 +40,16 @@ git push && git push --tags

The workflow will:
1. Build Linux binaries (x64 + arm64)
2. Create a GitHub Release with the binaries
3. Set the npm package version to match
4. Publish `@lyricalstring/gale` to npm
2. Build macOS binaries (x64 + arm64)
3. Create a GitHub Release with the binaries
4. Stage the binaries into `npm/bin/<target>/gale`
5. Set the npm package version to match
6. Publish `@lyricalstring/gale` to npm

### Option B: Manual

```bash
# 1. Build the binary for your platform
# 1. Build and stage the binary for your platform
./scripts/build-npm.sh

# 2. Set the version
Expand All @@ -56,9 +59,8 @@ The workflow will:
cd npm && npm publish --access public
```

Note: For users to install successfully, the GitHub Release for the matching
version must contain binaries for all supported platforms. Use the CI release
workflow for production releases.
Note: Production npm releases must include binaries for all supported platforms.
Use the CI release workflow for production releases.

## Rust targets reference

Expand All @@ -81,7 +83,7 @@ cargo install gale-lint
## Testing locally

```bash
# 1. Build for your current platform
# 1. Build and stage for your current platform
./scripts/build-npm.sh

# 2. Pack (dry run) to see what would be published
Expand All @@ -96,9 +98,9 @@ npx gale --version

## Troubleshooting

**"Gale binary not found"**: The postinstall download may have failed. Run
`npm rebuild @lyricalstring/gale` to retry, or check network access to
`github.com`.
**"Gale binary missing"**: The npm tarball did not include the expected
`bin/<target>/gale` file. Reinstall `@lyricalstring/gale`; if the error
persists, report a packaging bug.

**Unsupported platform**: The postinstall script only supports darwin and linux
on arm64/x64. Windows is not yet supported via npm. Build from source instead.
**Unsupported platform**: The npm launcher supports darwin and linux on
arm64/x64. Windows is not yet supported via npm. Build from source instead.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ Your `.stylelintrc` stays exactly the same. Gale reads the same config files, fo
npm install -D @lyricalstring/gale
```

The npm package automatically downloads the correct platform binary on install. Supported platforms: macOS (arm64, x64), Linux (x64, arm64).
The npm package includes prebuilt binaries for supported platforms, so install
does not run a postinstall script or download executables. Supported platforms:
macOS (arm64, x64), Linux (x64, arm64).

### Cargo

Expand Down Expand Up @@ -327,15 +329,16 @@ The [release workflow](.github/workflows/release.yml) will:

1. Build binaries for Linux (x64, arm64) and macOS (x64, arm64)
2. Create a GitHub Release with the binaries
3. Publish the npm package (`@lyricalstring/gale`) with the matching version
3. Stage those binaries inside the npm package
4. Publish the npm package (`@lyricalstring/gale`) with the matching version

### Manual npm build

```bash
# Build for current platform
# Build and stage the current platform binary in npm/bin/<target>/gale
./scripts/build-npm.sh

# Build for all platforms (requires cross + Docker)
# Build and stage all supported binaries (requires cross + Docker)
./scripts/build-npm.sh --all

# Set npm package version before building
Expand Down
53 changes: 51 additions & 2 deletions npm/bin/gale
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
#!/bin/sh
echo "Gale binary not found. Run 'npm rebuild @lyricalstring/gale' to install."
exit 1

set -eu

platform="$(uname -s)-$(uname -m)"

case "$platform" in
Darwin-arm64)
target="aarch64-apple-darwin"
;;
Darwin-x86_64)
target="x86_64-apple-darwin"
;;
Linux-aarch64|Linux-arm64)
target="aarch64-unknown-linux-gnu"
;;
Linux-x86_64)
target="x86_64-unknown-linux-gnu"
;;
*)
echo "Unsupported platform: $platform" >&2
echo "Supported: Darwin-arm64, Darwin-x86_64, Linux-aarch64, Linux-x86_64" >&2
exit 1
;;
esac

script="$0"

while [ -L "$script" ]; do
script_dir="$(CDPATH= cd "$(dirname "$script")" && pwd)"
link="$(readlink "$script")"

case "$link" in
/*)
script="$link"
;;
*)
script="$script_dir/$link"
;;
esac
done

bin_dir="$(CDPATH= cd "$(dirname "$script")" && pwd)"
binary="$bin_dir/$target/gale"

if [ ! -x "$binary" ]; then
echo "Gale binary missing for $target at $binary" >&2
echo "This package should include prebuilt binaries. Please reinstall @lyricalstring/gale or report a packaging bug." >&2
exit 1
fi

exec "$binary" "$@"
2 changes: 1 addition & 1 deletion npm/index.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This file exists so that tools like `resolve-bin` and `require.resolve()`
// can locate this package. The actual linter is the native binary in bin/.
// can locate this package. The actual linter is launched by bin/gale.
module.exports = {};
84 changes: 0 additions & 84 deletions npm/install.cjs

This file was deleted.

4 changes: 0 additions & 4 deletions npm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,10 @@
"bin": {
"gale": "bin/gale"
},
"scripts": {
"postinstall": "node install.cjs"
},
"files": [
"bin/",
"index.cjs",
"index.mjs",
"install.cjs",
"README.md"
],
"engines": {
Expand Down
20 changes: 10 additions & 10 deletions scripts/build-npm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ if [[ -n "$VERSION" ]]; then
fi

# --------------------------------------------------------------------------
# Target definitions: rust_target -> artifact_name
# Supported Rust targets
# --------------------------------------------------------------------------
declare -A TARGETS=(
["aarch64-apple-darwin"]="gale-aarch64-apple-darwin"
["x86_64-apple-darwin"]="gale-x86_64-apple-darwin"
["x86_64-unknown-linux-gnu"]="gale-x86_64-unknown-linux-gnu"
["aarch64-unknown-linux-gnu"]="gale-aarch64-unknown-linux-gnu"
TARGETS=(
"aarch64-apple-darwin"
"x86_64-apple-darwin"
"x86_64-unknown-linux-gnu"
"aarch64-unknown-linux-gnu"
)

# --------------------------------------------------------------------------
Expand Down Expand Up @@ -93,9 +93,9 @@ build_target() {
local src="$ROOT/target/release/gale"
fi

local dest="$NPM_DIR/bin/gale"
local dest="$NPM_DIR/bin/$rust_target/gale"
echo " Copying $src -> $dest"
mkdir -p "$NPM_DIR/bin"
mkdir -p "$(dirname "$dest")"
cp "$src" "$dest"
chmod +x "$dest"
echo " Done: $rust_target"
Expand All @@ -119,7 +119,7 @@ if [[ "$BUILD_ALL" == "true" ]]; then

CURRENT_TARGET="$(detect_current_target)"

for rust_target in "${!TARGETS[@]}"; do
for rust_target in "${TARGETS[@]}"; do
if [[ "$rust_target" == "$CURRENT_TARGET" ]]; then
build_target "$rust_target" "false"
else
Expand All @@ -137,7 +137,7 @@ echo "=========================================="
echo " Build complete!"
echo "=========================================="
echo ""
echo "Binary ready in: $NPM_DIR/bin/gale"
echo "Binaries ready in: $NPM_DIR/bin/"
echo ""
echo "To publish:"
echo ""
Expand Down