diff --git a/.github/workflows/prebuild.yml b/.github/workflows/prebuild.yml new file mode 100644 index 0000000..d8115ca --- /dev/null +++ b/.github/workflows/prebuild.yml @@ -0,0 +1,144 @@ +name: Prebuild + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + prebuild: + strategy: + matrix: + include: + # Linux x64 + - os: ubuntu-latest + arch: x64 + + # Linux ARM64 + - os: ubuntu-latest + arch: arm64 + + # macOS x64 + - os: macos-latest + arch: x64 + + # macOS ARM64 + - os: macos-latest + arch: arm64 + + # Windows x64 + - os: windows-latest + arch: x64 + + # Windows x86 + - os: windows-latest + arch: ia32 + + runs-on: ${{ matrix.os }} + + name: Prebuild ${{ matrix.os }} - ${{ matrix.arch }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + architecture: ${{ matrix.arch }} + + - name: Install ALSA headers (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libasound2-dev + + - name: Setup ARM64 cross-compilation (Linux ARM64) + if: runner.os == 'Linux' && matrix.arch == 'arm64' + run: | + sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + sudo apt-get install -y libasound2-dev:arm64 + + - name: Install dependencies + run: npm install --ignore-scripts + + - name: Prebuild (Linux x64) + if: runner.os == 'Linux' && matrix.arch == 'x64' + run: prebuildify --napi --strip + + - name: Prebuild (Linux ARM64) + if: runner.os == 'Linux' && matrix.arch == 'arm64' + run: | + export CC=aarch64-linux-gnu-gcc + export CXX=aarch64-linux-gnu-g++ + export npm_config_arch=arm64 + prebuildify --napi --strip --arch arm64 + + - name: Prebuild (macOS) + if: runner.os == 'macOS' + run: prebuildify --napi --strip + + - name: Prebuild (Windows) + if: runner.os == 'Windows' + run: prebuildify --napi --strip --arch ${{ matrix.arch }} + + - name: Upload prebuilds + uses: actions/upload-artifact@v4 + with: + name: prebuilds-${{ matrix.os }}-${{ matrix.arch }} + path: prebuilds/ + retention-days: 7 + + release: + needs: prebuild + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Download all prebuilds + uses: actions/download-artifact@v4 + with: + path: prebuilds-artifacts + + - name: Consolidate prebuilds + run: | + mkdir -p prebuilds + # Copy maintaining the directory structure that prebuild-install expects + # Each artifact contains: prebuilds/[platform-arch]/node.napi.node + cp -r prebuilds-artifacts/*/prebuilds/* prebuilds/ 2>/dev/null || true + # If the above fails, try flat structure + for dir in prebuilds-artifacts/*/; do + if [ -d "$dir/prebuilds" ]; then + cp -r "$dir/prebuilds/"* prebuilds/ + fi + done + echo "Prebuild directory structure:" + ls -R prebuilds/ + + - name: Create tarball with prebuilds + run: | + npm install --ignore-scripts + npm pack + mv speaker-*.tgz speaker-${{ github.ref_name }}.tgz + echo "Tarball contents:" + tar -tzf speaker-${{ github.ref_name }}.tgz | grep -E 'prebuilds|package.json' | head -20 + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: speaker-${{ github.ref_name }}.tgz + generate_release_notes: true + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index fd6a5bb..854e278 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /node_modules/ /package-lock.json /yarn.lock +/prebuilds/ # dev files /?.js diff --git a/.prebuildrc b/.prebuildrc new file mode 100644 index 0000000..c046aea --- /dev/null +++ b/.prebuildrc @@ -0,0 +1,5 @@ +{ + "strip": true, + "tag-prefix": "v" +} + diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 0000000..f7d2466 --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,154 @@ +# Publishing Guide + +This guide explains how to publish a new version of `node-speaker` with prebuilt binaries using GitHub Releases. + +## Prerequisites + +1. **GitHub Access**: You must have push access to the repository and permissions to create releases +2. **GitHub Token**: The default `GITHUB_TOKEN` is automatically provided by GitHub Actions + +## Publishing Process + +### 1. Prepare the Release + +1. Update the version in `package.json`: + ```bash + npm version patch # or minor, or major + ``` + +2. Update `History.md` with the changes in this release + +3. Commit the changes: + ```bash + git add package.json package-lock.json History.md + git commit -m "Prepare for vX.Y.Z release" + ``` + +### 2. Create and Push Tag + +The prebuild workflow is triggered when you push a tag starting with `v`: + +```bash +git tag v0.5.6 # Use your actual version number +git push origin master +git push origin v0.5.6 +``` + +### 3. Monitor GitHub Actions + +1. Go to the [Actions tab](https://github.com/SlvCtrlPlus/node-speaker/actions) on GitHub +2. Wait for the "Prebuild" workflow to complete +3. The workflow will: + - Build N-API binaries for all supported platforms (6 builds total) + - Each binary works across all Node.js 18+ versions thanks to N-API + - Upload the binaries as artifacts + - Create a GitHub Release with: + - Complete package tarball with all prebuilds + - Individual `.node` binaries for each platform + - Auto-generated release notes + +### 4. Verify Publication + +1. Check that the release was created: + - Go to [Releases](https://github.com/SlvCtrlPlus/node-speaker/releases) + - Verify the new version is listed + - Check that all prebuilt binaries are attached + +2. Test installation from GitHub: + ```bash + # Install from GitHub release + npm install https://github.com/SlvCtrlPlus/node-speaker/releases/download/v0.5.6/speaker-v0.5.6.tgz + + # Or install from git tag + npm install github:SlvCtrlPlus/node-speaker#v0.5.6 + ``` + +## Manual Prebuild (Testing) + +To test the prebuild process locally before publishing: + +### Single Platform + +Build for your current platform: + +```bash +npm run prebuild +``` + +This creates binaries in the `prebuilds/` directory. + +### All Platforms (Cross-compilation) + +Build for all platforms using Docker: + +```bash +npm run prebuild-all +``` + +Note: This requires Docker and can take significant time. + +### Test Local Prebuild + +After creating local prebuilds, test that they install correctly: + +```bash +# In another directory +npm install /path/to/node-speaker +``` + +The installation should use the prebuilt binary instead of compiling. + +## Troubleshooting + +### Build Failures + +If the GitHub Actions build fails: + +1. Check the build logs in the Actions tab +2. Common issues: + - Missing dependencies on specific platforms + - Node version compatibility + - Architecture-specific compilation issues + +### GitHub Release Failures + +If creating the GitHub Release fails: + +1. Verify repository has "Read and write permissions" for workflows: + - Go to Settings → Actions → General → Workflow permissions + - Select "Read and write permissions" +2. Check that the tag was pushed correctly +3. Ensure no release already exists for that tag + +### Prebuilds Not Found During Installation + +If users report compilation from source when prebuilds should exist: + +1. Verify prebuilds exist in the GitHub Release assets +2. Check that the platform/Node version is supported +3. Ensure users are installing from the release tarball, not directly from git +4. For git installations, prebuilds must be committed or users need to build from source + +## Security + +- The `GITHUB_TOKEN` is automatically provided by GitHub Actions +- No manual token configuration needed for GitHub Releases +- Limit repository write access to trusted maintainers +- Review workflow permissions regularly + +## Optional: Publishing to npm + +If you later decide to also publish to npm, you can: + +1. Add `NPM_TOKEN` to GitHub Actions secrets +2. Uncomment the npm publish step in `.github/workflows/prebuild.yml` +3. Follow the standard npm publishing process + +## Support + +For issues with the publishing process: + +1. Check existing GitHub Issues +2. Review the [RELEASE-CHECKLIST.md](RELEASE-CHECKLIST.md) +3. Contact the package maintainers + diff --git a/README.md b/README.md index ebb45f4..83ec96d 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,30 @@ these days. ## Installation +### From npm + Simply compile and install `node-speaker` using `npm`: ```sh npm install speaker ``` +### From GitHub Releases (with prebuilt binaries) + +Install a specific release from GitHub: + +```sh +npm install https://github.com/YOUR_USERNAME/node-speaker/releases/download/v0.5.6/speaker-v0.5.6.tgz +``` + +Or install from a git tag: + +```sh +npm install github:YOUR_USERNAME/node-speaker#v0.5.6 +``` + +### Platform Requirements + On Debian/Ubuntu, the [ALSA][alsa] backend is selected by default, so be sure to have the `alsa.h` header file in place: diff --git a/package.json b/package.json index 8c6cc89..3820eef 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,32 @@ { "name": "speaker", - "version": "0.5.5", + "version": "0.1.0", "license": "(MIT AND LGPL-2.1-only)", "description": "Output PCM audio data to the speakers", "author": "Nathan Rajlich (http://tootallnate.net)", - "repository": "TooTallNate/node-speaker", + "repository": "github:SlvCtrlPlus/node-speaker", + "binary": { + "napi_versions": [3] + }, "main": "index.js", "types": "index.d.ts", "scripts": { - "test": "standard && node-gyp rebuild --mpg123-backend=dummy && mocha --reporter spec" + "test": "standard && node-gyp rebuild --mpg123-backend=dummy && mocha --reporter spec", + "install": "prebuild-install || node-gyp rebuild", + "prebuild": "prebuildify --napi --strip", + "prebuild-all": "prebuildify-cross --napi --strip" }, "dependencies": { "bindings": "^1.3.0", "buffer-alloc": "^1.1.0", - "debug": "^4.0.0" + "debug": "^4.0.0", + "prebuild-install": "^7.1.2" }, "devDependencies": { "@types/node": "^18.0.0", "mocha": "^11.7.5", + "prebuildify": "^6.0.1", + "prebuildify-cross": "^5.1.1", "standard": "^17.1.2" }, "engines": {