Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add script to update all polkadot-js deps, and resolutions to latest #63

Merged
merged 13 commits into from
Apr 21, 2022
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"substrate-exec-eslint": "./scripts/substrate-exec-eslint.cjs",
"substrate-exec-jest": "./scripts/substrate-exec-jest.cjs",
"substrate-exec-rimraf": "./scripts/substrate-exec-rimraf.cjs",
"substrate-exec-tsc": "./scripts/substrate-exec-tsc.cjs"
"substrate-exec-tsc": "./scripts/substrate-exec-tsc.cjs",
"substrate-update-pjs-deps": "./scripts/substrate-update-pjs-deps.cjs"
},
"files": [
"config",
Expand Down
200 changes: 200 additions & 0 deletions scripts/substrate-update-pjs-deps.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#!/usr/bin/env node
'use strict';

const fs = require('fs');
const https = require('https');
const { resolve } = require('path');
const { readdir, stat } = require('fs').promises;

/**
* polkadot-js package information, and specifications
*/
const depSpecs = {
api: {
releaseLink: 'https://api.github.com/repos/polkadot-js/api/releases/latest',
packages: [
'api',
'api-augment',
'api-base',
'api-derive',
'rpc-core',
'rpc-augment',
'rpc-provider',
'types',
'types-augment',
'types-codec',
'types-create',
'types-support',
'types-known',
],
},
apps: {
releaseLink: 'https://api.github.com/repos/polkadot-js/apps/releases/latest',
packages: [
'apps-config'
],
},
common: {
releaseLink: 'https://api.github.com/repos/polkadot-js/common/releases/latest',
packages: [
'util',
'util-crypto',
'keyring',
'networks',
'x-fetch',
'x-global',
'x-bigint',
'x-ws',
],
},
wasm: {
releaseLink: 'https://api.github.com/repos/polkadot-js/wasm/releases/latest',
packages: [
'wasm-crypto'
],
}
}

/**
* This will fetch the latest release from github, returns the response as
* a JSON object.
*
* @param {string} url Latest release link
* @returns
*/
async function fetchRelease(url) {
const [h, ...args] = url.split('://')[1].split('/');
const [host, _port] = h.split(':');

const options = {
method: 'GET',
host,
port: 443,
path: '/' + args.join('/'),
headers: {
'User-Agent': 'request'
}
};

return new Promise(function(resolve, reject) {
const req = https.request(options, function (res) {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error(`Status Code: ${res.statusCode}`));
}

const data = [];

res.on('data', chunk => {
data.push(chunk);
});

res.on('end', function() {
resolve(JSON.parse(Buffer.concat(data).toString()))
});
})

req.on('error', reject);

req.end();
})
}

/**
* Given a package.json file update all the resolutions and dependencies
* that are polkadot-js packages
*
* @param {string} path Path to the package.json file
* @param {object} config Object contains keys that are package names, and values
* which are their corresponding versions
*/
function updatePackageJson(path, config) {
const rawData = fs.readFileSync(path);
const packageJson = JSON.parse(rawData);
const deps = packageJson['dependencies'];
const resolutions = packageJson['resolutions'];

for(const packageName of Object.keys(config)) {
// check and update dependencies key
if (deps && Object.keys(deps).includes(packageName)) {
packageJson['dependencies'][packageName] = config[packageName];
}

// check and update resolutions key
if (resolutions && Object.keys(resolutions).includes(packageName)) {
packageJson['resolutions'][packageName] = config[packageName];
}
}

try {
fs.writeFileSync(path, JSON.stringify(packageJson, null, 2).concat('\n'));
console.log(`Succesfully updated => ${path}`);
} catch (e) {
console.error(e)
}
}

/**
* Generator function to recursively lazy iterate through each directory. This searches
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It this recursive variant an idiom in JS?

It's elegant and nice but I would still prefer iterative variant...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It this recursive variant an idiom in JS?

I would say in some senses yes. When it comes to most kinds of traversing, recursion is pretty popular. The main focus being, it's a little easier to maintain and read IMO. Where it could be an issue is where memory intensive processing is happening and can cause memory leaks. In this case though we are void of that.

It's elegant and nice but I would still prefer iterative variant...

In most cases I would prefer the iterative variant as well, but in this case for readability and maintenance I would say lets keep it recursive. It does a nice job of establishing the lazy iterator without any confusing logic.

* for all package.json files in a dir, not including node_modules, and hidden dirs.
*
* @param {string} rootPath root path of the repository
* @param {array} ignorePaths an array of paths to ignore
*/
async function* getFiles(rootPath, ignorePaths) {
const fileNames = await readdir(rootPath);
for (const fileName of fileNames) {
const path = resolve(rootPath, fileName);
const curPath = path.split('/').slice(-1)[0];
if (ignorePaths.includes(curPath)) {
// Do not traverse any path that is ignored
continue;
} else if (curPath.startsWith('.')) {
// Do no traverse any hidden directories
continue;
} else if ((await stat(path)).isDirectory()) {
yield* getFiles(path, ignorePaths);
} else if (path.endsWith('package.json')) {
yield path;
}
}
}

async function main(rootPath = './') {
/**
* Paths to ignore when travesing a directions
*/
const pathsToIgnore = [
'node_modules',
'build',
'lib',
];
// iterate through constants and create an object that stores each packages name
// to their corresponding versions.
const packageToVersion = {};
for (const packageKey of Object.keys(depSpecs)) {
const packageRelease = await fetchRelease(depSpecs[packageKey].releaseLink);
const packageVersion = packageRelease['tag_name'];
for (const packageName of depSpecs[packageKey].packages) {
packageToVersion[`@polkadot/${packageName}`] = packageVersion.substring(1);
}
}

// Iterate through each file using the generator function and find the package.json
for await (const path of getFiles(rootPath, pathsToIgnore)) {
if (path) {
updatePackageJson(path, packageToVersion);
}
}
}

const argv = require('yargs')
.options({
'--path': {
description: 'Path to directory',
type: 'string'
}
})
.strict()
.argv;

main(argv.path).catch(err => console.log(err)).finally(() => process.exit());
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,7 @@ __metadata:
substrate-exec-jest: ./scripts/substrate-exec-jest.cjs
substrate-exec-rimraf: ./scripts/substrate-exec-rimraf.cjs
substrate-exec-tsc: ./scripts/substrate-exec-tsc.cjs
substrate-update-pjs-deps: ./scripts/substrate-update-pjs-deps.cjs
languageName: unknown
linkType: soft

Expand Down