rocketh 0.17.0-next.0 → 0.17.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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +30 -0
- package/dist/cli.js.map +1 -0
- package/dist/environment/deployment-store.d.ts +3 -0
- package/dist/environment/deployment-store.d.ts.map +1 -0
- package/dist/environment/deployment-store.js +49 -0
- package/dist/environment/deployment-store.js.map +1 -0
- package/dist/utils/fs.d.ts +16 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +52 -0
- package/dist/utils/fs.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
import { loadEnv } from 'ldenv';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
5
|
+
import { loadAndExecuteDeployments } from './executor/index.js';
|
|
6
|
+
loadEnv();
|
|
7
|
+
const commandName = "rocketh";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name(commandName)
|
|
11
|
+
.version(pkg.version)
|
|
12
|
+
.usage(`${commandName}`)
|
|
13
|
+
.description('execute deploy scripts and store the deployments')
|
|
14
|
+
.option('-s, --scripts <value>', 'path the folder containing the deploy scripts to execute')
|
|
15
|
+
.option('-t, --tags <value>', 'comma separated list of tags to execute')
|
|
16
|
+
.option('-d, --deployments <value>', 'folder where deployments are saved')
|
|
17
|
+
.option('--skip-gas-report', 'if set skip gas report')
|
|
18
|
+
.option('--skip-prompts', 'if set skip any prompts')
|
|
19
|
+
.option('--save-deployments', 'if set, save deployments')
|
|
20
|
+
.requiredOption('-e, --environment <value>', 'environment to use')
|
|
21
|
+
.parse(process.argv);
|
|
22
|
+
const options = program.opts();
|
|
23
|
+
loadAndExecuteDeployments({
|
|
24
|
+
...options,
|
|
25
|
+
logLevel: 1,
|
|
26
|
+
askBeforeProceeding: options.skipPrompts ? false : true,
|
|
27
|
+
reportGasUse: options.skipGasReport ? false : true,
|
|
28
|
+
saveDeployments: options.saveDeployments,
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,OAAO,EAAC,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAM,IAAI,EAAE,MAAM,EAAC,CAAC;AACtD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,EAAE,CAAC;AAEV,MAAM,WAAW,GAAG,SAAS,CAAC;AAC9B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACL,IAAI,CAAC,WAAW,CAAC;KACjB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,KAAK,CAAC,GAAG,WAAW,EAAE,CAAC;KACvB,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,uBAAuB,EAAE,0DAA0D,CAAC;KAC3F,MAAM,CAAC,oBAAoB,EAAE,yCAAyC,CAAC;KACvE,MAAM,CAAC,2BAA2B,EAAE,oCAAoC,CAAC;KACzE,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;KACrD,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;KACnD,MAAM,CAAC,oBAAoB,EAAE,0BAA0B,CAAC;KACxD,cAAc,CAAC,2BAA2B,EAAE,oBAAoB,CAAC;KACjE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;AAG/B,yBAAyB,CAAC;IACzB,GAAI,OAA2B;IAC/B,QAAQ,EAAE,CAAC;IACX,mBAAmB,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;IACvD,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;IAClD,eAAe,EAAE,OAAO,CAAC,eAAe;CACxC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-store.d.ts","sourceRoot":"","sources":["../../src/environment/deployment-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAEzD,wBAAgB,uBAAuB,IAAI,eAAe,CAmEzD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
export function createFSDeploymentStore() {
|
|
4
|
+
function getFolder(deploymentsFolder, environmentName) {
|
|
5
|
+
return path.join(deploymentsFolder, environmentName);
|
|
6
|
+
}
|
|
7
|
+
function getFile(deploymentsFolder, environmentName, name) {
|
|
8
|
+
return path.join(deploymentsFolder, environmentName, name);
|
|
9
|
+
}
|
|
10
|
+
async function ensureChainInfoRecorded(deploymentsFolder, environmentName, chainId, genesisHash) {
|
|
11
|
+
if (!(await hasFile(deploymentsFolder, environmentName, '.chain'))) {
|
|
12
|
+
await writeFile(deploymentsFolder, environmentName, '.chain', JSON.stringify({ chainId, genesisHash }));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function writeFileWithChainInfo(chaininfo, deploymentsFolder, environmentName, name, content) {
|
|
16
|
+
await ensureChainInfoRecorded(deploymentsFolder, environmentName, chaininfo.chainId, chaininfo.genesisHash);
|
|
17
|
+
fs.mkdirSync(getFolder(deploymentsFolder, environmentName), { recursive: true });
|
|
18
|
+
fs.writeFileSync(getFile(deploymentsFolder, environmentName, name), content);
|
|
19
|
+
}
|
|
20
|
+
async function writeFile(deploymentsFolder, environmentName, name, content) {
|
|
21
|
+
fs.mkdirSync(getFolder(deploymentsFolder, environmentName), { recursive: true });
|
|
22
|
+
fs.writeFileSync(getFile(deploymentsFolder, environmentName, name), content);
|
|
23
|
+
}
|
|
24
|
+
async function readFile(deploymentsFolder, environmentName, name) {
|
|
25
|
+
return fs.readFileSync(getFile(deploymentsFolder, environmentName, name), 'utf-8');
|
|
26
|
+
}
|
|
27
|
+
async function deleteFile(deploymentsFolder, environmentName, name) {
|
|
28
|
+
fs.unlinkSync(getFile(deploymentsFolder, environmentName, name));
|
|
29
|
+
}
|
|
30
|
+
async function listFiles(deploymentsFolder, environmentName) {
|
|
31
|
+
return fs.readdirSync(getFolder(deploymentsFolder, environmentName));
|
|
32
|
+
}
|
|
33
|
+
async function hasFile(deploymentsFolder, environmentName, name) {
|
|
34
|
+
return fs.existsSync(getFile(deploymentsFolder, environmentName, name));
|
|
35
|
+
}
|
|
36
|
+
async function deleteAll(deploymentsFolder, environmentName) {
|
|
37
|
+
fs.rmSync(getFolder(deploymentsFolder, environmentName), { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
writeFileWithChainInfo,
|
|
41
|
+
listFiles,
|
|
42
|
+
hasFile,
|
|
43
|
+
deleteAll,
|
|
44
|
+
readFile,
|
|
45
|
+
writeFile,
|
|
46
|
+
deleteFile,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=deployment-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-store.js","sourceRoot":"","sources":["../../src/environment/deployment-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface LookupFileOptions {
|
|
2
|
+
pathOnly?: boolean;
|
|
3
|
+
rootDir?: string;
|
|
4
|
+
predicate?: (file: string) => boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function lookupFile(dir: string, formats: string[], options?: LookupFileOptions): string | undefined;
|
|
7
|
+
export declare function traverseMultipleDirectory(dirs: readonly string[]): string[];
|
|
8
|
+
export declare const traverse: (dir: string, result?: any[], topDir?: string, filter?: (name: string, stats: any) => boolean) => Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
path: string;
|
|
11
|
+
relativePath: string;
|
|
12
|
+
mtimeMs: number;
|
|
13
|
+
directory: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAIA,UAAU,iBAAiB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAc1G;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAU3E;AAED,eAAO,MAAM,QAAQ,GACpB,KAAK,MAAM,EACX,SAAQ,GAAG,EAAO,EAClB,SAAS,MAAM,EACf,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,KAC5C,KAAK,CAAC;IACR,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACnB,CAoBA,CAAC"}
|
package/dist/utils/fs.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// taken from https://github.com/vitejs/vite/blob/63524bac878e8d3771d34ad7ad2e10cd16870ff4/packages/vite/src/node/utils.ts#L371-L400
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export function lookupFile(dir, formats, options) {
|
|
5
|
+
for (const format of formats) {
|
|
6
|
+
const fullPath = path.join(dir, format);
|
|
7
|
+
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
|
|
8
|
+
const result = options?.pathOnly ? fullPath : fs.readFileSync(fullPath, 'utf-8');
|
|
9
|
+
if (!options?.predicate || options.predicate(result)) {
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const parentDir = path.dirname(dir);
|
|
15
|
+
if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) {
|
|
16
|
+
return lookupFile(parentDir, formats, options);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function traverseMultipleDirectory(dirs) {
|
|
20
|
+
const filepaths = [];
|
|
21
|
+
for (const dir of dirs) {
|
|
22
|
+
let filesStats = traverse(dir);
|
|
23
|
+
filesStats = filesStats.filter((v) => !v.directory);
|
|
24
|
+
for (const filestat of filesStats) {
|
|
25
|
+
filepaths.push(path.join(dir, filestat.relativePath));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return filepaths;
|
|
29
|
+
}
|
|
30
|
+
export const traverse = function (dir, result = [], topDir, filter // TODO any is Stats
|
|
31
|
+
) {
|
|
32
|
+
fs.readdirSync(dir).forEach((name) => {
|
|
33
|
+
const fPath = path.resolve(dir, name);
|
|
34
|
+
const stats = fs.statSync(fPath);
|
|
35
|
+
if ((!filter && !name.startsWith('.')) || (filter && filter(name, stats))) {
|
|
36
|
+
const fileStats = {
|
|
37
|
+
name,
|
|
38
|
+
path: fPath,
|
|
39
|
+
relativePath: path.relative(topDir || dir, fPath),
|
|
40
|
+
mtimeMs: stats.mtimeMs,
|
|
41
|
+
directory: stats.isDirectory(),
|
|
42
|
+
};
|
|
43
|
+
if (fileStats.directory) {
|
|
44
|
+
result.push(fileStats);
|
|
45
|
+
return traverse(fPath, result, topDir || dir, filter);
|
|
46
|
+
}
|
|
47
|
+
result.push(fileStats);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"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"}
|