Skip to content

Commit

Permalink
✨ Draft workflow for building & publishing packages (magicblock-labs#16)
Browse files Browse the repository at this point in the history
* ✨ Draft workflow for building & publishing packages

* 🚧 Workflow WIP

* 👷 Update workflow

* 👷 Update workflow

* 👷 Update CI

* 👷 Publish to github npm registry

* 👷 Update workflow

* 👷 Update workflow\

* 📝 Fix template

* 👷 Remove dry-run

* 👷 Publish packages for 0.0.1

* 👷 Enable cross

* 👷 Use cross for windows

* 📦 Add parent package

* 👷 Add Ring for windows build

* 👷 Add ring to cli crates on windows

* 👷 Add ring to cli crates on windows

* 👷 Use no features for windows build

* 👷 Remove dependencies step

* 👷 Publish binaries to release

* 👷 Set release tag

* 👷 Update binary name

* 👷 Improve artifact name

* 👷 Remove dry run

* 📝 Update package.json template

* 📝 Update package template

* 📝 Update archs

* 📝 Use npm

* 👷 Add repo checkout step

* 👷 Add npm install step

* 👷 Update workdlow file
  • Loading branch information
GabrielePicco authored Feb 23, 2024
1 parent cacbfc1 commit fc7301c
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 39 deletions.
172 changes: 172 additions & 0 deletions .github/workflows/publish-packages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: Publish bolt-cli packages
on:
release:
types: [ published ]
workflow_dispatch:
inputs:
release_version:
description: 'The release version'
required: true
default: '0.0.1'

jobs:
publish-npm-binaries:
name: Publish NPM packages
runs-on: ${{ matrix.build.os }}
strategy:
fail-fast: false
matrix:
build:
- {
NAME: linux-x64-glibc,
OS: ubuntu-20.04,
TOOLCHAIN: stable,
TARGET: x86_64-unknown-linux-gnu,
}
- {
NAME: linux-x86-glibc,
OS: ubuntu-22.04,
TOOLCHAIN: stable,
TARGET: i686-unknown-linux-gnu,
}
- {
NAME: linux-arm64-glibc,
OS: ubuntu-20.04,
TOOLCHAIN: stable,
TARGET: aarch64-unknown-linux-gnu,
}
- {
NAME: win32-x64-msvc,
OS: windows-2022,
TOOLCHAIN: stable,
TARGET: x86_64-pc-windows-msvc,
}
- {
NAME: win32-x86-msvc,
OS: windows-2022,
TOOLCHAIN: stable,
TARGET: i686-pc-windows-msvc,
}
- {
NAME: darwin-x64,
OS: macos-11,
TOOLCHAIN: stable,
TARGET: x86_64-apple-darwin,
}
- {
NAME: darwin-arm64,
OS: macos-11,
TOOLCHAIN: stable,
TARGET: aarch64-apple-darwin,
}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set the release version
shell: bash
run: echo "RELEASE_VERSION=${github.event.inputs.release_version || GITHUB_REF:11}" >> $GITHUB_ENV

- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.build.TOOLCHAIN }}
target: ${{ matrix.build.TARGET }}
override: true

- name: Build (linux/macos)
if: matrix.build.OS != 'windows-2022'
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --manifest-path=cli/Cargo.toml --release --locked --target ${{ matrix.build.TARGET }}

- name: Build (windows)
if: matrix.build.OS == 'windows-2022'
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path=cli/Cargo.toml --no-default-features --release --locked --target ${{ matrix.build.TARGET }}

