@graphprotocol/graph-cli 0.23.2 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/README.md +83 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +2 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/json.ts +2 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +2 -7
- package/examples/basic-event-handlers/package.json +1 -1
- package/examples/basic-event-handlers/yarn.lock +4 -4
- package/examples/example-subgraph/package.json +1 -1
- package/examples/example-subgraph/yarn.lock +4 -4
- package/package.json +1 -1
- package/src/codegen/types/index.js +8 -1
- package/src/command-helpers/scaffold.js +66 -0
- package/src/commands/init.js +128 -92
- package/src/migrations/mapping_api_version_0_0_5.js +74 -0
- package/src/protocols/ethereum/contract.js +22 -0
- package/src/protocols/ethereum/scaffold/manifest.js +32 -0
- package/src/protocols/ethereum/scaffold/mapping.js +76 -0
- package/src/protocols/ethereum/subgraph.js +0 -14
- package/src/protocols/index.js +88 -8
- package/src/protocols/near/contract.js +46 -0
- package/src/protocols/near/scaffold/manifest.js +16 -0
- package/src/protocols/near/scaffold/mapping.js +39 -0
- package/src/protocols/near/subgraph.js +1 -23
- package/src/{scaffold.test.js → scaffold/ethereum.test.js} +27 -19
- package/src/scaffold/index.js +149 -0
- package/src/scaffold/mapping.js +49 -0
- package/src/scaffold/near.test.js +89 -0
- package/src/scaffold/schema.js +62 -0
- package/src/subgraph.js +8 -0
- package/src/validation/contract.js +56 -0
- package/src/validation/index.js +2 -1
- package/src/validation/manifest.js +0 -29
- package/tests/cli/init/{abis → ethereum/abis}/Marketplace.json +0 -0
- package/tests/cli/init/{abis → ethereum/abis}/OverloadedElements.json +0 -0
- package/tests/cli/init/{abis → ethereum/abis}/SoloMargin.json +0 -0
- package/tests/cli/init/{from-contract-with-abi-and-structs.stderr → ethereum/from-contract-with-abi-and-structs.stderr} +1 -1
- package/tests/cli/init/{from-contract-with-abi-and-structs.stdout → ethereum/from-contract-with-abi-and-structs.stdout} +0 -0
- package/tests/cli/init/{from-contract-with-abi.stderr → ethereum/from-contract-with-abi.stderr} +1 -1
- package/tests/cli/init/{from-contract-with-abi.stdout → ethereum/from-contract-with-abi.stdout} +0 -0
- package/tests/cli/init/{from-contract-with-overloaded-elements.stderr → ethereum/from-contract-with-overloaded-elements.stderr} +1 -1
- package/tests/cli/init/{from-contract-with-overloaded-elements.stdout → ethereum/from-contract-with-overloaded-elements.stdout} +0 -0
- package/tests/cli/init/{from-contract.stderr → ethereum/from-contract.stderr} +1 -1
- package/tests/cli/init/{from-contract.stdout → ethereum/from-contract.stdout} +0 -0
- package/tests/cli/init/{from-example.stderr → ethereum/from-example.stderr} +0 -0
- package/tests/cli/init/{from-example.stdout → ethereum/from-example.stdout} +0 -0
- package/tests/cli/init/near/from-contract.stderr +12 -0
- package/tests/cli/init/near/from-contract.stdout +12 -0
- package/tests/cli/init.test.js +143 -112
- package/tests/cli/util.js +56 -41
- package/tests/cli/validation/near-is-valid/subgraph.yaml +1 -0
- package/src/scaffold.js +0 -364
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const { ascTypeForProtocol, valueTypeForAsc } = require('../codegen/types')
|
|
2
|
+
const util = require('../codegen/util')
|
|
3
|
+
|
|
4
|
+
const abiEvents = abi =>
|
|
5
|
+
util.disambiguateNames({
|
|
6
|
+
values: abi.data.filter(item => item.get('type') === 'event'),
|
|
7
|
+
getName: event => event.get('name'),
|
|
8
|
+
setName: (event, name) => event.set('_alias', name),
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const protocolTypeToGraphQL = (protocol, name) => {
|
|
12
|
+
let ascType = ascTypeForProtocol(protocol, name)
|
|
13
|
+
return valueTypeForAsc(ascType)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const generateField = ({ name, type, protocolName }) =>
|
|
17
|
+
`${name}: ${protocolTypeToGraphQL(protocolName, type)}! # ${type}`
|
|
18
|
+
|
|
19
|
+
const generateEventFields = ({ index, input, protocolName }) =>
|
|
20
|
+
input.type == 'tuple'
|
|
21
|
+
? util
|
|
22
|
+
.unrollTuple({ value: input, path: [input.name || `param${index}`], index })
|
|
23
|
+
.map(({ path, type }) => generateField({ name: path.join('_'), type, protocolName }))
|
|
24
|
+
: [generateField({ name: input.name || `param${index}`, type: input.type, protocolName })]
|
|
25
|
+
|
|
26
|
+
const generateEventType = (event, protocolName) => `type ${event._alias} @entity {
|
|
27
|
+
id: ID!
|
|
28
|
+
${event.inputs
|
|
29
|
+
.reduce(
|
|
30
|
+
(acc, input, index) => acc.concat(generateEventFields({ input, index, protocolName })),
|
|
31
|
+
[],
|
|
32
|
+
)
|
|
33
|
+
.join('\n')}
|
|
34
|
+
}`
|
|
35
|
+
|
|
36
|
+
const generateExampleEntityType = (protocol, events) => {
|
|
37
|
+
if (protocol.hasABIs() && events.length > 0) {
|
|
38
|
+
return `type ExampleEntity @entity {
|
|
39
|
+
id: ID!
|
|
40
|
+
count: BigInt!
|
|
41
|
+
${events[0].inputs
|
|
42
|
+
.reduce((acc, input, index) => acc.concat(generateEventFields({ input, index, protocolName: protocol.name })), [])
|
|
43
|
+
.slice(0, 2)
|
|
44
|
+
.join('\n')}
|
|
45
|
+
}`
|
|
46
|
+
} else {
|
|
47
|
+
return `type ExampleEntity @entity {
|
|
48
|
+
id: ID!
|
|
49
|
+
block: Bytes!
|
|
50
|
+
count: BigInt!
|
|
51
|
+
}`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
abiEvents,
|
|
57
|
+
protocolTypeToGraphQL,
|
|
58
|
+
generateField,
|
|
59
|
+
generateEventFields,
|
|
60
|
+
generateEventType,
|
|
61
|
+
generateExampleEntityType,
|
|
62
|
+
}
|
package/src/subgraph.js
CHANGED
|
@@ -145,6 +145,13 @@ At least one such handler must be defined.`,
|
|
|
145
145
|
}, immutable.List())
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
static validateContractValues(manifest, protocol) {
|
|
149
|
+
return validation.validateContractValues(
|
|
150
|
+
manifest,
|
|
151
|
+
protocol,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
148
155
|
// Validate that data source names are unique, so they don't overwrite each other.
|
|
149
156
|
static validateUniqueDataSourceNames(manifest) {
|
|
150
157
|
let names = []
|
|
@@ -231,6 +238,7 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
231
238
|
? immutable.List()
|
|
232
239
|
: immutable.List.of(
|
|
233
240
|
...protocolSubgraph.validateManifest(),
|
|
241
|
+
...Subgraph.validateContractValues(manifest, protocol),
|
|
234
242
|
...Subgraph.validateUniqueDataSourceNames(manifest),
|
|
235
243
|
...Subgraph.validateUniqueTemplateNames(manifest),
|
|
236
244
|
...Subgraph.validateHandlers(manifest, protocol, protocolSubgraph),
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const immutable = require('immutable')
|
|
2
|
+
|
|
3
|
+
const validateContract = (value, ProtocolContract) => {
|
|
4
|
+
const contract = new ProtocolContract(value)
|
|
5
|
+
|
|
6
|
+
const { valid, error } = contract.validate()
|
|
7
|
+
|
|
8
|
+
if (!valid) {
|
|
9
|
+
return {
|
|
10
|
+
valid,
|
|
11
|
+
error: `Contract ${ProtocolContract.identifierName()} is invalid: ${value}\n${error}`,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return { valid, error }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const validateContractValues = (manifest, protocol) => {
|
|
19
|
+
const ProtocolContract = protocol.getContract()
|
|
20
|
+
|
|
21
|
+
const fieldName = ProtocolContract.identifierName()
|
|
22
|
+
|
|
23
|
+
return manifest
|
|
24
|
+
.get('dataSources')
|
|
25
|
+
.filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
|
|
26
|
+
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
27
|
+
let path = ['dataSources', dataSourceIndex, 'source', fieldName]
|
|
28
|
+
|
|
29
|
+
// No need to validate if the source has no contract field
|
|
30
|
+
if (!dataSource.get('source').has(fieldName)) {
|
|
31
|
+
return errors
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let contractValue = dataSource.getIn(['source', fieldName])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const { valid, error } = validateContract(contractValue, ProtocolContract)
|
|
38
|
+
|
|
39
|
+
// Validate whether the contract is valid for the protocol
|
|
40
|
+
if (valid) {
|
|
41
|
+
return errors
|
|
42
|
+
} else {
|
|
43
|
+
return errors.push(
|
|
44
|
+
immutable.fromJS({
|
|
45
|
+
path,
|
|
46
|
+
message: error,
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}, immutable.List())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
validateContract,
|
|
55
|
+
validateContractValues,
|
|
56
|
+
}
|
package/src/validation/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
validateSchema: require('./schema').validateSchema,
|
|
3
3
|
validateManifest: require('./manifest').validateManifest,
|
|
4
|
-
validateContractValues: require('./
|
|
4
|
+
validateContractValues: require('./contract').validateContractValues,
|
|
5
|
+
validateContract: require('./contract').validateContract,
|
|
5
6
|
}
|
|
@@ -282,35 +282,6 @@ const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
|
|
|
282
282
|
return validateDataSourceNetworks(value, protocol)
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
const validateContractValues = (manifest, protocol, fieldName, validator, errorMessage) =>
|
|
286
|
-
manifest
|
|
287
|
-
.get('dataSources')
|
|
288
|
-
.filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
|
|
289
|
-
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
290
|
-
let path = ['dataSources', dataSourceIndex, 'source', fieldName]
|
|
291
|
-
|
|
292
|
-
// No need to validate if the source has no contract field
|
|
293
|
-
if (!dataSource.get('source').has(fieldName)) {
|
|
294
|
-
return errors
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
let contractValue = dataSource.getIn(['source', fieldName])
|
|
298
|
-
|
|
299
|
-
// Validate whether the contract is valid
|
|
300
|
-
if (validator(contractValue)) {
|
|
301
|
-
return errors
|
|
302
|
-
} else {
|
|
303
|
-
return errors.push(
|
|
304
|
-
immutable.fromJS({
|
|
305
|
-
path,
|
|
306
|
-
message: `\
|
|
307
|
-
Contract ${fieldName} is invalid: ${contractValue}${errorMessage ? `\n${errorMessage}` : ''}`,
|
|
308
|
-
}),
|
|
309
|
-
)
|
|
310
|
-
}
|
|
311
|
-
}, immutable.List())
|
|
312
|
-
|
|
313
285
|
module.exports = {
|
|
314
286
|
validateManifest,
|
|
315
|
-
validateContractValues,
|
|
316
287
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/tests/cli/init/{from-contract-with-abi.stdout → ethereum/from-contract-with-abi.stdout}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
- Create subgraph scaffold
|
|
2
|
+
Generate subgraph
|
|
3
|
+
- Create subgraph scaffold
|
|
4
|
+
Write subgraph to directory
|
|
5
|
+
- Create subgraph scaffold
|
|
6
|
+
✔ Create subgraph scaffold
|
|
7
|
+
- Initialize subgraph repository
|
|
8
|
+
✔ Initialize subgraph repository
|
|
9
|
+
- Install dependencies with yarn
|
|
10
|
+
✔ Install dependencies with yarn
|
|
11
|
+
- Generate ABI and schema types with yarn codegen
|
|
12
|
+
✔ Generate ABI and schema types with yarn codegen
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
Subgraph user/near-from-contract created in from-contract
|
|
3
|
+
|
|
4
|
+
Next steps:
|
|
5
|
+
|
|
6
|
+
1. Run `graph auth` to authenticate with your deploy key.
|
|
7
|
+
|
|
8
|
+
2. Type `cd from-contract` to enter the subgraph.
|
|
9
|
+
|
|
10
|
+
3. Run `yarn deploy` to deploy the subgraph.
|
|
11
|
+
|
|
12
|
+
Make sure to visit the documentation on https://thegraph.com/docs/ for further information.
|
package/tests/cli/init.test.js
CHANGED
|
@@ -1,125 +1,156 @@
|
|
|
1
|
-
const fs = require('fs-extra')
|
|
2
1
|
const path = require('path')
|
|
3
2
|
const { cliTest } = require('./util')
|
|
4
3
|
|
|
5
4
|
describe('Init', () => {
|
|
6
|
-
|
|
5
|
+
const baseDir = path.join(__dirname, 'init')
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let subgraphDir3 = path.join(baseDir, 'from-contract-with-abi')
|
|
11
|
-
let subgraphDir4 = path.join(baseDir, 'from-contract-with-abi-and-structs')
|
|
12
|
-
let subgraphDir5 = path.join(baseDir, 'from-contract-with-overloaded-elements')
|
|
7
|
+
describe('Ethereum', () => {
|
|
8
|
+
const ethereumBaseDir = path.join(baseDir, 'ethereum')
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
10
|
+
cliTest(
|
|
11
|
+
'From example',
|
|
12
|
+
[
|
|
13
|
+
'init',
|
|
14
|
+
'--protocol',
|
|
15
|
+
'ethereum',
|
|
16
|
+
'--studio',
|
|
17
|
+
'--from-example',
|
|
18
|
+
'user/example-subgraph',
|
|
19
|
+
path.join(ethereumBaseDir, 'from-example'),
|
|
20
|
+
],
|
|
21
|
+
path.join('init', 'ethereum', 'from-example'),
|
|
22
|
+
{
|
|
23
|
+
exitCode: 0,
|
|
24
|
+
timeout: 100000,
|
|
25
|
+
cwd: ethereumBaseDir,
|
|
26
|
+
deleteDir: true,
|
|
27
|
+
},
|
|
28
|
+
)
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
cliTest(
|
|
31
|
+
'From contract',
|
|
32
|
+
[
|
|
33
|
+
'init',
|
|
34
|
+
'--protocol',
|
|
35
|
+
'ethereum',
|
|
36
|
+
'--studio',
|
|
37
|
+
'--from-contract',
|
|
38
|
+
'0xF87E31492Faf9A91B02Ee0dEAAd50d51d56D5d4d',
|
|
39
|
+
'--network',
|
|
40
|
+
'mainnet',
|
|
41
|
+
'user/subgraph-from-contract',
|
|
42
|
+
path.join(ethereumBaseDir, 'from-contract'),
|
|
43
|
+
],
|
|
44
|
+
path.join('init', 'ethereum', 'from-contract'),
|
|
45
|
+
{
|
|
46
|
+
exitCode: 0,
|
|
47
|
+
timeout: 100000,
|
|
48
|
+
cwd: ethereumBaseDir,
|
|
49
|
+
deleteDir: true,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
cliTest(
|
|
54
|
+
'From contract with abi',
|
|
55
|
+
[
|
|
56
|
+
'init',
|
|
57
|
+
'--protocol',
|
|
58
|
+
'ethereum',
|
|
59
|
+
'--studio',
|
|
60
|
+
'--from-contract',
|
|
61
|
+
'0xF87E31492Faf9A91B02Ee0dEAAd50d51d56D5d4d',
|
|
62
|
+
'--abi',
|
|
63
|
+
path.join(ethereumBaseDir, 'abis', 'Marketplace.json'),
|
|
64
|
+
'--network',
|
|
65
|
+
'mainnet',
|
|
66
|
+
'user/subgraph-from-contract-with-abi',
|
|
67
|
+
path.join(ethereumBaseDir, 'from-contract-with-abi'),
|
|
68
|
+
],
|
|
69
|
+
path.join('init', 'ethereum', 'from-contract-with-abi'),
|
|
70
|
+
{
|
|
71
|
+
exitCode: 0,
|
|
72
|
+
timeout: 100000,
|
|
73
|
+
cwd: ethereumBaseDir,
|
|
74
|
+
deleteDir: true,
|
|
75
|
+
},
|
|
76
|
+
)
|
|
51
77
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
cliTest(
|
|
79
|
+
'From contract with abi and structs',
|
|
80
|
+
[
|
|
81
|
+
'init',
|
|
82
|
+
'--protocol',
|
|
83
|
+
'ethereum',
|
|
84
|
+
'--studio',
|
|
85
|
+
'--from-contract',
|
|
86
|
+
'0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e',
|
|
87
|
+
'--abi',
|
|
88
|
+
path.join(ethereumBaseDir, 'abis', 'SoloMargin.json'),
|
|
89
|
+
'--network',
|
|
90
|
+
'mainnet',
|
|
91
|
+
'user/subgraph-from-contract-with-abi-and-structs',
|
|
92
|
+
path.join(ethereumBaseDir, 'from-contract-with-abi-and-structs'),
|
|
93
|
+
],
|
|
94
|
+
path.join('init', 'ethereum', 'from-contract-with-abi-and-structs'),
|
|
95
|
+
{
|
|
96
|
+
exitCode: 0,
|
|
97
|
+
timeout: 100000,
|
|
98
|
+
cwd: ethereumBaseDir,
|
|
99
|
+
deleteDir: true,
|
|
100
|
+
},
|
|
101
|
+
)
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
cliTest(
|
|
104
|
+
'From contract with overloaded elements',
|
|
105
|
+
[
|
|
106
|
+
'init',
|
|
107
|
+
'--protocol',
|
|
108
|
+
'ethereum',
|
|
109
|
+
'--studio',
|
|
110
|
+
'--from-contract',
|
|
111
|
+
'0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e',
|
|
112
|
+
'--abi',
|
|
113
|
+
path.join(ethereumBaseDir, 'abis', 'OverloadedElements.json'),
|
|
114
|
+
'--network',
|
|
115
|
+
'mainnet',
|
|
116
|
+
'user/subgraph-from-contract-with-overloaded-elements',
|
|
117
|
+
path.join(ethereumBaseDir, 'from-contract-with-overloaded-elements'),
|
|
118
|
+
],
|
|
119
|
+
path.join('init', 'ethereum', 'from-contract-with-overloaded-elements'),
|
|
120
|
+
{
|
|
121
|
+
exitCode: 0,
|
|
122
|
+
timeout: 100000,
|
|
123
|
+
cwd: ethereumBaseDir,
|
|
124
|
+
deleteDir: true,
|
|
125
|
+
},
|
|
126
|
+
)
|
|
127
|
+
})
|
|
89
128
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
[
|
|
93
|
-
'init',
|
|
94
|
-
'--studio',
|
|
95
|
-
'--from-contract',
|
|
96
|
-
'0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e',
|
|
97
|
-
'--abi',
|
|
98
|
-
path.join(baseDir, 'abis', 'SoloMargin.json'),
|
|
99
|
-
'--network',
|
|
100
|
-
'mainnet',
|
|
101
|
-
'user/subgraph-from-contract-with-abi-and-structs',
|
|
102
|
-
subgraphDir4,
|
|
103
|
-
],
|
|
104
|
-
'init/from-contract-with-abi-and-structs',
|
|
105
|
-
{ exitCode: 0, timeout: 100000, cwd: baseDir },
|
|
106
|
-
)
|
|
129
|
+
describe('NEAR', () => {
|
|
130
|
+
const nearBaseDir = path.join(baseDir, 'near')
|
|
107
131
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
cliTest(
|
|
133
|
+
'From contract',
|
|
134
|
+
[
|
|
135
|
+
'init',
|
|
136
|
+
'--protocol',
|
|
137
|
+
'near',
|
|
138
|
+
'--product',
|
|
139
|
+
'hosted-service',
|
|
140
|
+
'--from-contract',
|
|
141
|
+
'app.good-morning.near',
|
|
142
|
+
'--network',
|
|
143
|
+
'near-mainnet',
|
|
144
|
+
'user/near-from-contract',
|
|
145
|
+
path.join(nearBaseDir, 'from-contract'),
|
|
146
|
+
],
|
|
147
|
+
path.join('init', 'near', 'from-contract'),
|
|
148
|
+
{
|
|
149
|
+
exitCode: 0,
|
|
150
|
+
timeout: 100000,
|
|
151
|
+
cwd: nearBaseDir,
|
|
152
|
+
deleteDir: true,
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
})
|
|
125
156
|
})
|
package/tests/cli/util.js
CHANGED
|
@@ -1,57 +1,72 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
1
|
+
const fs = require('fs-extra')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const spawn = require('spawn-command')
|
|
4
4
|
const stripAnsi = require('strip-ansi')
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// Deletes folder if:
|
|
7
|
+
// - flag is true
|
|
8
|
+
// - folder exists
|
|
9
|
+
const deleteDir = (dir, flag) => {
|
|
10
|
+
if (flag && fs.existsSync(dir)) {
|
|
11
|
+
fs.removeSync(dir)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const resolvePath = p => path.join(__dirname, p)
|
|
16
|
+
|
|
17
|
+
const cliTest = (title, args, testPath, options = {}) => {
|
|
7
18
|
test(
|
|
8
19
|
title,
|
|
9
20
|
async () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// Use the provided cwd if desired
|
|
13
|
-
let cwd =
|
|
14
|
-
options !== undefined && options.cwd ? options.cwd : resolvePath(`./${testPath}`)
|
|
21
|
+
try {
|
|
22
|
+
deleteDir(resolvePath(`./${testPath}`), options.deleteDir)
|
|
15
23
|
|
|
16
|
-
|
|
24
|
+
// Use the provided cwd if desired
|
|
25
|
+
let cwd =
|
|
26
|
+
options.cwd ? options.cwd : resolvePath(`./${testPath}`)
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
if (options !== undefined && options.exitCode !== undefined) {
|
|
20
|
-
expectedExitCode = options.exitCode
|
|
21
|
-
}
|
|
22
|
-
let expectedStdout = undefined
|
|
23
|
-
try {
|
|
24
|
-
expectedStdout = fs.readFileSync(resolvePath(`./${testPath}.stdout`), 'utf-8')
|
|
25
|
-
} catch (e) {}
|
|
28
|
+
let [exitCode, stdout, stderr] = await runGraphCli(args, cwd)
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} catch (e) {}
|
|
31
|
-
|
|
32
|
-
if (expectedStderr !== undefined) {
|
|
33
|
-
// For some reason the error sometimes comes in stdout, then
|
|
34
|
-
// stderr comes empty.
|
|
35
|
-
//
|
|
36
|
-
// If that's the case, we should throw it so it's easier
|
|
37
|
-
// to debug the error.
|
|
38
|
-
//
|
|
39
|
-
// TODO: investigate why that happens (somewhere it should
|
|
40
|
-
// be using console.error or print.error for example) so this
|
|
41
|
-
// check can be removed.
|
|
42
|
-
if (stderr.length === 0 && stdout.length !== 0) {
|
|
43
|
-
throw new Error(stdout)
|
|
30
|
+
let expectedExitCode = undefined
|
|
31
|
+
if (options.exitCode !== undefined) {
|
|
32
|
+
expectedExitCode = options.exitCode
|
|
44
33
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
let expectedStdout = undefined
|
|
35
|
+
try {
|
|
36
|
+
expectedStdout = fs.readFileSync(resolvePath(`./${testPath}.stdout`), 'utf-8')
|
|
37
|
+
} catch (e) {}
|
|
38
|
+
|
|
39
|
+
let expectedStderr = undefined
|
|
40
|
+
try {
|
|
41
|
+
expectedStderr = fs.readFileSync(resolvePath(`./${testPath}.stderr`), 'utf-8')
|
|
42
|
+
} catch (e) {}
|
|
43
|
+
|
|
44
|
+
if (expectedStderr !== undefined) {
|
|
45
|
+
// For some reason the error sometimes comes in stdout, then
|
|
46
|
+
// stderr comes empty.
|
|
47
|
+
//
|
|
48
|
+
// If that's the case, we should throw it so it's easier
|
|
49
|
+
// to debug the error.
|
|
50
|
+
//
|
|
51
|
+
// TODO: investigate why that happens (somewhere it should
|
|
52
|
+
// be using console.error or print.error for example) so this
|
|
53
|
+
// check can be removed.
|
|
54
|
+
if (stderr.length === 0 && stdout.length !== 0) {
|
|
55
|
+
throw new Error(stdout)
|
|
56
|
+
}
|
|
57
|
+
expect(stripAnsi(stderr)).toBe(expectedStderr)
|
|
58
|
+
}
|
|
59
|
+
if (expectedExitCode !== undefined) {
|
|
60
|
+
expect(exitCode).toBe(expectedExitCode)
|
|
61
|
+
}
|
|
62
|
+
if (expectedStdout !== undefined) {
|
|
63
|
+
expect(stripAnsi(stdout)).toBe(expectedStdout)
|
|
64
|
+
}
|
|
65
|
+
} finally {
|
|
66
|
+
deleteDir(resolvePath(`./${testPath}`), options.deleteDir)
|
|
52
67
|
}
|
|
53
68
|
},
|
|
54
|
-
|
|
69
|
+
options.timeout || undefined,
|
|
55
70
|
)
|
|
56
71
|
}
|
|
57
72
|
|