Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01320f9748 | ||
|
|
91cdd434b6 | ||
|
|
ed8b053d7b | ||
|
|
8ae5b66824 | ||
|
|
563021aa0b | ||
|
|
13c35a5f65 | ||
|
|
ee1223c9f6 | ||
|
|
c368d0b546 | ||
|
|
ad06481408 | ||
|
|
a928669fc7 | ||
|
|
69d3313f90 | ||
|
|
04c1d68333 |
@@ -0,0 +1,133 @@
|
||||
const path = require('node:path');
|
||||
|
||||
const execWrap = require('./utils/exec-wrap');
|
||||
const githubRequest = require('./utils/github-request');
|
||||
const wrapCli = require('./utils/wrap-cli');
|
||||
const launchGitWorkflow = require('./utils/git-workflow');
|
||||
const launchGithubWorkflow = require('./utils/github-workflow');
|
||||
|
||||
const typesProjectJson = require(path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'libs',
|
||||
'types',
|
||||
'project.json'
|
||||
));
|
||||
|
||||
const TYPE_UPDATE_BRANCH = 'fix/types';
|
||||
|
||||
const cliArgsSpecs = [
|
||||
{
|
||||
name: 'apiUrl',
|
||||
arg: 'url',
|
||||
required: true,
|
||||
validate: (value) => {
|
||||
try {
|
||||
new URL(value);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Invalid url found: ${value}. Make sure you pass in a valid url using the "--url" flag.`
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'apiVersion',
|
||||
arg: 'version',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'apiCommitHash',
|
||||
arg: 'commit',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'apiRepoName',
|
||||
arg: 'repo',
|
||||
default: 'vega',
|
||||
},
|
||||
{
|
||||
name: 'apiRepoOwner',
|
||||
arg: 'owner',
|
||||
default: 'vegaprotocol',
|
||||
},
|
||||
{
|
||||
name: 'frontendRepoName',
|
||||
arg: 'fe-repo',
|
||||
default: 'frontend-monorepo',
|
||||
},
|
||||
{
|
||||
name: 'frontendRepoOwner',
|
||||
arg: 'fe-owner',
|
||||
default: 'vegaprotocol',
|
||||
},
|
||||
{
|
||||
name: 'githubAuthToken',
|
||||
arg: 'token',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
const getGenerateCmd = (projectJson) => {
|
||||
if (
|
||||
projectJson &&
|
||||
projectJson.targets &&
|
||||
projectJson.targets.generate &&
|
||||
projectJson.targets.generate.options &&
|
||||
projectJson.targets.generate.options.commands
|
||||
) {
|
||||
return projectJson.targets.generate.options.commands.join(' && ');
|
||||
}
|
||||
};
|
||||
|
||||
const run = async ({
|
||||
apiUrl,
|
||||
apiVersion,
|
||||
apiRepoOwner,
|
||||
apiRepoName,
|
||||
apiCommitHash,
|
||||
githubAuthToken,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
}) => {
|
||||
const generateCmd = getGenerateCmd(typesProjectJson);
|
||||
|
||||
execWrap({
|
||||
cmd: `NX_VEGA_URL=${apiUrl} ${generateCmd}`,
|
||||
errMessage:
|
||||
'There was an error trying to regenerating the types for the frontend.',
|
||||
});
|
||||
|
||||
const unstagedFiles = execWrap({
|
||||
cmd: `git diff --name-only`,
|
||||
errMessage: `Error listing unstaged files`,
|
||||
})
|
||||
.split('\n')
|
||||
.filter((file) => file !== '');
|
||||
|
||||
if (unstagedFiles.length) {
|
||||
launchGitWorkflow({
|
||||
branchName: TYPE_UPDATE_BRANCH,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
commitMessage: `update types for v${apiVersion} on HEAD:${apiCommitHash}`,
|
||||
});
|
||||
|
||||
await launchGithubWorkflow({
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
githubAuthToken,
|
||||
issueBody: {
|
||||
title: `[automated] Update types for datanode v${apiVersion}`,
|
||||
body: `Update the frontend based on the [datanode changes](https://github.com/${apiRepoOwner}/${apiRepoName}/commit/${apiCommitHash}).`,
|
||||
},
|
||||
prBody: {
|
||||
head: TYPE_UPDATE_BRANCH,
|
||||
title: 'Update types',
|
||||
body: `Patches the frontend based on the [datanode changes](https://github.com/${apiRepoOwner}/${apiRepoName}/commit/${apiCommitHash}).`,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
wrapCli(run, cliArgsSpecs);
|
||||
@@ -0,0 +1,149 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const execWrap = require('./utils/exec-wrap');
|
||||
const githubRequest = require('./utils/github-request');
|
||||
const wrapCli = require('./utils/wrap-cli');
|
||||
const launchGitWorkflow = require('./utils/git-workflow');
|
||||
const launchGithubWorkflow = require('./utils/github-workflow');
|
||||
|
||||
const NETWORK_UPDATE_BRANCH = 'fix/networks';
|
||||
const STATIC_APP_PATH = path.join(__dirname, '..', 'apps', 'static');
|
||||
const NETWORK_CONFIG_PATH = path.join(STATIC_APP_PATH, 'src', 'assets');
|
||||
|
||||
const getJson = (value, errMessage) => {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (err) {
|
||||
throw new Error(errMessage);
|
||||
}
|
||||
};
|
||||
|
||||
const cliArgsSpecs = [
|
||||
{
|
||||
name: 'payload',
|
||||
arg: 'payload',
|
||||
required: true,
|
||||
validate: (rawPayload) => {
|
||||
const payload = getJson(
|
||||
rawPayload,
|
||||
'The payload must be a valid json object'
|
||||
);
|
||||
Object.keys(payload).forEach((network) => {
|
||||
const item = payload[network] || {};
|
||||
console.log(item);
|
||||
if (typeof item.chainId !== 'string') {
|
||||
throw new Error(
|
||||
`The network "${network}" must have a valid chainId.`
|
||||
);
|
||||
}
|
||||
if (!Array.isArray(item.hosts)) {
|
||||
throw new Error(
|
||||
`The network "${network}" must have a valid list of hosts.`
|
||||
);
|
||||
}
|
||||
item.hosts.forEach((host) => {
|
||||
try {
|
||||
new URL(host);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`The host "${host}" on the network "${network}" must be a valid url.`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'networkCommitHash',
|
||||
arg: 'commit',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'networkRepoName',
|
||||
arg: 'repo',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'networkRepoOwner',
|
||||
arg: 'owner',
|
||||
default: 'vegaprotocol',
|
||||
},
|
||||
{
|
||||
name: 'frontendRepoName',
|
||||
arg: 'fe-repo',
|
||||
default: 'frontend-monorepo',
|
||||
},
|
||||
{
|
||||
name: 'frontendRepoOwner',
|
||||
arg: 'fe-owner',
|
||||
default: 'vegaprotocol',
|
||||
},
|
||||
{
|
||||
name: 'githubAuthToken',
|
||||
arg: 'token',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
const getNetworkConfigFileName = (network) =>
|
||||
`${network.toLowerCase()}-network.json`;
|
||||
|
||||
const findTargetConfig = (network) => {
|
||||
const fileName = getNetworkConfigFileName(network);
|
||||
return path.join(NETWORK_CONFIG_PATH, fileName);
|
||||
};
|
||||
|
||||
const run = async ({
|
||||
payload,
|
||||
networkCommitHash,
|
||||
networkRepoName,
|
||||
networkRepoOwner,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
githubAuthToken,
|
||||
}) => {
|
||||
const networks = JSON.parse(payload);
|
||||
for (let network in networks) {
|
||||
const file = findTargetConfig(network);
|
||||
if (fs.existsSync(file)) {
|
||||
const fd = fs.openSync(file, 'w+');
|
||||
fs.writeSync(fd, file, JSON.stringify(networks[network]));
|
||||
}
|
||||
}
|
||||
|
||||
const unstagedFiles = execWrap({
|
||||
cmd: `git diff --name-only`,
|
||||
errMessage: `Error listing unstaged files`,
|
||||
})
|
||||
.split('\n')
|
||||
.filter((file) => file !== '');
|
||||
|
||||
console.log(frontendRepoOwner, frontendRepoName);
|
||||
|
||||
if (unstagedFiles.length) {
|
||||
launchGitWorkflow({
|
||||
branchName: NETWORK_UPDATE_BRANCH,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
commitMessage: `update networks based on ${networkRepoOwner}/${networkRepoName} HEAD:${networkCommitHash}`,
|
||||
});
|
||||
|
||||
await launchGithubWorkflow({
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
githubAuthToken,
|
||||
issueBody: {
|
||||
title: `[automated] Update network configuration`,
|
||||
body: `Update the frontend based on the [datanode changes](https://github.com/${networkRepoOwner}/${networkRepoName}/commit/${networkCommitHash}).`,
|
||||
},
|
||||
prBody: {
|
||||
head: NETWORK_UPDATE_BRANCH,
|
||||
title: 'Update networks',
|
||||
body: `Patches the frontend based on the [network changes](https://github.com/${networkRepoOwner}/${networkRepoName}/commit/${networkCommitHash}).`,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
wrapCli(run, cliArgsSpecs);
|
||||
@@ -0,0 +1,14 @@
|
||||
const path = require('node:path');
|
||||
const { execSync } = require('node:child_process');
|
||||
|
||||
const appRoot = path.join(__dirname, '..', '..');
|
||||
|
||||
module.exports = ({ cmd, errMessage }) => {
|
||||
console.log(`executing: "${cmd}"`);
|
||||
try {
|
||||
const result = execSync(cmd, { cwd: appRoot, stdout: process.stdout });
|
||||
return result.toString();
|
||||
} catch (err) {
|
||||
throw new Error(errMessage);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const execWrap = require('./exec-wrap');
|
||||
|
||||
module.exports = ({
|
||||
branchName,
|
||||
commitMessage,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
}) => {
|
||||
const remoteBranches = execWrap({
|
||||
cmd: `git ls-remote --heads ssh://github.com/${frontendRepoOwner}/${frontendRepoName}.git ${branchName}`,
|
||||
errMessage: `Error checking if the branch "${branchName}" exists on the origin.`,
|
||||
});
|
||||
const localBranches = execWrap({
|
||||
cmd: 'git branch',
|
||||
errMessage: `Error getting local branch names.`,
|
||||
});
|
||||
|
||||
if (
|
||||
remoteBranches.includes(branchName) ||
|
||||
localBranches.includes(branchName)
|
||||
) {
|
||||
const currentBranchName = execWrap({
|
||||
cmd: `git branch --show-current`,
|
||||
errMessage: `Error getting current branch name.`,
|
||||
});
|
||||
|
||||
if (currentBranchName !== branchName) {
|
||||
execWrap({
|
||||
cmd: `git checkout ${branchName}`,
|
||||
errMessage: `There was an error trying to check out the branch "${branchName}".`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
execWrap({
|
||||
cmd: `git checkout -b ${branchName}`,
|
||||
errMessage: `There was an error trying to check out the branch "${branchName}".`,
|
||||
});
|
||||
}
|
||||
|
||||
execWrap({
|
||||
cmd: `git add .`,
|
||||
errMessage: `Error staging changed files.`,
|
||||
});
|
||||
|
||||
execWrap({
|
||||
cmd: `git commit -m 'chore: ${commitMessage}' --no-verify`,
|
||||
errMessage: `Error checking if the branch "${branchName}" exists on the origin.`,
|
||||
});
|
||||
|
||||
execWrap({
|
||||
cmd: `git push -u ssh://github.com/${frontendRepoOwner}/${frontendRepoName}.git ${branchName} --no-verify`,
|
||||
errMessage: 'Error pushing changes.',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const https = require('node:https');
|
||||
const request = require('./request');
|
||||
|
||||
module.exports = async (url, { githubAuthToken, body }) => {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
Authorization: `token ${githubAuthToken}`,
|
||||
'User-Agent': '',
|
||||
},
|
||||
};
|
||||
options.agent = new https.Agent(options);
|
||||
|
||||
return request(url, {
|
||||
...options,
|
||||
body,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
const githubRequest = require('./github-request');
|
||||
|
||||
module.exports = async ({
|
||||
issueBody,
|
||||
prBody,
|
||||
frontendRepoOwner,
|
||||
frontendRepoName,
|
||||
githubAuthToken,
|
||||
}) => {
|
||||
const { number, html_url: issueHtmlUrl } = await githubRequest(
|
||||
`https://api.github.com/repos/${frontendRepoOwner}/${frontendRepoName}/issues`,
|
||||
{
|
||||
githubAuthToken,
|
||||
body: JSON.stringify(issueBody),
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`Issue created: ${issueHtmlUrl}`);
|
||||
|
||||
const { html_url: prHtmlUrl } = await githubRequest(
|
||||
`https://api.github.com/repos/${frontendRepoOwner}/${frontendRepoName}/pulls`,
|
||||
{
|
||||
githubAuthToken,
|
||||
body: JSON.stringify({
|
||||
base: prBody.base || 'master',
|
||||
title: `fix/${number}: ${prBody.title}`,
|
||||
head: prBody.head,
|
||||
body: `
|
||||
# Related issues 🔗
|
||||
|
||||
Closes #${number}
|
||||
|
||||
# Description ℹ️
|
||||
|
||||
${prBody.body}
|
||||
|
||||
# Technical 👨🔧
|
||||
|
||||
This pull request was automatically generated.
|
||||
`,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`Pull request created: ${prHtmlUrl}`);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
module.exports = ({ specs, args = [] }) => {
|
||||
const defaultConfig = {
|
||||
apiUrl: undefined,
|
||||
apiVersion: undefined,
|
||||
};
|
||||
|
||||
return specs.reduce((acc, spec) => {
|
||||
const match = args.find((arg) => arg.startsWith(`--${spec.arg}=`));
|
||||
const value = (match || '').replace(`--${spec.arg}=`, '');
|
||||
|
||||
if (spec.required && !value) {
|
||||
throw new Error(`Cannot find required CLI argument "--${spec.arg}".`);
|
||||
}
|
||||
if (typeof spec.validate === 'function') {
|
||||
spec.validate(value);
|
||||
}
|
||||
return {
|
||||
...acc,
|
||||
[spec.name]: value || spec.default,
|
||||
};
|
||||
}, {});
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
const https = require('node:https');
|
||||
|
||||
module.exports = (url, options) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const req = https.request(url, options, (res) => {
|
||||
res.setEncoding('utf8');
|
||||
let rawData = '';
|
||||
res.on('data', (chunk) => {
|
||||
rawData += chunk.toString();
|
||||
});
|
||||
res.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
res.on('end', () => {
|
||||
if (res.statusCode >= 400) {
|
||||
reject(new Error(`HTTPS ${res.statusCode}: ${rawData}`));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const parsedData = JSON.parse(rawData);
|
||||
resolve(parsedData);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (options.method === 'POST' && options.body) {
|
||||
req.write(options.body);
|
||||
}
|
||||
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
const parseCliArgs = require('./parse-cli-args');
|
||||
|
||||
module.exports = async function main(run, specs) {
|
||||
try {
|
||||
const config = parseCliArgs({
|
||||
specs,
|
||||
args: process.argv,
|
||||
});
|
||||
await run(config);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user