@@ -3,7 +3,7 @@ import { URL } from 'url';
3
3
import { Args , Command , Flags , ux } from '@oclif/core' ;
4
4
import { print , prompt } from 'gluegun' ;
5
5
import { identifyDeployKey } from '../command-helpers/auth' ;
6
- import { createCompiler } from '../command-helpers/compiler' ;
6
+ import { appendApiVersionForGraph , createCompiler } from '../command-helpers/compiler' ;
7
7
import * as DataSourcesExtractor from '../command-helpers/data-sources' ;
8
8
import { DEFAULT_IPFS_URL } from '../command-helpers/ipfs' ;
9
9
import { createJsonRpcClient } from '../command-helpers/jsonrpc' ;
@@ -12,6 +12,7 @@ import { chooseNodeUrl } from '../command-helpers/node';
12
12
import { validateStudioNetwork } from '../command-helpers/studio' ;
13
13
import { assertGraphTsVersion , assertManifestApiVersion } from '../command-helpers/version' ;
14
14
import Protocol from '../protocols' ;
15
+ import { create } from 'ipfs-http-client' ;
15
16
16
17
const headersFlag = Flags . custom < Record < string , string > > ( {
17
18
summary : 'Add custom headers that will be used by the IPFS HTTP client.' ,
@@ -67,6 +68,10 @@ export default class DeployCommand extends Command {
67
68
char : 'i' ,
68
69
default : DEFAULT_IPFS_URL ,
69
70
} ) ,
71
+ 'ipfs-hash' : Flags . string ( {
72
+ summary : 'IPFS hash of the subgraph manifest to deploy.' ,
73
+ required : false ,
74
+ } ) ,
70
75
headers : headersFlag ( ) ,
71
76
'debug-fork' : Flags . string ( {
72
77
summary : 'ID of a remote subgraph whose store will be GraphQL queried.' ,
@@ -111,6 +116,7 @@ export default class DeployCommand extends Command {
111
116
'debug-fork' : debugFork ,
112
117
network,
113
118
'network-file' : networkFile ,
119
+ 'ipfs-hash' : ipfsHash ,
114
120
} ,
115
121
} = await this . parse ( DeployCommand ) ;
116
122
@@ -138,16 +144,6 @@ export default class DeployCommand extends Command {
138
144
] )
139
145
. then ( ( { product } ) => product as string ) ) ;
140
146
141
- try {
142
- const dataSourcesAndTemplates = await DataSourcesExtractor . fromFilePath ( manifest ) ;
143
-
144
- for ( const { network } of dataSourcesAndTemplates ) {
145
- validateStudioNetwork ( { studio, product, network } ) ;
146
- }
147
- } catch ( e ) {
148
- this . error ( e , { exit : 1 } ) ;
149
- }
150
-
151
147
const { node } = chooseNodeUrl ( {
152
148
product,
153
149
studio,
@@ -158,56 +154,9 @@ export default class DeployCommand extends Command {
158
154
this . error ( 'No Graph node provided' ) ;
159
155
}
160
156
161
- let protocol ;
162
- try {
163
- // Checks to make sure deploy doesn't run against
164
- // older subgraphs (both apiVersion and graph-ts version).
165
- //
166
- // We don't want the deploy to run without these conditions
167
- // because that would mean the CLI would try to compile code
168
- // using the wrong AssemblyScript compiler.
169
- await assertManifestApiVersion ( manifest , '0.0.5' ) ;
170
- await assertGraphTsVersion ( path . dirname ( manifest ) , '0.25.0' ) ;
171
-
172
- const dataSourcesAndTemplates = await DataSourcesExtractor . fromFilePath ( manifest ) ;
173
-
174
- protocol = Protocol . fromDataSources ( dataSourcesAndTemplates ) ;
175
- } catch ( e ) {
176
- this . error ( e , { exit : 1 } ) ;
177
- }
178
-
179
- if ( network ) {
180
- const identifierName = protocol . getContract ( ) ! . identifierName ( ) ;
181
- await updateSubgraphNetwork ( manifest , network , networkFile , identifierName ) ;
182
- }
183
-
184
157
const isStudio = node . match ( / s t u d i o / ) ;
185
158
const isHostedService = node . match ( / t h e g r a p h .c o m / ) && ! isStudio ;
186
159
187
- const compiler = createCompiler ( manifest , {
188
- ipfs,
189
- headers,
190
- outputDir,
191
- outputFormat : 'wasm' ,
192
- skipMigrations,
193
- blockIpfsMethods : isStudio || undefined , // Network does not support publishing subgraphs with IPFS methods
194
- protocol,
195
- } ) ;
196
-
197
- // Exit with an error code if the compiler couldn't be created
198
- if ( ! compiler ) {
199
- this . exit ( 1 ) ;
200
- return ;
201
- }
202
-
203
- // Ask for label if not on hosted service
204
- let versionLabel = versionLabelFlag ;
205
- if ( ! versionLabel && ! isHostedService ) {
206
- versionLabel = await ux . prompt ( 'Which version label to use? (e.g. "v0.0.1")' , {
207
- required : true ,
208
- } ) ;
209
- }
210
-
211
160
const requestUrl = new URL ( node ) ;
212
161
const client = createJsonRpcClient ( requestUrl ) ;
213
162
@@ -228,6 +177,14 @@ export default class DeployCommand extends Command {
228
177
client . options . headers = { Authorization : 'Bearer ' + deployKey } ;
229
178
}
230
179
180
+ // Ask for label if not on hosted service
181
+ let versionLabel = versionLabelFlag ;
182
+ if ( ! versionLabel && ! isHostedService ) {
183
+ versionLabel = await ux . prompt ( 'Which version label to use? (e.g. "v0.0.1")' , {
184
+ required : true ,
185
+ } ) ;
186
+ }
187
+
231
188
// eslint-disable-next-line @typescript-eslint/no-this-alias -- request needs it
232
189
const self = this ;
233
190
@@ -259,8 +216,8 @@ export default class DeployCommand extends Command {
259
216
'\nYou may need to create it at https://thegraph.com/explorer/dashboard.' ;
260
217
} else {
261
218
errorMessage += `
262
- Make sure to create the subgraph first by running the following command:
263
- $ graph create --node ${ node } ${ subgraphName } ` ;
219
+ Make sure to create the subgraph first by running the following command:
220
+ $ graph create --node ${ node } ${ subgraphName } `;
264
221
}
265
222
}
266
223
@@ -291,11 +248,93 @@ $ graph create --node ${node} ${subgraphName}`;
291
248
print . info ( '\nSubgraph endpoints:' ) ;
292
249
print . info ( `Queries (HTTP): ${ queries } ` ) ;
293
250
print . info ( `` ) ;
251
+ process . exit ( 0 ) ;
294
252
}
295
253
} ,
296
254
) ;
297
255
} ;
298
256
257
+ // we are provided the IPFS hash, so we deploy directly
258
+ if ( ipfsHash ) {
259
+ // Connect to the IPFS node (if a node address was provided)
260
+ const ipfsClient = create ( { url : appendApiVersionForGraph ( ipfs . toString ( ) ) , headers } ) ;
261
+
262
+ // Fetch the manifest from IPFS
263
+ const manifestBuffer = ipfsClient . cat ( ipfsHash ) ;
264
+ let manifestFile = '' ;
265
+ for await ( const chunk of manifestBuffer ) {
266
+ manifestFile += chunk . toString ( ) ;
267
+ }
268
+
269
+ if ( ! manifestFile ) {
270
+ this . error ( `Could not find subgraph manifest at IPFS hash ${ ipfsHash } ` , { exit : 1 } ) ;
271
+ }
272
+
273
+ await ipfsClient . pin . add ( ipfsHash ) ;
274
+
275
+ try {
276
+ const dataSourcesAndTemplates = DataSourcesExtractor . fromManifestString ( manifestFile ) ;
277
+
278
+ for ( const { network } of dataSourcesAndTemplates ) {
279
+ validateStudioNetwork ( { studio, product, network } ) ;
280
+ }
281
+ } catch ( e ) {
282
+ this . error ( e , { exit : 1 } ) ;
283
+ }
284
+
285
+ await deploySubgraph ( ipfsHash ) ;
286
+ return ;
287
+ }
288
+
289
+ try {
290
+ const dataSourcesAndTemplates = await DataSourcesExtractor . fromFilePath ( manifest ) ;
291
+
292
+ for ( const { network } of dataSourcesAndTemplates ) {
293
+ validateStudioNetwork ( { studio, product, network } ) ;
294
+ }
295
+ } catch ( e ) {
296
+ this . error ( e , { exit : 1 } ) ;
297
+ }
298
+
299
+ let protocol ;
300
+ try {
301
+ // Checks to make sure deploy doesn't run against
302
+ // older subgraphs (both apiVersion and graph-ts version).
303
+ //
304
+ // We don't want the deploy to run without these conditions
305
+ // because that would mean the CLI would try to compile code
306
+ // using the wrong AssemblyScript compiler.
307
+ await assertManifestApiVersion ( manifest , '0.0.5' ) ;
308
+ await assertGraphTsVersion ( path . dirname ( manifest ) , '0.25.0' ) ;
309
+
310
+ const dataSourcesAndTemplates = await DataSourcesExtractor . fromFilePath ( manifest ) ;
311
+
312
+ protocol = Protocol . fromDataSources ( dataSourcesAndTemplates ) ;
313
+ } catch ( e ) {
314
+ this . error ( e , { exit : 1 } ) ;
315
+ }
316
+
317
+ if ( network ) {
318
+ const identifierName = protocol . getContract ( ) ! . identifierName ( ) ;
319
+ await updateSubgraphNetwork ( manifest , network , networkFile , identifierName ) ;
320
+ }
321
+
322
+ const compiler = createCompiler ( manifest , {
323
+ ipfs,
324
+ headers,
325
+ outputDir,
326
+ outputFormat : 'wasm' ,
327
+ skipMigrations,
328
+ blockIpfsMethods : isStudio || undefined , // Network does not support publishing subgraphs with IPFS methods
329
+ protocol,
330
+ } ) ;
331
+
332
+ // Exit with an error code if the compiler couldn't be created
333
+ if ( ! compiler ) {
334
+ this . exit ( 1 ) ;
335
+ return ;
336
+ }
337
+
299
338
if ( watch ) {
300
339
await compiler . watchAndCompile ( async ipfsHash => {
301
340
if ( ipfsHash !== undefined ) {
0 commit comments