Skip to content

Commit 6023470

Browse files
gnd: Add gnd indexer command that delegates to graph-indexer
Adds an `Indexer` subcommand to gnd that forwards commands to the `graph-indexer` binary from the `indexer-cli` npm package. This lets users run indexer management commands (allocations, rules, cost models, etc.) directly through gnd. - `version`, `help` and their short forms are forwarded as top-level commands; all other subcommands get the `indexer` namespace prepended (required by graph-indexer's Gluegun plugin system) - `--help` is handled by clap (works without graph-indexer installed) - On Unix, uses exec() for clean signal forwarding and exit codes - Clear error message when graph-indexer is not on $PATH
1 parent 2b4675a commit 6023470

File tree

4 files changed

+188
-1
lines changed

4 files changed

+188
-1
lines changed

gnd/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,52 @@ gnd dev [OPTIONS]
378378
| `--ethereum-rpc` | | Ethereum RPC URL |
379379
| `--ipfs` | | IPFS node URL |
380380

381+
### `gnd indexer`
382+
383+
Manage indexer operations via [`indexer-cli`](https://github.com/graphprotocol/indexer/tree/main/packages/indexer-cli).
384+
385+
Requires `graph-indexer` to be installed and on `$PATH`:
386+
387+
```bash
388+
npm install -g @graphprotocol/indexer-cli
389+
```
390+
391+
```bash
392+
gnd indexer <subcommand> [args...]
393+
```
394+
395+
**Help:**
396+
397+
There are two ways to get help:
398+
399+
| Command | What it shows |
400+
|---------|---------------|
401+
| `gnd indexer --help` | gnd's own help for the indexer subcommand (works without `graph-indexer` installed) |
402+
| `gnd indexer help` | Full `graph-indexer` help with all available commands (requires `graph-indexer`) |
403+
404+
**Examples:**
405+
406+
```bash
407+
# Check indexer status
408+
gnd indexer status --network arbitrum-one
409+
410+
# Manage indexing rules
411+
gnd indexer rules get all --network mainnet
412+
gnd indexer rules set <deployment> decisionBasis always --network mainnet
413+
414+
# Manage allocations
415+
gnd indexer allocations get --network arbitrum-one
416+
417+
# Manage cost models
418+
gnd indexer cost get
419+
420+
# View available indexer commands
421+
gnd indexer help
422+
423+
# Check graph-indexer version
424+
gnd indexer version
425+
```
426+
381427
### `gnd completions`
382428

383429
Generate shell completions.

gnd/docs/migrating-from-graph-cli.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ gnd deploy my-subgraph # defaults to Studio
3333
| `graph test` | `gnd test` | Identical flags |
3434
| `graph clean` | `gnd clean` | Identical flags (new in graph-cli 0.80+) |
3535
| `graph publish` | `gnd publish` | Identical flags |
36+
| `graph indexer` | `gnd indexer` | Delegates to `graph-indexer` — requires `indexer-cli` installed |
3637
| `graph local` | N/A | Not implemented - use graph-node's test infrastructure |
3738
| `graph node` | N/A | Not implemented - use `graphman` |
3839

@@ -67,6 +68,7 @@ Same success checkmarks, step descriptions, and progress indicators:
6768

6869
- `0` for success
6970
- `1` for any error
71+
- `gnd indexer` passes through the exit code from `graph-indexer`
7072

7173
### Configuration Files
7274

@@ -83,6 +85,20 @@ Code generation produces identical AssemblyScript output (after formatting). You
8385

8486
## What's Different
8587

88+
### Indexer Commands
89+
90+
`gnd indexer` provides access to indexer management commands via [`indexer-cli`](https://github.com/graphprotocol/indexer/tree/main/packages/indexer-cli). Requires `graph-indexer` on `$PATH`:
91+
92+
```bash
93+
npm install -g @graphprotocol/indexer-cli
94+
95+
gnd indexer status --network arbitrum-one
96+
gnd indexer rules get all --network mainnet
97+
gnd indexer allocations get --network arbitrum-one
98+
```
99+
100+
Note: `gnd indexer --help` shows gnd's own help and works without `graph-indexer` installed. Use `gnd indexer help` to see the full list of `graph-indexer` commands.
101+
86102
### Commands Not Available
87103

88104
#### `graph local`

gnd/src/main.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use std::ffi::OsString;
12
use std::io;
3+
use std::process::Command;
24

3-
use anyhow::Result;
5+
use anyhow::{bail, Result};
46
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
57
use clap_complete::{generate, Shell};
68
use git_testament::{git_testament, render_testament};
@@ -83,6 +85,22 @@ enum Commands {
8385
/// Remove build artifacts and generated files
8486
Clean(CleanOpt),
8587

88+
/// Manage indexer operations. Requires `graph-indexer` to be installed and available on $PATH.
89+
///
90+
/// Install it with:
91+
///
92+
/// npm install -g @graphprotocol/indexer-cli
93+
///
94+
/// Arguments are forwarded to `graph-indexer`. For example:
95+
///
96+
/// gnd indexer allocations get --network arbitrum-one
97+
///
98+
/// Use `gnd indexer help` for more details on available commands.
99+
Indexer {
100+
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
101+
args: Vec<OsString>,
102+
},
103+
86104
/// Generate shell completions
87105
Completions(CompletionsOpt),
88106
}
@@ -153,6 +171,57 @@ fn generate_completions(completions_opt: CompletionsOpt) -> Result<()> {
153171
Ok(())
154172
}
155173

174+
/// Delegates to the `graph-indexer` binary from the `indexer-cli` npm package.
175+
///
176+
/// The `graph-indexer` CLI expects all indexer management commands to be
177+
/// prefixed with `indexer` (e.g. `graph-indexer indexer allocations get ...`).
178+
/// This is because `graph-indexer` uses Gluegun's plugin system where `indexer`
179+
/// is the plugin namespace. We prepend it automatically so that users can write
180+
/// `gnd indexer allocations get` instead of the longer form.
181+
fn run_indexer(args: Vec<OsString>) -> Result<()> {
182+
let mut cmd = Command::new("graph-indexer");
183+
// `version` and `help` are top-level commands, but all other commands
184+
// require the `indexer` namespace prefix (e.g. `graph-indexer indexer allocations get`).
185+
let first = args.first().and_then(|s| s.to_str());
186+
match first {
187+
Some("version" | "--version" | "v" | "-v" | "help" | "h") => {}
188+
// If no arguments are provided, default to showing top-level help
189+
None => {
190+
cmd.arg("help");
191+
}
192+
_ => {
193+
cmd.arg("indexer");
194+
}
195+
}
196+
cmd.args(&args);
197+
198+
#[cfg(unix)]
199+
{
200+
use std::os::unix::process::CommandExt;
201+
let err = cmd.exec();
202+
if err.kind() == io::ErrorKind::NotFound {
203+
bail!(
204+
"'graph-indexer' not found on $PATH. Install indexer-cli: npm install -g @graphprotocol/indexer-cli"
205+
);
206+
}
207+
bail!("failed to exec 'graph-indexer': {err}");
208+
}
209+
210+
#[cfg(not(unix))]
211+
{
212+
match cmd.status() {
213+
Ok(status) if status.success() => Ok(()),
214+
Ok(status) => std::process::exit(status.code().unwrap_or(1)),
215+
Err(e) if e.kind() == io::ErrorKind::NotFound => {
216+
bail!(
217+
"'graph-indexer' not found on $PATH. Install indexer-cli: npm install -g @graphprotocol/indexer-cli"
218+
);
219+
}
220+
Err(e) => bail!("failed to run 'graph-indexer': {e}"),
221+
}
222+
}
223+
}
224+
156225
#[tokio::main]
157226
async fn main() -> Result<()> {
158227
std::env::set_var("ETHEREUM_REORG_THRESHOLD", "10");
@@ -186,6 +255,7 @@ async fn main() -> Result<()> {
186255
run_test(test_opt).await
187256
}
188257
Commands::Clean(clean_opt) => run_clean(clean_opt),
258+
Commands::Indexer { args } => run_indexer(args),
189259
Commands::Completions(completions_opt) => generate_completions(completions_opt),
190260
};
191261

gnd/tests/cli_commands.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,61 @@ fn run_gnd_success(args: &[&str], cwd: &Path) -> std::process::Output {
8080
output
8181
}
8282

83+
// ============================================================================
84+
// gnd indexer tests
85+
// ============================================================================
86+
87+
#[test]
88+
fn test_indexer_missing_binary_error() {
89+
let gnd = verify_gnd_binary();
90+
91+
// Run with an empty PATH so graph-indexer cannot be found.
92+
let output = Command::new(&gnd)
93+
.args(["indexer", "status", "--network", "mainnet"])
94+
.env("PATH", "")
95+
.output()
96+
.expect("Failed to execute gnd");
97+
98+
assert!(
99+
!output.status.success(),
100+
"gnd indexer should fail when graph-indexer is not on $PATH"
101+
);
102+
103+
let stderr = String::from_utf8_lossy(&output.stderr);
104+
assert!(
105+
stderr.contains("graph-indexer") && stderr.contains("not found"),
106+
"Error should mention graph-indexer not found. Got:\n{stderr}"
107+
);
108+
assert!(
109+
stderr.contains("indexer-cli"),
110+
"Error should mention indexer-cli install instructions. Got:\n{stderr}"
111+
);
112+
}
113+
114+
#[test]
115+
fn test_indexer_clap_help() {
116+
let gnd = verify_gnd_binary();
117+
118+
// `--help` is intercepted by clap, not forwarded to graph-indexer.
119+
let output = Command::new(&gnd)
120+
.args(["indexer", "--help"])
121+
.env("PATH", "")
122+
.output()
123+
.expect("Failed to execute gnd");
124+
125+
assert!(output.status.success(), "gnd indexer --help should succeed");
126+
127+
let stdout = String::from_utf8_lossy(&output.stdout);
128+
assert!(
129+
stdout.contains("indexer-cli"),
130+
"Help should mention indexer-cli. Got:\n{stdout}"
131+
);
132+
assert!(
133+
stdout.contains("graph-indexer"),
134+
"Help should mention graph-indexer. Got:\n{stdout}"
135+
);
136+
}
137+
83138
// ============================================================================
84139
// gnd init tests
85140
// ============================================================================

0 commit comments

Comments
 (0)