Skip to content

Commit

Permalink
Improve release script
Browse files Browse the repository at this point in the history
* Add --push-back
* Add --registry
* Add --skip-checks
* Demand --release and --next
* Use parse-git-remote to find dojo remote
* If --push-back is specified and no dojo remote found, quit
* Move functionality of can-publish-check and repo-is-clean-check into functions
* Add checks back to release script
  • Loading branch information
bryanforbes committed Jul 18, 2018
1 parent 015059b commit 76a8776
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 48 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"devDependencies": {
"@types/node": "^6.0.54",
"@types/parse-git-config": "^2.0.0",
"@types/yargs": "^8.0.2",
"codecov": "~3.0.4",
"copyfiles": "^1.2.0",
Expand All @@ -53,6 +54,7 @@
},
"dependencies": {
"chalk": "^2.3.0",
"parse-git-config": "^2.0.2",
"rxjs": "^5.5.6",
"yargs": "^10.0.3"
},
Expand Down
22 changes: 2 additions & 20 deletions src/can-publish-check.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import chalk from 'chalk';
import { runAsPromise } from './utils/process';
import { canPublish } from './utils/checks';

const yargs = require('yargs');

Expand All @@ -10,24 +9,7 @@ const { initial: isInitialRelease } = yargs.option('initial', {
}).argv;

(async function() {
let user = '';

try {
const whoami = await runAsPromise('npm', ['whoami']);
user = whoami.trim();
} catch (e) {
console.log(chalk.red('failed running "npm whoami". are you not logged into npm?'));
if (!(await canPublish(isInitialRelease))) {
process.exit(1);
}

if (!isInitialRelease) {
const maintainers = JSON.parse(await runAsPromise('npm', ['view', '.', '--json'])).maintainers.map(
(maintainer: string) => maintainer.replace(/\s<.*/, '')
);

if (maintainers.indexOf(user) < 0) {
console.log(chalk.red(`cannot publish this package with user ${user}`));
process.exit(1);
}
}
})();
89 changes: 73 additions & 16 deletions src/release.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,60 @@
import chalk from 'chalk';
import { EOL } from 'os';
import * as yargs from 'yargs';
import * as parse from 'parse-git-config';
import { runAsPromise } from './utils/process';

const yargs = require('yargs');
import { canPublish, isRepoClean } from './utils/checks';

const {
release: releaseVersion,
next: nextVersion,
'dry-run': dryRun,
'push-back': pushBack,
'skip-checks': skipChecks,
tag: releaseTag,
initial: isInitialRelease
initial: isInitialRelease,
registry: npmRegistry
}: {
release: string;
next: string;
'dry-run': boolean;
'push-back': boolean;
'skip-checks': boolean;
tag: string;
initial: boolean;
registry: string | undefined;
} = yargs
.option('release', {
type: 'string'
type: 'string',
demandOption: true
})
.option('next', {
type: 'string'
type: 'string',
demandOption: true
})
.option('dry-run', {
type: 'boolean',
default: false
})
.option('skip-checks', {
type: 'boolean',
default: false
})
.option('push-back', {
type: 'boolean',
default: false
})
.option('tag', {
type: 'string',
default: 'next'
})
.option('initial', {
type: 'boolean',
default: false
}).argv;
})
.option('registry', {
type: 'string',
describe: 'NPM registry to publish to'
}).argv as any;