- name: Build the NPM package
shell: bash
run: |
# set the binary name
bin="bolt"
# derive the OS and architecture from the build matrix name
# note: when split by a hyphen, first part is the OS and the second is the architecture
node_os=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f1)
export node_os
node_arch=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f2)
export node_arch
# set the version
export node_version="${{ env.RELEASE_VERSION }}"
# set the package name
# note: use 'windows' as OS name instead of 'win32'
if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
export node_pkg="${bin}-cli-windows-${node_arch}"
else
export node_pkg="${bin}-cli-${node_os}-${node_arch}"
fi
echo "node_pkg=${node_pkg}" >> $GITHUB_ENV
# create the package directory
mkdir -p "${node_pkg}/bin"
# generate package.json from the template
envsubst < cli/npm-package/package.json.tmpl > "${node_pkg}/package.json"
cat "${node_pkg}/package.json"
# copy the binary into the package
# note: windows binaries has '.exe' extension
if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
bin="${bin}.exe"
fi
echo "bin_name=${bin}" >> $GITHUB_ENV
cp "target/${{ matrix.build.TARGET }}/release/${bin}" "${node_pkg}/bin"
cp "target/${{ matrix.build.TARGET }}/release/${bin}" "${node_pkg}/bin"
# Create the release bin file
release_name="bolt-${{ matrix.build.NAME }}"
if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
release_name="${release_name}.exe"
fi
echo "release_name=${release_name}" >> $GITHUB_ENV
mv "target/${{ matrix.build.TARGET }}/release/${bin}" "target/${{ matrix.build.TARGET }}/release/${release_name}"
- name: Publish binary to GitHub release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/${{ matrix.build.TARGET }}/release/${{ env.release_name }}
overwrite: true
tag: "v${{ env.RELEASE_VERSION }}"
release_name: "v${{ env.RELEASE_VERSION }}"
asset_name: "${{ env.release_name }}"

- name: Publish the NPM package
shell: bash
run: |
cd ${{ env.node_pkg }}
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
npm set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-wrapper-npm-package:
name: Publish wrapper NPM packages
runs-on: ubuntu-20.04
needs: publish-npm-binaries
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Publish the NPM package
shell: bash
run: |
cd cli/npm-package
npm install
npm run build
cd lib
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
npm set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ tests/examples/target
tests/examples/node_modules
tests/examples/.yarn

cli/npm-package/lib
cli/npm-package/.npmrc
cli/npm-package/.yarnrc
cli/npm-package/package-lock.json
.npmrc
.yarnrc

