mirror of
https://github.com/all-contributors/cli.git
synced 2025-01-10 05:56:29 +00:00
* fix: Adjusting file access that was clashing with uncontrolled promises * review: Adding code review changing and linting * fix(cli): rectify an async call Co-authored-by: Maximilian Berkmann <maxieberkmann@gmail.com>
This commit is contained in:
parent
feefb2aac2
commit
f54703d0ce
5 changed files with 212 additions and 202 deletions
|
@ -9,5 +9,6 @@ module.exports = {
|
||||||
'import/extensions': 0,
|
'import/extensions': 0,
|
||||||
'consistent-return': 0,
|
'consistent-return': 0,
|
||||||
'no-process-exit': 0,
|
'no-process-exit': 0,
|
||||||
}
|
'no-continue': 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
"homepage": "https://github.com/all-contributors/all-contributors-cli#readme",
|
"homepage": "https://github.com/all-contributors/all-contributors-cli#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.7.6",
|
"@babel/runtime": "^7.7.6",
|
||||||
|
"ac-learn": "^1.5.1",
|
||||||
"async": "^3.1.0",
|
"async": "^3.1.0",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"ac-learn": "^1.0.3",
|
"ac-learn": "^1.0.3",
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
"inquirer": "^7.3.3",
|
"inquirer": "^7.3.3",
|
||||||
"json-fixer": "^1.6.8",
|
"json-fixer": "^1.6.8",
|
||||||
"lodash": "^4.11.2",
|
"lodash": "^4.11.2",
|
||||||
"name-your-contributors": "^3.4.0",
|
"name-your-contributors": "^3.8.3",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"pify": "^5.0.0",
|
"pify": "^5.0.0",
|
||||||
"yargs": "^15.0.1",
|
"yargs": "^15.0.1",
|
||||||
|
|
248
src/cli.js
248
src/cli.js
|
@ -12,7 +12,7 @@ const util = require('./util')
|
||||||
const repo = require('./repo')
|
const repo = require('./repo')
|
||||||
const updateContributors = require('./contributors')
|
const updateContributors = require('./contributors')
|
||||||
const {getContributors} = require('./discover')
|
const {getContributors} = require('./discover')
|
||||||
const learner = require('./discover/learner')
|
const {getLearner} = require('./discover/learner')
|
||||||
|
|
||||||
const cwd = process.cwd()
|
const cwd = process.cwd()
|
||||||
const defaultRCFile = path.join(cwd, '.all-contributorsrc')
|
const defaultRCFile = path.join(cwd, '.all-contributorsrc')
|
||||||
|
@ -51,10 +51,26 @@ const yargv = yargs
|
||||||
}
|
}
|
||||||
}).argv
|
}).argv
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
if (error) {
|
||||||
|
console.error(error.message)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function suggestCommands(cmd) {
|
||||||
|
const availableCommands = ['generate', 'add', 'init', 'check']
|
||||||
|
const suggestion = didYouMean(cmd, availableCommands)
|
||||||
|
|
||||||
|
if (suggestion) console.log(chalk.bold(`Did you mean ${suggestion}`))
|
||||||
|
}
|
||||||
|
|
||||||
function startGeneration(argv) {
|
function startGeneration(argv) {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
argv.files.map(file => {
|
argv.files.map(file => {
|
||||||
const filePath = path.join(cwd, file)
|
const filePath = path.join(cwd, file)
|
||||||
|
|
||||||
return util.markdown.read(filePath).then(fileContent => {
|
return util.markdown.read(filePath).then(fileContent => {
|
||||||
const newFileContent = generate(argv, argv.contributors, fileContent)
|
const newFileContent = generate(argv, argv.contributors, fileContent)
|
||||||
return util.markdown.write(filePath, newFileContent)
|
return util.markdown.write(filePath, newFileContent)
|
||||||
|
@ -63,7 +79,7 @@ function startGeneration(argv) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addContribution(argv) {
|
async function addContribution(argv) {
|
||||||
util.configFile.readConfig(argv.config) // ensure the config file exists
|
util.configFile.readConfig(argv.config) // ensure the config file exists
|
||||||
const username = argv._[1] === undefined ? undefined : String(argv._[1])
|
const username = argv._[1] === undefined ? undefined : String(argv._[1])
|
||||||
/* Example: (for clarity & debugging purposes)
|
/* Example: (for clarity & debugging purposes)
|
||||||
|
@ -85,10 +101,18 @@ function addContribution(argv) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const contributions = argv._[2]
|
const contributions = argv._[2]
|
||||||
|
|
||||||
// Add or update contributor in the config file
|
// Add or update contributor in the config file
|
||||||
return updateContributors(argv, username, contributions).then(
|
let data
|
||||||
data => {
|
|
||||||
|
try {
|
||||||
|
data = await updateContributors(argv, username, contributions)
|
||||||
|
} catch (error) {
|
||||||
|
return console.error('Contributor Update fail:', error)
|
||||||
|
}
|
||||||
|
|
||||||
argv.contributors = data.contributors
|
argv.contributors = data.contributors
|
||||||
|
|
||||||
/* Example
|
/* Example
|
||||||
[ { login: 'Berkmann18',
|
[ { login: 'Berkmann18',
|
||||||
name: 'Maximilian Berkmann',
|
name: 'Maximilian Berkmann',
|
||||||
|
@ -97,31 +121,26 @@ function addContribution(argv) {
|
||||||
contributions: [ 'code', 'ideas' ] },
|
contributions: [ 'code', 'ideas' ] },
|
||||||
{ already in argv.contributors } ]
|
{ already in argv.contributors } ]
|
||||||
*/
|
*/
|
||||||
return startGeneration(argv).then(
|
|
||||||
() => {
|
try {
|
||||||
if (argv.commit) {
|
await startGeneration(argv)
|
||||||
return util.git.commit(argv, data)
|
|
||||||
|
return argv.commit ? util.git.commit(argv, data) : null
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Generation fail:', error)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
err => console.error('Generation fail:', err),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
err => console.error('Contributor Update fail:', err),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkContributors(argv) {
|
async function checkContributors(argv) {
|
||||||
const configData = util.configFile.readConfig(argv.config)
|
const configData = util.configFile.readConfig(argv.config)
|
||||||
|
|
||||||
return repo
|
const repoContributors = await repo.getContributors(
|
||||||
.getContributors(
|
|
||||||
configData.projectOwner,
|
configData.projectOwner,
|
||||||
configData.projectName,
|
configData.projectName,
|
||||||
configData.repoType,
|
configData.repoType,
|
||||||
configData.repoHost,
|
configData.repoHost,
|
||||||
)
|
)
|
||||||
.then(repoContributors => {
|
|
||||||
// console.dir(repoContributors) //['jfmengels', 'jakebolam', ...]
|
|
||||||
const checkKey = repo.getCheckKey(configData.repoType)
|
const checkKey = repo.getCheckKey(configData.repoType)
|
||||||
const knownContributions = configData.contributors.reduce((obj, item) => {
|
const knownContributions = configData.contributors.reduce((obj, item) => {
|
||||||
obj[item[checkKey]] = item.contributions
|
obj[item[checkKey]] = item.contributions
|
||||||
|
@ -155,134 +174,115 @@ function checkContributors(argv) {
|
||||||
)
|
)
|
||||||
process.stdout.write(`${missingFromRepo.join(', ')}\n`)
|
process.stdout.write(`${missingFromRepo.join(', ')}\n`)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchContributors(argv) {
|
async function fetchContributors(argv) {
|
||||||
// console.log('argv=', argv);
|
const {reviewers, commitAuthors, issueCreators} = await getContributors(
|
||||||
// const configData = util.configFile.readConfig(argv.config)
|
argv.projectOwner,
|
||||||
// console.log('configData')
|
argv.projectName,
|
||||||
// console.dir(configData)
|
)
|
||||||
|
|
||||||
return getContributors(argv.projectOwner, argv.projectName).then(
|
|
||||||
repoContributors => {
|
|
||||||
// repoContributors = {prCreators, prCommentators, issueCreators, issueCommentators, reviewers, commitAuthors, commitCommentators}
|
|
||||||
// console.dir(repoContributors)
|
|
||||||
|
|
||||||
// const checkKey = repo.getCheckKey(configData.repoType)
|
|
||||||
// const knownContributions = configData.contributors.reduce((obj, item) => {
|
|
||||||
// obj[item[checkKey]] = item.contributions
|
|
||||||
// return obj
|
|
||||||
// }, {})
|
|
||||||
// console.log('knownContributions', knownContributions) //{ jfmengels: ['code', 'test', 'doc'], ...}
|
|
||||||
// const knownContributors = configData.contributors.map(
|
|
||||||
// contributor => contributor[checkKey],
|
|
||||||
// )
|
|
||||||
// console.log('knownContributors', knownContributors) //['kentcdodds', 'ben-eb', ...]
|
|
||||||
|
|
||||||
// let contributors = new Set(
|
|
||||||
// repoContributors.prCreators.map(usr => usr.login),
|
|
||||||
// )
|
|
||||||
|
|
||||||
// repoContributors.issueCreators.forEach(usr => contributors.add(usr.login))
|
|
||||||
// repoContributors.reviewers.forEach(usr => contributors.add(usr.login))
|
|
||||||
// repoContributors.commitAuthors.forEach(usr => contributors.add(usr.login))
|
|
||||||
// contributors = Array.from(contributors)
|
|
||||||
|
|
||||||
// console.log('ctbs=', contributors);
|
|
||||||
|
|
||||||
//~1. Auto-add reviewers for review~
|
|
||||||
//~2. Auto-add issue creators for any categories found~
|
|
||||||
//~3. Auto-add commit authors~
|
|
||||||
//4. Roll onto other contribution categories following https://www.draw.io/#G1uL9saIuZl3rj8sOo9xsLOPByAe28qhwa
|
|
||||||
|
|
||||||
const args = {...argv, _: []}
|
const args = {...argv, _: []}
|
||||||
const contributorsToAdd = []
|
const contributorsToAdd = []
|
||||||
repoContributors.reviewers.forEach(usr => {
|
const learner = await getLearner()
|
||||||
// args._ = ['add', usr.login, 'review']
|
|
||||||
// addContribution(args)
|
reviewers.forEach(usr => {
|
||||||
contributorsToAdd.push({login: usr.login, contributions: ['review']})
|
contributorsToAdd.push({login: usr.login, contributions: ['review']})
|
||||||
// console.log(
|
|
||||||
// `Adding ${chalk.underline('Reviewer')} ${chalk.blue(usr.login)}`,
|
console.log(
|
||||||
// )
|
`Adding ${chalk.underline('Reviewer')} ${chalk.blue(usr.login)}`,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
repoContributors.issueCreators.forEach(usr => {
|
issueCreators.forEach(usr => {
|
||||||
// console.log('usr=', usr.login, 'labels=', usr.labels)
|
|
||||||
const contributor = {
|
const contributor = {
|
||||||
login: usr.login,
|
login: usr.login,
|
||||||
contributions: [],
|
contributions: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
usr.labels.forEach(lbl => {
|
usr.labels.forEach(lbl => {
|
||||||
const guesses = learner.classify(lbl).filter(c => c && c !== 'null')
|
const guessedCategory = learner
|
||||||
if (guesses.length) {
|
.classify(lbl)
|
||||||
const category = guesses[0]
|
.find(ctr => ctr && ctr !== 'null')
|
||||||
// args._ = ['', usr.login, category]
|
|
||||||
// addContribution(args)
|
|
||||||
if (!contributor.contributions.includes(category))
|
|
||||||
contributor.contributions.push(category)
|
|
||||||
// console.log(
|
|
||||||
// `Adding ${chalk.blue(usr.login)} for ${chalk.underline(category)}`,
|
|
||||||
// )
|
|
||||||
} //else console.warn(`Oops, I couldn't find any category for the "${lbl}" label`)
|
|
||||||
})
|
|
||||||
const existingContributor = contributorsToAdd.filter(
|
|
||||||
ctrb => ctrb.login === usr.login,
|
|
||||||
)
|
|
||||||
if (existingContributor.length) {
|
|
||||||
existingContributor[0].contributions = [
|
|
||||||
...new Set(
|
|
||||||
existingContributor[0].contributions.concat(
|
|
||||||
contributor.contributions,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
} else contributorsToAdd.push(contributor)
|
|
||||||
})
|
|
||||||
|
|
||||||
repoContributors.commitAuthors.forEach(usr => {
|
if (!guessedCategory) {
|
||||||
// const contributor = {
|
console.warn(
|
||||||
// login: usr.login,
|
`Oops, I couldn't find any category for the "${lbl}" label`,
|
||||||
// contributions: [],
|
|
||||||
// }
|
|
||||||
// console.log('commit auth:', usr)
|
|
||||||
const existingContributor = contributorsToAdd.filter(
|
|
||||||
ctrb => ctrb.login === usr.login,
|
|
||||||
)
|
)
|
||||||
if (existingContributor.length) {
|
|
||||||
//there's no label or commit message info so use only code for now
|
return
|
||||||
if (!existingContributor[0].contributions.includes('code')) {
|
|
||||||
existingContributor[0].contributions.push('code')
|
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
contributorsToAdd.push({login: usr.login, contributions: ['code']})
|
|
||||||
})
|
|
||||||
|
|
||||||
// console.log('contributorsToAdd=', contributorsToAdd)
|
if (!contributor.contributions.includes(guessedCategory)) {
|
||||||
contributorsToAdd.forEach(contributor => {
|
contributor.contributions.push(guessedCategory)
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`Adding ${chalk.blue(contributor.login)} for ${chalk.underline(
|
`Adding ${chalk.blue(usr.login)} for ${chalk.underline(
|
||||||
contributor.contributions.join('/'),
|
guessedCategory,
|
||||||
)}`,
|
)}`,
|
||||||
)
|
)
|
||||||
args._ = ['', contributor.login, contributor.contributions.join(',')]
|
}
|
||||||
// if (contributor.contributions.length) addContribution(args)
|
|
||||||
// else console.log('Skipping', contributor.login)
|
|
||||||
})
|
})
|
||||||
},
|
|
||||||
err => console.error('fetch error:', err),
|
const existingContributor = contributorsToAdd.find(
|
||||||
|
ctr => ctr.login === usr.login,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existingContributor) {
|
||||||
|
existingContributor.contributions.push(...contributor.contributions)
|
||||||
|
} else {
|
||||||
|
contributorsToAdd.push(contributor)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
commitAuthors.forEach(usr => {
|
||||||
|
const existingContributor = contributorsToAdd.find(
|
||||||
|
ctr => ctr.login === usr.login,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existingContributor) {
|
||||||
|
// There's no label or commit message info so use only code for now
|
||||||
|
if (!existingContributor.contributions.includes('code')) {
|
||||||
|
existingContributor.contributions.push('code')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contributorsToAdd.push({login: usr.login, contributions: ['code']})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: Roll onto other contribution categories following https://www.draw.io/#G1uL9saIuZl3rj8sOo9xsLOPByAe28qhwa
|
||||||
|
|
||||||
|
for (const contributor of contributorsToAdd) {
|
||||||
|
if (!contributor.contributions.length) {
|
||||||
|
console.log('Skipping', contributor.login)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format contributor contributions
|
||||||
|
const contributions = contributor.contributions.join('/')
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Adding ${chalk.blue(contributor.login)} for ${chalk.underline(
|
||||||
|
contributions,
|
||||||
|
)}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
args._ = ['', contributor.login, contributor.contributions.join(',')]
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
await addContribution(args)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Adding ${chalk.blue(contributor.login)} for ${chalk.underline(
|
||||||
|
contributions,
|
||||||
|
)} Failed: ${JSON.stringify(error)}`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError(error) {
|
|
||||||
if (error) {
|
|
||||||
console.error(error.stack || error.message || error)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
}
|
||||||
process.exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function promptForCommand(argv) {
|
async function promptForCommand(argv) {
|
||||||
const questions = [
|
const questions = [
|
||||||
{
|
{
|
||||||
type: 'list',
|
type: 'list',
|
||||||
|
@ -312,9 +312,9 @@ function promptForCommand(argv) {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
return inquirer.prompt(questions).then(answers => {
|
const answers = await inquirer.prompt(questions)
|
||||||
|
|
||||||
return answers.command || argv._[0]
|
return answers.command || argv._[0]
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
promptForCommand(yargv)
|
promptForCommand(yargv)
|
||||||
|
|
|
@ -4,15 +4,18 @@ const {Spinner} = require('clui')
|
||||||
const privateToken = (process.env && process.env.PRIVATE_TOKEN) || ''
|
const privateToken = (process.env && process.env.PRIVATE_TOKEN) || ''
|
||||||
const loader = new Spinner('Loading...')
|
const loader = new Spinner('Loading...')
|
||||||
|
|
||||||
const getContributors = function(owner, name, token = privateToken) {
|
const getContributors = async function(owner, name, token = privateToken) {
|
||||||
loader.start()
|
loader.start()
|
||||||
const contributors = nyc.repoContributors({
|
|
||||||
|
const contributors = await nyc.repoContributors({
|
||||||
token,
|
token,
|
||||||
user: owner,
|
user: owner,
|
||||||
repo: name,
|
repo: name,
|
||||||
commits: true,
|
commits: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
loader.stop()
|
loader.stop()
|
||||||
|
|
||||||
return contributors
|
return contributors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,21 +3,26 @@ const Learner = require('ac-learn')
|
||||||
|
|
||||||
const JSON_PATH = `${__dirname}/learner.json`
|
const JSON_PATH = `${__dirname}/learner.json`
|
||||||
|
|
||||||
//@TODO: Use the JSON methods from `ac-learn` to get the whole thing saveable
|
async function getLearner() {
|
||||||
const learner = new Learner()
|
const learner = new Learner()
|
||||||
/* eslint-disable no-console */
|
|
||||||
|
try {
|
||||||
if (existsSync(JSON_PATH)) {
|
if (existsSync(JSON_PATH)) {
|
||||||
learner.loadAndDeserializeClassifier(JSON_PATH).then(classifier => {
|
learner.classifier = await learner.loadAndDeserializeClassifier(JSON_PATH)
|
||||||
learner.classifier = classifier
|
|
||||||
// console.log('Re-using existing classifier')
|
|
||||||
}, console.error)
|
|
||||||
} else {
|
} else {
|
||||||
learner.crossValidate(6)
|
learner.crossValidate(6)
|
||||||
learner.eval()
|
learner.eval()
|
||||||
learner.serializeAndSaveClassifier(JSON_PATH).then(_ => {
|
|
||||||
// console.log('Classifier saved', classifier)
|
|
||||||
}, console.error)
|
|
||||||
}
|
|
||||||
/* eslint-enable no-console */
|
|
||||||
|
|
||||||
module.exports = learner
|
await learner.serializeAndSaveClassifier(JSON_PATH)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return learner
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getLearner,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue