From a2db422b60b8f81d6264175d8112cd8d443aadb2 Mon Sep 17 00:00:00 2001 From: Salama Ashoush Date: Mon, 27 May 2024 18:25:52 +0200 Subject: [PATCH] new ci --- .github/workflows/bloat.tmpl | 13 ++ .github/workflows/bloat.yml | 43 ++++ .../workflows/{release.yml => changeset.yml} | 2 +- .github/workflows/ci.yml | 152 +++++++++++++ .github/workflows/release_crates.yml | 20 ++ .github/workflows/release_pactup.yml | 201 +++++++++++++++++ .github/workflows/rust.yml | 211 ------------------ .gitignore | 1 + README.md | 6 +- bin/pactup | 145 ++++++++++++ package.json | 19 +- scripts/generate-package.mjs | 109 +++++++++ 12 files changed, 703 insertions(+), 219 deletions(-) create mode 100644 .github/workflows/bloat.tmpl create mode 100644 .github/workflows/bloat.yml rename .github/workflows/{release.yml => changeset.yml} (98%) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release_crates.yml create mode 100644 .github/workflows/release_pactup.yml delete mode 100644 .github/workflows/rust.yml create mode 100644 bin/pactup create mode 100644 scripts/generate-package.mjs diff --git a/.github/workflows/bloat.tmpl b/.github/workflows/bloat.tmpl new file mode 100644 index 0000000..c334ff0 --- /dev/null +++ b/.github/workflows/bloat.tmpl @@ -0,0 +1,13 @@ +# Bloat Summary + +## Largest functions + +``` +${BLOAT_FUNC} +``` + +## Largest crates + +``` +${BLOAT_CRATE} +``` diff --git a/.github/workflows/bloat.yml b/.github/workflows/bloat.yml new file mode 100644 index 0000000..50e1c97 --- /dev/null +++ b/.github/workflows/bloat.yml @@ -0,0 +1,43 @@ +# Run `cargo bloat` for finding out what takes most of the space in your executable. + +name: Cargo Bloat + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + bloat: + name: Cargo Bloat + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: taiki-e/checkout-action@v1 + + - name: Cache + uses: Swatinem/rust-cache@v2 + + - name: Install cargo-bloat + uses: taiki-e/install-action@v2 + with: + tool: cargo-bloat + + - name: Run + run: | + export CMD="cargo bloat" + + # Get largest functions + export BLOAT_FUNC_CMD="${CMD} -n 10" + export BLOAT_FUNC=`${BLOAT_FUNC_CMD}` + echo "${BLOAT_FUNC}" + + # Get largest crates + export BLOAT_CRATE_CMD="${CMD} --crates -n 10" + export BLOAT_CRATE=`${BLOAT_CRATE_CMD}` + echo "${BLOAT_CRATE}" + + # Render summary + envsubst < .github/workflows/bloat.tmpl > $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/release.yml b/.github/workflows/changeset.yml similarity index 98% rename from .github/workflows/release.yml rename to .github/workflows/changeset.yml index d432451..1827f41 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/changeset.yml @@ -1,4 +1,4 @@ -name: release +name: changeset on: push: branches: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e9ebcc4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,152 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize] + paths-ignore: + - "**/*.md" + - "**/*.yml" + - "!.github/workflows/ci.yml" + push: + branches: + - main + - "renovate/**" + paths-ignore: + - "**/*.md" + - "**/*.yml" + - "!.github/workflows/ci.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: ${{ github.ref_name != 'main' }} + +defaults: + run: + shell: bash + +env: + CARGO_INCREMENTAL: 0 + RUSTFLAGS: "-D warnings" + +jobs: + test: + name: Test + strategy: + fail-fast: false + matrix: + include: + # - os: windows-latest + - os: ubuntu-latest + - os: macos-14 + runs-on: ${{ matrix.os }} + env: + # https://github.com/mozilla/sccache/blob/main/docs/S3.md + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SCCACHE_BUCKET: ${{ secrets.SCCACHE_BUCKET }} + SCCACHE_ENDPOINT: ${{ secrets.SCCACHE_ENDPOINT }} + SCCACHE_REGION: auto + RUSTC_WRAPPER: ${{ vars.USE_SCCACHE == 'true' && 'sccache' || '' }} + CARGO_INCREMENTAL: 0 + SCCACHE_LOCAL_RW_MODE: + steps: + - uses: taiki-e/checkout-action@v1 + - uses: Boshen/setup-rust@main + with: + # warm cache factory for all other CI jobs + # cache `target` directory to avoid download crates + save-cache: ${{ github.ref_name == 'main' }} + cache-key: warm + # cache build outputs to speed up compilation + - uses: mozilla-actions/sccache-action@v0.0.4 + if: ${{ vars.USE_SCCACHE == 'true' }} + - run: cargo test --no-run + - run: cargo test + - run: cargo ck + + typos: + name: Spell Check + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - uses: crate-ci/typos@master + with: + files: . + + deny: + name: Cargo Deny + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + src: + - 'Cargo.lock' + + - uses: Boshen/setup-rust@main + if: steps.filter.outputs.src == 'true' + with: + restore-cache: false + tools: cargo-deny + + - if: steps.filter.outputs.src == 'true' + run: cargo deny check + + unused-deps: + name: Check Unused Dependencies + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + src: + - '**/*.rs' + - '**/Cargo.toml' + - 'Cargo.lock' + - uses: Boshen/setup-rust@main + with: + restore-cache: false + if: steps.filter.outputs.src == 'true' + - uses: cargo-bins/cargo-binstall@main + if: steps.filter.outputs.src == 'true' + - run: cargo binstall --no-confirm cargo-shear + if: steps.filter.outputs.src == 'true' + - run: cargo shear + if: steps.filter.outputs.src == 'true' + + format: + name: Format + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - uses: Boshen/setup-rust@main + with: + components: rustfmt + restore-cache: false + - run: cargo fmt --all -- --check + + lint: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - uses: Boshen/setup-rust@main + with: + components: clippy + - run: cargo lint -- -D warnings + + doc: + name: Doc + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - uses: Boshen/setup-rust@main + with: + components: rust-docs + - run: RUSTDOCFLAGS='-D warnings' cargo doc --no-deps --document-private-items diff --git a/.github/workflows/release_crates.yml b/.github/workflows/release_crates.yml new file mode 100644 index 0000000..78f5279 --- /dev/null +++ b/.github/workflows/release_crates.yml @@ -0,0 +1,20 @@ +name: Release Crates + +on: + push: + branches: + - main + paths: + - Cargo.toml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release: + name: Release crates + runs-on: ubuntu-latest + steps: + - uses: taiki-e/checkout-action@v1 + - run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/release_pactup.yml b/.github/workflows/release_pactup.yml new file mode 100644 index 0000000..fefd26c --- /dev/null +++ b/.github/workflows/release_pactup.yml @@ -0,0 +1,201 @@ +name: Release pactup + +on: + push: + branches: + - main + paths: + - package.json # Please only commit this file, so we don't need to wait for all the other CI jobs to finish. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + check: + name: Check version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + version_changed: ${{ steps.version.outputs.changed }} + steps: + - uses: taiki-e/checkout-action@v1 + + - name: Check version changes + uses: EndBug/version-check@v2 + id: version + with: + static-checking: localIsNew + file-url: https://unpkg.com/pactup@latest/package.json + file-name: package.json + + - name: Set version name + if: steps.version.outputs.changed == 'true' + run: | + echo "Version change found! New version: ${{ steps.version.outputs.version }} (${{ steps.version.outputs.version_type }})" + + build: + needs: check + if: needs.check.outputs.version_changed == 'true' + env: + version: ${{ needs.check.outputs.version }} + OXC_VERSION: ${{ needs.check.outputs.version }} + strategy: + matrix: + include: + # - os: windows-latest + # target: x86_64-pc-windows-msvc + # code-target: win32-x64 + + # - os: windows-latest + # target: aarch64-pc-windows-msvc + # code-target: win32-arm64 + + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + code-target: linux-x64-gnu + + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + code-target: linux-arm64-gnu + + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + code-target: linux-x64-musl + + - os: ubuntu-latest + target: aarch64-unknown-linux-musl + code-target: linux-arm64-musl + + - os: macos-latest + target: x86_64-apple-darwin + code-target: darwin-x64 + + - os: macos-latest + target: aarch64-apple-darwin + code-target: darwin-arm64 + + name: Package ${{ matrix.code-target }} + runs-on: ${{ matrix.os }} + steps: + - uses: taiki-e/checkout-action@v1 + + - name: Install cross + uses: taiki-e/install-action@cross + + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: release-${{ matrix.target }} + + - name: Add Rust Target + run: rustup target add ${{ matrix.target }} + + - name: Build pactup with cross + run: cross build --release --target=${{ matrix.target }} + + # The binaries are zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss + - name: Archive Binaries + if: runner.os == 'Windows' + run: | + PACTUP_BIN_NAME=pactup-${{ matrix.code-target }} + mv target/${{ matrix.target }}/release/pactup.exe $PACTUP_BIN_NAME.exe + 7z a $PACTUP_BIN_NAME.zip $PACTUP_BIN_NAME.exe + + # The binaries are zipped to fix permission loss https://github.com/actions/upload-artifact#permission-loss + - name: Archive Binaries + if: runner.os != 'Windows' + run: | + PACTUP_BIN_NAME=pactup-${{ matrix.code-target }} + mv target/${{ matrix.target }}/release/pactup $PACTUP_BIN_NAME + tar czf $PACTUP_BIN_NAME.tar.gz $PACTUP_BIN_NAME + + - name: Upload Binary + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + name: binaries-${{ matrix.code-target }} + path: | + *.zip + *.tar.gz + + publish: + name: Publish + needs: build + runs-on: ubuntu-latest + permissions: + contents: write # for softprops/action-gh-release@v1 + id-token: write # for `npm publish --provenance` + steps: + - uses: taiki-e/checkout-action@v1 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: "https://registry.npmjs.org" + + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Unzip + uses: montudor/action-zip@v1 + with: + args: unzip -qq *.zip -d . + + - name: Untar + run: ls *.gz | xargs -i tar xf {} + + - name: Generate npm packages + run: | + node scripts/generate-packages.mjs + cat package.json + for package in npm/pactup*; do cat $package/package.json ; echo ; done + + - name: Publish npm packages as latest + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # NOTE: The trailing slash on $package/ changes it to publishing the directory + run: | + for package in npm/pactup* + do + npm publish $package/ --tag latest --provenance --access public + echo '----' + done + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: pactup v${{ needs.check.outputs.version }} + tag_name: pactup_v${{ needs.check.outputs.version }} + draft: true + files: pactup-* + fail_on_unmatched_files: true + + - name: wait 3 minutes for smoke test + run: sleep 180s + + smoke: + needs: publish + strategy: + matrix: + include: + # - os: windows-latest + - os: ubuntu-latest + - os: ubuntu-latest + container: node:22-alpine # musl + - os: macos-latest + name: Smoke Test ${{ matrix.os }} ${{ matrix.container }} + runs-on: ${{ matrix.os }} + container: ${{ matrix.container }} + steps: + - name: Test + run: | + ldd --version || true + npx pactup@${{ needs.check.outputs.version }} --version diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index afd1b03..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,211 +0,0 @@ -name: Rust - -on: - pull_request: - push: - branches: - - main - -concurrency: - group: ci-${{ github.head_ref }} - cancel-in-progress: true - -env: - RUST_VERSION: stable -jobs: - fmt: - runs-on: ubuntu-latest - steps: - - uses: hecrj/setup-rust-action@v2 - with: - rust-version: ${{env.RUST_VERSION}} - - uses: Swatinem/rust-cache@v2 - - uses: actions/checkout@v4 - - name: cargo fmt - run: cargo fmt -- --check - - clippy: - runs-on: ubuntu-latest - steps: - - uses: hecrj/setup-rust-action@v2 - with: - rust-version: ${{env.RUST_VERSION}} - - uses: Swatinem/rust-cache@v2 - - uses: actions/checkout@v4 - - name: cargo clippy - run: cargo clippy -- -D warnings - - unit_tests: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macOS-latest] - steps: - - uses: hecrj/setup-rust-action@v2 - with: - rust-version: ${{env.RUST_VERSION}} - - uses: Swatinem/rust-cache@v2 - - uses: actions/checkout@v4 - - name: Run tests - run: cargo test - - # build_windows_release: - # runs-on: windows-latest - # name: "Release build for Windows" - # steps: - # - uses: hecrj/setup-rust-action@v2 - # with: - # rust-version: ${{env.RUST_VERSION}} - # - uses: Swatinem/rust-cache@v2 - # - uses: actions/checkout@v4 - # - name: Build release binary - # run: cargo build --release - # env: - # RUSTFLAGS: "-C target-feature=+crt-static" - # - uses: actions/upload-artifact@v3 - # with: - # name: pactup-windows - # path: target/release/pactup.exe - - build_macos_release: - runs-on: macos-latest - name: "Release build for macOS" - steps: - - uses: hecrj/setup-rust-action@v2 - with: - rust-version: ${{env.RUST_VERSION}} - - uses: Swatinem/rust-cache@v2 - - uses: actions/checkout@v4 - - name: Build release binary - run: cargo build --release - env: - LZMA_API_STATIC: "true" - - name: List dynamically linked libraries - run: otool -L target/release/pactup - - uses: actions/upload-artifact@v4 - with: - name: pactup-macos - path: target/release/pactup - - build_static_linux_binary: - name: "Build static Linux binary" - runs-on: ubuntu-latest - steps: - - uses: hecrj/setup-rust-action@v2 - with: - rust-version: ${{env.RUST_VERSION}} - targets: x86_64-unknown-linux-gnu - - uses: Swatinem/rust-cache@v2 - with: - key: static-linux-binary - - - uses: actions/checkout@v4 - - name: Build release binary - run: cargo build --release --target x86_64-unknown-linux-gnu - - uses: actions/upload-artifact@v4 - with: - name: pactup-linux - path: target/x86_64-unknown-linux-gnu/release/pactup - # Unfortunatly, No pact binary is available for linux arm - # build_static_arm_binary: - # name: "Build ARM binary" - # strategy: - # matrix: - # include: - # - arch: arm64 - # rust_target: aarch64-unknown-linux-gnu - # docker_image: arm64v8/ubuntu - # docker_platform: aarch64 - # - arch: arm32 - # rust_target: armv7-unknown-linux-gnueabihf - # docker_image: arm32v7/ubuntu - # docker_platform: armv7 - # runs-on: ubuntu-latest - # env: - # RUST_TARGET: ${{ matrix.rust_target }} - # steps: - # - name: Set up QEMU - # id: qemu - # uses: docker/setup-qemu-action@v3 - # - uses: hecrj/setup-rust-action@v2 - # with: - # rust-version: ${{env.RUST_VERSION}} - # - uses: Swatinem/rust-cache@v2 - # with: - # key: arm-binary-${{ matrix.arch }} - # - name: "Download `cross` crate" - # run: cargo install cross - # - uses: actions/checkout@v4 - # - name: "Build release" - # run: cross build --target $RUST_TARGET --release - # - uses: uraimo/run-on-arch-action@v2.7.2 - # name: Sanity test - # with: - # arch: ${{matrix.docker_platform}} - # distro: ubuntu18.04 - - # # Not required, but speeds up builds by storing container images in - # # a GitHub package registry. - # githubToken: ${{ github.token }} - - # env: | - # RUST_LOG: pactup=debug - - # dockerRunArgs: | - # --volume "${PWD}/target/${{matrix.rust_target}}/release:/artifacts" - - # # Set an output parameter `uname` for use in subsequent steps - # run: | - # echo "Hello from $(uname -a)" - # /artifacts/pactup --version - # echo "pactup install 4.11" - # /artifacts/pactup install 4.11 - # echo "pactup exec --using=4.11 -- pact --version" - # /artifacts/pactup exec --using=4.11 -- pact --version - - # - uses: actions/upload-artifact@v3 - # with: - # name: pactup-${{ matrix.arch }} - # path: target/${{ env.RUST_TARGET }}/release/pactup - - ensure_commands_markdown_is_up_to_date: - runs-on: ubuntu-latest - name: Ensure command docs are up-to-date - needs: [build_static_linux_binary] - steps: - - name: install necessary shells - run: sudo apt-get update && sudo apt-get install -y fish zsh bash - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: pactup-linux - path: target/release - - name: mark binary as executable - run: chmod +x target/release/pactup - - name: install pactup as binary - run: | - sudo install target/release/pactup /bin - pactup --version - - uses: pnpm/action-setup@v4 - with: - run_install: false - - uses: actions/setup-node@v4 - with: - node-version: 22.x - cache: "pnpm" - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - - uses: actions/cache@v4 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - run: pnpm install - - name: Generate command markdown - run: | - pnpm run generate-command-docs --check --pactup-path=$(which pactup) diff --git a/.gitignore b/.gitignore index 0156e8f..6cfc330 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ feature_tests/.tmp *.log .vercel .proxy +npm/ diff --git a/README.md b/README.md index f2adf49..062bc59 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ macOS installations using the installation script are deprecated in favor of the Example: ```sh -curl -fsSL https://raw.githubusercontent.com/kadena-community/pactup/main/scripts/install.sh | bash -s -- --install-dir "./.pactup" --skip-shell +curl -fsSL https://raw.githubusercontent.com//main/scripts/install.sh | bash -s -- --install-dir "./.pactup" --skip-shell ``` ### Manually @@ -66,7 +66,7 @@ Then, [set up your shell for pactup](#shell-setup) #### Using a release binary (Linux/macOS/Windows) -- Download the [latest release binary](https://github.com/Schniz/pactup/releases) for your system +- Download the [latest release binary](https://github.com/kadena-community/pactup/releases) for your system - Make it available globally on `PATH` environment variable - [Set up your shell for pactup](#shell-setup) @@ -210,7 +210,7 @@ cargo build cargo run -- --help # Will behave like `pactup --help` ``` -### Running Tests: +### Running Tests ```sh cargo test diff --git a/bin/pactup b/bin/pactup new file mode 100644 index 0000000..d032bc0 --- /dev/null +++ b/bin/pactup @@ -0,0 +1,145 @@ +#!/usr/bin/env node + +const isMusl = () => { + let musl = false; + if (process.platform === "linux") { + musl = isMuslFromFilesystem(); + if (musl === null) { + musl = isMuslFromReport(); + } + if (musl === null) { + musl = isMuslFromChildProcess(); + } + } + return musl; +}; + +const isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"); + +const isMuslFromFilesystem = () => { + const { readFileSync } = require("fs"); + try { + return readFileSync("/usr/bin/ldd", "utf-8").includes("musl"); + } catch { + return null; + } +}; + +const isMuslFromReport = () => { + const report = + typeof process.report.getReport === "function" + ? process.report.getReport() + : null; + if (!report) { + return null; + } + if (report.header && report.header.glibcVersionRuntime) { + return false; + } + if (Array.isArray(report.sharedObjects)) { + if (report.sharedObjects.some(isFileMusl)) { + return true; + } + } + return false; +}; + +const isMuslFromChildProcess = () => { + try { + return require("child_process") + .execSync("ldd --version", { encoding: "utf8" }) + .includes("musl"); + } catch (e) { + // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false + return false; + } +}; + +const { platform, arch, env, version, release } = process; + +const PLATFORMS = { + // win32: { + // x64: { + // musl: "@pactup/win32-x64/pactup.exe", + // gnu: "@pactup/win32-x64/pactup.exe", + // }, + // arm64: { + // musl: "@pactup/win32-arm64/pactup.exe", + // gnu: "@pactup/win32-arm64/pactup.exe", + // }, + // }, + darwin: { + x64: { + musl: "@pactup/darwin-x64/pactup", + gnu: "@pactup/darwin-x64/pactup", + }, + arm64: { + musl: "@pactup/darwin-arm64/pactup", + gnu: "@pactup/darwin-arm64/pactup", + }, + }, + linux: { + x64: { + musl: "@pactup/linux-x64-musl/pactup", + gnu: "@pactup/linux-x64-gnu/pactup", + }, + arm64: { + musl: "@pactup/linux-arm64-musl/pactup", + gnu: "@pactup/linux-arm64-gnu/pactup", + }, + }, +}; + +let binPath = PLATFORMS[platform]?.[arch]?.[isMusl() ? "musl" : "gnu"]; + +if (binPath) { + const result = require("child_process").spawnSync( + require.resolve(binPath), + process.argv.slice(2), + { + shell: false, + stdio: "inherit", + env: { + ...env, + JS_RUNTIME_VERSION: version, + JS_RUNTIME_NAME: release.name, + NODE_PACKAGE_MANAGER: detectPackageManager(), + }, + } + ); + + if (result.error) { + throw result.error; + } + + process.exitCode = result.status; +} else { + let target = `${platform}-${arch}`; + if (isMusl()) { + target = `${target}-musl`; + } + console.error( + `The pactup CLI package doesn't ship with prebuilt binaries for your platform (${target}) yet. ` + + "You can create an issue at https://github.com/kadena-community/pactup/issues for support." + ); + process.exitCode = 1; +} + +/** + * NPM, Yarn, and other package manager set the `npm_config_user_agent`. It has the following format: + * + * ``` + * "npm/8.3.0 node/v16.13.2 win32 x64 workspaces/false + * ``` + * + * @returns The package manager string (`npm/8.3.0`) or null if the user agent string isn't set. + */ +function detectPackageManager() { + const userAgent = env.npm_config_user_agent; + + if (userAgent == null) { + return null; + } + + return userAgent.split(" ")[0]; +} diff --git a/package.json b/package.json index 20a50d3..2fbe5dd 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,26 @@ { "name": "pactup", "version": "0.2.0", - "private": true, "repository": "git@github.com:kadena-community/pactup.git", - "author": "Salama Ashoush ", - "type": "module", + "author": "Salama Ashoush ", "packageManager": "pnpm@9.1.2", "license": "GPLv3", + "description": "Linter for the JavaScript Oxidation Compiler", + "keywords": [], + "homepage": "https://github.com/kadena-community/pactup", + "bugs": "https://github.com/kadena-community/pactup/issues", + "bin": "bin/pactup", + "engines": { + "node": ">=14.*" + }, + "files": [ + "bin/pactup", + "README.md" + ], "scripts": { "version:prepare": "changeset version && tsx ./scripts/prepare-version.ts", - "generate-command-docs": "tsx ./scripts/print-command-docs.ts" + "generate-command-docs": "tsx ./scripts/print-command-docs.ts", + "generate-npm-packages": "node ./scripts/generate-npm-packages.mjs" }, "changelog": { "repo": "kadena-community/pactup", diff --git a/scripts/generate-package.mjs b/scripts/generate-package.mjs new file mode 100644 index 0000000..3d2ea2c --- /dev/null +++ b/scripts/generate-package.mjs @@ -0,0 +1,109 @@ +// Code copied from [Rome](https://github.com/rome/tools/blob/main/npm/rome/scripts/generate-packages.mjs) + +import { resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import * as fs from "node:fs"; + +const PACTUP_BIN_NAME = "pactup"; +const PACTUP_ROOT = resolve(fileURLToPath(import.meta.url), "../.."); +const PACKAGES_ROOT = resolve(PACTUP_ROOT, "npm"); +const REPO_ROOT = PACTUP_ROOT; +const MANIFEST_PATH = resolve(PACTUP_ROOT, "package.json"); + +console.log(`PACTUP_ROOT: ${PACTUP_ROOT}`); +const rootManifest = JSON.parse( + fs.readFileSync(MANIFEST_PATH).toString("utf-8") +); + +const LIBC_MAPPING = { + gnu: "glibc", + musl: "musl", +}; + +function generateNativePackage(target) { + const packageName = `@${PACTUP_BIN_NAME}/${target}`; + const packageRoot = resolve(PACKAGES_ROOT, `${PACTUP_BIN_NAME}-${target}`); + + // Remove the directory just in case it already exists (it's autogenerated + // so there shouldn't be anything important there anyway) + fs.rmSync(packageRoot, { recursive: true, force: true }); + + // Create the package directory + console.log(`Create directory ${packageRoot}`); + fs.mkdirSync(packageRoot); + + // Generate the package.json manifest + const { version, author, license, homepage, bugs, repository } = rootManifest; + + const triple = target.split("-"); + const platform = triple[0]; + const arch = triple[1]; + const libc = triple[2] && { libc: [LIBC_MAPPING[triple[2]]] }; + const manifest = { + name: packageName, + version, + author, + license, + homepage, + bugs, + repository, + os: [platform], + cpu: [arch], + ...libc, + }; + + const manifestPath = resolve(packageRoot, "package.json"); + console.log(`Create manifest ${manifestPath}`); + fs.writeFileSync(manifestPath, JSON.stringify(manifest)); + + // Copy the binary + const ext = platform === "win32" ? ".exe" : ""; + + const pactupBinSource = resolve( + REPO_ROOT, + `${PACTUP_BIN_NAME}-${target}${ext}` + ); + const pactupBinTarget = resolve(packageRoot, `${PACTUP_BIN_NAME}${ext}`); + + console.log(`Copy pactup binary ${pactupBinSource}`); + fs.copyFileSync(pactupBinSource, pactupBinTarget); + fs.chmodSync(pactupBinTarget, 0o755); +} + +function writeManifest() { + const manifestPath = resolve(PACKAGES_ROOT, PACTUP_BIN_NAME, "package.json"); + + const manifestData = JSON.parse( + fs.readFileSync(manifestPath).toString("utf-8") + ); + + const nativePackages = TARGETS.map((target) => [ + `@${PACTUP_BIN_NAME}/${target}`, + rootManifest.version, + ]); + + manifestData["version"] = rootManifest.version; + manifestData["optionalDependencies"] = Object.fromEntries(nativePackages); + + console.log(`Update manifest ${manifestPath}`); + const content = JSON.stringify(manifestData); + fs.writeFileSync(manifestPath, content); +} + +// NOTE: Must update npm/pactup/bin/pactup +const TARGETS = [ + "win32-x64", + "win32-arm64", + "linux-x64-gnu", + "linux-arm64-gnu", + "linux-x64-musl", + "linux-arm64-musl", + "darwin-x64", + "darwin-arm64", +]; + +for (const target of TARGETS) { + generateNativePackage(target); +} + +writeManifest();