async function command(bin: string, args: string[], options: any = {}, executeOnDryRun = false) {
if (dryRun && !executeOnDryRun) {
Expand All @@ -45,25 +71,56 @@ async function command(bin: string, args: string[], options: any = {}, executeOn
return runAsPromise(bin, args, options);
}

function getGitRemote(gitBaseRemote: string): string | false {
const gitConfig = parse.sync();
const remotes = Object.keys(gitConfig)
.filter((key) => key.indexOf('remote') === 0)
.filter((key) => gitConfig[key].url.indexOf(gitBaseRemote) === 0)
.map((key) => gitConfig[key].url);

return remotes.length ? remotes[0] : false;
}

(async function() {
const hasDojoRemote =
(await command('git', ['remote'], {}, true)).split(EOL).filter((remote: string) => remote.trim() === 'dojo')
.length === 1;
const gitRemote = getGitRemote('git@github.com:dojo/');
const npmRegistryArgs = npmRegistry ? ['--registry', npmRegistry] : [];

console.log(chalk.yellow(`Version: ${releaseVersion}`));
console.log(chalk.yellow(`Next Version: ${nextVersion}`));
console.log(chalk.yellow(`Dry Run: ${dryRun}`));
console.log(chalk.yellow(`Push Back: ${hasDojoRemote}`));
console.log(chalk.yellow(`Push Back: ${pushBack}`));
if (gitRemote) {
console.log(chalk.yellow(`Dojo Remote: ${gitRemote}`));
} else {
console.log(chalk.red(`Dojo Remote: not found`));
if (pushBack) {
process.exit(1);
return;
}
}

if (skipChecks && !dryRun) {
console.log(chalk.red(`You can only skip-checks on a dry-run!`));
process.exit(1);
return;
}

if (!skipChecks && (!(await canPublish(isInitialRelease)) || !(await isRepoClean()))) {
process.exit(1);
return;
}

// update the version
await command('npm', ['version', releaseVersion, '--no-git-tag-version'], { cwd: 'dist/release' }, false);
await command('npm', ['version', releaseVersion, '--no-git-tag-version'], {}, false);

// run the release command
if (isInitialRelease) {
await command('npm', ['publish', '--tag', releaseTag, '--access', 'public'], { cwd: 'dist/release' });
await command('npm', ['publish', '--tag', releaseTag, '--access', 'public', ...npmRegistryArgs], {
cwd: 'dist/release'
});
} else {
await command('npm', ['publish', '--tag', releaseTag], { cwd: 'dist/release' });
await command('npm', ['publish', '--tag', releaseTag, ...npmRegistryArgs], { cwd: 'dist/release' });
}

// commit the changes
Expand All @@ -78,8 +135,8 @@ async function command(bin: string, args: string[], options: any = {}, executeOn
// commit the changes
await command('git', ['commit', '-am', `"Update package metadata"`], false);

if (hasDojoRemote) {
await command('git', ['push', 'dojo', 'master'], false);
await command('git', ['push', 'dojo', '--tags'], false);
if (pushBack && gitRemote) {
await command('git', ['push', gitRemote, 'master'], false);
await command('git', ['push', gitRemote, '--tags'], false);
}
})();
14 changes: 2 additions & 12 deletions src/repo-is-clean-check.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import chalk from 'chalk';
import { runAsPromise } from './utils/process';
import { isRepoClean } from './utils/checks';

(async function() {
const gitOutput = (await runAsPromise('git', ['status', '--porcelain'])).trim();

if (gitOutput) {
console.log(chalk.red('there are changes in the working tree'));
process.exit(1);
}

const revParse = (await runAsPromise('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).trim();
if (revParse !== 'master') {
console.log(chalk.red('not on master branch'));
if (!(await isRepoClean())) {
process.exit(1);
}
})();
44 changes: 44 additions & 0 deletions src/utils/checks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import chalk from 'chalk';
import { runAsPromise } from './process';

export async function canPublish(isInitialRelease: boolean) {
let user = '';

try {
const whoami = await runAsPromise('npm', ['whoami']);
user = whoami.trim();
} catch (e) {
console.log(chalk.red('failed running "npm whoami". are you not logged into npm?'));
return false;
}

if (!isInitialRelease) {
const maintainers = JSON.parse(await runAsPromise('npm', ['view', '.', '--json'])).maintainers.map(
(maintainer: string) => maintainer.replace(/\s<.*/, '')
);

if (maintainers.indexOf(user) < 0) {
console.log(chalk.red(`cannot publish this package with user ${user}`));
return false;
}
}

return true;
}

export async function isRepoClean() {
const gitOutput = (await runAsPromise('git', ['status', '--porcelain'])).trim();

if (gitOutput) {
console.log(chalk.red('there are changes in the working tree'));
return false;
}

const revParse = (await runAsPromise('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).trim();
if (revParse !== 'master') {
console.log(chalk.red('not on master branch'));
return false;
}

return true;
}

0 comments on commit 76a8776

Please sign in to comment.