Comparing version 0.6.2 to 0.7.0
@@ -12,3 +12,3 @@ 'use strict'; | ||
function github(method, ghPath, qs={}, json=true) { | ||
function github (method, ghPath, qs={}, json=true) { | ||
return rp({ | ||
@@ -39,11 +39,26 @@ uri: ghApi + ghPath, | ||
}, | ||
branches(orgRepo) { | ||
branches (orgRepo) { | ||
return allPages(`/repos/${orgRepo}/branches`); | ||
}, | ||
teams(orgRepo) { | ||
teams (orgRepo) { | ||
return allPages(`/repos/${orgRepo}/teams`); | ||
}, | ||
commits(orgRepo) { | ||
let {since, until} = options.commits; | ||
commits (orgRepo) { | ||
const {since, until} = options.commits; | ||
return allPages(`/repos/${orgRepo}/commits`, {since, until}); | ||
}, | ||
async prs (orgRepo) { | ||
// "/issues" API is used here as "/pulls" does not support "since" parameter | ||
// and "/search" has a very low rate limit | ||
const since = options.commits.since; | ||
const issues = await allPages(`/repos/${orgRepo}/issues`, {since, state: 'all'}); | ||
return issues.filter((i) => i.pull_request); | ||
}, | ||
async readme (orgRepo) { | ||
try { | ||
return await github.get(`/repos/${orgRepo}/readme`); | ||
} catch(err) { | ||
if (err.statusCode != 404) throw err; | ||
return err.response.body; | ||
} | ||
} | ||
@@ -55,23 +70,23 @@ }, | ||
}, | ||
team (org, teamName) { | ||
return github.getTeams(org).then(teams => { | ||
const team = teams.find(t => t.name == teamName); | ||
// TODO if team not found | ||
return allPages(`/teams/${team.id}/repos`); | ||
}); | ||
async team (org, teamName) { | ||
const teams = await github.getTeams(org); | ||
const team = teams.find(t => t.name == teamName); | ||
// TODO if team not found | ||
const repos = await allPages(`/teams/${team.id}/repos`); | ||
return repos.filter((r) => !r.fork); | ||
} | ||
}, | ||
getTeams: (org) => { | ||
if (orgTeams[org]) return Promise.resolve(orgTeams[org]); | ||
const p = orgTeams[org] = allPages(`/orgs/${org}/teams`); | ||
p.then( | ||
teams => (orgTeams[org] = teams), | ||
err => { console.error(err); delete orgTeams[org]; } | ||
); | ||
return p; | ||
async getTeams (org) { | ||
if (!orgTeams[org]) { | ||
orgTeams[org] = allPages(`/orgs/${org}/teams`); | ||
orgTeams[org] = await orgTeams[org]; | ||
} | ||
return orgTeams[org]; | ||
}, | ||
clearTeams: () => (orgTeams = {}), | ||
setOptions: (opts) => (options = opts) | ||
clearTeams() { | ||
orgTeams = {}; | ||
}, | ||
setOptions (opts) { | ||
options = opts; | ||
} | ||
}); | ||
@@ -88,18 +103,15 @@ | ||
const PAGE_SIZE = 30; | ||
function allPages(ghPath, qs={}, json=true) { | ||
async function allPages(ghPath, qs={}, json=true) { | ||
qs.per_page = PAGE_SIZE; | ||
let result = []; | ||
let page = 1; | ||
return getPage(); | ||
qs.page = 1; | ||
let result = [], rows; | ||
function getPage() { | ||
qs.page = page; | ||
return github.get(ghPath, qs, json) | ||
.then(rows => { | ||
result.push.apply(result, rows); | ||
if (rows.length < PAGE_SIZE) return result; | ||
page++; | ||
return getPage(); | ||
}); | ||
} | ||
do { | ||
rows = await github.get(ghPath, qs, json); | ||
if (!Array.isArray(rows)) throw new Error('expected array in response'); | ||
result = result.concat(rows); | ||
qs.page++; | ||
} while (rows && rows.length >= PAGE_SIZE); | ||
return result; | ||
} |
@@ -27,11 +27,11 @@ 'use strict'; | ||
const results = {}; | ||
for (const repoOrg in repoSourceRules) { | ||
const repoResults = results[repoOrg] = {}; | ||
const repoSources = repoSourceRules[repoOrg]; | ||
for (const orgRepo in repoSourceRules) { | ||
const repoResults = results[orgRepo] = {}; | ||
const repoSources = repoSourceRules[orgRepo]; | ||
for (const source in repoSources) { | ||
const sourceRules = repoSources[source]; | ||
const sourceData = await github.getSource[source](repoOrg); | ||
const sourceData = await github.getSource[source](orgRepo); | ||
for (const ruleName in sourceRules) { | ||
const ruleConfigs = sourceRules[ruleName]; | ||
repoResults[ruleName] = await checkRule(ruleName, ruleConfigs, sourceData); | ||
repoResults[ruleName] = await checkRule(orgRepo, ruleName, ruleConfigs, sourceData); | ||
} | ||
@@ -98,4 +98,4 @@ } | ||
function removeDisabledRules() { | ||
for (const repoOrg in repoSourceRules) { | ||
const repoSources = repoSourceRules[repoOrg]; | ||
for (const orgRepo in repoSourceRules) { | ||
const repoSources = repoSourceRules[orgRepo]; | ||
for (const source in repoSources) { | ||
@@ -106,3 +106,3 @@ if (Object.keys(repoSources[source]).length == 0) | ||
if (Object.keys(repoSources).length == 0) | ||
delete repoSourceRules[repoOrg]; | ||
delete repoSourceRules[orgRepo]; | ||
} | ||
@@ -216,3 +216,3 @@ } | ||
async function checkRule(ruleName, ruleConfigs, sourceData) { | ||
async function checkRule(orgRepo, ruleName, ruleConfigs, sourceData) { | ||
const ruleDefinition = execute.getRuleDefinition(ruleName); | ||
@@ -225,3 +225,3 @@ if (typeof ruleDefinition.check != 'function') { | ||
for (const ruleCfg of ruleConfigs) { | ||
const result = await ruleDefinition.check(ruleCfg, sourceData, github); | ||
const result = await ruleDefinition.check(ruleCfg, sourceData, orgRepo, github); | ||
if (!result.valid) { | ||
@@ -228,0 +228,0 @@ result.mode = ruleCfg.mode; |
@@ -105,2 +105,3 @@ 'use strict'; | ||
title: 'Commit names do not satisfy requirements', | ||
remind: false, | ||
comments: { | ||
@@ -107,0 +108,0 @@ create: 'Please use semantic commit names', |
{ | ||
"name": "gh-lint", | ||
"version": "0.6.2", | ||
"version": "0.7.0", | ||
"description": "Rule-based command-line tool for auditing GitHub repositories", | ||
@@ -5,0 +5,0 @@ "main": "lib/execute/index.js", |
@@ -33,2 +33,3 @@ # gh-lint | ||
- repo-homepage: check that repo has homepage specified in GitHub UI | ||
- repo-readme: check that repo has README file | ||
- repo-team: check that repo is assigned to one of specified teams | ||
@@ -50,2 +51,10 @@ | ||
#### PR rules | ||
By default, these rules analyse the PRs for the last 30 days. It can be changed using option `--since` (see below). | ||
- pr-review: check that all PRs have at least one review that approved them | ||
## Options | ||
@@ -52,0 +61,0 @@ |
@@ -80,2 +80,3 @@ { | ||
"title": { "type": "string" }, | ||
"remind": { "type": "boolean" }, | ||
"comments": { | ||
@@ -82,0 +83,0 @@ "type": "object", |
@@ -51,2 +51,17 @@ 'use strict'; | ||
} | ||
}, | ||
issues: { | ||
milo: { | ||
list() { | ||
mock('/repos/milojs/milo/issues?since=2017-05-01&state=all&per_page=30&page=1', | ||
'../fixtures/milojs_milo_issues.json'); | ||
}, | ||
pull(number) { | ||
mock(`/repos/milojs/milo/pulls/${number}`, `../fixtures/milojs_milo_pull${number}.json`); | ||
}, | ||
reviews(pullNumber) { | ||
mock(`/repos/milojs/milo/pulls/${pullNumber}/reviews?per_page=30&page=1`, | ||
`../fixtures/milojs_milo_pull${pullNumber}_reviews.json`); | ||
} | ||
} | ||
} | ||
@@ -56,4 +71,4 @@ }; | ||
function mock(apiPath, file) { | ||
nock('https://api.github.com').get(apiPath).reply(200, require(file)); | ||
function mock(apiPath, file, statusCode=200) { | ||
nock('https://api.github.com').get(apiPath).reply(statusCode, require(file)); | ||
} | ||
@@ -60,0 +75,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
873589
164
16379
71