diff --git a/.github/workflows/gnd-binary-build.yml b/.github/workflows/gnd-binary-build.yml index fff3e3a76c0..fd642606e69 100644 --- a/.github/workflows/gnd-binary-build.yml +++ b/.github/workflows/gnd-binary-build.yml @@ -2,6 +2,11 @@ name: Build gnd Binaries on: workflow_dispatch: + inputs: + dry_run: + description: 'Dry-run npm publish (no actual publish)' + type: boolean + default: false jobs: build: @@ -18,7 +23,7 @@ jobs: runner: ubuntu-22.04 asset_name: gnd-linux-aarch64 - target: x86_64-apple-darwin - runner: macos-13 + runner: macos-14 asset_name: gnd-macos-x86_64 - target: aarch64-apple-darwin runner: macos-latest @@ -29,21 +34,32 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 + + - name: Cache built binary + id: bin-cache + uses: actions/cache@v5 + with: + path: | + ${{ matrix.asset_name }}.gz + ${{ matrix.asset_name }}.zip + key: gnd-${{ matrix.target }}-${{ hashFiles('Cargo.lock', '**/Cargo.toml', '**/*.rs') }} - name: Install Rust toolchain + if: steps.bin-cache.outputs.cache-hit != 'true' run: | rustup toolchain install stable rustup target add ${{ matrix.target }} rustup default stable - name: Rust Cache + if: steps.bin-cache.outputs.cache-hit != 'true' uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} - name: Install dependencies (Ubuntu) - if: startsWith(matrix.runner, 'ubuntu') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'ubuntu') run: | sudo apt-get update sudo apt-get install -y protobuf-compiler musl-tools @@ -52,27 +68,26 @@ jobs: fi - name: Install dependencies (macOS) - if: startsWith(matrix.runner, 'macos') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'macos') run: | brew install protobuf - name: Install protobuf (Windows) - if: startsWith(matrix.runner, 'windows') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'windows') run: choco install protoc - - name: Build gnd binary (Unix/Mac) - if: ${{ !startsWith(matrix.runner, 'windows') }} + if: steps.bin-cache.outputs.cache-hit != 'true' && !startsWith(matrix.runner, 'windows') run: cargo build --bin gnd --release --target ${{ matrix.target }} env: CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - name: Build gnd binary (Windows) - if: startsWith(matrix.runner, 'windows') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'windows') run: cargo build --bin gnd --release --target ${{ matrix.target }} - name: Sign macOS binary - if: startsWith(matrix.runner, 'macos') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'macos') uses: lando/code-sign-action@v3 with: file: target/${{ matrix.target }}/release/gnd @@ -82,7 +97,7 @@ jobs: options: --options runtime --entitlements entitlements.plist - name: Notarize macOS binary - if: startsWith(matrix.runner, 'macos') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'macos') uses: lando/notarize-action@v2 with: product-path: target/${{ matrix.target }}/release/gnd @@ -91,20 +106,20 @@ jobs: appstore-connect-team-id: ${{ secrets.APPLE_TEAM_ID }} - name: Prepare binary (Unix) - if: ${{ !startsWith(matrix.runner, 'windows') }} + if: steps.bin-cache.outputs.cache-hit != 'true' && !startsWith(matrix.runner, 'windows') run: | cp target/${{ matrix.target }}/release/gnd ${{ matrix.asset_name }} chmod +x ${{ matrix.asset_name }} gzip ${{ matrix.asset_name }} - name: Prepare binary (Windows) - if: startsWith(matrix.runner, 'windows') + if: steps.bin-cache.outputs.cache-hit != 'true' && startsWith(matrix.runner, 'windows') run: | copy target\${{ matrix.target }}\release\gnd.exe ${{ matrix.asset_name }} 7z a -tzip ${{ matrix.asset_name }}.zip ${{ matrix.asset_name }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.asset_name }} path: | @@ -119,7 +134,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup GitHub CLI run: | @@ -129,7 +144,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: path: artifacts @@ -142,18 +157,195 @@ jobs: VERSION=${GITHUB_REF#refs/tags/} # Upload Linux x86_64 asset - gh release upload $VERSION artifacts/gnd-linux-x86_64/gnd-linux-x86_64.gz --repo $GITHUB_REPOSITORY - - # Upload Linux ARM64 asset - gh release upload $VERSION artifacts/gnd-linux-aarch64/gnd-linux-aarch64.gz --repo $GITHUB_REPOSITORY - - # Upload macOS x86_64 asset - gh release upload $VERSION artifacts/gnd-macos-x86_64/gnd-macos-x86_64.gz --repo $GITHUB_REPOSITORY - - # Upload macOS ARM64 asset - gh release upload $VERSION artifacts/gnd-macos-aarch64/gnd-macos-aarch64.gz --repo $GITHUB_REPOSITORY - - # Upload Windows x86_64 asset - gh release upload $VERSION artifacts/gnd-windows-x86_64.exe/gnd-windows-x86_64.exe.zip --repo $GITHUB_REPOSITORY + gh release upload $VERSION --clobber --repo $GITHUB_REPOSITORY \ + artifacts/gnd-linux-x86_64/gnd-linux-x86_64.gz \ + artifacts/gnd-linux-aarch64/gnd-linux-aarch64.gz \ + artifacts/gnd-macos-x86_64/gnd-macos-x86_64.gz \ + artifacts/gnd-macos-aarch64/gnd-macos-aarch64.gz \ + artifacts/gnd-windows-x86_64.exe/gnd-windows-x86_64.exe.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + publish-npm: + name: Publish npm package for ${{ matrix.platform }} + needs: release + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + strategy: + fail-fast: false + matrix: + include: + - platform: linux-x64 + asset: gnd-linux-x86_64.gz + os_field: linux + cpu_field: x64 + extract: gunzip + - platform: linux-arm64 + asset: gnd-linux-aarch64.gz + os_field: linux + cpu_field: arm64 + extract: gunzip + - platform: darwin-x64 + asset: gnd-macos-x86_64.gz + os_field: darwin + cpu_field: x64 + extract: gunzip + - platform: darwin-arm64 + asset: gnd-macos-aarch64.gz + os_field: darwin + cpu_field: arm64 + extract: gunzip + - platform: win32-x64 + asset: gnd-windows-x86_64.exe.zip + os_field: win32 + cpu_field: x64 + extract: unzip + steps: + - uses: actions/setup-node@v6 + with: + node-version: 24 + + - name: Download gnd binary env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GH_TOKEN: ${{ github.token }} + run: | + gh release download "${{ github.ref_name }}" \ + --repo "${{ github.repository }}" \ + --pattern "${{ matrix.asset }}" \ + --output ./binary-archive + + - name: Extract binary + run: | + mkdir -p pkg/bin + if [ "${{ matrix.extract }}" = "gunzip" ]; then + gunzip -c ./binary-archive > pkg/bin/gnd + chmod +x pkg/bin/gnd + else + unzip ./binary-archive -d pkg/bin + mv pkg/bin/*.exe pkg/bin/gnd.exe + fi + + - name: Determine version and npm tag + id: version + shell: bash + run: | + VERSION="${{ github.ref_name }}" + VERSION="${VERSION#v}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + # Prerelease versions (e.g. 0.42.2-dev.1) need an explicit --tag + if [[ "$VERSION" == *-* ]]; then + # Extract prerelease identifier (e.g. "dev" from "0.42.2-dev.1") + PRE="${VERSION#*-}" + TAG="${PRE%%.*}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + else + echo "tag=latest" >> $GITHUB_OUTPUT + fi + + - name: Create package.json + shell: bash + run: | + if [ "${{ matrix.os_field }}" = "win32" ]; then + BIN_PATH="./bin/gnd.exe" + else + BIN_PATH="./bin/gnd" + fi + + cat > pkg/package.json << EOF + { + "name": "@graphprotocol/gnd-${{ matrix.platform }}", + "version": "${{ steps.version.outputs.version }}", + "description": "gnd binary for ${{ matrix.platform }}", + "os": ["${{ matrix.os_field }}"], + "cpu": ["${{ matrix.cpu_field }}"], + "bin": { + "gnd": "${BIN_PATH}" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "license": "(Apache-2.0 OR MIT)", + "repository": { + "type": "git", + "url": "https://github.com/graphprotocol/graph-node.git" + } + } + EOF + + - name: Publish + run: npm publish --provenance --access public --tag ${{ steps.version.outputs.tag }} ${{ inputs.dry_run && '--dry-run' || '' }} + working-directory: pkg + + publish-npm-wrapper: + name: Publish @graphprotocol/gnd wrapper + needs: publish-npm + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: 24 + + - name: Determine version and npm tag + id: version + shell: bash + run: | + VERSION="${{ github.ref_name }}" + VERSION="${VERSION#v}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + if [[ "$VERSION" == *-* ]]; then + PRE="${VERSION#*-}" + TAG="${PRE%%.*}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + else + echo "tag=latest" >> $GITHUB_OUTPUT + fi + + - name: Create wrapper package + shell: bash + run: | + VERSION="${{ steps.version.outputs.version }}" + + mkdir -p pkg/bin + cp gnd/npm/bin/gnd.js pkg/bin/gnd.js + cp gnd/npm/README.md pkg/README.md + + cat > pkg/package.json << EOF + { + "name": "@graphprotocol/gnd", + "version": "${VERSION}", + "description": "Graph Node Development CLI", + "bin": { + "gnd": "./bin/gnd.js" + }, + "optionalDependencies": { + "@graphprotocol/gnd-darwin-arm64": "${VERSION}", + "@graphprotocol/gnd-darwin-x64": "${VERSION}", + "@graphprotocol/gnd-linux-arm64": "${VERSION}", + "@graphprotocol/gnd-linux-x64": "${VERSION}", + "@graphprotocol/gnd-win32-x64": "${VERSION}" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "license": "(Apache-2.0 OR MIT)", + "repository": { + "type": "git", + "url": "https://github.com/graphprotocol/graph-node.git" + } + } + EOF + + - name: Publish + run: npm publish --provenance --access public --tag ${{ steps.version.outputs.tag }} ${{ inputs.dry_run && '--dry-run' || '' }} + working-directory: pkg \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4b26127715c..7b7913a3cfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -867,21 +867,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse 0.2.4", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - [[package]] name = "anstream" version = "1.0.0" @@ -889,7 +874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", - "anstyle-parse 1.0.0", + "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -903,15 +888,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - [[package]] name = "anstyle-parse" version = "1.0.0" @@ -938,7 +914,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.1", + "windows-sys 0.60.2", ] [[package]] @@ -2078,9 +2054,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.8" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -2088,11 +2064,11 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.8" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "anstream 0.6.14", + "anstream", "anstyle", "clap_lex", "strsim", @@ -2110,9 +2086,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2122,9 +2098,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cobs" @@ -3249,7 +3225,7 @@ version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ - "anstream 1.0.0", + "anstream", "anstyle", "env_filter", "jiff", @@ -6291,7 +6267,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ - "heck 0.5.0", + "heck 0.4.1", "itertools 0.14.0", "log", "multimap", @@ -7882,12 +7858,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ - "rustix 0.38.34", - "windows-sys 0.48.0", + "rustix 1.0.7", + "windows-sys 0.60.2", ] [[package]] diff --git a/gnd/npm/README.md b/gnd/npm/README.md new file mode 100644 index 00000000000..acca621b4dc --- /dev/null +++ b/gnd/npm/README.md @@ -0,0 +1,35 @@ +# The Graph CLI + +This package installs the CLI for developing subgraphs for [The Graph +Network](https://thegraph.com/subgraphs/) It supports all aspects of +[developing, testing, and deploying subgraphs](https://thegraph.com/docs/en/subgraphs/quick-start/) locally and +on the network. + +This package is a complete replacement for the older +[graph-cli](https://www.npmjs.com/package/@graphprotocol/graph-cli) which +will over time be migrated to be a simple wrapper for `gnd`. Older +documentation will reference `graph-cli` in its instructions; running +`alias graph=gnd` in the shell make it possible to follow these +instructions verbatim with `gnd`. + +Besides the tools to develop subgraphs, `gnd` also contains a version of +[graph-node](https://github.com/graphprotocol/graph-node) tailored to +running subgraphs locally via `gnd dev`. + + +## Getting started + +Run `npm install -g @graphprotocol/gnd` to install `gnd`. + +After installation, you can create and run an example subgraph locally with +```bash +gnd init --from-example ethereum-gravatar 'My new subgraph' new-subgraph +cd new-subgraph +gnd codegen +gnd build +gnd dev --ethereum-rpc 'mainnet:' +``` + +If you have an existing contract for which you want to write a subgraph, +have a look at `gnd help init` and the `--from-contract` option. You can +also simply run `gnd init` and follow the prompts to set up your subgraph. diff --git a/gnd/npm/bin/gnd.js b/gnd/npm/bin/gnd.js new file mode 100644 index 00000000000..82a7ae5bf09 --- /dev/null +++ b/gnd/npm/bin/gnd.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +const { execFileSync } = require("child_process"); +const path = require("path"); + +const PLATFORMS = { + "darwin-arm64": "@graphprotocol/gnd-darwin-arm64", + "darwin-x64": "@graphprotocol/gnd-darwin-x64", + "linux-arm64": "@graphprotocol/gnd-linux-arm64", + "linux-x64": "@graphprotocol/gnd-linux-x64", + "win32-x64": "@graphprotocol/gnd-win32-x64", +}; + +const key = `${process.platform}-${process.arch}`; +const pkg = PLATFORMS[key]; +if (!pkg) { + console.error(`Unsupported platform: ${key}`); + process.exit(1); +} + +const bin = process.platform === "win32" ? "gnd.exe" : "gnd"; +const binPath = path.join( + require.resolve(`${pkg}/package.json`), + "..", + "bin", + bin +); + +try { + execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" }); +} catch (e) { + process.exit(e.status ?? 1); +}