Rebaseeeee
This commit is contained in:
alexcanessa 2017-10-16 02:45:59 +02:00 коммит произвёл Alex Canessa
Родитель 5eefffd2d7
Коммит 618973acbd
9 изменённых файлов: 3894 добавлений и 109 удалений

Просмотреть файл

@ -1,6 +1,6 @@
{
"presets": ["es2015", "es2017"],
"plugins": ["transform-runtime"],
"plugins": ["transform-runtime", "transform-object-rest-spread"],
"env": {
"test": {
"plugins": ["istanbul"]

Просмотреть файл

@ -45,7 +45,7 @@ module.exports = {
description: 'The token generated with repo access'
},
{
short: '-U',
short: '-a',
name: 'api-url',
valueType: '<url>',
description: 'Override the GitHub API URL, allows gren to connect to a private GHE installation'
@ -76,7 +76,7 @@ module.exports = {
defaultValue: 'issues'
},
{
short: '-a',
short: '-N',
name: 'include-messages',
valueType: '<merge|commits|all>',
description: 'Filter the messages added to the release notes. Only used when --data-source used is commits [commits]',

51
lib/gren-init.js Normal file
Просмотреть файл

@ -0,0 +1,51 @@
#!/usr/bin/env node
import gren from 'commander';
import { green } from 'chalk';
import ObjectAssignDeep from 'object-assign-deep';
import init from '../dist/_init';
import utils from '../dist/_utils';
import fs from 'fs';
gren
.name(`${green('gren')} release`)
.description('Initialise the module options.')
.parse(process.argv);
init()
.then(({
fileExist,
apiUrlType,
ignoreCommitsWithConfirm,
ignoreLabelsConfirm,
ignoreIssuesWithConfirm,
ignoreTagsWithConfirm,
fileType,
...data
}) => {
if (fileExist === 'abort') {
console.log('Command aborted.');
return;
}
if (fileExist === 'override') {
const fileContent = utils.writeConfigToFile(fileType, data);
utils.cleanConfig(true);
fs.writeFileSync(fileType, fileContent);
console.log(green(`\nGreat news! Your ${fileType} as been created!`));
return;
}
const currentConfig = utils.getConfigFromFile(process.cwd());
const fileContent = utils.writeConfigToFile(fileType, ObjectAssignDeep({}, currentConfig, data));
fs.writeFileSync(fileType, fileContent);
console.log(green(`\nGreat news! Your ${fileType} as been created!`));
})
.catch(error => {
console.log(error);
process.exit(1);
});

Просмотреть файл

@ -17,6 +17,7 @@ gren
.version(version)
.description(`gren (🤖 ) ${description}`)
.usage('<command> [options]')
.command('init', 'initialise the module')
.command('release', 'Release into chunk').alias('r')
.command('changelog', 'Write a motherfucking changelog').alias('c')
.command('examples', 'Show few examples of stuff that you can do <cmd>')

248
lib/src/_init.js Normal file
Просмотреть файл

@ -0,0 +1,248 @@
import inquirer from 'inquirer';
import utils from './_utils';
import GitHubInfo from './GitHubInfo';
import GitHub from 'github-api';
import chalk from 'chalk';
import { isUri } from 'valid-url';
const githubApi = new GitHubInfo();
const prompt = inquirer.createPromptModule();
const { GREN_GITHUB_TOKEN } = process.env;
if (!GREN_GITHUB_TOKEN) {
console.error(chalk.red('Can\'t find GREN_GITHUB_TOKEN. Please configure your environment') + chalk.blue('\nSee https://github.com/github-tools/github-release-notes#setup'));
process.exit(1);
}
const getInfo = async() => {
try {
const infos = await githubApi.repo;
return infos;
} catch (error) {
throw chalk.red('You have to run this command in a git repo folder');
}
};
const getLabels = async() => {
const { username, repo } = await getInfo();
try {
const gitHub = new GitHub({
GREN_GITHUB_TOKEN
});
const issues = gitHub.getIssues(username, repo);
const { data: labels } = await issues.listLabels();
return labels;
} catch (error) {
console.warn(chalk.bgYellow(chalk.black('I can\'t get your repo labels, make sure you are online to use the complete initialisation')));
return false;
}
};
const getQuestions = async() => {
const labels = await getLabels();
return [
{
name: 'apiUrlType',
type: 'list',
message: 'What type of APIs do you need?',
choices: [{
name: 'Normal',
value: false
},
{
name: 'GitHub Enterprise',
value: 'ghe'
}]
},
{
name: 'apiUrl',
type: 'input',
message: 'Write your Enterprise url',
suffix: chalk.blueBright(' e.g. https://MY_ENTERPRISE_DOMAIN/api/v3'),
when: ({ apiUrlType }) => apiUrlType === 'ghe',
validate: value => isUri(value) ? true : 'Please type a valid url'
},
{
name: 'dataSource',
type: 'list',
message: 'Where shall I get the informations from?',
choices: [{
value: 'issues',
name: 'Issues (Time based)'
},
{
value: 'milestones',
name: 'Issues (Milestone based)'
},
{
value: 'commits',
name: 'Commits'
},
{
value: 'prs',
name: 'Pull Requests'
}]
},
{
name: 'prefix',
type: 'input',
suffix: chalk.blueBright(' e.g. v'),
message: 'Do you want to add a prefix to release titles?'
},
{
name: 'includeMessages',
type: 'list',
message: 'Which type of commits do you want to include?',
choices: [{
value: 'merges',
name: 'Merges'
},
{
value: 'commits',
name: 'Commits'
},
{
value: 'all',
name: 'All'
}],
when: ({ dataSource }) => dataSource === 'commits'
},
{
name: 'ignoreCommitsWithConfirm',
type: 'confirm',
default: false,
message: 'Do you want to ignore commits containing certain words?',
when: ({ dataSource }) => dataSource === 'commits'
},
{
name: 'ignoreCommitsWith',
type: 'input',
message: 'Which ones? Use commas to separate.',
suffix: chalk.blueBright(' e.g. changelog,release'),
when: ({ ignoreCommitsWithConfirm, dataSource }) => dataSource === 'commits' && ignoreCommitsWithConfirm,
filter: value => value.replace(/\s/g).split(',')
},
{
name: 'ignoreLabelsConfirm',
type: 'confirm',
default: false,
message: 'Do you want to not output certain labels in the notes?',
when: ({ dataSource }) => Array.isArray(labels) && dataSource !== 'commits'
},
{
name: 'ignoreLabels',
type: 'checkbox',
message: 'Select the labels that should be excluded',
when: ({ ignoreLabelsConfirm }) => ignoreLabelsConfirm,
choices: Array.isArray(labels) && labels.map(({ name }) => name)
},
{
name: 'ignoreIssuesWithConfirm',
type: 'confirm',
message: 'Do you want to ignore issues/prs that have certain labels?',
default: false,
when: ({ dataSource }) => Array.isArray(labels) && dataSource !== 'commits'
},
{
name: 'ignoreIssuesWith',
type: 'checkbox',
message: 'Select the labels that should exclude the issue',
when: ({ ignoreIssuesWithConfirm }) => ignoreIssuesWithConfirm,
choices: Array.isArray(labels) && labels.map(({ name }) => name)
},
{
name: 'onlyMilestones',
type: 'confirm',
message: 'Do you want to only include issues/prs that belong to a milestone?',
default: false,
when: ({ dataSource }) => dataSource === 'issues' || dataSource === 'prs'
},
{
name: 'ignoreTagsWithConfirm',
type: 'confirm',
default: false,
message: 'Do you want to ignore tags containing certain words?'
},
{
name: 'ignoreTagsWith',
type: 'input',
message: 'Which ones? Use commas to separate',
suffix: chalk.blueBright(' e.g. -rc,-alpha,test'),
filter: value => value.replace(/\s/g).split(','),
when: ({ ignoreTagsWithConfirm }) => ignoreTagsWithConfirm
},
{
name: 'groupBy',
type: 'list',
message: 'Do you want to group your notes?',
when: ({ dataSource }) => dataSource !== 'commits',
choices: [{
value: false,
name: 'No'
},
{
value: 'label',
name: 'Use existing labels'
},
{
value: {},
name: 'Use custom configuration'
}]
},
{
name: 'milestoneMatch',
type: 'input',
default: 'Release {{tag_name}}',
message: 'How can I link your tags to Milestone titles?',
when: ({ dataSource }) => dataSource === 'milestones'
},
{
name: 'changelogFilename',
default: 'CHANGELOG.md',
message: 'What file name do you want for your changelog?',
vaidate: value => {
console.log(utils.getFileExtension(value));
return utils.getFileExtension(value) === 'md' ? true : 'Has to be a markdown file!';
}
},
{
name: 'fileExist',
type: 'list',
message: 'Looks like you already have a configuration file. What do you want me to do?',
choices: [{
value: 'abort',
name: 'Oops, stop this'
},
{
value: 'override',
name: 'Override my existing file'
},
{
value: 'merge',
name: 'Merge these settings over existing ones'
}],
when: () => Object.keys(utils.getConfigFromFile(process.cwd())).length > 0
},
{
name: 'fileType',
type: 'list',
message: 'Which extension would you like for your file?',
choices: utils.getFileTypes(),
when: ({ fileExist }) => fileExist !== 'abort'
}
];
};
const configure = async() => {
const questions = await getQuestions();
process.stdout.write('\n🤖 : Hello, I\'m going to ask a couple of questions, to set gren up!\n\n');
return prompt(questions);
};
export default configure;

Просмотреть файл

@ -1,6 +1,8 @@
const chalk = require('chalk');
const fs = require('fs');
const ora = require('ora');
const YAML = require('json2yaml');
const { js_beautify: beautify } = require('js-beautify');
require('require-yaml');
/**
@ -190,16 +192,42 @@ function requireConfig(filepath) {
* @return {Object} The configuration from the first found file or empty object
*/
function getConfigFromFile(path) {
return [
'.grenrc.yml',
'.grenrc.json',
'.grenrc.yaml',
'.grenrc.js',
'.grenrc'
]
return getFileTypes()
.reduce((carry, filename) => carry || requireConfig(path + '/' + filename), false) || {};
}
/**
* Return the extension of a filename
*
* @param {string} filename
*
* @return {string}
*/
function getFileExtension(filename) {
return filename.slice((Math.max(0, filename.lastIndexOf('.')) || Infinity) + 1);
}
/**
* Create the content for a configuratio file, based on extension and data
*
* @param {string} path
* @param {Object} data
*
* @return {string} File content
*/// istanbul ignore next
function writeConfigToFile(path, data) {
const extension = getFileExtension(getFileNameFromPath(path));
const dataType = {
yml: content => YAML.stringify(content),
yaml: content => YAML.stringify(content),
json: content => beautify(JSON.stringify(content)),
none: content => beautify(JSON.stringify(content)),
js: content => beautify(`module.exports = ${JSON.stringify(content)}`)
};
return dataType[extension || 'none'](data);
}
/**
* Get the filename from a path
*
@ -210,8 +238,49 @@ function getConfigFromFile(path) {
*
* @return {string}
*/
function getFileNameFromPath(path) {
return path.split('\\').pop().split('/').pop();
function getFileNameFromPath(path = '') {
return path.replace(/^.*[\\/]/, '');
}
/**
* Get the file types for the configuration
*
* @since 0.13.0
*
* @return {Array}
*/
function getFileTypes() {
return [
'.grenrc.yml',
'.grenrc.json',
'.grenrc.yaml',
'.grenrc.js',
'.grenrc'
];
}
/**
* Remove all the configuration files
*
* @since 0.13.0
*
* @param {Boolean} confirm Necessary to force the function.
*/
function cleanConfig(confirm, path = process.cwd()) {
if (confirm !== true) {
return;
}
getFileTypes().forEach(fileName => {
const file = `${path}/${fileName}`;
if (!fs.existsSync(file)) {
return false;
}
fs.unlinkSync(file);
return file;
});
}
/**
@ -221,15 +290,20 @@ function noop() {}
// Allow nodeunit to work. Has to be fixed.
module.exports = {
sortObject,
printTask,
task,
cleanConfig,
clearTasks,
dashToCamelCase,
isInRange,
convertStringToArray,
dashToCamelCase,
formatDate,
requireConfig,
getConfigFromFile,
noop
getFileExtension,
getFileNameFromPath,
getFileTypes,
isInRange,
noop,
printTask,
requireConfig,
sortObject,
task,
writeConfigToFile
};

3527
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -45,19 +45,28 @@
"homepage": "https://github.com/alexcanessa/github-release-notes#readme",
"dependencies": {
"babel-runtime": "^6.26.0",
"base-64": "^0.1.0",
"chalk": "^2.1.0",
"commander": "^2.11.0",
"connectivity": "^1.0.0",
"github-api": "^3.0.0",
"inquirer": "^3.3.0",
"install": "^0.10.1",
"js-beautify": "^1.7.4",
"json2yaml": "^1.1.0",
"minimist": "^1.2.0",
"node-fetch": "^1.7.3",
"npm": "^5.5.1",
"object-assign-deep": "^0.3.1",
"ora": "^1.3.0",
"require-yaml": "0.0.1"
"require-yaml": "0.0.1",
"valid-url": "^1.0.9"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-eslint": "^8.0.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.4.0",
"babel-preset-es2015": "^6.24.1",

Просмотреть файл

@ -87,13 +87,8 @@ describe('_utils.js', () => {
});
describe('requireConfig', () => {
const files = [
'.grenrc.yml',
'.grenrc.json',
'.grenrc.yaml',
'.grenrc.js',
'.grenrc'
].map(file => `${process.cwd()}/test/.temp/${file}`);
const files = utils.getFileTypes()
.map(file => `${process.cwd()}/test/.temp/${file}`);
const simpleObject = {
a: 1,
b: 2
@ -162,6 +157,50 @@ describe('_utils.js', () => {
});
});
describe('getFileExtension', () => {
it('Should return the extension of the file', () => {
assert.deepEqual(utils.getFileExtension('filename.txt'), 'txt', 'Just the filename');
assert.deepEqual(utils.getFileExtension('filename.something.txt'), 'txt', 'Filename with dots');
assert.deepEqual(utils.getFileExtension('.filename.txt'), 'txt', 'Filename that starts with dots');
});
});
describe('getFileNameFromPath', () => {
it('Should return the filename', () => {
assert.deepEqual(utils.getFileNameFromPath('path/to/filename.txt'), 'filename.txt', 'Simple path');
assert.deepEqual(utils.getFileNameFromPath('path/to/.filename.txt'), '.filename.txt', 'Simple path and filename with dot');
assert.deepEqual(utils.getFileNameFromPath('path/to\\ a \\(complex\\)/.filename.txt'), '.filename.txt', 'Complex path and filename with dot');
});
});
describe('getFileTypes', () => {
it('Should return an Array', () => {
assert.isArray(utils.getFileTypes(), 'Call the function');
});
});
describe('cleanConfig', () => {
const path = process.cwd() + '/test/.temp';
const fileContent = {
a: 1,
b: 2
};
beforeEach(() => {
fs.writeFileSync(`${path}/.grenrc`, JSON.stringify(fileContent));
});
it('Should not do anything', () => {
assert.isNotOk(utils.cleanConfig(), 'When no confirm has passed');
assert.isNotOk(utils.cleanConfig('hey'), 'When confirm has passed, but not true');
});
it('Should delete any config file present in path', () => {
utils.cleanConfig(true, path);
assert.isNotOk(fs.existsSync(`${path}/.grenrc`));
});
});
describe('noop', () => {
it('Should be a function that returns undefined', () => {
assert.deepEqual(utils.noop(), undefined, 'Running the function');