node-core-utils
Advanced tools
Comparing version 1.4.0 to 1.5.0
@@ -26,2 +26,4 @@ #!/usr/bin/env node | ||
data.logIntro(); | ||
const metadata = new MetadataGenerator(data).getMetadata(); | ||
@@ -28,0 +30,0 @@ const [SCISSOR_LEFT, SCISSOR_RIGHT] = MetadataGenerator.SCISSORS; |
@@ -5,6 +5,7 @@ 'use strict'; | ||
const fs = require('fs'); | ||
const { ClientRequest } = require('http'); | ||
const os = require('os'); | ||
const path = require('path'); | ||
const util = require('util'); | ||
const readline = require('readline'); | ||
const ghauth = util.promisify(require('ghauth')); | ||
const readFile = util.promisify(fs.readFile); | ||
@@ -20,3 +21,3 @@ const writeFile = util.promisify(fs.writeFile); | ||
async function auth() { | ||
async function auth(getCredentials = ghauth) { | ||
let username, token; | ||
@@ -27,4 +28,6 @@ // Try reading from ~/.ncurc | ||
} catch (e) { | ||
process.stdout.write('Reading configuration for node-core-utils failed:\n' + | ||
e.message + '\n'); | ||
process.stdout.write('If this is your first time running this command, ' + | ||
'follow the instructions to create an access token. ' + | ||
'If you prefer to create it yourself on Github, ' + | ||
'see https://github.com/joyeecheung/node-core-utils/blob/master/README.md.\n'); | ||
} | ||
@@ -38,33 +41,25 @@ | ||
// Ask the user for input and write to ~/.ncurc, then try again | ||
process.stdout.write('Please enter your Github user information:\n' + | ||
'[Github tokens can be created as described in ' + | ||
'https://help.github.com/articles/' + | ||
'creating-a-personal-access-token-for-the-command-line/]\n'); | ||
username = await prompt('Github user name'); | ||
token = await prompt('Github token'); | ||
check(username, token); | ||
const json = JSON.stringify({ username, token }, null, ' '); | ||
// Ask the user for input, create a token via github v3 API | ||
// then write to ~/.ncurc and try auth() again | ||
let credentials; | ||
try { | ||
credentials = await getCredentials({ | ||
noSave: true, | ||
scopes: ['user:email'], | ||
note: 'node-core-utils CLI tools' | ||
}); | ||
} catch (e) { | ||
process.stderr.write(`Could not get token: ${e.message}\n`); | ||
process.exit(1); | ||
} | ||
const json = JSON.stringify({ | ||
username: credentials.user, | ||
token: credentials.token | ||
}, null, ' '); | ||
await writeFile(authFile, json, { mode: | ||
0o600 /* owner read/write */ | ||
}); | ||
return auth(); | ||
} | ||
async function prompt(question) { | ||
return new Promise((resolve, reject) => { | ||
process.stdout.write(`${question}: `); | ||
const rl = readline.createInterface({ | ||
input: process.stdin | ||
}); | ||
rl.on('line', (line) => { | ||
rl.close(); | ||
process.stdin.removeListener('error', reject); | ||
process.stdin.removeListener('end', reject); | ||
resolve(line.trim()); | ||
}); | ||
process.stdin.on('error', reject); | ||
process.stdin.on('end', reject); | ||
}); | ||
return auth(getCredentials); | ||
} | ||
@@ -74,9 +69,17 @@ | ||
let cachedValue; | ||
return function() { | ||
return function(...args) { | ||
if (cachedValue !== undefined) { | ||
return cachedValue; | ||
} | ||
cachedValue = fn(); | ||
cachedValue = fn(...args); | ||
return cachedValue; | ||
}; | ||
} | ||
// This is an ugly hack to get around a bug in hyperquest & ghauth | ||
// which are not currently maintained | ||
const originalSetTimeout = ClientRequest.prototype.setTimeout; | ||
ClientRequest.prototype.setTimeout = function(msecs, ...args) { | ||
msecs = Math.min(msecs, Math.pow(2, 31) - 1); | ||
return originalSetTimeout.call(this, msecs, ...args); | ||
}; |
'use strict'; | ||
const FIXES_RE = /Fixes:\s*(\S+)/mg; | ||
const FIX_RE = /Fixes:\s*(\S+)/; | ||
const REFS_RE = /Refs?:\s*(\S+)/mg; | ||
const REF_RE = /Refs?:\s*(\S+)/; | ||
const FIXES_RE = /(Close[ds]?|Fix(e[ds])?|Resolve[sd]?)\s*:\s*(\S+)/mgi; | ||
const FIX_RE = /(Close[ds]?|Fix(e[ds])?|Resolve[sd]?)\s*:\s*(\S+)/i; | ||
const REFS_RE = /Refs?\s*:\s*(\S+)/mgi; | ||
const REF_RE = /Refs?\s*:\s*(\S+)/i; | ||
const { JSDOM } = require('jsdom'); | ||
@@ -13,3 +13,4 @@ | ||
class LinkParser { | ||
constructor(repo, html) { | ||
constructor(owner, repo, html) { | ||
this.owner = owner; | ||
this.repo = repo; | ||
@@ -20,3 +21,3 @@ this.OP = JSDOM.fragment(html); | ||
getFixesUrlsFromArray(arr) { | ||
const repo = this.repo; | ||
const { owner, repo } = this; | ||
const result = []; | ||
@@ -26,4 +27,4 @@ for (const item of arr) { | ||
if (!m) continue; | ||
const fix = m[1]; | ||
const url = fix.replace(/^#/, `${repo}#`).replace('#', '/issues/'); | ||
const fix = m[3]; | ||
const url = fix.replace(/^#/, `${owner}/${repo}#`).replace('#', '/issues/'); | ||
result.push(`https://github.com/${url}`); | ||
@@ -30,0 +31,0 @@ } |
@@ -27,2 +27,3 @@ 'use strict'; | ||
const prettyOptions = { | ||
crlf: EOL === '\r\n', | ||
forceColor: true, | ||
@@ -56,2 +57,3 @@ formatter(obj) { | ||
const logger = pino({ | ||
crlf: EOL === '\r\n', | ||
name: 'node-core-utils', | ||
@@ -58,0 +60,0 @@ safe: true, |
@@ -13,3 +13,4 @@ 'use strict'; | ||
constructor(data) { | ||
const { repo, pr, reviewers } = data; | ||
const { owner, repo, pr, reviewers } = data; | ||
this.owner = owner; | ||
this.repo = repo; | ||
@@ -27,6 +28,7 @@ this.pr = pr; | ||
pr: { url: prUrl, bodyHTML: op }, | ||
owner, | ||
repo | ||
} = this; | ||
const parser = new LinkParser(repo, op); | ||
const parser = new LinkParser(owner, repo, op); | ||
const fixes = parser.getFixes(); | ||
@@ -33,0 +35,0 @@ const refs = parser.getRefs(); |
@@ -45,8 +45,10 @@ 'use strict'; | ||
checkAll() { | ||
this.checkReviews(); | ||
this.checkPRWait(new Date()); | ||
this.checkCI(); | ||
const status = [ | ||
this.checkReviews(), | ||
this.checkPRWait(new Date()), | ||
this.checkCI() | ||
]; | ||
if (this.authorIsNew()) { | ||
this.checkAuthor(); | ||
status.push(this.checkAuthor()); | ||
} | ||
@@ -56,2 +58,4 @@ // TODO: maybe invalidate review after new commits? | ||
// does not support reading files changed | ||
return status.every((i) => i); | ||
} | ||
@@ -75,2 +79,3 @@ | ||
} = this; | ||
let status = true; | ||
@@ -80,2 +85,3 @@ if (rejected.length === 0) { | ||
} else { | ||
status = false; | ||
let hint = this.getTSCHint(rejected); | ||
@@ -88,2 +94,3 @@ logger.warn(`Rejections: ${rejected.length}${hint}`); | ||
if (approved.length === 0) { | ||
status = false; | ||
logger.warn(`Approvals: 0`); | ||
@@ -104,2 +111,3 @@ } else { | ||
if (tscApproval < 2) { | ||
status = false; | ||
logger.warn('semver-major requires at least two TSC approvals'); | ||
@@ -109,2 +117,4 @@ } | ||
} | ||
return status; | ||
} | ||
@@ -144,3 +154,6 @@ | ||
logger.warn(`${wait.timeLeft} hours left to land`); | ||
return false; | ||
} | ||
return true; | ||
} | ||
@@ -158,5 +171,8 @@ | ||
const ciMap = new CIParser(thread).parse(); | ||
let status = true; | ||
if (!ciMap.size) { | ||
logger.warn('No CI runs detected'); | ||
return false; | ||
} else if (!ciMap.get(FULL)) { | ||
status = false; | ||
logger.warn('No full CI runs detected'); | ||
@@ -169,2 +185,4 @@ } | ||
} | ||
return status; | ||
} | ||
@@ -182,3 +200,3 @@ | ||
if (!oddCommits.length) { | ||
return; | ||
return true; | ||
} | ||
@@ -194,2 +212,3 @@ | ||
} | ||
return false; | ||
} | ||
@@ -196,0 +215,0 @@ |
@@ -98,4 +98,26 @@ 'use strict'; | ||
} | ||
logIntro() { | ||
const { | ||
commits, | ||
logger, | ||
owner, | ||
prid, | ||
pr: { | ||
author: { login: author }, | ||
baseRefName, | ||
headRefName, | ||
labels, | ||
title | ||
} | ||
} = this; | ||
logger.info(`${title} #${prid}`); | ||
logger.info(`${author} wants to merge ${commits.length} ` + | ||
`commit${commits.length === 1 ? '' : 's'} into ` + | ||
`${owner}:${baseRefName} from ${author}:${headRefName}`); | ||
logger.info(`Labels: ${labels.nodes.map(label => label.name).join(' ')}`); | ||
} | ||
}; | ||
module.exports = PRData; |
{ | ||
"name": "node-core-utils", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "Utilities for Node.js core collaborators", | ||
@@ -11,6 +11,6 @@ "main": "./bin/metadata.js", | ||
"test": "npm run test-unit && npm run lint", | ||
"test-unit": "mocha --require intelli-espower-loader test/unit/*.test.js", | ||
"test-all": "mocha --require intelli-espower-loader test/**/*.test.js", | ||
"coverage": "nyc npm test", | ||
"coverage-all": "nyc npm run test-all", | ||
"test-unit": "mocha --require intelli-espower-loader test/unit/*.test.js --exit", | ||
"test-all": "mocha --require intelli-espower-loader test/**/*.test.js --exit", | ||
"coverage": "nyc --reporter=html --reporter=text --reporter=text-summary npm test", | ||
"coverage-all": "nyc --reporter=lcov --reporter=text --reporter=text-summary npm run test-all", | ||
"lint": "eslint .", | ||
@@ -32,4 +32,5 @@ "report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov" | ||
"chalk": "^2.2.0", | ||
"ghauth": "^3.2.1", | ||
"jsdom": "^11.3.0", | ||
"pino": "^4.8.0", | ||
"pino": "^4.9.0", | ||
"request": "^2.83.0", | ||
@@ -36,0 +37,0 @@ "request-promise-native": "^1.0.5", |
# Node.js Core Utilities | ||
[![npm](https://img.shields.io/npm/v/node-core-utils.svg?style=flat-square)](https://npmjs.org/package/node-core-utils) | ||
[![Build Status](https://travis-ci.org/joyeecheung/node-core-utils.svg?branch=master)](https://travis-ci.org/joyeecheung/node-core-utils) | ||
[![codecov](https://codecov.io/gh/joyeecheung/node-core-utils/branch/master/graph/badge.svg)](https://codecov.io/gh/joyeecheung/node-core-utils) | ||
[![Known Vulnerabilities](https://snyk.io/test/github/joyeecheung/node-core-utils/badge.svg)](https://snyk.io/test/github/joyeecheung/node-core-utils) | ||
[![Build Status](https://img.shields.io/travis/joyeecheung/node-core-utils.svg?style=flat-square)](https://travis-ci.org/joyeecheung/node-core-utils) | ||
[![codecov](https://img.shields.io/codecov/c/github/joyeecheung/node-core-utils.svg?style=flat-square)](https://codecov.io/gh/joyeecheung/node-core-utils) | ||
[![Known Vulnerabilities](https://snyk.io/test/github/joyeecheung/node-core-utils/badge.svg?style=flat-square)](https://snyk.io/test/github/joyeecheung/node-core-utils) | ||
CLI tools for Node.js Core collaborators | ||
CLI tools for Node.js Core collaborators. | ||
## Usage | ||
First, [follow these instructions](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) | ||
to create a personal access token. | ||
``` | ||
npm install -g node-core-utils | ||
``` | ||
After running any of the tools for the first-time, you will be asked to provide a | ||
GitHub username and password in order to create a personal access token. | ||
If you prefer not to provide your login credentials, [follow these instructions](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) | ||
to create the token. | ||
Note: We need to read the email of the PR author in order to check if it matches | ||
the email of the commit author. This requires checking the box `user:email` when | ||
the email of the commit author. This requires checking the box `user:email` when | ||
you create the personal access token (you can edit the permission later as well). | ||
@@ -27,6 +34,4 @@ | ||
If you install via npm, that's it. | ||
If you would prefer to build from the source, install and link: | ||
If you are using it from source, install and link: | ||
``` | ||
@@ -78,3 +83,3 @@ git clone git@github.com:joyeecheung/node-core-utils.git | ||
### TODO | ||
### Features | ||
@@ -91,1 +96,9 @@ - [x] Generate `PR-URL` | ||
- [ ] Check number of files changed (request pre-backport) | ||
### Contributing | ||
See [CONTRIBUTING.md](./CONTRIBUTING.md). | ||
### License | ||
MIT. See [LICENSE](./LICENSE). |
Sorry, the diff of this file is not supported yet
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
Network access
Supply chain riskThis module accesses the network.
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
39836
24
1075
102
7
1
+ Addedghauth@^3.2.1
+ Addedapplication-config@1.0.1(transitive)
+ Addedapplication-config-path@0.1.1(transitive)
+ Addedbl@1.1.2(transitive)
+ Addedduplexer2@0.0.2(transitive)
+ Addedghauth@3.2.1(transitive)
+ Addedhyperquest@2.0.0(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedmute-stream@0.0.8(transitive)
+ Addedprocess-nextick-args@1.0.7(transitive)
+ Addedread@1.0.7(transitive)
+ Addedreadable-stream@1.0.341.1.142.0.6(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addedthrough2@0.6.5(transitive)
Updatedpino@^4.9.0