Skip to content

Commit

Permalink
ci: npm release check (#684)
Browse files Browse the repository at this point in the history
* fix: add scripts to run new yarn pack script

* fix: configure new opts for yarn pack script

* fix(types): abstract types for procs

* fix: add script for checking npm releases

* fix: abstract script logic into one central area

* docs: update readme

* ci: add ci test for npm releases

* ci: fix error

* ci: fix pre install

* fix: setWsUrl

* add sig interrupt

* fix: error for sidecar

* fix: comments docs

* fix: refactor launchProcess params, add trim to stdout

* fix: remove default value for the command on launchProcess

* Update scripts/runYarnPack.ts

Co-authored-by: David <dvdplm@gmail.com>

* docs: update description, and give examples on to run it locally, and cleanup if there is an issue

* fix: give error instructions on how to cleanup if theres an issue, fix doc to active voice

* ci: description

* ci: fix the description to a comment

Co-authored-by: David <dvdplm@gmail.com>
  • Loading branch information
TarikGul and dvdplm committed Sep 29, 2021
1 parent 24e02be commit 9936df1
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 8 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,26 @@ jobs:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn build:docs

build-npm-release:
# This test is to make sure sidecar can release a binary without any errors.
# This script does not publish a release, but instead uses yarn to create a tarball and
# install it locally. Once installed a binary is attached to sidecars node_modules, and that
# binary is then tested against. For more in depth information reference the docs at
# `../../scripts/README.md`.

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn test:test-release

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
"test:init-e2e-tests:kusama": "yarn start:e2e-scripts --chain kusama",
"test:init-e2e-tests:westend": "yarn start:e2e-scripts --chain westend",
"start:e2e-scripts": "yarn build:scripts && node scripts/build/runChainTests.js",
"build:scripts": "cd scripts && substrate-exec-tsc",
"lint:scripts": "cd scripts && substrate-dev-run-lint"
"build:scripts": "substrate-exec-rimraf scripts/build/ && cd scripts && substrate-exec-tsc",
"lint:scripts": "cd scripts && substrate-dev-run-lint",
"start:test-release": "yarn build:scripts && node scripts/build/runYarnPack.js",
"test:test-release": "yarn start:test-release"
},
"dependencies": {
"@polkadot/api": "^6.0.5",
Expand Down
21 changes: 21 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,24 @@

This script calls the local e2e-tests helper library in order to test the current branch or development environment against
a collection of different blocks, across different runtimes. It does this for Polkadot, Kusama, and Westend.


## Script `runYarnPack.ts`

### Summary

This script's purpose is to do a dry-run npm release, and check if sidecar builds correctly. It uses `yarn pack` in order to create a tarball called `package.tgz` inside of our root directory. This tarball is a copy of what our release would be within the npm registry. We target that tarball using `yarn add ${__dirname}<path_to_file>/package.tgz` and add it as a dependency. Yarn will read the package.json of sidecar, and publish it as `@substrate/api-sidecar`. Once sidecar is fully installed a binary will be attached in `./node_modules/.bin/substrate-api-sidecar`, we then run that binary to check for any issues. After the test the dependency tree is cleaned and the tarball deleted.

In order to start this script locally, run from the root directory of this repository:

```bash
$ yarn
$ yarn test:test-release
```

If the cleanup has any issues, you may run from the root directory of this repository:

```bash
$ yarn remove @substrate/api-sidecar
$ rm -rf ./package.tgz
```
18 changes: 12 additions & 6 deletions scripts/config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { IChainConfig } from './types';

const defaultSasStartOpts = {
const defaultJestOpts = {
proc: 'jest',
resolver: 'PASS',
};

export const defaultSasStartOpts = {
proc: 'sidecar',
resolver: 'Check the root endpoint',
resolverStartupErr: 'error: uncaughtException: listen EADDRINUSE:',
args: ['start'],
};

const defaultJestOpts = {
proc: 'jest',
resolver: 'PASS',
};

export const defaultSasBuildOpts = {
proc: 'sidecar',
resolver: 'Build Finished',
args: ['build'],
};

export const defaultSasPackOpts = {
proc: 'sidecar-pack',
resolver: 'YN0000: Done in',
args: ['pack'],
};

export const config: Record<string, IChainConfig> = {
polkadot: {
wsUrl: 'wss://rpc.polkadot.io',
Expand Down
144 changes: 144 additions & 0 deletions scripts/runYarnPack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { defaultSasBuildOpts, defaultSasPackOpts } from './config';
import { killAll, launchProcess, setWsUrl } from './sidecarScriptApi';
import { ProcsType, StatusCode } from './types';

const procs: ProcsType = {};

/**
* Cleans up the remaining deps and files that should be temps
*/
const cleanup = async () => {
const { Failed } = StatusCode;

/**
* Cleanup dep tree
*/
console.log('Uninstalling Sidecar..');
const sasUnInstallPackOpts = {
proc: 'sidecar-install-pack',
resolver: 'YN0000: Done',
args: ['remove', '@substrate/api-sidecar'],
};
const sidecarUnInstallPack = await launchProcess('yarn', procs, sasUnInstallPackOpts);

if (sidecarUnInstallPack === Failed) {
console.error('UnInstalling sidecar package failed..');
console.error('Please uninstall the package using `yarn remove @substrate/api-sidecar`.');
killAll(procs);
}

/**
* Delete tarball
*/
console.log('Deleting tarball');
const sasDeleteTarballOpts = {
proc: 'delete-tarball',
resolver: '',
args: ['-rf', `${__dirname}/../../package.tgz`],
};
const deleteTarball = await launchProcess('rm', procs, sasDeleteTarballOpts);

if (deleteTarball === Failed) {
console.error('Error deleting tarball.');
console.error('In order to delete tarball run: `rm -rf ./package.tgz` from the root directory of the repository.');
killAll(procs);
}
};

/**
* This script creates a dry-run npm release and checks if sidecar
* launches succesfully.
*/
const main = async () => {
const { Failed, Success } = StatusCode;

/**
* Build sidecar
*/
console.log('Building Sidecar');
const sidecarBuild = await launchProcess('yarn', procs, defaultSasBuildOpts);

if (sidecarBuild === Failed) {
console.error('Sidecar failed to build, exiting...');
killAll(procs);
process.exit(1);
}

/**
* Build Tarball via yarn pack
*/
console.log('Building Local Npm release of Sidecar.');
const sidecarPack = await launchProcess('yarn', procs, defaultSasPackOpts);

if (sidecarPack === Failed) {
console.error('Sidecar failed to build an local npm tarball.');
killAll(procs);
process.exit(1);
}

/**
* Install tarball
*/
console.log('Installing Sidecar as a package');
const sasInstallPackOpts = {
proc: 'sidecar-install-pack',
resolver: 'YN0000: Done',
args: ['add', `${__dirname}/../../package.tgz`],
};
const sidecarInstallPack = await launchProcess('yarn', procs, sasInstallPackOpts);

if (sidecarInstallPack === Failed) {
console.error('Installing the binary failed..');
killAll(procs);
process.exit(1);
}

/**
* Start sidecar and see if it works
*/
setWsUrl('wss://kusama-rpc.polkadot.io');
console.log('Initializing Sidecar');
const sasStartPackOpts = {
proc: 'sidecar',
resolver: 'Check the root endpoint',
resolverStartupErr: 'Error',
args: [],
};
const sidecarStart = await launchProcess(
`${__dirname}/../../node_modules/.bin/substrate-api-sidecar`,
procs,
sasStartPackOpts
);

if (sidecarStart === Success) {
console.log('Successful Release Build of Sidecar');
killAll(procs);
await cleanup();
process.exit(0);
} else {
console.error('Release Build failed for Sidecar');
killAll(procs);
await cleanup();
process.exit(1);
}
};

/**
* Signal interrupt
*/
process.on('SIGINT', function () {
console.log('Caught interrupt signal');
killAll(procs);
process.exit();
});

/**
* Signal hangup terminal
*/
process.on('SIGHUP', function () {
console.log('Caught terminal termination');
killAll(procs);
process.exit();
});

main().finally(() => process.exit());
95 changes: 95 additions & 0 deletions scripts/sidecarScriptApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { spawn } from 'child_process';

import { IProcOpts, ProcsType, StatusCode } from './types';

/**
* Sets the url that sidecar will use in the env
*
* @param url ws url used in sidecar
*/
export const setWsUrl = (url: string): void => {
process.env.SAS_SUBSTRATE_WS_URL = url;
};

/**
* Kill all processes
*
* @param procs
*/
export const killAll = (procs: ProcsType): void => {
console.log('Killing all processes...');
for (const key of Object.keys(procs)) {
if (!procs[key].killed) {
try {
console.log(`Killing ${key}`);
// Kill child and all its descendants.
process.kill(-procs[key].pid, 'SIGTERM');
process.kill(-procs[key].pid, 'SIGKILL');
} catch (e) {
/**
* The error we are catching here silently, is when `-procs[key].pid` takes
* the range of all pid's inside of the subprocess group created with
* `spawn`, and one of the process's is either already closed or doesn't exist anymore.
*
* ex: `Error: kill ESRCH`
*
* This is a very specific use case of an empty catch block and is used
* outside of the scope of the API therefore justifiable, and should be used cautiously
* elsewhere.
*/
}
}
}
};

/**
* Launch any given process. It accepts an options object.
*
* @param cmd Optional Command will default to 'yarn'
* @param procs Object of saved processes
* @param IProcOpts