Skip to content

Commit

Permalink
feat: first release
Browse files Browse the repository at this point in the history
  • Loading branch information
neikvon committed Jul 14, 2018
1 parent 6b1d282 commit 74d8d73
Show file tree
Hide file tree
Showing 10 changed files with 3,646 additions and 0 deletions.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# fbi-task-commit
git commit and npm publish flow, formatting commit messages with commitizen.

> This is a fbi task. If you haven't installed [fbi](https://github.com/AlloyTeam/fbi) yet, use the following command to install.
>
> `$ npm i -g fbi` or `yarn global add fbi`
## Requirements
- `fbi v3.0+`
- `node v7.6+`

## Features

- select files for `git add`
- formatting commit messages with commitizen
- bump version
- `git push`
- `npm publish`

## Usage

**Install**

```bash
$ fbi add https://github.com/fbi-templates/fbi-task-commit.git
```

**Run**

```bash
$ cd path/to/git/repository
$ fbi commit
```


## More
- [Official templates](https://github.com/fbi-templates)
- [`fbi` documentation](https://neikvon.gitbooks.io/fbi/content/)

## License
[MIT](https://opensource.org/licenses/MIT)

## [Changelog](https://github.com/fbi-templates/fbi-task-commit/CHANGELOG.md)
13 changes: 13 additions & 0 deletions configs/standard-version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"infile": "CHANGELOG.md",
"message": "chore(release): %s",
"firstRelease": false,
"sign": false,
"noVerify": false,
"commitAll": false,
"silent": false,
"tagPrefix": "v",
"scripts": {},
"skip": {},
"dryRun": false
}
93 changes: 93 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const inquirer = require('inquirer')
const version = require('./lib/version')
const commit = require('./lib/commit')
const publish = require('./lib/publish')
const {
isGitRepo,
getStatus,
getUnpushedCommits,
push,
gitInit
} = require('./lib/git')

process.on('unhandledRejection', (reason, promise) => {
ctx.logger.error(
'Unhandled Rejection at: Promise ',
promise,
' reason: ',
reason
)
throw reason
})

process.on('uncaughtException', async error => {
ctx.logger.error(error)
process.exit(0)
})

const defaults = {
repoPath: process.cwd()
}

async function entry (options = defaults) {
// prevent additional parameters results in an git git error
process.argv = process.argv.slice(0, 3)

if (!await isGitRepo(options.repoPath)) {
await gitInit()
}

try {
const hadCommited = await commit(options)
if (hadCommited) {
ctx.logger.success('Selected files committed\n')
}

// bump version
await version.bump()

// push
const unPushed = await getUnpushedCommits()
if (unPushed) {
console.log()
ctx.logger.info(
`Unpushed commits(${unPushed.split('\n').filter(u => u).length}):`
)
console.log(unPushed)

const answer = await inquirer.prompt({
type: 'confirm',
name: 'pushCommits',
message: 'Do you want to push now?',
default: false
})

if (answer.pushCommits) {
await push()
await push('--tags')
ctx.logger.success('All commits and tags pushed\n')
}
}

// publish
if (hadCommited) {
await publish()
ctx.logger.success('Publish successfully\n')
}

// status
await getStatus()
const unPushed2 = await getUnpushedCommits()
if (unPushed2) {
console.log(
` (${unPushed2.split('\n').filter(u => u).length} commits unpushed)`
)
}
console.log()
} catch (err) {
ctx.logger.error(err)
process.exit(0)
}
}

module.exports = entry
65 changes: 65 additions & 0 deletions lib/commit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const path = require('path')
const execa = require('execa')
const inquirer = require('inquirer')
const { bootstrap } = require('@peak-stone/commitizen-promise/dist/cli/git-cz')
const { getStatus, getStaged, getUnpushedCommits } = require('./git')

function czCommit () {
return bootstrap({
cliPath: '@peak-stone/commitizen-promise',
config: {
path: '@peak-stone/cz-fbi'
}
})
}

async function commit (options) {
try {
const needAdd = await getStatus()
const unPushed = await getUnpushedCommits()
if (unPushed) {
console.log(
` (${unPushed.split('\n').filter(u => u).length} commits unpushed)`
)
}
console.log()

if (Array.isArray(needAdd)) {
// select files to add
const answer = await inquirer.prompt({
type: 'checkbox',
name: 'files',
message: 'select files staged for commit:',
choices: needAdd.map(n => {
return { name: n }
})
})

if (answer && answer.files && answer.files.length > 0) {
// add files
const filesToAdd = answer.files.length === needAdd.length
? '.'
: answer.files.join(' ')

await execa.shell(`git add ${filesToAdd}`, {
cwd: options.repoPath
})

await czCommit()
return true
}
}

const hasStaged = await getStaged()
if (hasStaged) {
await czCommit()
return true
} else {
ctx.logger.warn('Nothing to commit')
}
} catch (err) {
throw err
}
}

module.exports = commit
116 changes: 116 additions & 0 deletions lib/git.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
const execa = require('execa')
const getStream = require('get-stream')
const inquirer = require('inquirer')

const isWin = process.platform === 'win32'
const root = process.cwd()

async function isGitRepo (dir) {
try {
const ret = await execa.shell('git rev-parse --git-dir', {
cwd: dir
})
return !!ret
} catch (err) {
return false
}
}

function showStatus (filepath) {
return execa.shell(`git status --short ${filepath || ''}`, {
cwd: root,
stdio: 'inherit'
})
}

async function getStatus (filepath, nolog) {
const cmd = isWin
? `git status ${filepath || ''} --porcelain`
: `git status ${filepath || ''} --porcelain | sed s/^...//`
const stream = execa.shell(cmd, {
cwd: root
}).stdout

const stdout = await getStream(stream)

let ret = stdout.trim()

if (ret && !nolog) {
ret = ret.split('\n').filter(p => p.trim())
if (isWin) {
ret = ret.map(i => i.slice(3))
}
console.log()
ctx.logger.info('current status:')
await showStatus()
}
return ret
}

// show only staged files
async function getStaged () {
// git diff --staged
// git diff --cached --name-only
// git diff --name-only --cached | xargs
const stream = execa.shell('git diff --name-only --cached', {
cwd: root
}).stdout
let stdout = await getStream(stream)
stdout = stdout.trim()

if (stdout) {
ctx.logger.info('files to commit:')
console.log(ctx.utils.style.green(stdout))
console.log()
}
return stdout
}

// This will list out your local comment history (not yet pushed) with corresponding message
// git reflog
async function getUnpushedCommits () {
const stream = execa.shell('git cherry -v', {
cwd: root
}).stdout

return getStream(stream)
}

async function push (args) {
return execa.shell(`git push ${args || ''}`, {
cwd: root,
stdio: 'inherit'
})
}

function isClean () {
return getStatus('', true)
}

async function gitInit () {
const answer = await inquirer.prompt({
type: 'confirm',
name: 'initNow',
message: 'This is not a git repository. "git init" now?',
default: false
})

if (answer && answer.initNow) {
return execa.shell('git init', {
cwd: root
})
} else {
process.exit(0)
}
}

module.exports = {
isGitRepo,
showStatus,
getStatus,
getStaged,
getUnpushedCommits,
push,
isClean,
gitInit
}
13 changes: 13 additions & 0 deletions lib/pkg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const path = require('path')

const root = process.cwd()

async function pkgExist () {
return ctx.utils.fs.exist(path.join(root, 'package.json'))
}

function readPkg () {
return require(path.join(root, 'package.json'))
}

module.exports = { pkgExist, readPkg }
38 changes: 38 additions & 0 deletions lib/publish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const execa = require('execa')
const inquirer = require('inquirer')
const { pkgExist, readPkg } = require('./pkg')

const root = process.cwd()

async function publish () {
if (await pkgExist()) {
const answer = await inquirer.prompt({
type: 'confirm',
name: 'npmPublish',
message: 'Publish to npmjs.com ?',
default: false
})

if (answer && answer.npmPublish) {
const pkg = readPkg()
let cmd = 'npm publish'
if (pkg.name && pkg.name.startsWith('@')) {
const answerPub = await inquirer.prompt({
type: 'confirm',
name: 'public',
message: 'This is a scoped package, publish as public ?',
default: true
})

if (answerPub && answerPub.public) {
cmd += ' --access=public'
}
}

return execa.shell(cmd, {
cwd: root
})
}
}
}
module.exports = publish
Loading

0 comments on commit 74d8d73

Please sign in to comment.