Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .changeset/gold-deers-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'@graphprotocol/graph-cli': minor
---

Breaking changes to the CLI to prepare for the sunset of the hosted service.

- `graph auth`
- Removed `--product` flag
- Removed `--studio` flag
- Removed `node` argument
- `graph deploy`
- Removed `--product` flag
- Removed `--studio` flag
- Removed `--from-hosted-service` flag
- `graph init`
- Removed `--product` flag
- Removed `--studio` flag
- Removed `--allow-simple-name` flag
20 changes: 14 additions & 6 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ As of today, the command line interface supports the following commands:
The Graph CLI takes a subgraph manifest (defaults to `subgraph.yaml`) with references to:

- A GraphQL schema,
- Smart contract ABIs, and
- Mappings written in AssemblyScript.
- Smart contract ABIs,
- Mappings written in AssemblyScript for traditional subgraphs,
- Substreams package and triggers for substreams-based subgraphs

It compiles the mappings to WebAssembly, builds a ready-to-use version of the subgraph saved to IPFS
or a local directory for debugging, and deploys the subgraph to a
[Graph Node](https://github.com/graphprotocol/graph-node).
[Graph Node](https://github.com/graphprotocol/graph-node) instance or
[Subgraph Studio](https://thegraph.com/studio/). Additionally it allows you to publish your subgraph
to the decentralized network directly, making it available for indexing via
[Graph Explorer](https://thegraph.com/explorer)

## Installation

Expand Down Expand Up @@ -73,11 +77,15 @@ Use one of the following commands depending on your distribution:

The Graph CLI can be used with a local or self-hosted
[Graph Node](https://github.com/graphprotocol/graph-node) or with the
[Hosted Service](https://thegraph.com/explorer/). To help you get going, there are
[quick start guides](https://thegraph.com/docs/en/developer/quick-start/) available for both.
[Subgraph Studio](https://thegraph.com/studio/). To help you get going, there are
[quick start guides](https://thegraph.com/docs/en/quick-start/) available for both.

Additionally, you can use Graph CLI to
[publish](https://thegraph.com/docs/en/quick-start/#publishing-from-the-cli) your subgraph to the
decentralized network directly.

If you are ready to dive into the details of building a subgraph from scratch, there is a
[detailed walkthrough](https://thegraph.com/docs/en/developer/create-subgraph-hosted/) for that as
[detailed walkthrough](https://thegraph.com/docs/en/developing/creating-a-subgraph/) for that as
well, along with API documentation for the
[AssemblyScript API](https://thegraph.com/docs/en/developer/assemblyscript-api/).

Expand Down
76 changes: 3 additions & 73 deletions packages/cli/src/command-helpers/node.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,22 @@
import { URL } from 'url';
import { print } from 'gluegun';
import { GRAPH_CLI_SHARED_HEADERS } from '../constants';

export const SUBGRAPH_STUDIO_URL = 'https://api.studio.thegraph.com/deploy/';
const HOSTED_SERVICE_URL = 'https://api.thegraph.com/deploy/';
const HOSTED_SERVICE_INDEX_NODE_URL = 'https://api.thegraph.com/index-node/graphql';

export const validateNodeUrl = (node: string) => new URL(node);

export const normalizeNodeUrl = (node: string) => new URL(node).toString();

export function chooseNodeUrl({
product,
studio,
node,
allowSimpleName,
}: {
product: string | undefined;
studio: boolean | undefined;
node?: string;
allowSimpleName?: boolean;
}) {
export function chooseNodeUrl({ node }: { node?: string }) {
if (node) {
try {
validateNodeUrl(node);
return { node };
} catch (e) {
print.error(`Graph node "${node}" is invalid: ${e.message}`);
process.exit(1);
}
} else {
if (studio) {
product = 'subgraph-studio';
}
switch (product) {
case 'subgraph-studio':
node = SUBGRAPH_STUDIO_URL;
break;
case 'hosted-service':
node = HOSTED_SERVICE_URL;
break;
}
}
if (node?.match(/studio/) || product === 'subgraph-studio') {
allowSimpleName = true;
}
return { node, allowSimpleName };
}

export async function getHostedServiceSubgraphId({
subgraphName,
}: {
subgraphName: string;
}): Promise<{
subgraph: string;
synced: boolean;
health: 'healthy' | 'unhealthy' | 'failed';
}> {
const response = await fetch(HOSTED_SERVICE_INDEX_NODE_URL, {
method: 'POST',
body: JSON.stringify({
query: /* GraphQL */ `
query GraphCli_getSubgraphId($subgraphName: String!) {
indexingStatusForCurrentVersion(subgraphName: $subgraphName) {
subgraph
synced
health
}
}
`,
variables: {
subgraphName,
},
}),
headers: {
'content-type': 'application/json',
...GRAPH_CLI_SHARED_HEADERS,
},
});

const { data, errors } = await response.json();

if (errors) {
throw new Error(errors[0].message);
}

if (!data.indexingStatusForCurrentVersion) {
throw new Error(`Subgraph "${subgraphName}" not found on the hosted service`);
}

return data.indexingStatusForCurrentVersion;
return { node: SUBGRAPH_STUDIO_URL };
}
17 changes: 0 additions & 17 deletions packages/cli/src/command-helpers/subgraph.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
export const validateSubgraphName = (
name: string,
{ allowSimpleName }: { allowSimpleName?: boolean },
) => {
if (allowSimpleName) {
return name;
}
if (name.split('/').length !== 2) {
throw new Error(`Subgraph name "${name}" needs to have the format "<PREFIX>/${name}".

When using the Hosted Service at https://thegraph.com, <PREFIX> is the
name of your GitHub user or organization.

You can bypass this check with --allow-simple-name.`);
}
};

export const getSubgraphBasename = (name: string) => {
const segments = name.split('/', 2);
return segments[segments.length - 1];
Expand Down
44 changes: 3 additions & 41 deletions packages/cli/src/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,21 @@
static description = 'Sets the deploy key to use when deploying to a Graph node.';

static args = {
node: Args.string(),
'deploy-key': Args.string(),
};

static flags = {
help: Flags.help({
char: 'h',
}),

product: Flags.string({
summary: 'Select a product for which to authenticate.',
options: ['subgraph-studio', 'hosted-service'],
deprecated: {
message:
'In next major version, this flag will be removed. By default we will deploy to the Graph Studio. Learn more about Sunrise of Decentralized Data https://thegraph.com/blog/unveiling-updated-sunrise-decentralized-data/',
},
}),
studio: Flags.boolean({
summary: 'Shortcut for "--product subgraph-studio".',
exclusive: ['product'],
deprecated: {
message:
'In next major version, this flag will be removed. By default we will deploy to the Graph Studio. Learn more about Sunrise of Decentralized Data https://thegraph.com/blog/unveiling-updated-sunrise-decentralized-data/',
},
}),
};

async run() {
const {
args: { node: nodeOrDeployKey, 'deploy-key': deployKeyFlag },
flags: { product, studio },
let {
args: { 'deploy-key': deployKey },
} = await this.parse(AuthCommand);

// if user specifies --product or --studio then deployKey is the first parameter
let node: string | undefined;
let deployKey = deployKeyFlag;
if (product || studio) {
({ node } = chooseNodeUrl({ product, studio, node }));
deployKey = nodeOrDeployKey;
} else {
node = nodeOrDeployKey;
}

// eslint-disable-next-line -- prettier has problems with ||=
node =
node ||
(await ux.prompt('Which product to initialize?', {
required: true,
}));
const { node } = chooseNodeUrl({});

// eslint-disable-next-line -- prettier has problems with ||=
deployKey =
Expand All @@ -68,12 +34,8 @@
this.error('✖ Deploy key must not exceed 200 characters', { exit: 1 });
}

if (product === 'hosted-service' || node?.match(/api.thegraph.com/)) {
this.error('✖ The hosted service is deprecated', { exit: 1 });
}

try {
await saveDeployKey(node!, deployKey);

Check warning on line 38 in packages/cli/src/commands/auth.ts

View workflow job for this annotation

GitHub Actions / Lint

Forbidden non-null assertion
print.success(`Deploy key set for ${node}`);
} catch (e) {
this.error(e, { exit: 1 });
Expand Down
Loading
Loading