2 changes: 2 additions & 0 deletions cli/npm-package/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lib/**
scripts/**
15 changes: 15 additions & 0 deletions cli/npm-package/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"ignorePatterns": [
"lib/**",
"scripts/**"
],
"root": true
}
81 changes: 44 additions & 37 deletions cli/npm-package/bolt → cli/npm-package/bolt.ts
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,85 +1,93 @@
#!/usr/bin/env node
const fs = require("fs");
const { spawn, spawnSync } = require("child_process");
const path = require("path");
const { arch, platform } = require("os");
const { version } = require("./package.json");
import fs from "fs";
import { spawn, spawnSync } from "child_process";
import path from "path";
import { arch, platform } from "os";
import { version } from "./package.json";

const PACKAGE_VERSION = `bolt-cli ${version}`;
const PACKAGE_BOLT_PATH = path.join(__dirname, "bolt");

function getBinaryVersion(location) {
function getBinaryVersion(location: string): [string | null, string | null] {
const result = spawnSync(location, ["--version"]);
const error =
const error: string | null =
(result.error && result.error.toString()) ||
(result.stderr.length > 0 && result.stderr.toString().trim()) ||
null;
return [error, result.stdout && result.stdout.toString().trim()];
}

function runBolt(location) {
function getExePath(): string {
let os: string = platform();
let extension = "";
if (["win32", "cygwin"].includes(os)) {
os = "windows";
extension = ".exe";
}
const binaryName = `@magicblock-labs/bolt-cli-${os}-${arch()}/bin/bolt${extension}`;
try {
return require.resolve(binaryName);
} catch (e) {
throw new Error(
`Couldn't find application binary inside node_modules for ${os}-${arch()}`
);
}
}

function runBolt(location: string): void {
const args = process.argv.slice(2);
const bolt = spawn(location, args, { stdio: "inherit" });
bolt.on("exit", (code, signal) => {
bolt.on("exit", (code: number | null, signal: NodeJS.Signals | null) => {
process.on("exit", () => {
if (signal) {
process.kill(process.pid, signal);
} else {
} else if (code !== null) {
process.exit(code);
}
});
});

process.on("SIGINT", function () {
process.on("SIGINT", () => {
bolt.kill("SIGINT");
bolt.kill("SIGTERM");
});
}

function tryPackageBolt() {
if (arch() !== "x64" || platform() !== "linux") {
console.error(`Only x86_64 / Linux distributed in NPM package right now.`);
return false;
}

const [error, binaryVersion] = getBinaryVersion(PACKAGE_BOLT_PATH);
if (error !== null) {
console.error(`Failed to get version of local binary: ${error}`);
return false;
}
if (binaryVersion !== PACKAGE_VERSION) {
function tryPackageBolt(): boolean {
try {
const path = getExePath();
runBolt(path);
return true;
} catch (e) {
console.error(
`Package binary version is not correct. Expected "${PACKAGE_VERSION}", found "${binaryVersion}".`
"Failed to run bolt from package:",
e instanceof Error ? e.message : e
);
return false;
}

runBolt(PACKAGE_BOLT_PATH);
return true;
}

function trySystemBolt() {
console.error("Trying globally installed bolt.");

const absolutePath = process.env.PATH.split(":")
function trySystemBolt(): void {
const absolutePath = process.env.PATH?.split(path.delimiter)
.filter((dir) => dir !== path.dirname(process.argv[1]))
.find((dir) => {
try {
fs.accessSync(`${dir}/bolt`, fs.constants.X_OK);
return true;
} catch {
return false;
}
return true;
});

if (!absolutePath) {
console.error(`Could not find globally installed bolt, install with cargo.`);
process.exit();
console.error(
`Could not find globally installed bolt, please install with cargo.`
);
process.exit(1);
}

const absoluteBinaryPath = `${absolutePath}/bolt`;

const [error, binaryVersion] = getBinaryVersion(absoluteBinaryPath);

if (error !== null) {
console.error(`Failed to get version of global binary: ${error}`);
return;
Expand All @@ -93,5 +101,4 @@ function trySystemBolt() {

runBolt(absoluteBinaryPath);
}

tryPackageBolt() || trySystemBolt();
24 changes: 22 additions & 2 deletions cli/npm-package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,30 @@
},
"license": "MIT",
"bin": {
"bolt": "./bolt.js"
"bolt": "bolt.js"
},
"scripts": {
"prepack": "[ \"$(uname -op)\" != \"x86_64 GNU/Linux\" ] && (echo Can be packed only on x86_64 GNU/Linux && exit 1) || ([ \"$(./bolt --version)\" != \"bolt-cli $(jq -r .version package.json)\" ] && (echo Check bolt binary version && exit 2) || exit 0)"
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"build": "tsc",
"dev": "yarn build && node lib/index.js"
},
"devDependencies": {
"@types/node": "^20.8.8",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"eslint": "^8.31.0",
"typescript": "^4.9.4"
},
"optionalDependencies": {
"@magicblock-labs/bolt-cli-darwin-x64": "0.0.1",
"@magicblock-labs/bolt-cli-darwin-arm64": "0.0.1",
"@magicblock-labs/bolt-cli-linux-x86": "0.0.1",
"@magicblock-labs/bolt-cli-linux-x64": "0.0.1",
"@magicblock-labs/bolt-cli-linux-arm64": "0.0.1",
"@magicblock-labs/bolt-cli-windows-x86": "0.0.1",
"@magicblock-labs/bolt-cli-windows-x64": "0.0.1"
},
"publishConfig": {
"access": "public"
Expand Down
Loading

0 comments on commit fc7301c

Please sign in to comment.