diff --git a/gnd/README.md b/gnd/README.md index 7ab0bfae7b0..375e1ef0e01 100644 --- a/gnd/README.md +++ b/gnd/README.md @@ -26,11 +26,11 @@ gnd build # Deploy to a local Graph Node gnd create --node http://localhost:8020 my-name/my-subgraph -gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 my-name/my-subgraph +gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 -l v0.0.1 my-name/my-subgraph # Or deploy to Subgraph Studio gnd auth YOUR_DEPLOY_KEY -gnd deploy my-name/my-subgraph +gnd deploy -l v0.0.1 my-name/my-subgraph ``` ## Commands @@ -165,7 +165,7 @@ gnd deploy [MANIFEST] | `--node` | `-g` | Graph Node URL (defaults to Subgraph Studio) | | `--ipfs` | `-i` | IPFS node URL | | `--deploy-key` | | Deploy key for authentication | -| `--version-label` | `-l` | Version label for the deployment | +| `--version-label` | `-l` | Version label for the deployment (required in non-interactive mode) | | `--ipfs-hash` | | IPFS hash of already-uploaded manifest | | `--output-dir` | `-o` | Build output directory (default: `build/`) | | `--skip-migrations` | | Skip manifest migrations | @@ -173,17 +173,20 @@ gnd deploy [MANIFEST] | `--network-file` | | Path to networks config | | `--debug-fork` | | Fork subgraph ID for debugging | +If `--version-label` is omitted in an interactive terminal, `gnd deploy` prompts for it. +In non-interactive environments (CI/scripts), you must pass `--version-label`. + **Examples:** ```bash # Deploy to Subgraph Studio (uses saved auth key) -gnd deploy my-name/my-subgraph +gnd deploy -l v1.0.0 my-name/my-subgraph # Deploy to local Graph Node -gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 my-name/my-subgraph +gnd deploy --node http://localhost:8020 --ipfs http://localhost:5001 -l v1.0.0 my-name/my-subgraph -# Deploy with version label -gnd deploy -l v1.0.0 my-name/my-subgraph +# Deploy without --version-label in an interactive terminal (prompts) +gnd deploy my-name/my-subgraph ``` ### `gnd publish` diff --git a/gnd/docs/migrating-from-graph-cli.md b/gnd/docs/migrating-from-graph-cli.md index 960f2104f11..6203a6f2f21 100644 --- a/gnd/docs/migrating-from-graph-cli.md +++ b/gnd/docs/migrating-from-graph-cli.md @@ -15,7 +15,7 @@ graph deploy --studio my-subgraph # Use: gnd codegen gnd build -gnd deploy my-subgraph # defaults to Studio +gnd deploy my-subgraph # defaults to Studio; prompts for version label in interactive terminals ``` ## Command Mapping @@ -25,7 +25,7 @@ gnd deploy my-subgraph # defaults to Studio | `graph init` | `gnd init` | Identical flags | | `graph codegen` | `gnd codegen` | Identical flags | | `graph build` | `gnd build` | Identical flags | -| `graph deploy` | `gnd deploy` | Defaults to Studio if `--node` not provided | +| `graph deploy` | `gnd deploy` | Defaults to Studio if `--node` not provided; pass `--version-label` in non-interactive mode | | `graph create` | `gnd create` | Identical flags | | `graph remove` | `gnd remove` | Identical flags | | `graph auth` | `gnd auth` | Identical flags | @@ -208,12 +208,12 @@ Replace `graph` with `gnd` in your CI configuration: # Before - run: graph codegen - run: graph build -- run: graph deploy --studio ${{ secrets.SUBGRAPH_NAME }} +- run: graph deploy --studio -l ${{ github.sha }} ${{ secrets.SUBGRAPH_NAME }} # After - run: gnd codegen - run: gnd build -- run: gnd deploy ${{ secrets.SUBGRAPH_NAME }} +- run: gnd deploy -l ${{ github.sha }} ${{ secrets.SUBGRAPH_NAME }} ``` ### Step 5: Update package.json Scripts (Optional) @@ -225,11 +225,13 @@ If you have npm scripts calling graph-cli: "scripts": { "codegen": "gnd codegen", "build": "gnd build", - "deploy": "gnd deploy" + "deploy": "gnd deploy -l $VERSION_LABEL" } } ``` +Set `VERSION_LABEL` in your environment (for example, from a git tag or commit SHA). + ## Troubleshooting ### "Command not found: gnd" diff --git a/gnd/src/commands/deploy.rs b/gnd/src/commands/deploy.rs index 7f975511f46..5c9e744ba02 100644 --- a/gnd/src/commands/deploy.rs +++ b/gnd/src/commands/deploy.rs @@ -3,7 +3,10 @@ //! This command builds a subgraph (unless an IPFS hash is provided), //! uploads it to IPFS, and deploys it to a Graph Node. -use std::path::PathBuf; +use std::{ + io::{self, IsTerminal}, + path::PathBuf, +}; use anyhow::{Context, Result, anyhow}; use clap::Parser; @@ -12,6 +15,7 @@ use url::Url; use crate::commands::auth::get_deploy_key; use crate::commands::build::{BuildOpt, run_build}; use crate::output::{Step, step}; +use crate::prompt::{normalize_version_label, prompt_version_label}; use crate::services::GraphNodeClient; /// Default IPFS URL used by The Graph @@ -91,6 +95,12 @@ pub async fn run_deploy(opt: DeployOpt) -> Result<()> { None => get_deploy_key(node)?, }; + let version_label = + match resolve_version_label(opt.version_label.as_deref(), io::stdin().is_terminal())? { + Some(label) => label, + None => prompt_version_label()?, + }; + // Get or build the IPFS hash let ipfs_hash = match &opt.ipfs_hash { Some(hash) => { @@ -104,7 +114,14 @@ pub async fn run_deploy(opt: DeployOpt) -> Result<()> { }; // Deploy to Graph Node - deploy_to_node(&opt, node, &ipfs_hash, deploy_key.as_deref()).await + deploy_to_node( + &opt, + node, + &ipfs_hash, + &version_label, + deploy_key.as_deref(), + ) + .await } /// Validate that a URL is well-formed. @@ -127,6 +144,32 @@ fn validate_url(url: &str, name: &str) -> Result<()> { Ok(()) } +/// Parse and validate a normalized version label. +fn parse_version_label(label: &str) -> Result { + let normalized = normalize_version_label(label); + if normalized.is_empty() { + return Err(anyhow!("Version label cannot be empty")); + } + Ok(normalized) +} + +/// Resolve version label from flag or interactive prompt mode. +fn resolve_version_label( + version_label: Option<&str>, + stdin_is_terminal: bool, +) -> Result> { + match version_label { + Some(label) => parse_version_label(label) + .context("Invalid --version-label value") + .map(Some), + None if stdin_is_terminal => Ok(None), + None => Err(anyhow!( + "--version-label is required in non-interactive mode. \ + Pass --version-label