Skip to content

Commit

Permalink
feat(setup): add github actions as CI option (#502)
Browse files Browse the repository at this point in the history
* prepare setup for github actions

* add base github actions integration

* add manual prepare config generation

* fix

* checkout to base branch

* switch to release branch before trigger

* add schedule config

* scheduleCircleCI -> schedulePrepare

* rename NPM_TOKEN to NPM_AUTH_TOKEN for consistency

* fix vars names and typos

* Github to GitHub

* fix typo

* fix prepare

* return ciIntegration

* chore: rename files

* fix formatting

* use duble quotes in gh actions

* use single quote in condition

* use bash if statement to choose package manager

Co-authored-by: Eunjae Lee <[email protected]>
  • Loading branch information
2 people authored and Eunjae Lee committed Dec 20, 2019
1 parent d55895c commit 923cc87
Show file tree
Hide file tree
Showing 8 changed files with 381 additions and 83 deletions.
19 changes: 11 additions & 8 deletions packages/shipjs/src/flow/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import askQuestions from '../step/setup/askQuestions';
import addDevDependencies from '../step/setup/addDevDependencies';
import addScriptsToPackageJson from '../step/setup/addScriptsToPackageJson';
import addShipConfig from '../step/setup/addShipConfig';
import addCircleCIConfig from '../step/setup/addCircleCIConfig';
import { print } from '../util';
import { success } from '../color';

Expand All @@ -19,15 +18,14 @@ async function setup({ help = false, dir = '.', dryRun = false }) {
const {
baseBranch,
releaseBranch,
configureCircleCI,
scheduleCircleCI,
cronExpr,
useMonorepo,
mainVersionFile,
packagesToBump,
packagesToPublish,
isScoped,
isPublic,
ciIntegration,
ciConfig,
} = await askQuestions({ dir });
const outputs = [
addDevDependencies({ dependencies: ['shipjs'], dir, dryRun }),
Expand All @@ -44,11 +42,16 @@ async function setup({ help = false, dir = '.', dryRun = false }) {
dir,
dryRun,
}),
addCircleCIConfig({
ciIntegration.addConfig({
...ciConfig,
isScoped,
isPublic,
baseBranch,
configureCircleCI,
scheduleCircleCI,
cronExpr,
releaseBranch,
useMonorepo,
mainVersionFile,
packagesToBump,
packagesToPublish,
dir,
dryRun,
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import { getGitConfig } from 'shipjs-lib';
import runStep from '../runStep';
import runStep from '../../runStep';
import fs from 'fs';
import path from 'path';
import ejs from 'ejs';
import mkdirp from 'mkdirp';
import { print } from '../../util';
import { info, warning } from '../../color';
import { print } from '../../../util';
import { info, warning } from '../../../color';

export default ({
baseBranch,
configureCircleCI,
scheduleCircleCI,
cronExpr,
dir,
dryRun,
}) =>
export default ({ baseBranch, schedulePrepare, cronExpr, dir, dryRun }) =>
runStep(
{
title: 'Creating CircleCI configuration',
skipIf: () => !configureCircleCI,
},
() => {
const filePath = path.resolve(dir, '.circleci', 'config.yml');
Expand All @@ -38,7 +30,7 @@ export default ({
}
const content = getConfig({
baseBranch,
scheduleCircleCI,
schedulePrepare,
cronExpr,
gitUserName: getGitConfig('user.name') || 'Your Name',
gitUserEmail: getGitConfig('user.email') || '[email protected]',
Expand All @@ -62,7 +54,7 @@ export default ({

function getConfig({
baseBranch,
scheduleCircleCI,
schedulePrepare,
cronExpr,
gitUserName,
gitUserEmail,
Expand Down Expand Up @@ -114,7 +106,7 @@ jobs:
- run:
name: Run Tests
command: yarn test
<% if (scheduleCircleCI) { %>
<% if (schedulePrepare) { %>
prepare_release:
<<: *defaults
steps:
Expand Down Expand Up @@ -149,7 +141,7 @@ workflows:
- release_if_needed:
requires:
- test
<% if (scheduleCircleCI) { %>
<% if (schedulePrepare) { %>
schedule_release:
triggers:
- schedule:
Expand All @@ -162,6 +154,6 @@ workflows:
- prepare_release
<% } %>
`,
{ baseBranch, scheduleCircleCI, cronExpr, gitUserName, gitUserEmail }
{ baseBranch, schedulePrepare, cronExpr, gitUserName, gitUserEmail }
);
}
221 changes: 221 additions & 0 deletions packages/shipjs/src/step/setup/CI/addGitHubActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import { getGitConfig } from 'shipjs-lib';
import runStep from '../../runStep';
import fs from 'fs';
import path from 'path';
import ejs from 'ejs';
import mkdirp from 'mkdirp';
import { print } from '../../../util';
import { info, warning } from '../../../color';

export default ({
baseBranch,
releaseBranch,
manualPrepare,
schedulePrepare,
cronExpr,
dir,
dryRun,
}) =>
runStep(
{
title: 'Creating GitHub Actions configuration',
},
() => {
const gitUserName = getGitConfig('user.name') || 'Your Name';
const gitUserEmail = getGitConfig('user.email') || '[email protected]';

const log = [
createGitHubAction({
content: getBaseConfig({ releaseBranch }),
actionPath: '.github/workflows/shipjs-trigger.yml',
dir,
dryRun,
}),
manualPrepare &&
createGitHubAction({
content: getManualPrepareConfig({
baseBranch,
gitUserName,
gitUserEmail,
}),
actionPath: '.github/workflows/shipjs-manual-prepare.yml',
dir,
dryRun,
}),
schedulePrepare &&
createGitHubAction({
content: getScheduleConfig({
baseBranch,
cronExpr,
gitUserName,
gitUserEmail,
}),
actionPath: '.github/workflows/shipjs-schedule-prepare.yml',
dir,
dryRun,
}),

() => {
print(' You still need to finish setting up at GitHub Actions.');
// add link to readme here
},
].filter(Boolean);

return () => log.forEach(printResult => printResult());
}
);

function createGitHubAction({ content, actionPath, dir, dryRun }) {
const filePath = path.resolve(dir, actionPath);

if (fs.existsSync(filePath)) {
return () => {
print(`${warning('✘')} \`${actionPath}\` already exists.`);
};
}

if (dryRun) {
print(actionPath);
print(content);
} else {
mkdirp.sync(path.dirname(filePath));
fs.writeFileSync(filePath, content);
}
return () => {
print(`${info('✔')} Created \`${actionPath}\`.`);
};
}

function getBaseConfig({ releaseBranch }) {
return ejs.render(
`
name: Ship js trigger
on:
push:
branches:
- <%= releaseBranch %>
jobs:
build:
name: Build
runs-on: Ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
registry-url: "https://registry.npmjs.org"
- run: git switch <%= releaseBranch %>
- run: |
if [ -f "yarn.lock" ]; then
yarn install
else
npm install
fi
- run: npm run release:trigger
env:
GITHUB_TOKEN: \${{ secrets.GH_TOKEN }}
NODE_AUTH_TOKEN: \${{ secrets.NPM_AUTH_TOKEN }}
`,
{ releaseBranch }
);
}

function getManualPrepareConfig({ baseBranch, gitUserName, gitUserEmail }) {
return ejs.render(
`
name: Ship js Manual Prepare
on:
issue_comment:
types: [created]
jobs:
manual_prepare:
if: |
github.event_name == 'issue_comment' &&
(github.event.comment.author_association == 'member' || github.event.comment.author_association == 'owner') &&
startsWith(github.event.comment.body, '@shipjs prepare')
runs-on: Ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 0
ref: <%= baseBranch %>
- uses: actions/setup-node@master
- run: |
if [ -f "yarn.lock" ]; then
yarn install
else
npm install
fi
- run: |
git config --global user.email "<%= gitUserEmail %>"
git config --global user.name "<%= gitUserName %>"
- run: npm run release:prepare -- --yes --no-browse
env:
GITHUB_TOKEN: \${{ secrets.GH_TOKEN }}
create_done_comment:
if: success()
needs: manual_prepare
runs-on: Ubuntu-latest
steps:
- uses: actions/github@master
env:
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
with:
args: comment "@\${{ github.actor }} \`shipjs prepare\` done"
create_fail_comment:
if: cancelled() || failure()
needs: manual_prepare
runs-on: Ubuntu-latest
steps:
- uses: actions/github@master
env:
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
with:
args: comment "@\${{ github.actor }} \`shipjs prepare\` fail"
`,
{ baseBranch, gitUserName, gitUserEmail }
);
}

function getScheduleConfig({
baseBranch,
cronExpr,
gitUserName,
gitUserEmail,
}) {
return ejs.render(
`
name: Ship js Schedule Prepare
on:
schedule:
# * is a special character in YAML so you have to quote this string
- cron: "<%= cronExpr %>"
jobs:
schedule_prepare:
runs-on: Ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 0
ref: <%= baseBranch %>
- uses: actions/setup-node@master
- run: |
if [ -f "yarn.lock" ]; then
yarn install
else
npm install
fi
- run: |
git config --global user.email "<%= gitUserEmail %>"
git config --global user.name "<%= gitUserName %>"
- run: npm run release:prepare -- --yes --no-browse
env:
GITHUB_TOKEN: \${{ secrets.GH_TOKEN }}
`,
{ baseBranch, cronExpr, gitUserName, gitUserEmail }
);
}
37 changes: 37 additions & 0 deletions packages/shipjs/src/step/setup/CI/askCircleCI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import inquirer from 'inquirer';
import formatMessage from '../formatMessage';

export default async function askCircleCI() {
const { schedulePrepare } = await inquirer.prompt([
{
type: 'confirm',
name: 'schedulePrepare',
message: 'Schedule your release via CircleCI?',
default: true,
},
]);
const offset = new Date().getTimezoneOffset() / 60;
const hour = 11 + offset;
const tuesday = 2;
const defaultCronExpr = `0 ${hour} * * ${tuesday}`;
const { cronExpr } = await inquirer.prompt(
[
schedulePrepare
? {
type: 'input',
name: 'cronExpr',
message: formatMessage(
'When to release?',
'To learn about cron expressions, visit https://crontab.guru/\nThe default value ("Every Tuesday 11am")'
),
default: defaultCronExpr,
}
: undefined,
].filter(Boolean)
);

return {
schedulePrepare,
cronExpr,
};
}
Loading

0 comments on commit 923cc87

Please sign in to comment.