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: Support Github Actions CI #265

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- run: npm install
- run: npm test
- run: npm run cov:send
- run: npm run cov:check
8 changes: 7 additions & 1 deletion src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ export async function checkArgs(): Promise<TypescriptStarterArgsOptions> {
--appveyor include Appveyor for Windows CI
--description, -d package.json description
--dom include DOM type definitions
--githubactions include Github Actions CI
--node include node.js type definitions
--strict enable stricter type-checking
--travis include Travis CI configuration
--yarn use yarn (default: npm)

--no-circleci don't include CircleCI
--no-cspell don't include cspell
--no-editorconfig don't include .editorconfig
--no-editorconfig don't include .editorconfig
--no-functional don't enable eslint-plugin-functional
--no-install skip yarn/npm install
--no-vscode don't include VS Code debugging config
Expand Down Expand Up @@ -62,6 +63,10 @@ export async function checkArgs(): Promise<TypescriptStarterArgsOptions> {
default: true,
type: 'boolean',
},
githubactions: {
default: false,
type: 'boolean',
},
install: {
default: true,
type: 'boolean',
Expand Down Expand Up @@ -129,6 +134,7 @@ export async function checkArgs(): Promise<TypescriptStarterArgsOptions> {
domDefinitions: cli.flags.dom,
editorconfig: cli.flags.editorconfig,
functional: cli.flags.functional,
githubactions: cli.flags.githubactions,
install: cli.flags.install,
nodeDefinitions: cli.flags.node,
projectName: input,
Expand Down
7 changes: 7 additions & 0 deletions src/cli/inquire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export async function inquire(): Promise<TypescriptStarterCLIOptions> {
cspell = 'cspell',
editorconfig = 'editorconfig',
functional = 'functional',
githubactions = 'githubactions',
strict = 'strict',
travis = 'travis',
vscode = 'vscode',
Expand Down Expand Up @@ -126,6 +127,11 @@ export async function inquire(): Promise<TypescriptStarterCLIOptions> {
name: 'Include Travis CI config',
value: Extras.travis,
},
{
checked: false,
name: 'Include Github Actions CI config',
value: Extras.githubactions,
},
],
message: '🚀 More fun stuff:',
name: 'extras',
Expand Down Expand Up @@ -167,6 +173,7 @@ export async function inquire(): Promise<TypescriptStarterCLIOptions> {
: false,
editorconfig: extras.includes(Extras.editorconfig),
functional: extras.includes(Extras.functional),
githubactions: extras.includes(Extras.githubactions),
install: true,
nodeDefinitions: definitions
? [TypeDefinitions.node, TypeDefinitions.nodeAndDom].includes(
Expand Down
191 changes: 95 additions & 96 deletions src/cli/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,72 +18,73 @@ export enum Placeholders {

// We implement these as function factories to make unit testing easier.

export const cloneRepo = (
spawner: typeof execa,
suppressOutput = false
) => async (
repoInfo: {
readonly branch: string;
readonly repo: string;
},
workingDirectory: string,
dir: string
) => {
const projectDir = join(workingDirectory, dir);
const gitHistoryDir = join(projectDir, '.git');
const args =
repoInfo.branch === '.'
? ['clone', '--depth=1', repoInfo.repo, dir]
: [
'clone',
'--depth=1',
`--branch=${repoInfo.branch}`,
repoInfo.repo,
dir,
];
try {
await spawner('git', args, {
cwd: workingDirectory,
stdio: suppressOutput ? 'pipe' : 'inherit',
});
} catch (err) {
if (err.exitCodeName === 'ENOENT') {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`
export const cloneRepo =
(spawner: typeof execa, suppressOutput = false) =>
async (
repoInfo: {
readonly branch: string;
readonly repo: string;
},
workingDirectory: string,
dir: string
) => {
const projectDir = join(workingDirectory, dir);
const gitHistoryDir = join(projectDir, '.git');
const args =
repoInfo.branch === '.'
? ['clone', '--depth=1', repoInfo.repo, dir]
: [
'clone',
'--depth=1',
`--branch=${repoInfo.branch}`,
repoInfo.repo,
dir,
];
try {
await spawner('git', args, {
cwd: workingDirectory,
stdio: suppressOutput ? 'pipe' : 'inherit',
});
} catch (err) {
if ((err as any).exitCodeName === 'ENOENT') {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`
Git is not installed on your PATH. Please install Git and try again.

For more information, visit: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
`);
} else {
} else {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`Git clone failed.`);
}
}
try {
const revParseResult = await spawner('git', ['rev-parse', 'HEAD'], {
cwd: projectDir,
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'inherit'],
});
const commitHash = revParseResult.stdout;
return { commitHash, gitHistoryDir };
} catch (err) {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`Git clone failed.`);
throw new Error(`Git rev-parse failed.`);
}
}
try {
const revParseResult = await spawner('git', ['rev-parse', 'HEAD'], {
cwd: projectDir,
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'inherit'],
});
const commitHash = revParseResult.stdout;
return { commitHash, gitHistoryDir };
} catch (err) {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`Git rev-parse failed.`);
}
};
};

export const getGithubUsername = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fetcher: any
) => async (email: string | undefined): Promise<string> => {
if (email === Placeholders.email) {
return Placeholders.username;
}
return fetcher(email).catch(() => {
return Placeholders.username;
});
};
export const getGithubUsername =
(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fetcher: any
) =>
async (email: string | undefined): Promise<string> => {
if (email === Placeholders.email) {
return Placeholders.username;
}
return fetcher(email).catch(() => {
return Placeholders.username;
});
};

export const getUserInfo = (spawner: typeof execa) => async () => {
const opts: Options = {
Expand All @@ -105,46 +106,43 @@ export const getUserInfo = (spawner: typeof execa) => async () => {
}
};

export const initialCommit = (spawner: typeof execa) => async (
hash: string,
projectDir: string
): Promise<void> => {
const opts: Options = {
cwd: projectDir,
encoding: 'utf8',
stdio: 'pipe',
export const initialCommit =
(spawner: typeof execa) =>
async (hash: string, projectDir: string): Promise<void> => {
const opts: Options = {
cwd: projectDir,
encoding: 'utf8',
stdio: 'pipe',
};
await spawner('git', ['init'], opts);
await spawner('git', ['add', '-A'], opts);
await spawner(
'git',
[
'commit',
'-m',
`Initial commit\n\nCreated with bitjson/typescript-starter@${hash}`,
],
opts
);
};
await spawner('git', ['init'], opts);
await spawner('git', ['add', '-A'], opts);
await spawner(
'git',
[
'commit',
'-m',
`Initial commit\n\nCreated with bitjson/typescript-starter@${hash}`,
],
opts
);
};

export const install = (spawner: typeof execa) => async (
runner: Runner,
projectDir: string
) => {
const opts: Options = {
cwd: projectDir,
encoding: 'utf8',
stdio: 'inherit',
export const install =
(spawner: typeof execa) => async (runner: Runner, projectDir: string) => {
const opts: Options = {
cwd: projectDir,
encoding: 'utf8',
stdio: 'inherit',
};
try {
runner === Runner.Npm
? spawner('npm', ['install'], opts)
: spawner('yarn', opts);
} catch (err) {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`Installation failed. You'll need to install manually.`);
}
};
try {
runner === Runner.Npm
? spawner('npm', ['install'], opts)
: spawner('yarn', opts);
} catch (err) {
// eslint-disable-next-line functional/no-throw-statement
throw new Error(`Installation failed. You'll need to install manually.`);
}
};

/**
* Returns the URL and branch to clone. We clone the branch (tag) at the current
Expand Down Expand Up @@ -210,6 +208,7 @@ export const addInferredOptions = async (
domDefinitions: userOptions.domDefinitions,
editorconfig: userOptions.editorconfig,
functional: userOptions.functional,
githubactions: userOptions.githubactions,
install: userOptions.install,
nodeDefinitions: userOptions.nodeDefinitions,
projectName: userOptions.projectName,
Expand Down
2 changes: 2 additions & 0 deletions src/cli/tests/cli.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ test(`${TestDirectories.five}: Sandboxed: npm install, initial commit`, async (t
// cspell: disable-next-line
fullName: 'Satoshi Nakamoto',
functional: true,
githubactions: false,
install: true,
nodeDefinitions: false,
projectName: TestDirectories.five,
Expand Down Expand Up @@ -436,6 +437,7 @@ test(`${TestDirectories.six}: Sandboxed: yarn, no initial commit`, async (t) =>
email: Placeholders.email,
fullName: Placeholders.name,
functional: true,
githubactions: false,
install: true,
nodeDefinitions: true,
projectName: TestDirectories.six,
Expand Down
4 changes: 4 additions & 0 deletions src/cli/typescript-starter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export async function typescriptStarter(
fullName,
githubUsername,
functional,
githubactions,
install,
nodeDefinitions,
projectName,
Expand Down Expand Up @@ -215,6 +216,9 @@ export async function typescriptStarter(
if (!travis) {
del([normalizePath(join(projectPath, '.travis.yml'))]);
}
if (!githubactions) {
del([normalizePath(join(projectPath, '.github', 'workflows', 'ci.yaml'))]);
}
if (!editorconfig) {
del([normalizePath(join(projectPath, '.editorconfig'))]);
}
Expand Down
1 change: 1 addition & 0 deletions src/cli/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type TypescriptStarterCLIOptions = {
readonly domDefinitions: boolean;
readonly editorconfig: boolean;
readonly functional: boolean;
readonly githubactions: boolean;
readonly install: boolean;
readonly nodeDefinitions: boolean;
readonly projectName: string;
Expand Down