diff --git a/.gitignore b/.gitignore index 28e9544c..341f9a07 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ coverage dist bin test/**.js.xml +.vscode diff --git a/lib/gren-init.js b/lib/gren-init.js index 9d4f822c..2ff1f214 100644 --- a/lib/gren-init.js +++ b/lib/gren-init.js @@ -38,7 +38,7 @@ init() return; } - const currentConfig = utils.getConfigFromFile(process.cwd()); + const currentConfig = utils.getGrenConfig(process.cwd()); const fileContent = utils.writeConfigToFile(fileType, ObjectAssignDeep({}, currentConfig, data)); fs.writeFileSync(fileType, fileContent); diff --git a/lib/src/Program.js b/lib/src/Program.js index d1e0a784..6f5b5762 100644 --- a/lib/src/Program.js +++ b/lib/src/Program.js @@ -1,6 +1,6 @@ import GitHubInfo from './GitHubInfo'; import program from 'commander'; -import { getConfigFromFile } from './_utils.js'; +import { getGrenConfig } from './_utils.js'; /** Class creating a Commander program, managing the options passed via bash and config file. */ class Program { @@ -18,7 +18,7 @@ class Program { this.options = Object.assign( {}, - getConfigFromFile(props.cwd, program.config), + getGrenConfig(props.cwd, program.config), this._getOptionsFromObject(this.program, this.defaults) ); } diff --git a/lib/src/_init.js b/lib/src/_init.js index 60e6c681..1ffec874 100644 --- a/lib/src/_init.js +++ b/lib/src/_init.js @@ -226,7 +226,7 @@ const getQuestions = async() => { value: 'merge', name: 'Merge these settings over existing ones' }], - when: () => Object.keys(utils.getConfigFromFile(process.cwd())).length > 0 + when: () => Object.keys(utils.getGrenConfig(process.cwd())).length > 0 }, { name: 'fileType', diff --git a/lib/src/_utils.js b/lib/src/_utils.js index 47d95570..dcbbf6c4 100644 --- a/lib/src/_utils.js +++ b/lib/src/_utils.js @@ -4,6 +4,7 @@ const ora = require('ora'); const YAML = require('json2yaml'); const Path = require('path'); const { js_beautify: beautify } = require('js-beautify'); +const requireFromUrl = require('require-from-url/sync'); require('require-yaml'); /** @@ -176,6 +177,8 @@ function requireConfig(filepath) { return false; } + process.stdout.write(chalk.cyan(`Getting gren config from local file ${filepath}\n`)); + if (getFileNameFromPath(filepath).match(/\./g).length === 1) { return JSON.parse(fs.readFileSync(filepath, 'utf8')); } @@ -187,7 +190,7 @@ function requireConfig(filepath) { * Get configuration from the one of the config files * * @since 0.6.0 - * @public + * @private * * @param {string} path Path where to look for config files * @return {Object} The configuration from the first found file or empty object @@ -292,6 +295,71 @@ function cleanConfig(confirm, path = process.cwd()) { }); } +/** + * judge whether to get config from remote uri + * @since 0.18.0 + * @private + * + * @param {string} path + * + * @returns {string} + */ +function getRemoteUrl(path) { + const pkgPath = Path.join(path, 'package.json'); + const pkgExist = fs.existsSync(pkgPath); + const { gren = '' } = pkgExist ? require(pkgPath) : {}; + return gren; +} + +/** + * get config from remote + * @since 0.18.0 + * @private + * + * @param {string} path Path where to look for config files + * @return {Object} The configuration from the first found file or empty object +*/ +function getConfigFromRemote(url) { + if (!url) return null; + + process.stdout.write(chalk.cyan(`Fetching gren config from remote: ${url}\n`)); + + let config = null; + try { + config = requireFromUrl(url); + } catch (error) { + // console.error(error); + process.stdout.write(chalk.cyan(`Fetched remote config fail: ${url}\n`)); + throw new Error(error); + } + + process.stdout.write(chalk.cyan(`Fetched remote config succeed`)); + + return config; +} + +/** + * combine getConfigFromRemote & getGrenConfig + * @since 0.18.0 + * @public + * + * @param {string} path Path where to look for config files + * @return {Object} The configuration from the first found file or empty object +*/ +function getGrenConfig(path, ...args) { + const remoteUrl = getRemoteUrl(path); + let config; + if (remoteUrl) { + config = getConfigFromRemote(remoteUrl); + } + + if (!config) { + config = getConfigFromFile(path, ...args); + } + + return config; +} + /** * Just a noop function */ @@ -305,6 +373,9 @@ module.exports = { dashToCamelCase, formatDate, getConfigFromFile, + getRemoteUrl, + getConfigFromRemote, + getGrenConfig, getFileExtension, getFileNameFromPath, getFileTypes, diff --git a/package-lock.json b/package-lock.json index 1c7910d3..407c9679 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3083,7 +3083,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3104,12 +3105,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3124,17 +3127,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3251,7 +3257,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3263,6 +3270,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3277,6 +3285,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3284,12 +3293,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3308,6 +3319,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3388,7 +3400,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3400,6 +3413,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3485,7 +3499,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3521,6 +3536,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3540,6 +3556,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3583,12 +3600,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -9052,6 +9071,7 @@ "version": "0.1.4", "bundled": true, "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -9382,7 +9402,8 @@ "is-buffer": { "version": "1.1.6", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "is-builtin-module": { "version": "1.0.0", @@ -9493,6 +9514,7 @@ "version": "3.2.2", "bundled": true, "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -9539,7 +9561,8 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "lru-cache": { "version": "4.1.3", @@ -9805,7 +9828,8 @@ "repeat-string": { "version": "1.6.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "require-directory": { "version": "2.1.1", @@ -11273,6 +11297,11 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-url": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/require-from-url/-/require-from-url-3.1.3.tgz", + "integrity": "sha512-SWYVQr6rZMumhsE0MGL3caGtBNDBPQRm7JV4fsxb8Nc+LR42QkmLPP56P+Y9jncZLNrrk4SpE/Ozaf8Jo3ialA==" + }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", diff --git a/package.json b/package.json index a2430398..b121c6d1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "github-release-notes", + "name": "@femessage/github-release-notes", "version": "0.17.0", "description": "Create a release from a tag and uses issues or commits to creating the release notes. It also can generate a CHANGELOG.md file based on the release notes (or generate a brand new).", "main": "./github-release-notes.js", @@ -14,7 +14,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/github-tools/github-release-notes.git" + "url": "git+https://github.com/femessage/github-release-notes.git" }, "directories": { "bin": "./bin", @@ -37,13 +37,14 @@ ], "author": "alexcanessa", "contributors": [ - "Alex Canessa " + "Alex Canessa ", + "Han " ], "license": "ISC", "bugs": { - "url": "https://github.com/alexcanessa/github-release-notes/issues" + "url": "https://github.com/femessage/github-release-notes/issues" }, - "homepage": "https://github.com/alexcanessa/github-release-notes#readme", + "homepage": "https://github.com/femessage/github-release-notes#readme", "dependencies": { "babel-runtime": "^6.26.0", "base-64": "^0.1.0", @@ -61,6 +62,7 @@ "object-assign-deep": "^0.3.1", "ora": "^1.3.0", "regex-match-all": "^1.0.2", + "require-from-url": "^3.1.3", "require-yaml": "0.0.1", "valid-url": "^1.0.9" }, @@ -96,5 +98,6 @@ "nyc": "^13.1.0", "tap-nyan": "^1.1.0", "yamljs": "^0.3.0" - } + }, + "gren": "https://raw.githubusercontent.com/FEMessage/.github/master/.grenrc.js" } diff --git a/test/_utils.spec.js b/test/_utils.spec.js index 73f64e95..3a788d74 100644 --- a/test/_utils.spec.js +++ b/test/_utils.spec.js @@ -174,6 +174,36 @@ describe('_utils.js', () => { }); }); + describe('getRemoteUrl', () => { + const filename = process.cwd() + '/test/.temp/package.json'; + const fileContent = { + gren: 'testUri' + }; + + beforeEach(() => { + fs.writeFileSync(filename, JSON.stringify(fileContent)); + }); + + it('Should always return a String', () => { + assert.isOk(typeof utils.getRemoteUrl(process.cwd() + '/test/.temp') === 'string', 'The type is a string'); + assert.deepEqual(utils.getRemoteUrl(process.cwd() + '/test/.temp'), fileContent.gren, 'Given the right package path'); + assert.deepEqual(utils.getRemoteUrl(process.cwd() + '/test'), '', 'Given a path with no package.json'); + }); + + afterEach(() => { + fs.unlinkSync(filename); + }); + }); + + describe('getConfigFromRemote', () => { + const grenRemote = 'https://raw.githubusercontent.com/FEMessage/github-release-notes/master/.grenrc.js'; + const grenrc = require(process.cwd() + '/.grenrc.js'); + + it('Should fetch config from remote url', () => { + assert.deepEqual(utils.getConfigFromRemote(grenRemote), grenrc, 'Given a remote gren config'); + }); + }); + describe('getFileExtension', () => { it('Should return the extension of the file', () => { assert.deepEqual(utils.getFileExtension('filename.txt'), 'txt', 'Just the filename');