Skip to content

Commit 06cebab

Browse files
committed
feat: added the discover module + fetch command
For more info, please check #186
1 parent cdd00de commit 06cebab

File tree

5 files changed

+222
-14
lines changed

5 files changed

+222
-14
lines changed

src/cli.js

Lines changed: 165 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const generate = require('./generate')
1111
const util = require('./util')
1212
const repo = require('./repo')
1313
const updateContributors = require('./contributors')
14+
const {getContributors} = require('./discover')
15+
const learner = require('./discover/learner')
1416

1517
const cwd = process.cwd()
1618
const defaultRCFile = path.join(cwd, '.all-contributorsrc')
@@ -64,16 +66,48 @@ function startGeneration(argv) {
6466
function addContribution(argv) {
6567
util.configFile.readConfig(argv.config) // ensure the config file exists
6668
const username = argv._[1] === undefined ? undefined : String(argv._[1])
69+
/* Example: (for clarity & debugging purposes)
70+
{
71+
_: [ 'add' ],
72+
projectName: 'cz-cli',
73+
projectOwner: 'commitizen',
74+
repoType: 'github',
75+
repoHost: 'https://github.com',
76+
files: [ 'AC.md' ],
77+
imageSize: 100,
78+
commit: false,
79+
commitConvention: 'angular',
80+
contributors: [],
81+
contributorsPerLine: 7,
82+
'contributors-per-line': 7,
83+
config: '/mnt/c/Users/max/Projects/cz-cli/.all-contributorsrc',
84+
'$0': '../all-contributors-cli/src/cli.js'
85+
}
86+
*/
6787
const contributions = argv._[2]
6888
// Add or update contributor in the config file
69-
return updateContributors(argv, username, contributions).then(data => {
70-
argv.contributors = data.contributors
71-
return startGeneration(argv).then(() => {
72-
if (argv.commit) {
73-
return util.git.commit(argv, data)
74-
}
75-
})
76-
})
89+
return updateContributors(argv, username, contributions).then(
90+
data => {
91+
argv.contributors = data.contributors
92+
/* Example
93+
[ { login: 'Berkmann18',
94+
name: 'Maximilian Berkmann',
95+
avatar_url: 'https://avatars0.githubusercontent.com/u/8260834?v=4',
96+
profile: 'http://maxcubing.wordpress.com',
97+
contributions: [ 'code', 'ideas' ] },
98+
{ already in argv.contributors } ]
99+
*/
100+
return startGeneration(argv).then(
101+
() => {
102+
if (argv.commit) {
103+
return util.git.commit(argv, data)
104+
}
105+
},
106+
err => console.error('Generation fail:', err),
107+
)
108+
},
109+
err => console.error('Contributor Update fail:', err),
110+
)
77111
}
78112

79113
function checkContributors(argv) {
@@ -87,6 +121,7 @@ function checkContributors(argv) {
87121
configData.repoHost,
88122
)
89123
.then(repoContributors => {
124+
// console.dir(repoContributors) //['jfmengels', 'jakebolam', ...]
90125
const checkKey = repo.getCheckKey(configData.repoType)
91126
const knownContributions = configData.contributors.reduce((obj, item) => {
92127
obj[item[checkKey]] = item.contributions
@@ -123,6 +158,122 @@ function checkContributors(argv) {
123158
})
124159
}
125160

161+
function fetchContributors(argv) {
162+
// console.log('argv=', argv);
163+
// const configData = util.configFile.readConfig(argv.config)
164+
// console.log('configData')
165+
// console.dir(configData)
166+
167+
return getContributors(argv.projectOwner, argv.projectName).then(
168+
repoContributors => {
169+
// repoContributors = {prCreators, prCommentators, issueCreators, issueCommentators, reviewers, commitAuthors, commitCommentators}
170+
// console.dir(repoContributors)
171+
172+
// const checkKey = repo.getCheckKey(configData.repoType)
173+
// const knownContributions = configData.contributors.reduce((obj, item) => {
174+
// obj[item[checkKey]] = item.contributions
175+
// return obj
176+
// }, {})
177+
// console.log('knownContributions', knownContributions) //{ jfmengels: ['code', 'test', 'doc'], ...}
178+
// const knownContributors = configData.contributors.map(
179+
// contributor => contributor[checkKey],
180+
// )
181+
// console.log('knownContributors', knownContributors) //['kentcdodds', 'ben-eb', ...]
182+
183+
// let contributors = new Set(
184+
// repoContributors.prCreators.map(usr => usr.login),
185+
// )
186+
187+
// repoContributors.issueCreators.forEach(usr => contributors.add(usr.login))
188+
// repoContributors.reviewers.forEach(usr => contributors.add(usr.login))
189+
// repoContributors.commitAuthors.forEach(usr => contributors.add(usr.login))
190+
// contributors = Array.from(contributors)
191+
192+
// console.log('ctbs=', contributors);
193+
194+
//~1. Auto-add reviewers for review~
195+
//~2. Auto-add issue creators for any categories found~
196+
//~3. Auto-add commit authors~
197+
//4. Roll onto other contribution categories following https://www.draw.io/#G1uL9saIuZl3rj8sOo9xsLOPByAe28qhwa
198+
199+
const args = {...argv, _: []}
200+
const contributorsToAdd = []
201+
repoContributors.reviewers.forEach(usr => {
202+
// args._ = ['add', usr.login, 'review']
203+
// addContribution(args)
204+
contributorsToAdd.push({login: usr.login, contributions: ['review']})
205+
// console.log(
206+
// `Adding ${chalk.underline('Reviewer')} ${chalk.blue(usr.login)}`,
207+
// )
208+
})
209+
210+
repoContributors.issueCreators.forEach(usr => {
211+
// console.log('usr=', usr.login, 'labels=', usr.labels)
212+
const contributor = {
213+
login: usr.login,
214+
contributions: [],
215+
}
216+
usr.labels.forEach(lbl => {
217+
const guesses = learner.classify(lbl).filter(c => c && c !== 'null')
218+
if (guesses.length) {
219+
const category = guesses[0]
220+
// args._ = ['', usr.login, category]
221+
// addContribution(args)
222+
if (!contributor.contributions.includes(category))
223+
contributor.contributions.push(category)
224+
// console.log(
225+
// `Adding ${chalk.blue(usr.login)} for ${chalk.underline(category)}`,
226+
// )
227+
} //else console.warn(`Oops, I couldn't find any category for the "${lbl}" label`)
228+
})
229+
const existingContributor = contributorsToAdd.filter(
230+
ctrb => ctrb.login === usr.login,
231+
)
232+
if (existingContributor.length) {
233+
existingContributor[0].contributions = [
234+
...new Set(
235+
existingContributor[0].contributions.concat(
236+
contributor.contributions,
237+
),
238+
),
239+
]
240+
} else contributorsToAdd.push(contributor)
241+
})
242+
243+
repoContributors.commitAuthors.forEach(usr => {
244+
// const contributor = {
245+
// login: usr.login,
246+
// contributions: [],
247+
// }
248+
// console.log('commit auth:', usr)
249+
const existingContributor = contributorsToAdd.filter(
250+
ctrb => ctrb.login === usr.login,
251+
)
252+
if (existingContributor.length) {
253+
//there's no label or commit message info so use only code for now
254+
if (!existingContributor[0].contributions.includes('code')) {
255+
existingContributor[0].contributions.push('code')
256+
}
257+
} else
258+
contributorsToAdd.push({login: usr.login, contributions: ['code']})
259+
})
260+
261+
// console.log('contributorsToAdd=', contributorsToAdd)
262+
contributorsToAdd.forEach(contributor => {
263+
console.log(
264+
`Adding ${chalk.blue(contributor.login)} for ${chalk.underline(
265+
contributor.contributions.join('/'),
266+
)}`,
267+
)
268+
args._ = ['', contributor.login, contributor.contributions.join(',')]
269+
// if (contributor.contributions.length) addContribution(args)
270+
// else console.log('Skipping', contributor.login)
271+
})
272+
},
273+
err => console.error('fetch error:', err),
274+
)
275+
}
276+
126277
function onError(error) {
127278
if (error) {
128279
console.error(error.stack || error.message || error)
@@ -151,6 +302,10 @@ function promptForCommand(argv) {
151302
'Compare contributors from the repository with the credited ones',
152303
value: 'check',
153304
},
305+
{
306+
name: 'Fetch contributors from the repository',
307+
value: 'fetch',
308+
},
154309
],
155310
when: !argv._[0],
156311
default: 0,
@@ -173,6 +328,8 @@ promptForCommand(yargv)
173328
return addContribution(yargv)
174329
case 'check':
175330
return checkContributors(yargv)
331+
case 'fetch':
332+
return fetchContributors(yargv)
176333
default:
177334
throw new Error(`Unknown command ${command}`)
178335
}

src/contributors/index.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@ function isNewContributor(contributorList, username) {
1010

1111
module.exports = function addContributor(options, username, contributions) {
1212
const answersP = prompt(options, username, contributions)
13-
const contributorsP = answersP.then(answers =>
14-
add(options, answers.username, answers.contributions, repo.getUserInfo),
15-
)
13+
const contributorsP = answersP
14+
.then(answers =>
15+
add(options, answers.username, answers.contributions, repo.getUserInfo),
16+
)
17+
//eslint-disable-next-line no-console
18+
.catch(err => console.error('contributorsP error:', err))
1619

17-
const writeContributorsP = contributorsP.then(contributors =>
18-
util.configFile.writeContributors(options.config, contributors),
19-
)
20+
const writeContributorsP = contributorsP
21+
.then(contributors => {
22+
// console.log('opts.config=', options.config, 'contributors=', contributors)
23+
return util.configFile.writeContributors(options.config, contributors)
24+
})
25+
//eslint-disable-next-line no-console
26+
.catch(err => console.error('writeContributorsP error:', err))
2027

2128
return Promise.all([answersP, contributorsP, writeContributorsP]).then(
2229
res => {
@@ -32,5 +39,7 @@ module.exports = function addContributor(options, username, contributions) {
3239
),
3340
}
3441
},
42+
//eslint-disable-next-line no-console
43+
err => console.error('contributors fail: ', err),
3544
)
3645
}

src/discover/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const nyc = require('name-your-contributors')
2+
const {Spinner} = require('clui')
3+
4+
const privateToken = (process.env && process.env.PRIVATE_TOKEN) || ''
5+
const loader = new Spinner('Loading...')
6+
7+
const getContributors = function(owner, name, token = privateToken) {
8+
loader.start()
9+
const contributors = nyc.repoContributors({
10+
token,
11+
user: owner,
12+
repo: name,
13+
commits: true,
14+
})
15+
loader.stop()
16+
return contributors
17+
}
18+
19+
module.exports = {getContributors}

src/discover/learner.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const {existsSync} = require('fs')
2+
const Learner = require('ac-learn')
3+
4+
const JSON_PATH = `${__dirname}/learner.json`
5+
6+
//@TODO: Use the JSON methods from `ac-learn` to get the whole thing saveable
7+
const learner = new Learner()
8+
/* eslint-disable no-console */
9+
if (existsSync(JSON_PATH)) {
10+
learner.loadAndDeserializeClassifier(JSON_PATH).then(classifier => {
11+
learner.classifier = classifier
12+
// console.log('Re-using existing classifier')
13+
}, console.error)
14+
} else {
15+
learner.crossValidate(6)
16+
learner.eval()
17+
learner.serializeAndSaveClassifier(JSON_PATH).then(_ => {
18+
// console.log('Classifier saved', classifier)
19+
}, console.error)
20+
}
21+
/* eslint-enable no-console */
22+
23+
module.exports = learner

src/discover/learner.json

Whitespace-only changes.

0 commit comments

Comments
 (0)