@graphprotocol/graph-cli
Version:
CLI for building for and deploying to The Graph
85 lines (84 loc) • 4.28 kB
JavaScript
import path from 'node:path';
import { filesystem, patching } from 'gluegun';
import yaml from 'yaml';
import { step, withSpinner } from './spinner.js';
export const updateSubgraphNetwork = async (manifest, network, networksFile, identifierName) => await withSpinner(`Update sources network`, `Failed to update sources network`, `Warnings while updating sources network`, async (spinner) => {
step(spinner, `Reading networks config`);
const allNetworks = await filesystem.read(networksFile, 'json');
const networkConfig = allNetworks[network];
// Exit if the network passed with --network does not exits in networks.json
if (!networkConfig) {
throw new Error(`Network '${network}' was not found in '${networksFile}'`);
}
await patching.update(manifest, content => {
const subgraph = yaml.parse(content);
const networkSources = Object.keys(networkConfig);
const subgraphSources = subgraph.dataSources.map((value) => value.name);
// Update the dataSources network config
subgraph.dataSources = subgraph.dataSources.map((source) => {
if (!networkSources.includes(source.name)) {
throw new Error(`'${source.name}' was not found in the '${network}' configuration, please update!`);
}
if (hasChanges(identifierName, network, networkConfig[source.name], source)) {
step(spinner, `Update '${source.name}' network configuration`);
source.network = network;
source.source = source.source.abi ? { abi: source.source.abi } : {};
Object.assign(source.source, networkConfig[source.name]);
}
else {
step(spinner, `Skip '${source.name}': No changes to network configuration`);
}
return source;
});
// All data sources should be on the same network,
// so we have to update the network of all templates too.
// eslint-disable-next-line -- prettier has problems with &&=
subgraph.templates &&
(subgraph.templates = subgraph.templates.map((template) => ({
...template,
network,
})));
const unusedSources = networkSources.filter(x => !subgraphSources.includes(x));
for (const source of unusedSources) {
step(spinner, `dataSource '${source}' from '${networksFile}' not found in ${manifest}`);
}
const yaml_doc = new yaml.Document();
yaml_doc.contents = subgraph;
return yaml_doc.toString();
});
});
export const initNetworksConfig = async (directory, identifierName) => await withSpinner(`Initialize networks config`, `Failed to initialize networks config`, `Warnings while initializing networks config`, async () => {
const subgraphStr = filesystem.read(path.join(directory, 'subgraph.yaml'));
const subgraph = yaml.parse(subgraphStr);
const networks = subgraph.dataSources.reduce((acc, source) => Object.assign(acc, {
[source.network]: {
[source.name]: {
[identifierName]: source.source.address,
startBlock: source.source.startBlock,
},
},
}), {});
filesystem.write(`${directory}/networks.json`, networks);
return true;
});
// Checks if any network attribute has been changed
function hasChanges(identifierName, network, networkConfig, dataSource) {
const networkChanged = dataSource.network !== network;
// Return directly if the network is different
if (networkChanged)
return networkChanged;
const addressChanged = networkConfig[identifierName] !== dataSource.source[identifierName];
const startBlockChanged = networkConfig.startBlock !== dataSource.source.startBlock;
return networkChanged || addressChanged || startBlockChanged;
}
export async function updateNetworksFile(network, dataSource, address, networksFile) {
await patching.update(networksFile, config => {
if (Object.keys(config).includes(network)) {
Object.assign(config[network], { [dataSource]: { address } });
}
else {
Object.assign(config, { [network]: { [dataSource]: { address } } });
}
return config;
});
}