From 63c61ad80b18c97640dcbff137c868f5d9f783a9 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Tue, 29 Jan 2019 11:38:54 -0500 Subject: [PATCH 01/18] Reorder files for test and install packages --- package-lock.json | 151 ++++++++++++++++++++++++++++++ package.json | 8 +- test/{ => integration}/cleanup.js | 6 +- test/mocha.opts | 1 + 4 files changed, 161 insertions(+), 5 deletions(-) rename test/{ => integration}/cleanup.js (68%) create mode 100644 test/mocha.opts diff --git a/package-lock.json b/package-lock.json index c798d9d..70818f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,6 +95,12 @@ "es-abstract": "^1.7.0" } }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -132,6 +138,12 @@ "concat-map": "0.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -144,6 +156,29 @@ "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", "dev": true }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -159,6 +194,12 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -237,6 +278,15 @@ "ms": "^2.1.1" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -252,6 +302,12 @@ "object-keys": "^1.0.12" } }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -696,6 +752,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -722,6 +784,12 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -742,6 +810,12 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -1016,6 +1090,71 @@ "minimist": "0.0.8" } }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -1219,6 +1358,12 @@ "pify": "^2.0.0" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -1532,6 +1677,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", diff --git a/package.json b/package.json index 91f8e85..003d8fb 100644 --- a/package.json +++ b/package.json @@ -20,18 +20,22 @@ "scripts": { "postinstall": "node --no-warnings install/index.js", "start": "node --no-warnings src/index.js", - "cleanup": "node --no-warnings test/cleanup.js" + "cleanup": "node --no-warnings test/integration/cleanup.js", + "test": "mocha" }, "engines": { "node": ">=10.9.0" }, "devDependencies": { + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", "eslint": "^5.12.0", "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", "eslint-plugin-node": "^8.0.1", - "eslint-plugin-react": "^7.12.3" + "eslint-plugin-react": "^7.12.3", + "mocha": "^5.2.0" }, "dependencies": { "inquirer": "^6.2.1" diff --git a/test/cleanup.js b/test/integration/cleanup.js similarity index 68% rename from test/cleanup.js rename to test/integration/cleanup.js index 4dcd220..109ca45 100644 --- a/test/cleanup.js +++ b/test/integration/cleanup.js @@ -1,5 +1,5 @@ -const utils = require('../src/utils'); -const githubHandler = require('../src/githubHandler'); +const utils = require('../../src/utils'); +const githubHandler = require('../../src/githubHandler'); function cleanup(path = 'a-demo-project') { const name = utils.string.normalizeName(path); @@ -12,4 +12,4 @@ function cleanup(path = 'a-demo-project') { githubHandler.deleteRepo(name, 'nmicht'); } -cleanup(process.argv[2]); +// cleanup(process.argv[2]); diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..4a52320 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +--recursive From 98fdfdde19408fa61ab0c3b980c036c423d8b7b2 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Tue, 29 Jan 2019 11:39:18 -0500 Subject: [PATCH 02/18] Unit test for auth handler --- src/auth/index.js | 5 ++-- test/unit-tests/auth/index.js | 43 +++++++++++++++++++++++++++++ test/unit-tests/auth/test-auth.json | 16 +++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 test/unit-tests/auth/index.js create mode 100644 test/unit-tests/auth/test-auth.json diff --git a/src/auth/index.js b/src/auth/index.js index 4e7df89..5691159 100644 --- a/src/auth/index.js +++ b/src/auth/index.js @@ -39,7 +39,7 @@ async function findUser(user, jsonPath = settings.authPath) { * Get the Github token from the auth file * @param {String} user The user owner of the token * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file - * @return {String} The github token or empty string. + * @return {String|undefined} The github token or undefined if there is no token. */ async function getToken(user, jsonPath = settings.authPath) { let userData; @@ -50,7 +50,7 @@ async function getToken(user, jsonPath = settings.authPath) { userData = await firstUser(); } - const { token } = userData || ''; + const token = userData ? userData.token : undefined; return token; } @@ -99,6 +99,7 @@ async function updateAuthFile(user, token, jsonPath = settings.authPath) { } module.exports = { + getFileData, firstUser, findUser, getToken, diff --git a/test/unit-tests/auth/index.js b/test/unit-tests/auth/index.js new file mode 100644 index 0000000..8bf57f0 --- /dev/null +++ b/test/unit-tests/auth/index.js @@ -0,0 +1,43 @@ +const assert = require('assert'); +const should = require('chai').should(); + +const auth = require('../../../src/auth'); + +describe('Authentication file management', () => { + const filePath = 'test/unit-tests/auth/test-auth.json'; + + it('getFileData should return a valid object', async () => { + const file = await auth.getFileData(filePath); + file.should.be.a('object'); + }); + + it('The object from file should have github property', async () => { + const file = await auth.getFileData(filePath); + file.should.have.property('github'); + }); + + it('firsUser should return the first user', async () => { + const user = await auth.firstUser(filePath); + user.user.should.be.equals('first'); + }); + + it('findUser should return the user', async () => { + const user = await auth.findUser('second', filePath); + user.user.should.be.equals('second'); + }); + + it('findUser should return undefined when the user is not found', async () => { + const user = await auth.findUser('forth', filePath); + should.equal(user, undefined); + }); + + it('getToken should return the token when the user exists', async () => { + const token = await auth.getToken('first', filePath); + token.should.be.equals('the-token'); + }); + + it('getToken should return undefined if the user does not exist', async () => { + const token = await auth.getToken('forth', filePath); + should.equal(token, undefined); + }); +}); diff --git a/test/unit-tests/auth/test-auth.json b/test/unit-tests/auth/test-auth.json new file mode 100644 index 0000000..61047d9 --- /dev/null +++ b/test/unit-tests/auth/test-auth.json @@ -0,0 +1,16 @@ +{ + "github": [ + { + "user": "first", + "token": "the-token" + }, + { + "user": "second", + "token": "second-token" + }, + { + "user": "third", + "token": "third-token" + } + ] +} From 77151ee9762e1b85af755f03a8224d59ca87c700 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Tue, 29 Jan 2019 11:39:42 -0500 Subject: [PATCH 03/18] Unit test for gitHandler --- src/gitHandler/index.js | 10 ++--- test/unit-tests/gitHandler/index.js | 58 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 test/unit-tests/gitHandler/index.js diff --git a/src/gitHandler/index.js b/src/gitHandler/index.js index 8ee2189..c42ca07 100644 --- a/src/gitHandler/index.js +++ b/src/gitHandler/index.js @@ -2,19 +2,19 @@ const utils = require('../utils'); /** * Get the git user property from the git configuration - * @param {String} prop The property requested, ex. name - * @return {String} The git config value for the user + * @param {String} prop The property requested, ex. name + * @return {String|undefined} The git config value for the user */ async function userValue(prop) { - let data = ''; + let data; try { - data = await utils.process.execp(`git config user.${prop}`); + data = (await utils.process.execp(`git config user.${prop}`)).trim(); } catch (error) { console.error(error); } - return data.trim(); + return data; } /** diff --git a/test/unit-tests/gitHandler/index.js b/test/unit-tests/gitHandler/index.js new file mode 100644 index 0000000..11e7f11 --- /dev/null +++ b/test/unit-tests/gitHandler/index.js @@ -0,0 +1,58 @@ +const chai = require("chai"); +const chaiAsPromised = require("chai-as-promised"); +chai.use(chaiAsPromised); +const should = chai.should(); +const fs = require('fs').promises; +const path = require('path'); +const os = require('os'); + +const gitHandler = require('../../../src/gitHandler'); +const utils = require('../../../src/utils'); + + +describe('Git handler', () => { + const parentPath = path.resolve(path.join(os.homedir(), 'temp')); + const folderPath = path.resolve(path.join(os.homedir(), 'temp', 'project')); + + before('create a project test folder', async () => { + await fs.mkdir(parentPath, { recursive: true }); + await fs.mkdir(folderPath, { recursive: true }); + }); + + after('clean up the project test folder', async () => { + await utils.files.deleteDirRecursive(parentPath); + }); + + it('userValue for name should return a string without error', async () => { + const value = await gitHandler.userValue('name'); + value.should.be.a('string'); + }); + + it('userValue for email should return a string without error', async () => { + const value = await gitHandler.userValue('email'); + value.should.be.a('string'); + }); + + it('userValue for not real value should return undefined', async () => { + const value = await gitHandler.userValue('false'); + should.equal(value, undefined); + }); + + it('git init creates a hidden .git folder', async () => { + await gitHandler.init(folderPath); + return fs.access(path.join(folderPath, '.git')).should.not.eventually.be.rejectedWith(Error); + }); + + it('commit should appear on log', async () => { + await utils.process.execp('touch README.md', folderPath); + await gitHandler.commit(folderPath, 'Initial commit'); + const resp = await utils.process.execp('git log --pretty=format:%s -1', folderPath); + resp.should.equal('Initial commit'); + }); + + it('add remote should work', async () => { + await gitHandler.addRemote(folderPath, 'someurl', 'origin'); + const resp = await utils.process.execp('git remote get-url origin', folderPath); + resp.should.equal('someurl'); + }); +}); From fa514831c50a221cd1f21c2c9034bd3d40541d6f Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Tue, 29 Jan 2019 17:06:42 -0500 Subject: [PATCH 04/18] Rename tests and adding test for utils.files and utils.string --- README.md | 2 +- package-lock.json | 132 +++++++----------- package.json | 10 +- src/utils/files.js | 8 +- .../auth/{index.js => index.test.js} | 5 - .../gitHandler/{index.js => index.test.js} | 3 +- test/unit-tests/utils/file.txt | 1 + test/unit-tests/utils/files.test.js | 45 ++++++ test/unit-tests/utils/string.test.js | 0 9 files changed, 108 insertions(+), 98 deletions(-) rename test/unit-tests/auth/{index.js => index.test.js} (89%) rename test/unit-tests/gitHandler/{index.js => index.test.js} (94%) create mode 100644 test/unit-tests/utils/file.txt create mode 100644 test/unit-tests/utils/files.test.js create mode 100644 test/unit-tests/utils/string.test.js diff --git a/README.md b/README.md index cb439bb..89c0205 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ An [npm initializer][npm/init] to scaffold a node project and include basic tool ## Requirements - `npm >= 6.5` -- `node >= 10.1.0` +- `node >= 10.12.0` ## Usage diff --git a/package-lock.json b/package-lock.json index 70818f1..7ae1c22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -318,9 +318,9 @@ } }, "emoji-regex": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "error-ex": { @@ -363,9 +363,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.0.tgz", - "integrity": "sha512-LntwyPxtOHrsJdcSwyQKVtHofPHdv+4+mFwEe91r2V13vqpM8yLr7b1sW+Oo/yheOPkWYsYlYJCkzlFAt8KV7g==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.1.tgz", + "integrity": "sha512-54NV+JkTpTu0d8+UYSA8mMKAG4XAsaOrozA9rCW7tgneg1mevcL7wIotPC+fZ0SkWwdhNqoXoxnQCTBp7UvTsg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -457,13 +457,13 @@ } }, "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", + "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", "dev": true, "requires": { "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { @@ -494,21 +494,21 @@ } }, "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", + "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", "dev": true, "requires": { "contains-path": "^0.1.0", - "debug": "^2.6.8", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.3.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" + "resolve": "^1.9.0" }, "dependencies": { "debug": { @@ -539,17 +539,17 @@ } }, "eslint-plugin-jsx-a11y": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz", - "integrity": "sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.0.tgz", + "integrity": "sha512-KpibpIdKT0nbDG7G/ILWoZoN5G9cj3h1IHARxzvHk5Nt2LQ7oPUutbO9QbT1FKNHLPZB6BaoA1ASSLOiJZVEUQ==", "dev": true, "requires": { "aria-query": "^3.0.0", "array-includes": "^3.0.3", "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.1", + "axobject-query": "^2.0.2", "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^6.5.1", + "emoji-regex": "^7.0.2", "has": "^1.0.3", "jsx-ast-utils": "^2.0.1" } @@ -577,9 +577,9 @@ } }, "eslint-plugin-react": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.3.tgz", - "integrity": "sha512-WTIA3cS8OzkPeCi4KWuPmjR33lgG9r9Y/7RmnLTRw08MZKgAfnK/n3BO4X0S67MPkVLazdfCNT/XWqcDu4BLTA==", + "version": "7.12.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz", + "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==", "dev": true, "requires": { "array-includes": "^3.0.3", @@ -713,13 +713,12 @@ } }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^2.0.0" } }, "flat-cache": { @@ -1037,14 +1036,6 @@ "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { @@ -1317,13 +1308,10 @@ } }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -1370,28 +1358,13 @@ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^1.0.0" + "find-up": "^2.1.0" } }, "pluralize": { @@ -1447,17 +1420,6 @@ "requires": { "find-up": "^2.0.0", "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } } }, "regexpp": { @@ -1547,9 +1509,9 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "slice-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz", - "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { "ansi-styles": "^3.2.0", @@ -1633,14 +1595,14 @@ } }, "table": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.1.tgz", - "integrity": "sha512-qmhNs2GEHNqY5fd2Mo+8N1r2sw/rvTAAvBZTaTx+Y7PHLypqyrxr1MdIu0pLw6Xvl/Gi4ONu/sdceP8vvUjkyA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/table/-/table-5.2.2.tgz", + "integrity": "sha512-f8mJmuu9beQEDkKHLzOv4VxVYlU68NpdzjbGPl69i4Hx0sTopJuNxuzJd17iV2h24dAfa93u794OnDA5jqXvfQ==", "dev": true, "requires": { "ajv": "^6.6.1", "lodash": "^4.17.11", - "slice-ansi": "2.0.0", + "slice-ansi": "^2.0.0", "string-width": "^2.1.1" } }, diff --git a/package.json b/package.json index 003d8fb..07c7f1b 100644 --- a/package.json +++ b/package.json @@ -24,17 +24,17 @@ "test": "mocha" }, "engines": { - "node": ">=10.9.0" + "node": ">=10.12.0" }, "devDependencies": { "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "eslint": "^5.12.0", + "eslint": "^5.12.1", "eslint-config-airbnb": "^17.1.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-jsx-a11y": "^6.1.2", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-jsx-a11y": "^6.2.0", "eslint-plugin-node": "^8.0.1", - "eslint-plugin-react": "^7.12.3", + "eslint-plugin-react": "^7.12.4", "mocha": "^5.2.0" }, "dependencies": { diff --git a/src/utils/files.js b/src/utils/files.js index 53aa8e6..4c53ebb 100644 --- a/src/utils/files.js +++ b/src/utils/files.js @@ -25,8 +25,14 @@ function resolvePath(originalPath) { * @return {Promise} The json object from the file */ async function readJsonFile(file) { + let json; + const fileContent = await fs.readFile(resolvePath(file), 'utf8'); - const json = JSON.parse(fileContent); + try { + json = JSON.parse(fileContent); + } catch (e) { + throw e; + } return json; } diff --git a/test/unit-tests/auth/index.js b/test/unit-tests/auth/index.test.js similarity index 89% rename from test/unit-tests/auth/index.js rename to test/unit-tests/auth/index.test.js index 8bf57f0..548af62 100644 --- a/test/unit-tests/auth/index.js +++ b/test/unit-tests/auth/index.test.js @@ -6,11 +6,6 @@ const auth = require('../../../src/auth'); describe('Authentication file management', () => { const filePath = 'test/unit-tests/auth/test-auth.json'; - it('getFileData should return a valid object', async () => { - const file = await auth.getFileData(filePath); - file.should.be.a('object'); - }); - it('The object from file should have github property', async () => { const file = await auth.getFileData(filePath); file.should.have.property('github'); diff --git a/test/unit-tests/gitHandler/index.js b/test/unit-tests/gitHandler/index.test.js similarity index 94% rename from test/unit-tests/gitHandler/index.js rename to test/unit-tests/gitHandler/index.test.js index 11e7f11..82cf412 100644 --- a/test/unit-tests/gitHandler/index.js +++ b/test/unit-tests/gitHandler/index.test.js @@ -52,7 +52,8 @@ describe('Git handler', () => { it('add remote should work', async () => { await gitHandler.addRemote(folderPath, 'someurl', 'origin'); - const resp = await utils.process.execp('git remote get-url origin', folderPath); + let resp = await utils.process.execp('git remote get-url origin', folderPath); + resp = resp.replace('\n', ''); resp.should.equal('someurl'); }); }); diff --git a/test/unit-tests/utils/file.txt b/test/unit-tests/utils/file.txt new file mode 100644 index 0000000..d34fd41 --- /dev/null +++ b/test/unit-tests/utils/file.txt @@ -0,0 +1 @@ +A simple file diff --git a/test/unit-tests/utils/files.test.js b/test/unit-tests/utils/files.test.js new file mode 100644 index 0000000..7472cff --- /dev/null +++ b/test/unit-tests/utils/files.test.js @@ -0,0 +1,45 @@ +const chai = require("chai"); +const chaiAsPromised = require("chai-as-promised"); +chai.use(chaiAsPromised); +const should = chai.should(); +const os = require('os'); +const path = require('path'); +const fs = require('fs').promises; + +const utils = require('../../../src/utils'); + +describe('Utils for files', () => { + const jsonPath = 'test/unit-tests/auth/test-auth.json'; + const otherFile = 'test/unit-tests/utils/file.txt'; + const tempFolder = path.resolve(path.join(os.homedir(), 'temp')); + const testFolder = path.resolve(path.join(os.homedir(), 'temp', 'project')); + + it('resolve path works using tilde on any os different than win32', async () => { + utils.files.resolvePath('~').should.equal(os.homedir()); + }); + + it('read json file should return a valid object', async () => { + const file = await utils.files.readJsonFile(jsonPath); + file.should.be.a('object'); + }); + + it('read json file should throw error when file is not a json', async () => { + return utils.files.readJsonFile(otherFile).should.eventually.be.rejectedWith(Error); + }); + + it('copy dir will create all the parent folders required', async () => { + await utils.files.copyDirRecursive('test/unit-tests', testFolder); + return fs.access(tempFolder).should.not.eventually.be.rejectedWith(Error); + }); + + it('copy dir count should matches for dir and files'); + + it('delete should remove the folder and its content', async () => { + await utils.files.deleteDirRecursive(tempFolder); + return fs.access(tempFolder).should.eventually.be.rejectedWith(Error); + }); + + + + +}); diff --git a/test/unit-tests/utils/string.test.js b/test/unit-tests/utils/string.test.js new file mode 100644 index 0000000..e69de29 From b1094b3323304f840656b1ed415d17cefc507e04 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Wed, 30 Jan 2019 18:32:41 -0500 Subject: [PATCH 05/18] String tests --- test/integration/cleanup.js | 15 ------------ test/integration/create-project.test.js | 23 ++++++++++++++++++ test/unit-tests/auth/index.test.js | 1 - test/unit-tests/gitHandler/index.test.js | 9 +++---- test/unit-tests/utils/files.test.js | 11 ++++----- test/unit-tests/utils/string.test.js | 30 ++++++++++++++++++++++++ 6 files changed, 62 insertions(+), 27 deletions(-) delete mode 100644 test/integration/cleanup.js create mode 100644 test/integration/create-project.test.js diff --git a/test/integration/cleanup.js b/test/integration/cleanup.js deleted file mode 100644 index 109ca45..0000000 --- a/test/integration/cleanup.js +++ /dev/null @@ -1,15 +0,0 @@ -const utils = require('../../src/utils'); -const githubHandler = require('../../src/githubHandler'); - -function cleanup(path = 'a-demo-project') { - const name = utils.string.normalizeName(path); - - // Remove test folder - console.log(`Deleting folder ${path}`); - utils.files.deleteDirRecursive(path); - - // Delete github project - githubHandler.deleteRepo(name, 'nmicht'); -} - -// cleanup(process.argv[2]); diff --git a/test/integration/create-project.test.js b/test/integration/create-project.test.js new file mode 100644 index 0000000..8b6b74f --- /dev/null +++ b/test/integration/create-project.test.js @@ -0,0 +1,23 @@ +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); + +chai.use(chaiAsPromised); +const should = chai.should(); + +const githubHandler = require('../../src/gitHandler'); +const utils = require('../../src/utils'); + +describe('Create a project', () => { + const projectPath = '~/dev/my-new-project'; + + after('Delete the project', () => { + const name = utils.string.normalizeName(projectPath); + + // Remove test folder + console.log(`Deleting folder ${projectPath}`); + utils.files.deleteDirRecursive(projectPath); + + // Delete github project + githubHandler.deleteRepo(name, 'nmicht'); + }); +}); diff --git a/test/unit-tests/auth/index.test.js b/test/unit-tests/auth/index.test.js index 548af62..826d405 100644 --- a/test/unit-tests/auth/index.test.js +++ b/test/unit-tests/auth/index.test.js @@ -1,4 +1,3 @@ -const assert = require('assert'); const should = require('chai').should(); const auth = require('../../../src/auth'); diff --git a/test/unit-tests/gitHandler/index.test.js b/test/unit-tests/gitHandler/index.test.js index 82cf412..f601775 100644 --- a/test/unit-tests/gitHandler/index.test.js +++ b/test/unit-tests/gitHandler/index.test.js @@ -1,10 +1,11 @@ -const chai = require("chai"); -const chaiAsPromised = require("chai-as-promised"); -chai.use(chaiAsPromised); -const should = chai.should(); const fs = require('fs').promises; const path = require('path'); const os = require('os'); +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); + +chai.use(chaiAsPromised); +const should = chai.should(); const gitHandler = require('../../../src/gitHandler'); const utils = require('../../../src/utils'); diff --git a/test/unit-tests/utils/files.test.js b/test/unit-tests/utils/files.test.js index 7472cff..8a62dd8 100644 --- a/test/unit-tests/utils/files.test.js +++ b/test/unit-tests/utils/files.test.js @@ -1,10 +1,11 @@ +const os = require('os'); +const path = require('path'); +const fs = require('fs').promises; const chai = require("chai"); const chaiAsPromised = require("chai-as-promised"); + chai.use(chaiAsPromised); const should = chai.should(); -const os = require('os'); -const path = require('path'); -const fs = require('fs').promises; const utils = require('../../../src/utils'); @@ -38,8 +39,4 @@ describe('Utils for files', () => { await utils.files.deleteDirRecursive(tempFolder); return fs.access(tempFolder).should.eventually.be.rejectedWith(Error); }); - - - - }); diff --git a/test/unit-tests/utils/string.test.js b/test/unit-tests/utils/string.test.js index e69de29..aaf05c0 100644 --- a/test/unit-tests/utils/string.test.js +++ b/test/unit-tests/utils/string.test.js @@ -0,0 +1,30 @@ +const path = require('path'); +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); + +chai.use(chaiAsPromised); +const should = chai.should(); + +const utils = require('../../../src/utils'); + +describe('Utils for strings', () => { + + it('A project name with camelcase, whitespaces and underscore get normalized', async () => { + const testPath = path.resolve(path.join('temp', 'un_Gran proyECTO')); + utils.string.normalizeName(testPath).should.equal('un-gran-proyecto'); + }); + + it('Replace a string using a dictionary', async () => { + const dictionary = { + FIRST: 'first element', + SECOND: 'second element', + THIRD: 'third element', + }; + + const theString = 'On the FIRST the things get weird for this THIRD test.'; + + const replaced = utils.string.replaceByDictionary(theString, dictionary); + + replaced.should.equal('On the first element the things get weird for this third element test.'); + }); +}); From 569e8e7c68dcfd2c5aa430aad7a69225942593d4 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Wed, 30 Jan 2019 18:34:11 -0500 Subject: [PATCH 06/18] Reorganize settings to one class --- .gitignore | 1 + README.md | 2 +- package.json | 4 +- scripts/cleanup.js | 15 +++ install/index.js => scripts/install.js | 22 ++-- src/auth/index.js | 60 +++-------- src/gitHandler/index.js | 8 +- src/project/index.js | 4 +- src/questionnaire/index.js | 8 +- src/questionnaire/questions.js | 4 +- src/settings/index.js | 43 +++++++- src/settings/st.js | 101 ++++++++++++++++++ src/template/index.js | 5 +- src/utils/string.js | 2 +- .../licenses}/Apache-License-2.0 | 0 {licenses => templates/licenses}/GNU-AGPLv3 | 0 {licenses => templates/licenses}/GNU-GPLv3 | 0 {licenses => templates/licenses}/GNU-LGPLv3 | 0 {licenses => templates/licenses}/ISC-License | 0 {licenses => templates/licenses}/MIT-License | 0 .../licenses}/Mozilla-Public-License-2.0 | 0 .../nodejs-project}/.editorconfig | 0 .../nodejs-project}/.eslintrc | 0 .../nodejs-project}/.gitignore | 0 .../nodejs-project}/README.md | 0 .../nodejs-project}/package.json | 0 .../nodejs-project}/src/index.js | 0 27 files changed, 201 insertions(+), 78 deletions(-) create mode 100644 scripts/cleanup.js rename install/index.js => scripts/install.js (61%) create mode 100644 src/settings/st.js rename {licenses => templates/licenses}/Apache-License-2.0 (100%) rename {licenses => templates/licenses}/GNU-AGPLv3 (100%) rename {licenses => templates/licenses}/GNU-GPLv3 (100%) rename {licenses => templates/licenses}/GNU-LGPLv3 (100%) rename {licenses => templates/licenses}/ISC-License (100%) rename {licenses => templates/licenses}/MIT-License (100%) rename {licenses => templates/licenses}/Mozilla-Public-License-2.0 (100%) rename {template => templates/nodejs-project}/.editorconfig (100%) rename {template => templates/nodejs-project}/.eslintrc (100%) rename {template => templates/nodejs-project}/.gitignore (100%) rename {template => templates/nodejs-project}/README.md (100%) rename {template => templates/nodejs-project}/package.json (100%) rename {template => templates/nodejs-project}/src/index.js (100%) diff --git a/.gitignore b/.gitignore index 2bd2ffa..fb0889c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/* .env .idea +create-nodejs-settings.json diff --git a/README.md b/README.md index 89c0205..194c758 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Create NodeJS Project Logo -# Node Project Initializer +# Node.js Project Initializer [![License][license-image]][license-url] [![version][npm-image]][npm-url] diff --git a/package.json b/package.json index 07c7f1b..7b0f12d 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "license": "MIT", "private": false, "scripts": { - "postinstall": "node --no-warnings install/index.js", + "postinstall": "node --no-warnings scripts/install.js", "start": "node --no-warnings src/index.js", - "cleanup": "node --no-warnings test/integration/cleanup.js", + "cleanup": "node --no-warnings scripts/cleanup.js", "test": "mocha" }, "engines": { diff --git a/scripts/cleanup.js b/scripts/cleanup.js new file mode 100644 index 0000000..5cb78c8 --- /dev/null +++ b/scripts/cleanup.js @@ -0,0 +1,15 @@ +const utils = require('../src/utils'); +const githubHandler = require('../src/githubHandler'); + +function cleanup(projectPath = 'a-demo-project') { + const name = utils.string.normalizeName(projectPath); + + // Remove test folder + console.log(`Deleting folder ${projectPath}`); + utils.files.deleteDirRecursive(projectPath); + + // Delete github project + githubHandler.deleteRepo(name, 'nmicht'); +} + +cleanup(process.argv[2]); diff --git a/install/index.js b/scripts/install.js similarity index 61% rename from install/index.js rename to scripts/install.js index 92e8f8b..87b2cde 100644 --- a/install/index.js +++ b/scripts/install.js @@ -2,8 +2,6 @@ const questions = require('../src/questionnaire/questions'); const settings = require('../src/settings'); const auth = require('../src/auth'); -const AUTH_PATH = settings.authPath; - /** * Install function for the package, it set up the github auth details * TODO Consider the case for a previous auth file with different tokens @@ -12,7 +10,7 @@ const AUTH_PATH = settings.authPath; let user; try { - user = await auth.firstUser(AUTH_PATH); + user = await auth.firstUser(); } catch (e) { // console.log('fixme'); } @@ -20,15 +18,13 @@ const AUTH_PATH = settings.authPath; const authUser = await questions.getGithubUser(user.user || ''); const authToken = await questions.getAuthToken(user.user || '', user.token || ''); - const authDetails = { - github: [ - { - user: authUser.github.user, - token: authToken.github.token, - }, - ], - }; + settings.auth.github = [ + { + user: authUser.github.user, + token: authToken.github.token, + }, + ]; - await auth.writeAuthFile(authDetails, AUTH_PATH); - console.log(`File ${AUTH_PATH} created with your github details`); + await settings.writeFile(); + console.log('File created with your github details'); })(); diff --git a/src/auth/index.js b/src/auth/index.js index 5691159..ac4a751 100644 --- a/src/auth/index.js +++ b/src/auth/index.js @@ -1,51 +1,37 @@ -const fs = require('fs').promises; - const settings = require('../settings'); const utils = require('../utils'); -/** - * Get the auth file contents converted to json - * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file - * @return {Promise} - */ -function getFileData(jsonPath = settings.authPath) { - return utils.files.readJsonFile(jsonPath); -} - /** * Return the first user on the auth data - * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file * @return {Object|undefined} */ -async function firstUser(jsonPath = settings.authPath) { - const auth = await getFileData(jsonPath); +async function firstUser() { + const auth = settings.auth.github; - return auth.github[0]; + return auth[0]; } /** * Find a user on the auth file * @param {String} user The user to find - * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file * @return {Object|undefined} */ -async function findUser(user, jsonPath = settings.authPath) { - const auth = await getFileData(jsonPath); +async function findUser(user) { + const auth = settings.auth.github; - return auth.github.find(obj => obj.user === user); + return auth.find(obj => obj.user === user); } /** * Get the Github token from the auth file * @param {String} user The user owner of the token - * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file * @return {String|undefined} The github token or undefined if there is no token. */ -async function getToken(user, jsonPath = settings.authPath) { +async function getToken(user) { let userData; if (user) { - userData = await findUser(user, jsonPath); + userData = await findUser(user); } else { userData = await firstUser(); } @@ -55,54 +41,38 @@ async function getToken(user, jsonPath = settings.authPath) { return token; } -/** - * Write the auth data json in the file - * @param {Object} data The object/json data - * @param {String} [jsonPath=settings.authPath] The path - * @return {Promise} - */ -function writeAuthFile(data, jsonPath = settings.authPath) { - const authPath = utils.files.resolvePath(jsonPath); - const json = JSON.stringify(data, null, 2); - return fs.writeFile(authPath, json); -} - /** * Update the auth data file * @param {String} user The user owner of the token * @param {String} token The token - * @param {String} [jsonPath=settings.authPath] The path for the create-nodejs-project.json file * @return {Boolean} True in case the file gets updated */ -async function updateAuthFile(user, token, jsonPath = settings.authPath) { +async function updateToken(user, token) { let currentToken = ''; let userIndex; - const authPath = utils.files.resolvePath(jsonPath); - const auth = await getFileData(jsonPath); + const auth = settings.auth.github; currentToken = firstUser().token; if (user) { // TODO consider the case for a new user data - userIndex = auth.github.findIndex(elem => elem.user === user); - currentToken = auth.github[userIndex].token; + userIndex = auth.findIndex(elem => elem.user === user); + currentToken = auth[userIndex].token; } if (currentToken === token) { return false; } - auth.github[userIndex].token = token; - writeAuthFile(auth, authPath); + auth[userIndex].token = token; + settings.writeFile(); return true; } module.exports = { - getFileData, firstUser, findUser, getToken, - updateAuthFile, - writeAuthFile, + updateToken, }; diff --git a/src/gitHandler/index.js b/src/gitHandler/index.js index c42ca07..238e9b0 100644 --- a/src/gitHandler/index.js +++ b/src/gitHandler/index.js @@ -20,7 +20,7 @@ async function userValue(prop) { /** * Initialize a git repository on the given path * @param {String} [path='.'] The path for the git project - * @return {String} The result of the git init command + * @return {String} The result of the git init command or empty in case of error */ async function init(path = '.') { let resp = ''; @@ -38,7 +38,7 @@ async function init(path = '.') { * Add all and commit * @param {String} [path='.'] The path for the git project * @param {String} [msg='Initial commit'] The commit message - * @return {String} The result of the git commit command + * @return {String} The result of the git commit command or empty in case of error */ async function commit(path = '.', msg = 'Initial commit') { let resp = ''; @@ -57,7 +57,7 @@ async function commit(path = '.', msg = 'Initial commit') { * @param {String} [path='.'] The path for the git project * @param {[type]} url The remote url * @param {String} [remote='origin'] The name for the remote - * @return {String} The result of the git command + * @return {String} The result of the git command or empty in case of error */ async function addRemote(path = '.', url, remote = 'origin') { let resp = ''; @@ -76,7 +76,7 @@ async function addRemote(path = '.', url, remote = 'origin') { * @param {String} [path='.'] The path for the git project * @param {String} [remote='origin'] The remote to push * @param {String} [branch='master'] The branch pushed - * @return {String} Tne result of the git push command + * @return {String} Tne result of the git push command or empty in case of error */ async function push(path = '.', remote = 'origin', branch = 'master') { let resp = ''; diff --git a/src/project/index.js b/src/project/index.js index 38cf436..0b81d31 100644 --- a/src/project/index.js +++ b/src/project/index.js @@ -254,8 +254,8 @@ class Project { projectName: utils.string.normalizeName(destPath), gitUserName: name, gitUserEmail: email, - license: settings.default.license, - version: settings.default.version, + license: settings.defaults.license, + version: settings.defaults.version, }; }); diff --git a/src/questionnaire/index.js b/src/questionnaire/index.js index 20e1d6d..8736c1b 100644 --- a/src/questionnaire/index.js +++ b/src/questionnaire/index.js @@ -22,12 +22,14 @@ async function run(name) { resp.hasRemote = !!remoteAnswers.git.url; } else { authFileAnswers = await questions.getAuthFile(); + settings.settingsPath = authFileAnswers.settingsPath; + settings.writeFile(); - currentAuthUser = await auth.firstUser(authFileAnswers.authPath); + currentAuthUser = await auth.firstUser(); userAnswers = await questions.getGithubUser(currentAuthUser.user); - currentToken = await auth.getToken(userAnswers.github.user, authFileAnswers.authPath); + currentToken = await auth.getToken(userAnswers.github.user); tokenAnswers = await questions.getAuthToken(userAnswers.github.user, currentToken); @@ -40,7 +42,7 @@ async function run(name) { } if (updateAnswers.updateToken) { - auth.updateAuthFile(github.user, github.token, settings.authPath); + auth.updateToken(github.user, github.token, settings.settingsPath); } if (!currentToken) { diff --git a/src/questionnaire/questions.js b/src/questionnaire/questions.js index e86e13b..f53490a 100644 --- a/src/questionnaire/questions.js +++ b/src/questionnaire/questions.js @@ -127,9 +127,9 @@ async function getAuthFile() { return inquirer.prompt([ { type: 'input', - name: 'authPath', + name: 'settingsPath', message: 'What is the path for the create-nodejs-project.json file?', - default: settings.authPath, + default: settings.settingsPath, validate: (ans) => { const path = utils.files.resolvePath(ans); if (path && fs.existsSync(path)) { diff --git a/src/settings/index.js b/src/settings/index.js index 154fc0c..e32f237 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -1,5 +1,9 @@ const path = require('path'); -const os = require('os'); +const fs = require('fs').promises; + +const utils = require('../utils'); + +const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-nodejs-settings.json')); const settings = { lintPkgs: [ @@ -26,11 +30,44 @@ const settings = { 'MIT License', 'ISC License', ], - authPath: path.join(os.homedir(), 'create-nodejs-project.json'), - default: { + settingsPath: SETTINGS_PATH, + templatesPath: path.resolve(path.join(__dirname, '..', '..', 'templates')), + nodejsTemplatePath: path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), + licensesPath: path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), + defaults: { license: 'GNU GPLv3', version: '0.1.0', }, + auth: { + github: [ + { + user: 'YOUR_USER', + token: 'YOUR_TOKEN', + }, + ], + }, + /** + * Write the auth data json in the file + * @param {Object} data The object/json data + * @param {String} filePath The path + * @return {Promise} + */ + writeFile: function writeFile(data = this, filePath = this.settingsPath) { + const json = JSON.stringify(data, null, 2); + return fs.writeFile(filePath, json); + }, + readFile: async function readFile(filePath = this.settingsPath) { + const json = await utils.files.readJsonFile(filePath); + this.defaults = json.defaults; + this.auth = json.auth; + this.lintPkgs = json.lintPkgs; + this.testingPkgs = json.testingPkgs; + this.licenses = json.licenses; + this.settingsPath = json.settingsPath; + this.templatesPath = json.templatesPath; + this.nodejsTemplatePath = json.nodejsTemplatePath; + this.licensesPath = json.licensesPath; + }, }; module.exports = settings; diff --git a/src/settings/st.js b/src/settings/st.js new file mode 100644 index 0000000..f11f7d4 --- /dev/null +++ b/src/settings/st.js @@ -0,0 +1,101 @@ +const path = require('path'); +const fs = require('fs').promises; + +const utils = require('../utils'); + +const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-nodejs-settings.json')); + +class Settings { + + constructor({ + lintPkgs = [ + 'eslint', + 'eslint-plugin-node', + 'eslint-config-airbnb', + 'eslint-plugin-import', + 'eslint-plugin-jsx-a11y', + 'eslint-plugin-react', + ], + testingPkgs = [ + 'jest', + 'mocha', + 'chai', + 'sinon', + 'nock', + ], + licenses = [ + 'GNU AGPLv3', + 'GNU GPLv3', + 'GNU LGPLv3', + 'Mozilla Public License 2.0', + 'Apache License 2.0', + 'MIT License', + 'ISC License', + ], + settingsPath = SETTINGS_PATH, + templatesPath = path.resolve(path.join(__dirname, '..', '..', 'templates')), + nodejsTemplatePath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), + licensesPath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), + defaults = { + license: 'GNU GPLv3', + version: '0.1.0', + }, + auth = { + github: [ + { + user: 'YOUR_USER', + token: 'YOUR_TOKEN', + }, + ], + }, + }) { + this.defaults = defaults; + this.auth = { + github: [ + { + user: auth.github.user, + token: auth.github.token, + } + ] + }; + this.lintPkgs = lintPkgs; + this.testingPkgs = testingPkgs; + this.licenses = { + license: licenses.license, + version: licenses.version, + } + this.settingsPath = settingsPath; + this.templatesPath = templatesPath; + this.nodejsTemplatePath = nodejsTemplatePath; + this.licensesPath = licensesPath; + } + + /** + * Write the auth data json in the file + * @param {Object} data The object/json data + * @param {String} filePath The path + * @return {Promise} + */ + update(data = this, filePath = this.settingsPath) { + const json = JSON.stringify(data, null, 2); + return fs.writeFile(filePath, json); + } + + async load(filePath = this.settingsPath) { + const json = await utils.files.readJsonFile(filePath); + this.defaults = json.defaults; + this.auth = json.auth; + this.lintPkgs = json.lintPkgs; + this.testingPkgs = json.testingPkgs; + this.licenses = json.licenses; + this.settingsPath = json.settingsPath; + this.templatesPath = json.templatesPath; + this.nodejsTemplatePath = json.nodejsTemplatePath; + this.licensesPath = json.licensesPath; + } +} + +const settings = new Settings(); +settings.load(); + +module.exports = settings; diff --git a/src/template/index.js b/src/template/index.js index 3c01454..5bc880e 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -2,9 +2,10 @@ const fs = require('fs').promises; const path = require('path'); const utils = require('../utils'); +const settings = require('../settings'); -const TEMPLATE_PATH = path.join(__dirname, '..', '..', 'template'); -const LICENSES_PATH = path.join(__dirname, '..', '..', 'licenses'); +const TEMPLATE_PATH = settings.nodejsTemplatePath; +const LICENSES_PATH = settings.licensesPath; /** * Update a file using a dictionary diff --git a/src/utils/string.js b/src/utils/string.js index 62b3ca7..e183b3b 100644 --- a/src/utils/string.js +++ b/src/utils/string.js @@ -22,7 +22,7 @@ function replaceByDictionary(original, dictionary) { * @return {String} A name normalized without blank spaces all lowercase */ function normalizeName(filepath) { - return path.basename(filepath).toLowerCase().replace(' ', '-'); + return path.basename(filepath).toLowerCase().replace(/(\s|_)/g, '-'); } diff --git a/licenses/Apache-License-2.0 b/templates/licenses/Apache-License-2.0 similarity index 100% rename from licenses/Apache-License-2.0 rename to templates/licenses/Apache-License-2.0 diff --git a/licenses/GNU-AGPLv3 b/templates/licenses/GNU-AGPLv3 similarity index 100% rename from licenses/GNU-AGPLv3 rename to templates/licenses/GNU-AGPLv3 diff --git a/licenses/GNU-GPLv3 b/templates/licenses/GNU-GPLv3 similarity index 100% rename from licenses/GNU-GPLv3 rename to templates/licenses/GNU-GPLv3 diff --git a/licenses/GNU-LGPLv3 b/templates/licenses/GNU-LGPLv3 similarity index 100% rename from licenses/GNU-LGPLv3 rename to templates/licenses/GNU-LGPLv3 diff --git a/licenses/ISC-License b/templates/licenses/ISC-License similarity index 100% rename from licenses/ISC-License rename to templates/licenses/ISC-License diff --git a/licenses/MIT-License b/templates/licenses/MIT-License similarity index 100% rename from licenses/MIT-License rename to templates/licenses/MIT-License diff --git a/licenses/Mozilla-Public-License-2.0 b/templates/licenses/Mozilla-Public-License-2.0 similarity index 100% rename from licenses/Mozilla-Public-License-2.0 rename to templates/licenses/Mozilla-Public-License-2.0 diff --git a/template/.editorconfig b/templates/nodejs-project/.editorconfig similarity index 100% rename from template/.editorconfig rename to templates/nodejs-project/.editorconfig diff --git a/template/.eslintrc b/templates/nodejs-project/.eslintrc similarity index 100% rename from template/.eslintrc rename to templates/nodejs-project/.eslintrc diff --git a/template/.gitignore b/templates/nodejs-project/.gitignore similarity index 100% rename from template/.gitignore rename to templates/nodejs-project/.gitignore diff --git a/template/README.md b/templates/nodejs-project/README.md similarity index 100% rename from template/README.md rename to templates/nodejs-project/README.md diff --git a/template/package.json b/templates/nodejs-project/package.json similarity index 100% rename from template/package.json rename to templates/nodejs-project/package.json diff --git a/template/src/index.js b/templates/nodejs-project/src/index.js similarity index 100% rename from template/src/index.js rename to templates/nodejs-project/src/index.js From 072bb7211c4a3218504c01348e685b986a6b1b53 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Wed, 30 Jan 2019 21:51:42 -0500 Subject: [PATCH 07/18] Dependency injection for settings and refactor on dependencies --- scripts/cleanup.js | 9 +- scripts/install.js | 16 ++- src/auth/index.js | 78 ------------ src/githubHandler/index.js | 7 +- src/index.js | 4 + src/project/index.js | 27 +++-- src/questionnaire/index.js | 18 ++- src/questionnaire/questions.js | 14 ++- src/settings/index.js | 210 +++++++++++++++++++++++---------- src/settings/st.js | 101 ---------------- src/template/index.js | 28 ++--- 11 files changed, 215 insertions(+), 297 deletions(-) delete mode 100644 src/auth/index.js delete mode 100644 src/settings/st.js diff --git a/scripts/cleanup.js b/scripts/cleanup.js index 5cb78c8..e49528d 100644 --- a/scripts/cleanup.js +++ b/scripts/cleanup.js @@ -1,7 +1,10 @@ -const utils = require('../src/utils'); +const settings = require('../src/settings'); const githubHandler = require('../src/githubHandler'); +const utils = require('../src/utils'); + +async function cleanup(projectPath = 'a-demo-project') { + await settings.load(); -function cleanup(projectPath = 'a-demo-project') { const name = utils.string.normalizeName(projectPath); // Remove test folder @@ -9,7 +12,7 @@ function cleanup(projectPath = 'a-demo-project') { utils.files.deleteDirRecursive(projectPath); // Delete github project - githubHandler.deleteRepo(name, 'nmicht'); + githubHandler.deleteRepo(name, settings.githubAuth.user, settings.githubAuth.token); } cleanup(process.argv[2]); diff --git a/scripts/install.js b/scripts/install.js index 87b2cde..8715a76 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -1,6 +1,5 @@ const questions = require('../src/questionnaire/questions'); const settings = require('../src/settings'); -const auth = require('../src/auth'); /** * Install function for the package, it set up the github auth details @@ -8,9 +7,10 @@ const auth = require('../src/auth'); */ (async () => { let user; + await settings.load(); try { - user = await auth.firstUser(); + user = await settings.firstUser(); } catch (e) { // console.log('fixme'); } @@ -18,13 +18,11 @@ const auth = require('../src/auth'); const authUser = await questions.getGithubUser(user.user || ''); const authToken = await questions.getAuthToken(user.user || '', user.token || ''); - settings.auth.github = [ - { - user: authUser.github.user, - token: authToken.github.token, - }, - ]; + settings.githubAuth = { + user: authUser.github.user, + token: authToken.github.token, + }; - await settings.writeFile(); + await settings.update(); console.log('File created with your github details'); })(); diff --git a/src/auth/index.js b/src/auth/index.js deleted file mode 100644 index ac4a751..0000000 --- a/src/auth/index.js +++ /dev/null @@ -1,78 +0,0 @@ -const settings = require('../settings'); -const utils = require('../utils'); - -/** - * Return the first user on the auth data - * @return {Object|undefined} - */ -async function firstUser() { - const auth = settings.auth.github; - - return auth[0]; -} - -/** - * Find a user on the auth file - * @param {String} user The user to find - * @return {Object|undefined} - */ -async function findUser(user) { - const auth = settings.auth.github; - - return auth.find(obj => obj.user === user); -} - -/** - * Get the Github token from the auth file - * @param {String} user The user owner of the token - * @return {String|undefined} The github token or undefined if there is no token. - */ -async function getToken(user) { - let userData; - - if (user) { - userData = await findUser(user); - } else { - userData = await firstUser(); - } - - const token = userData ? userData.token : undefined; - - return token; -} - -/** - * Update the auth data file - * @param {String} user The user owner of the token - * @param {String} token The token - * @return {Boolean} True in case the file gets updated - */ -async function updateToken(user, token) { - let currentToken = ''; - let userIndex; - const auth = settings.auth.github; - - currentToken = firstUser().token; - - if (user) { - // TODO consider the case for a new user data - userIndex = auth.findIndex(elem => elem.user === user); - currentToken = auth[userIndex].token; - } - - if (currentToken === token) { - return false; - } - - auth[userIndex].token = token; - settings.writeFile(); - - return true; -} - -module.exports = { - firstUser, - findUser, - getToken, - updateToken, -}; diff --git a/src/githubHandler/index.js b/src/githubHandler/index.js index 0c50a4d..4049574 100644 --- a/src/githubHandler/index.js +++ b/src/githubHandler/index.js @@ -1,5 +1,4 @@ const utils = require('../utils'); -const auth = require('../auth'); /** * Create a github repository @@ -11,7 +10,7 @@ const auth = require('../auth'); * @param {String} [user=''] The github user * @return {json|Boolean} In case of success will return the json from the * github api response, otherwise, return false. - * @throws If the token is not present + * @throws {Error} If the token is not present */ async function create({ name, @@ -58,12 +57,12 @@ async function create({ * Delete a github repository * @param {String} name The name of the repository * @param {String} user The owner of the repository + * @param {String} token The github token for the user * @return {json|Boolean} In case of success will return the json from the * github api response, otherwise, return false. * @throws If the token is not present */ -async function deleteRepo(name, user) { - const token = await auth.getToken(user); +async function deleteRepo(name, user, token) { let data; const headers = { diff --git a/src/index.js b/src/index.js index 5215964..587e91a 100755 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,14 @@ #!/usr/bin/env node +const settings = require('./settings'); const Project = require('./project'); (async () => { // TODO Work with args + await settings.load(); + Project.setDependencies(settings); + const destPath = await Project.getDestPath(process.argv[2]); const details = await Project.getDetails(destPath); diff --git a/src/project/index.js b/src/project/index.js index 0b81d31..a6ed22c 100644 --- a/src/project/index.js +++ b/src/project/index.js @@ -1,12 +1,10 @@ -const pathModule = require('path'); const fs = require('fs').promises; +const questionnaire = require('../questionnaire'); const gitHandler = require('../gitHandler'); const githubHandler = require('../githubHandler'); -const settings = require('../settings'); -const utils = require('../utils'); const template = require('../template'); -const questionnaire = require('../questionnaire'); +const utils = require('../utils'); /** * Project handle all the information for the new node project @@ -165,7 +163,7 @@ class Project { */ async installDependencies() { console.info('Installing dev dependencies ...'); - const args = ['install', '-D', ...settings.lintPkgs, ...this.testPackages]; + const args = ['install', '-D', ...Project.settings.lintPkgs, ...this.testPackages]; await utils.process.spawnp( 'npm', args, @@ -200,11 +198,16 @@ class Project { * @return {Promise} */ async generateTemplateFiles() { - await template.copyTemplate(this.path); + await template.copyTemplate(Project.settings.nodejsTemplatePath, this.path); return Promise.all([ template.updateTemplateFiles(this.dictionary, this.path), - template.copyLicense(this.license, this.dictionary, this.path), + template.copyLicense( + this.license, + this.dictionary, + Project.settings.licensesPath, + this.path + ), ]); } @@ -254,13 +257,13 @@ class Project { projectName: utils.string.normalizeName(destPath), gitUserName: name, gitUserEmail: email, - license: settings.defaults.license, - version: settings.defaults.version, + license: Project.settings.defaults.license, + version: Project.settings.defaults.version, }; }); // Questionnaire for the options - const answers = await questionnaire.run(defaults); + const answers = await questionnaire.run(defaults, Project.settings); // Add extra values to the answers Object.assign(answers, { @@ -291,6 +294,10 @@ class Project { .catch(() => resolve(destPath)); }); } + + static setDependencies(settings) { + Project.settings = settings; + } } module.exports = Project; diff --git a/src/questionnaire/index.js b/src/questionnaire/index.js index 8736c1b..415b0c4 100644 --- a/src/questionnaire/index.js +++ b/src/questionnaire/index.js @@ -1,8 +1,6 @@ const questions = require('./questions'); -const auth = require('../auth'); -const settings = require('../settings'); -async function run(name) { +async function run(name, settings) { let remoteAnswers; let authFileAnswers; let userAnswers; @@ -15,21 +13,21 @@ async function run(name) { let currentAuthUser; let currentToken; - const resp = await questions.getProjectDetails(name); + const resp = await questions.getProjectDetails(name, settings.licenses, settings.testingPkgs); if (!resp.useGithub) { remoteAnswers = await questions.getGitRemoteDetails(); resp.hasRemote = !!remoteAnswers.git.url; } else { - authFileAnswers = await questions.getAuthFile(); - settings.settingsPath = authFileAnswers.settingsPath; - settings.writeFile(); + authFileAnswers = await questions.getAuthFile(settings.settingsPath); + const { settingsPath } = authFileAnswers; + settings.update('settingsPath', settingsPath); - currentAuthUser = await auth.firstUser(); + currentAuthUser = await settings.firstUser(); userAnswers = await questions.getGithubUser(currentAuthUser.user); - currentToken = await auth.getToken(userAnswers.github.user); + currentToken = await settings.getToken(userAnswers.github.user); tokenAnswers = await questions.getAuthToken(userAnswers.github.user, currentToken); @@ -42,7 +40,7 @@ async function run(name) { } if (updateAnswers.updateToken) { - auth.updateToken(github.user, github.token, settings.settingsPath); + settings.updateToken(github.user, github.token, settings.settingsPath); } if (!currentToken) { diff --git a/src/questionnaire/questions.js b/src/questionnaire/questions.js index f53490a..093a97a 100644 --- a/src/questionnaire/questions.js +++ b/src/questionnaire/questions.js @@ -1,7 +1,6 @@ const inquirer = require('inquirer'); const fs = require('fs'); -const settings = require('../settings'); const utils = require('../utils'); /** @@ -12,9 +11,11 @@ const utils = require('../utils'); * @param {String} defaults.license The default license for the project * @param {String} defaults.gitUserName The git username setup for the project * @param {String} defaults.gitUserEmail The git username setup for the project + * @param {String} licenses The list of options for licenses + * @param {String} testingPkgs The list of options for testingPkgs * @return {Promise} */ -async function getProjectDetails(defaults) { +async function getProjectDetails(defaults, licenses, testingPkgs) { return inquirer.prompt([ { type: 'input', @@ -47,7 +48,7 @@ async function getProjectDetails(defaults) { type: 'list', name: 'license', message: 'Please select a license', - choices: settings.licenses, + choices: licenses, default: defaults.license, }, @@ -88,7 +89,7 @@ async function getProjectDetails(defaults) { type: 'checkbox', name: 'testPackages', message: 'Which test packages do you want to include?', - choices: settings.testingPkgs, + choices: testingPkgs, }, { @@ -121,15 +122,16 @@ async function getGitRemoteDetails() { /** * Run the prompts to geth the path for the auth file + * @param {String} settingsPath The default path for the settings file * @return {Promise} */ -async function getAuthFile() { +async function getAuthFile(settingsPath) { return inquirer.prompt([ { type: 'input', name: 'settingsPath', message: 'What is the path for the create-nodejs-project.json file?', - default: settings.settingsPath, + default: settingsPath, validate: (ans) => { const path = utils.files.resolvePath(ans); if (path && fs.existsSync(path)) { diff --git a/src/settings/index.js b/src/settings/index.js index e32f237..60c4ca4 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -5,69 +5,159 @@ const utils = require('../utils'); const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-nodejs-settings.json')); -const settings = { - lintPkgs: [ - 'eslint', - 'eslint-plugin-node', - 'eslint-config-airbnb', - 'eslint-plugin-import', - 'eslint-plugin-jsx-a11y', - 'eslint-plugin-react', - ], - testingPkgs: [ - 'jest', - 'mocha', - 'chai', - 'sinon', - 'nock', - ], - licenses: [ - 'GNU AGPLv3', - 'GNU GPLv3', - 'GNU LGPLv3', - 'Mozilla Public License 2.0', - 'Apache License 2.0', - 'MIT License', - 'ISC License', - ], - settingsPath: SETTINGS_PATH, - templatesPath: path.resolve(path.join(__dirname, '..', '..', 'templates')), - nodejsTemplatePath: path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), - licensesPath: path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), - defaults: { - license: 'GNU GPLv3', - version: '0.1.0', - }, - auth: { - github: [ - { - user: 'YOUR_USER', - token: 'YOUR_TOKEN', - }, +class Settings { + constructor({ + lintPkgs = [ + 'eslint', + 'eslint-plugin-node', + 'eslint-config-airbnb', + 'eslint-plugin-import', + 'eslint-plugin-jsx-a11y', + 'eslint-plugin-react', ], - }, + testingPkgs = [ + 'jest', + 'mocha', + 'chai', + 'sinon', + 'nock', + ], + licenses = [ + 'GNU AGPLv3', + 'GNU GPLv3', + 'GNU LGPLv3', + 'Mozilla Public License 2.0', + 'Apache License 2.0', + 'MIT License', + 'ISC License', + ], + settingsPath = SETTINGS_PATH, + templatesPath = path.resolve(path.join(__dirname, '..', '..', 'templates')), + nodejsTemplatePath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), + licensesPath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), + defaults = { + license: 'GNU GPLv3', + version: '0.1.0', + }, + githubAuth = { + user: 'YOUR_USER', + token: 'YOUR_TOKEN', + }, + }) { + this.licenses = licenses; + this.githubAuth = { + user: githubAuth.user, + token: githubAuth.token, + }; + this.lintPkgs = lintPkgs; + this.testingPkgs = testingPkgs; + this.defaults = { + license: defaults.license, + version: defaults.version, + }; + this.settingsPath = settingsPath; + this.templatesPath = templatesPath; + this.nodejsTemplatePath = nodejsTemplatePath; + this.licensesPath = licensesPath; + } + /** * Write the auth data json in the file - * @param {Object} data The object/json data - * @param {String} filePath The path + * @param {String} [property='all'] The property to be updated + * @param {String|Array|Object} [data=''] The value to be updated + * @param {String} filePath The path of the file * @return {Promise} */ - writeFile: function writeFile(data = this, filePath = this.settingsPath) { - const json = JSON.stringify(data, null, 2); + update(property = 'all', value = '', filePath = this.settingsPath) { + if (property !== 'all') { + this[property] = value; + } + const json = JSON.stringify(this, null, 2); return fs.writeFile(filePath, json); - }, - readFile: async function readFile(filePath = this.settingsPath) { - const json = await utils.files.readJsonFile(filePath); - this.defaults = json.defaults; - this.auth = json.auth; - this.lintPkgs = json.lintPkgs; - this.testingPkgs = json.testingPkgs; - this.licenses = json.licenses; - this.settingsPath = json.settingsPath; - this.templatesPath = json.templatesPath; - this.nodejsTemplatePath = json.nodejsTemplatePath; - this.licensesPath = json.licensesPath; - }, -}; - -module.exports = settings; + } + + async load(filePath = this.settingsPath) { + try { + fs.access(filePath); + const json = await utils.files.readJsonFile(filePath); + this.defaults = json.defaults; + this.githubAuth = json.githubAuth; + this.lintPkgs = json.lintPkgs; + this.testingPkgs = json.testingPkgs; + this.licenses = json.licenses; + this.settingsPath = json.settingsPath; + this.templatesPath = json.templatesPath; + this.nodejsTemplatePath = json.nodejsTemplatePath; + this.licensesPath = json.licensesPath; + } catch (e) { + // nothing + } + return this; + } + + /** + * Return the first user on the auth data + * @return {Object|undefined} + */ + async firstUser() { + return this.githubAuth; + } + + /** + * Find a user on the auth file + * @param {String} user The user to find + * @return {Object|undefined} + */ + async findUser(user) { + return this.githubAuth.user === user ? this.githubAuth : undefined; + } + + /** + * Get the Github token from the auth file + * @param {String} user The user owner of the token + * @return {String|undefined} The github token or undefined if there is no token. + */ + async getToken(user) { + // let userData; + // + // if (user) { + // userData = await this.findUser(user); + // } else { + // userData = await this.firstUser(); + // } + // + // const token = userData ? userData.token : undefined; + + return this.githubAuth.user === user ? this.githubAuth.token : undefined; + } + + /** + * Update the auth data file + * @param {String} user The user owner of the token + * @param {String} token The token + * @return {Boolean} True in case the file gets updated + */ + async updateToken(user, token) { + let currentToken = ''; + let userIndex; + + currentToken = this.firstUser().token; + + if (user) { + // TODO consider the case for a new user data + userIndex = this.githubAuth.findIndex(elem => elem.user === user); + currentToken = this.githubAuth[userIndex].token; + } + + if (currentToken === token) { + return false; + } + + this.githubAuth[userIndex].token = token; + this.update(); + + return true; + } +} + +module.exports = new Settings({}); diff --git a/src/settings/st.js b/src/settings/st.js deleted file mode 100644 index f11f7d4..0000000 --- a/src/settings/st.js +++ /dev/null @@ -1,101 +0,0 @@ -const path = require('path'); -const fs = require('fs').promises; - -const utils = require('../utils'); - -const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-nodejs-settings.json')); - -class Settings { - - constructor({ - lintPkgs = [ - 'eslint', - 'eslint-plugin-node', - 'eslint-config-airbnb', - 'eslint-plugin-import', - 'eslint-plugin-jsx-a11y', - 'eslint-plugin-react', - ], - testingPkgs = [ - 'jest', - 'mocha', - 'chai', - 'sinon', - 'nock', - ], - licenses = [ - 'GNU AGPLv3', - 'GNU GPLv3', - 'GNU LGPLv3', - 'Mozilla Public License 2.0', - 'Apache License 2.0', - 'MIT License', - 'ISC License', - ], - settingsPath = SETTINGS_PATH, - templatesPath = path.resolve(path.join(__dirname, '..', '..', 'templates')), - nodejsTemplatePath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), - licensesPath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), - defaults = { - license: 'GNU GPLv3', - version: '0.1.0', - }, - auth = { - github: [ - { - user: 'YOUR_USER', - token: 'YOUR_TOKEN', - }, - ], - }, - }) { - this.defaults = defaults; - this.auth = { - github: [ - { - user: auth.github.user, - token: auth.github.token, - } - ] - }; - this.lintPkgs = lintPkgs; - this.testingPkgs = testingPkgs; - this.licenses = { - license: licenses.license, - version: licenses.version, - } - this.settingsPath = settingsPath; - this.templatesPath = templatesPath; - this.nodejsTemplatePath = nodejsTemplatePath; - this.licensesPath = licensesPath; - } - - /** - * Write the auth data json in the file - * @param {Object} data The object/json data - * @param {String} filePath The path - * @return {Promise} - */ - update(data = this, filePath = this.settingsPath) { - const json = JSON.stringify(data, null, 2); - return fs.writeFile(filePath, json); - } - - async load(filePath = this.settingsPath) { - const json = await utils.files.readJsonFile(filePath); - this.defaults = json.defaults; - this.auth = json.auth; - this.lintPkgs = json.lintPkgs; - this.testingPkgs = json.testingPkgs; - this.licenses = json.licenses; - this.settingsPath = json.settingsPath; - this.templatesPath = json.templatesPath; - this.nodejsTemplatePath = json.nodejsTemplatePath; - this.licensesPath = json.licensesPath; - } -} - -const settings = new Settings(); -settings.load(); - -module.exports = settings; diff --git a/src/template/index.js b/src/template/index.js index 5bc880e..4dd0bbe 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -2,16 +2,12 @@ const fs = require('fs').promises; const path = require('path'); const utils = require('../utils'); -const settings = require('../settings'); - -const TEMPLATE_PATH = settings.nodejsTemplatePath; -const LICENSES_PATH = settings.licensesPath; /** - * Update a file using a dictionary - * @param {Object} dictionary A key-value dictionary - * @param {String} [filePath=''] The path for the file - */ +* Update a file using a dictionary +* @param {Object} dictionary A key-value dictionary +* @param {String} [filePath=''] The path for the file +*/ async function updateFile(dictionary, filePath = '') { const resolvedFilePath = utils.files.resolvePath(filePath); @@ -24,17 +20,17 @@ async function updateFile(dictionary, filePath = '') { } /** - * Copy the template folder recursively - * @param {String} templatePath The template path - * @param {String} destPath The destination - */ -async function copyTemplate(destPath) { - await utils.files.copyDirRecursive(TEMPLATE_PATH, destPath); +* Copy the template folder recursively +* @param {String} templatePath The template path +* @param {String} destPath The destination +*/ +async function copyTemplate(originPath, destPath) { + await utils.files.copyDirRecursive(originPath, destPath); } -async function copyLicense(license, dictionary, destPath) { +async function copyLicense(license, dictionary, originPath, destPath) { // Get the license file - const resolvedFilePath = path.join(LICENSES_PATH, license.replace(' ', '-')); + const resolvedFilePath = path.join(originPath, license.replace(' ', '-')); const originalFile = await fs.readFile(resolvedFilePath, 'utf8'); // Replace with dictionary From aafc9f88cde337612838db70249717926a62ef42 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Wed, 30 Jan 2019 22:11:04 -0500 Subject: [PATCH 08/18] Fix tests after refactor --- create-nodejs-project-example.json | 12 -------- create-nodejs-settings-example.json | 38 +++++++++++++++++++++++ src/settings/index.js | 8 ++--- test/unit-tests/auth/index.test.js | 37 ----------------------- test/unit-tests/auth/test-auth.json | 16 ---------- test/unit-tests/settings/index.test.js | 40 +++++++++++++++++++++++++ test/unit-tests/settings/test-auth.json | 38 +++++++++++++++++++++++ test/unit-tests/utils/files.test.js | 2 +- 8 files changed, 121 insertions(+), 70 deletions(-) delete mode 100644 create-nodejs-project-example.json create mode 100644 create-nodejs-settings-example.json delete mode 100644 test/unit-tests/auth/index.test.js delete mode 100644 test/unit-tests/auth/test-auth.json create mode 100644 test/unit-tests/settings/index.test.js create mode 100644 test/unit-tests/settings/test-auth.json diff --git a/create-nodejs-project-example.json b/create-nodejs-project-example.json deleted file mode 100644 index 3d77d1e..0000000 --- a/create-nodejs-project-example.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "github": [ - { - "user": "YOUR_USER", - "token": "YOUR_TOKEN" - }, - { - "user": "OTHER_USER", - "token": "OTHER_TOKEN" - } - ] -} diff --git a/create-nodejs-settings-example.json b/create-nodejs-settings-example.json new file mode 100644 index 0000000..ef8dea5 --- /dev/null +++ b/create-nodejs-settings-example.json @@ -0,0 +1,38 @@ +{ + "licenses": [ + "GNU AGPLv3", + "GNU GPLv3", + "GNU LGPLv3", + "Mozilla Public License 2.0", + "Apache License 2.0", + "MIT License", + "ISC License" + ], + "githubAuth": { + "user": "YOUR_USER", + "token": "YOUR_TOKEN" + }, + "lintPkgs": [ + "eslint", + "eslint-plugin-node", + "eslint-config-airbnb", + "eslint-plugin-import", + "eslint-plugin-jsx-a11y", + "eslint-plugin-react" + ], + "testingPkgs": [ + "jest", + "mocha", + "chai", + "sinon", + "nock" + ], + "defaults": { + "license": "GNU GPLv3", + "version": "0.1.0" + }, + "settingsPath": "/YOUR_PATH/create-nodejs-project/create-nodejs-settings.json", + "templatesPath": "/YOUR_PATH/create-nodejs-project/templates", + "nodejsTemplatePath": "/YOUR_PATH/create-nodejs-project/templates/nodejs-project", + "licensesPath": "/YOUR_PATH/create-nodejs-project/templates/licenses" +} diff --git a/src/settings/index.js b/src/settings/index.js index 60c4ca4..2a65840 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -99,7 +99,7 @@ class Settings { * Return the first user on the auth data * @return {Object|undefined} */ - async firstUser() { + firstUser() { return this.githubAuth; } @@ -108,7 +108,7 @@ class Settings { * @param {String} user The user to find * @return {Object|undefined} */ - async findUser(user) { + findUser(user) { return this.githubAuth.user === user ? this.githubAuth : undefined; } @@ -117,7 +117,7 @@ class Settings { * @param {String} user The user owner of the token * @return {String|undefined} The github token or undefined if there is no token. */ - async getToken(user) { + getToken(user) { // let userData; // // if (user) { @@ -154,7 +154,7 @@ class Settings { } this.githubAuth[userIndex].token = token; - this.update(); + await this.update(); return true; } diff --git a/test/unit-tests/auth/index.test.js b/test/unit-tests/auth/index.test.js deleted file mode 100644 index 826d405..0000000 --- a/test/unit-tests/auth/index.test.js +++ /dev/null @@ -1,37 +0,0 @@ -const should = require('chai').should(); - -const auth = require('../../../src/auth'); - -describe('Authentication file management', () => { - const filePath = 'test/unit-tests/auth/test-auth.json'; - - it('The object from file should have github property', async () => { - const file = await auth.getFileData(filePath); - file.should.have.property('github'); - }); - - it('firsUser should return the first user', async () => { - const user = await auth.firstUser(filePath); - user.user.should.be.equals('first'); - }); - - it('findUser should return the user', async () => { - const user = await auth.findUser('second', filePath); - user.user.should.be.equals('second'); - }); - - it('findUser should return undefined when the user is not found', async () => { - const user = await auth.findUser('forth', filePath); - should.equal(user, undefined); - }); - - it('getToken should return the token when the user exists', async () => { - const token = await auth.getToken('first', filePath); - token.should.be.equals('the-token'); - }); - - it('getToken should return undefined if the user does not exist', async () => { - const token = await auth.getToken('forth', filePath); - should.equal(token, undefined); - }); -}); diff --git a/test/unit-tests/auth/test-auth.json b/test/unit-tests/auth/test-auth.json deleted file mode 100644 index 61047d9..0000000 --- a/test/unit-tests/auth/test-auth.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "github": [ - { - "user": "first", - "token": "the-token" - }, - { - "user": "second", - "token": "second-token" - }, - { - "user": "third", - "token": "third-token" - } - ] -} diff --git a/test/unit-tests/settings/index.test.js b/test/unit-tests/settings/index.test.js new file mode 100644 index 0000000..afb049c --- /dev/null +++ b/test/unit-tests/settings/index.test.js @@ -0,0 +1,40 @@ +const should = require('chai').should(); + +const settings = require('../../../src/settings'); + +describe('Settings management', () => { + const filePath = 'test/unit-tests/auth/test-settings.json'; + + before('load settings data', async () => { + await settings.load(filePath); + }); + + it('The object settings should have githubAuth property', () => { + settings.should.have.property('githubAuth'); + }); + + it('firsUser should return the first user', () => { + const user = settings.firstUser(); + user.user.should.be.equals('YOUR_USER'); + }); + + it('findUser should return the user', () => { + const user = settings.findUser('YOUR_USER', filePath); + user.user.should.be.equals('YOUR_USER'); + }); + + it('findUser should return undefined when the user is not found', () => { + const user = settings.findUser('forth', filePath); + should.equal(user, undefined); + }); + + it('getToken should return the token when the user exists', () => { + const token = settings.getToken('YOUR_USER', filePath); + token.should.be.equals('YOUR_TOKEN'); + }); + + it('getToken should return undefined if the user does not exist', () => { + const token = settings.getToken('forth', filePath); + should.equal(token, undefined); + }); +}); diff --git a/test/unit-tests/settings/test-auth.json b/test/unit-tests/settings/test-auth.json new file mode 100644 index 0000000..ef8dea5 --- /dev/null +++ b/test/unit-tests/settings/test-auth.json @@ -0,0 +1,38 @@ +{ + "licenses": [ + "GNU AGPLv3", + "GNU GPLv3", + "GNU LGPLv3", + "Mozilla Public License 2.0", + "Apache License 2.0", + "MIT License", + "ISC License" + ], + "githubAuth": { + "user": "YOUR_USER", + "token": "YOUR_TOKEN" + }, + "lintPkgs": [ + "eslint", + "eslint-plugin-node", + "eslint-config-airbnb", + "eslint-plugin-import", + "eslint-plugin-jsx-a11y", + "eslint-plugin-react" + ], + "testingPkgs": [ + "jest", + "mocha", + "chai", + "sinon", + "nock" + ], + "defaults": { + "license": "GNU GPLv3", + "version": "0.1.0" + }, + "settingsPath": "/YOUR_PATH/create-nodejs-project/create-nodejs-settings.json", + "templatesPath": "/YOUR_PATH/create-nodejs-project/templates", + "nodejsTemplatePath": "/YOUR_PATH/create-nodejs-project/templates/nodejs-project", + "licensesPath": "/YOUR_PATH/create-nodejs-project/templates/licenses" +} diff --git a/test/unit-tests/utils/files.test.js b/test/unit-tests/utils/files.test.js index 8a62dd8..28e6354 100644 --- a/test/unit-tests/utils/files.test.js +++ b/test/unit-tests/utils/files.test.js @@ -10,7 +10,7 @@ const should = chai.should(); const utils = require('../../../src/utils'); describe('Utils for files', () => { - const jsonPath = 'test/unit-tests/auth/test-auth.json'; + const jsonPath = 'test/unit-tests/settings/test-auth.json'; const otherFile = 'test/unit-tests/utils/file.txt'; const tempFolder = path.resolve(path.join(os.homedir(), 'temp')); const testFolder = path.resolve(path.join(os.homedir(), 'temp', 'project')); From 752c15f5c25b177d3c3075508f68808a7f7af87d Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 02:04:14 -0500 Subject: [PATCH 09/18] Update jsdoc for methods, classes and modules --- scripts/install.js | 4 +- src/gitHandler/index.js | 18 +++++++-- src/githubHandler/index.js | 24 ++++++++---- src/project/index.js | 24 ++++++++++++ src/questionnaire/index.js | 23 ++++++++--- src/questionnaire/questions.js | 40 +++++++++++-------- src/settings/index.js | 70 +++++++++++++++++++--------------- src/template/index.js | 30 ++++++++++++++- src/utils/files.js | 22 ++++++++--- src/utils/process.js | 15 +++++--- src/utils/requests.js | 20 +++++++--- src/utils/string.js | 9 ++++- 12 files changed, 211 insertions(+), 88 deletions(-) diff --git a/scripts/install.js b/scripts/install.js index 8715a76..1bb9825 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -15,8 +15,8 @@ const settings = require('../src/settings'); // console.log('fixme'); } - const authUser = await questions.getGithubUser(user.user || ''); - const authToken = await questions.getAuthToken(user.user || '', user.token || ''); + const authUser = await questions.promptGithubUser(user.user || ''); + const authToken = await questions.promptAuthToken(user.user || '', user.token || ''); settings.githubAuth = { user: authUser.github.user, diff --git a/src/gitHandler/index.js b/src/gitHandler/index.js index 238e9b0..02d0ab9 100644 --- a/src/gitHandler/index.js +++ b/src/gitHandler/index.js @@ -2,6 +2,7 @@ const utils = require('../utils'); /** * Get the git user property from the git configuration + * @method userValue * @param {String} prop The property requested, ex. name * @return {String|undefined} The git config value for the user */ @@ -19,6 +20,7 @@ async function userValue(prop) { /** * Initialize a git repository on the given path + * @method init * @param {String} [path='.'] The path for the git project * @return {String} The result of the git init command or empty in case of error */ @@ -36,9 +38,11 @@ async function init(path = '.') { /** * Add all and commit - * @param {String} [path='.'] The path for the git project - * @param {String} [msg='Initial commit'] The commit message - * @return {String} The result of the git commit command or empty in case of error + * @method commit + * @param {String} [path='.'] The path for the git project + * @param {String} [msg='Initial commit'] The commit message + * @return {String} The result of the git commit command + * or empty in case of error */ async function commit(path = '.', msg = 'Initial commit') { let resp = ''; @@ -54,8 +58,9 @@ async function commit(path = '.', msg = 'Initial commit') { /** * Add a remote to a git project + * @method addRemote * @param {String} [path='.'] The path for the git project - * @param {[type]} url The remote url + * @param {String} url The remote url * @param {String} [remote='origin'] The name for the remote * @return {String} The result of the git command or empty in case of error */ @@ -73,6 +78,7 @@ async function addRemote(path = '.', url, remote = 'origin') { /** * Push from local to a remote + * @method push * @param {String} [path='.'] The path for the git project * @param {String} [remote='origin'] The remote to push * @param {String} [branch='master'] The branch pushed @@ -90,6 +96,10 @@ async function push(path = '.', remote = 'origin', branch = 'master') { return resp; } +/** + * A git handler + * @module gitHandler + */ module.exports = { userValue, init, diff --git a/src/githubHandler/index.js b/src/githubHandler/index.js index 4049574..5c70cf3 100644 --- a/src/githubHandler/index.js +++ b/src/githubHandler/index.js @@ -2,15 +2,18 @@ const utils = require('../utils'); /** * Create a github repository + * @method create * @param {String} name The name for the github project - * @param {Boolean} [isPrivate=false] Defines is the project will be created as private - * or public on github + * @param {Boolean} [isPrivate=false] Defines is the project will be created + * as private or public on github * @param {String} [description=''] The description for the github project * @param {String} [url=''] The url for the github project - * @param {String} [user=''] The github user - * @return {json|Boolean} In case of success will return the json from the - * github api response, otherwise, return false. - * @throws {Error} If the token is not present + * @param {Object} [github] + * @param {String} [github.user=''] The github user + * @param {String} [github.token=''] The github token + * @return {String} data The response from github or undefined in + * case of error + * @throws If the token is not present */ async function create({ name, @@ -55,11 +58,12 @@ async function create({ /** * Delete a github repository + * @method deleteRepo * @param {String} name The name of the repository * @param {String} user The owner of the repository * @param {String} token The github token for the user - * @return {json|Boolean} In case of success will return the json from the - * github api response, otherwise, return false. + * @return {json|undefined} In case of success will return the response from + * github, in case of error will return undefined. * @throws If the token is not present */ async function deleteRepo(name, user, token) { @@ -90,6 +94,10 @@ async function deleteRepo(name, user, token) { // TODO include a method to handle the topics (will require to get the github user) +/** + * A github api handler + * @module githubHandler + */ module.exports = { create, deleteRepo, diff --git a/src/project/index.js b/src/project/index.js index 51d33b6..50079e7 100644 --- a/src/project/index.js +++ b/src/project/index.js @@ -15,6 +15,7 @@ const utils = require('../utils'); class Project { /** * The Project constructor + * @method constructor * @param {String} [name=''] The name of the project * @param {String} [description=''] The description of the project * @param {String} [version='0.1.0'] The version for the project @@ -26,6 +27,9 @@ class Project { * @param {String} [author.email=''] The email of the author * @param {[type]} [author.url=''] The url of the author * @param {Boolean} [useGithub=false] If the project will use the github integration + * @param {Object} [github] + * @param {String} [github.user=''] The github user + * @param {String} [github.token=''] The github token * @param {Boolean} [hasRemote=false] If the project has a git url * @param {Object} [git] * @param {String} [git.name=''] The git project name @@ -147,6 +151,7 @@ class Project { /** * Set the github values into the object + * @method setGithubValues * @param {Object} data All the github data */ setGithubValues(data) { @@ -159,6 +164,7 @@ class Project { /** * Install the npm dev dependencies + * @method installDependencies * @return {Promise} */ async installDependencies() { @@ -173,6 +179,7 @@ class Project { /** * Do the initial commit for the project + * @method commit * @return {Promise} */ async commit() { @@ -183,6 +190,7 @@ class Project { /** * Push the project code to the remote + * @method push * @return {Promise} */ async push() { @@ -195,6 +203,7 @@ class Project { /** * Copy the template files to the project folder, update them and generate the * license. + * @method generateTemplateFiles * @return {Promise} */ async generateTemplateFiles() { @@ -213,6 +222,7 @@ class Project { /** * Create a github repository for the project + * @method createGithubRepository * @return {Promise} */ async createGithubRepository() { @@ -227,6 +237,7 @@ class Project { /** * Initialize a git repository on the project folder + * @method initializeGitRepository * @return {Promise} */ async initializeGitRepository() { @@ -237,6 +248,7 @@ class Project { /** * Create the project folder + * @method createFolder * @return {Promise} */ async createFolder() { @@ -246,6 +258,7 @@ class Project { /** * Obtain the project details + * @method getDetails * @param {String} destPath The project destination full path folder * @return {Promise} */ @@ -275,8 +288,10 @@ class Project { /** * Obtain the destination path for the project + * @method getDestPath * @param {String} arg The param used when the initializer runs * @return {Promise} + * @throws if the path is not valid */ static async getDestPath(arg) { const destPath = utils.files.resolvePath(arg); @@ -295,9 +310,18 @@ class Project { }); } + /** + * Set the project dependencies + * @method setDependencies + * @param {Settings} settings Settings object to be injected as dependency + */ static setDependencies(settings) { Project.settings = settings; } } +/** + * The project class + * @module project + */ module.exports = Project; diff --git a/src/questionnaire/index.js b/src/questionnaire/index.js index 415b0c4..256234c 100644 --- a/src/questionnaire/index.js +++ b/src/questionnaire/index.js @@ -1,5 +1,12 @@ const questions = require('./questions'); +/** + * Runs the full questionnaire for the configuration of the project + * @method run + * @param {String} name The name for the project + * @param {Settings} settings The settings object + * @return {Object} An object with all the answers + */ async function run(name, settings) { let remoteAnswers; let authFileAnswers; @@ -13,30 +20,30 @@ async function run(name, settings) { let currentAuthUser; let currentToken; - const resp = await questions.getProjectDetails(name, settings.licenses, settings.testingPkgs); + const resp = await questions.promptProjectDetails(name, settings.licenses, settings.testingPkgs); if (!resp.useGithub) { - remoteAnswers = await questions.getGitRemoteDetails(); + remoteAnswers = await questions.promptGitRemoteDetails(); resp.hasRemote = !!remoteAnswers.git.url; } else { - authFileAnswers = await questions.getAuthFile(settings.settingsPath); + authFileAnswers = await questions.promptSettingsFile(settings.settingsPath); const { settingsPath } = authFileAnswers; settings.update('settingsPath', settingsPath); currentAuthUser = await settings.firstUser(); - userAnswers = await questions.getGithubUser(currentAuthUser.user); + userAnswers = await questions.promptGithubUser(currentAuthUser.user); currentToken = await settings.getToken(userAnswers.github.user); - tokenAnswers = await questions.getAuthToken(userAnswers.github.user, currentToken); + tokenAnswers = await questions.promptAuthToken(userAnswers.github.user, currentToken); github.user = userAnswers.github.user; github.token = tokenAnswers.github.token; if (github.user !== currentAuthUser.user || github.token !== currentToken) { - updateAnswers = await questions.confirmUpdateToken(); + updateAnswers = await questions.promptUpdateToken(); } if (updateAnswers.updateToken) { @@ -53,6 +60,10 @@ async function run(name, settings) { return resp; } +/** + * The questionnaire for the project + * @module questionnaire + */ module.exports = { run, }; diff --git a/src/questionnaire/questions.js b/src/questionnaire/questions.js index 093a97a..0a56f37 100644 --- a/src/questionnaire/questions.js +++ b/src/questionnaire/questions.js @@ -5,17 +5,18 @@ const utils = require('../utils'); /** * Run the prompts to get the details for the project + * @method promptProjectDetails * @param {Object} defaults * @param {String} defaults.projectName The default name for the project * @param {String} defaults.version The default version for the project * @param {String} defaults.license The default license for the project * @param {String} defaults.gitUserName The git username setup for the project * @param {String} defaults.gitUserEmail The git username setup for the project - * @param {String} licenses The list of options for licenses - * @param {String} testingPkgs The list of options for testingPkgs + * @param {Array} licenses The list of options for licenses + * @param {Array} testingPkgs The list of options for testingPkgs * @return {Promise} */ -async function getProjectDetails(defaults, licenses, testingPkgs) { +async function promptProjectDetails(defaults, licenses, testingPkgs) { return inquirer.prompt([ { type: 'input', @@ -102,9 +103,10 @@ async function getProjectDetails(defaults, licenses, testingPkgs) { /** * Run the prompts to get the details for the remote git + * @method promptGitRemoteDetails * @return {Promise} */ -async function getGitRemoteDetails() { +async function promptGitRemoteDetails() { return inquirer.prompt([ { type: 'input', @@ -122,10 +124,11 @@ async function getGitRemoteDetails() { /** * Run the prompts to geth the path for the auth file + * @method promptSettingsFile * @param {String} settingsPath The default path for the settings file * @return {Promise} */ -async function getAuthFile(settingsPath) { +async function promptSettingsFile(settingsPath) { return inquirer.prompt([ { type: 'input', @@ -145,10 +148,11 @@ async function getAuthFile(settingsPath) { /** * Run the prompts to get the github user + * @method promptGithubUser * @param {String} user The current user on the auth file * @return {Promise} */ -async function getGithubUser(user) { +async function promptGithubUser(user) { return inquirer.prompt([ { type: 'input', @@ -161,11 +165,12 @@ async function getGithubUser(user) { /** * Run the prompts to get the github token + * @method promptAuthToken * @param {String} user The current github user on the auth file * @param {String} token The current github user on the auth file * @return {Promise} */ -async function getAuthToken(user, token) { +async function promptAuthToken(user, token) { return inquirer.prompt([ { type: 'input', @@ -178,23 +183,28 @@ async function getAuthToken(user, token) { /** * Run the prompt to confirm if the user wants to update the token + * @method promptUpdateToken * @return {Promise} */ -async function confirmUpdateToken() { +async function promptUpdateToken() { return inquirer.prompt([ { type: 'confirm', name: 'updateToken', - message: 'Do you want to update the create-nodejs-project.json file with this token?', + message: 'Do you want to update the settings file with this token?', }, ]); } +/** + * The questions for the questionnaire + * @module questions + */ module.exports = { - getProjectDetails, - getGitRemoteDetails, - getAuthFile, - getAuthToken, - confirmUpdateToken, - getGithubUser, + promptProjectDetails, + promptGitRemoteDetails, + promptSettingsFile, + promptAuthToken, + promptUpdateToken, + promptGithubUser, }; diff --git a/src/settings/index.js b/src/settings/index.js index 2a65840..6da0a9d 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -5,7 +5,12 @@ const utils = require('../utils'); const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-nodejs-settings.json')); +/** + * A settings class + * @class Settings + */ class Settings { + constructor({ lintPkgs = [ 'eslint', @@ -63,6 +68,7 @@ class Settings { /** * Write the auth data json in the file + * @method update * @param {String} [property='all'] The property to be updated * @param {String|Array|Object} [data=''] The value to be updated * @param {String} filePath The path of the file @@ -76,66 +82,65 @@ class Settings { return fs.writeFile(filePath, json); } + /** + * Load the settings values from the settings file + * @method load + * @param {String} [filePath=this.settingsPath] The path for the settings file + * @return {Promise} + */ async load(filePath = this.settingsPath) { - try { - fs.access(filePath); - const json = await utils.files.readJsonFile(filePath); - this.defaults = json.defaults; - this.githubAuth = json.githubAuth; - this.lintPkgs = json.lintPkgs; - this.testingPkgs = json.testingPkgs; - this.licenses = json.licenses; - this.settingsPath = json.settingsPath; - this.templatesPath = json.templatesPath; - this.nodejsTemplatePath = json.nodejsTemplatePath; - this.licensesPath = json.licensesPath; - } catch (e) { - // nothing - } - return this; + fs.access(filePath); + const json = await utils.files.readJsonFile(filePath); + this.defaults = json.defaults; + this.githubAuth = json.githubAuth; + this.lintPkgs = json.lintPkgs; + this.testingPkgs = json.testingPkgs; + this.licenses = json.licenses; + this.settingsPath = json.settingsPath; + this.templatesPath = json.templatesPath; + this.nodejsTemplatePath = json.nodejsTemplatePath; + this.licensesPath = json.licensesPath; } /** - * Return the first user on the auth data + * Return the first user on the auth settings + * @method firstUser * @return {Object|undefined} + * TODO implement logic to allow multiple auth values */ firstUser() { return this.githubAuth; } /** - * Find a user on the auth file + * Find a user on the auth settings + * @method findUser * @param {String} user The user to find * @return {Object|undefined} + * TODO implement logic to allow multiple auth values */ findUser(user) { return this.githubAuth.user === user ? this.githubAuth : undefined; } /** - * Get the Github token from the auth file + * Get the Github token from the auth settings + * @method getToken * @param {String} user The user owner of the token * @return {String|undefined} The github token or undefined if there is no token. + * TODO implement logic to allow multiple auth values */ getToken(user) { - // let userData; - // - // if (user) { - // userData = await this.findUser(user); - // } else { - // userData = await this.firstUser(); - // } - // - // const token = userData ? userData.token : undefined; - return this.githubAuth.user === user ? this.githubAuth.token : undefined; } /** - * Update the auth data file + * Update the auth settings + * @method updateToken * @param {String} user The user owner of the token * @param {String} token The token - * @return {Boolean} True in case the file gets updated + * @return {Promise} Resolve with true in case the file gets updated + * TODO implement logic to allow multiple auth values */ async updateToken(user, token) { let currentToken = ''; @@ -160,4 +165,7 @@ class Settings { } } +/** + * @module settings + */ module.exports = new Settings({}); diff --git a/src/template/index.js b/src/template/index.js index 4dd0bbe..17e2354 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -5,8 +5,10 @@ const utils = require('../utils'); /** * Update a file using a dictionary +* @method updateFile * @param {Object} dictionary A key-value dictionary * @param {String} [filePath=''] The path for the file +* @return {Promise} */ async function updateFile(dictionary, filePath = '') { const resolvedFilePath = utils.files.resolvePath(filePath); @@ -21,13 +23,25 @@ async function updateFile(dictionary, filePath = '') { /** * Copy the template folder recursively +* @method copyTemplate * @param {String} templatePath The template path * @param {String} destPath The destination +* @return {Promise} */ -async function copyTemplate(originPath, destPath) { - await utils.files.copyDirRecursive(originPath, destPath); +async function copyTemplate(templatePath, destPath) { + await utils.files.copyDirRecursive(templatePath, destPath); } +/** + * Read the license file, update its content with the project data and save it + * on the new destination + * @method copyLicense + * @param {String} license The license name + * @param {Object} dictionary The dictionary used to update the license content + * @param {String} originPath The path for the licenses folder + * @param {String} destPath The destination path + * @return {Promise} + */ async function copyLicense(license, dictionary, originPath, destPath) { // Get the license file const resolvedFilePath = path.join(originPath, license.replace(' ', '-')); @@ -42,6 +56,14 @@ async function copyLicense(license, dictionary, originPath, destPath) { console.log(`File ${licensePath} created`); } +/** + * Update some of the template files with the project data + * @method updateTemplateFiles + * @param {Object} dictionary The dictionary with the data to be updated on the + * template files + * @param {String} destPath The destination path + * @return {Promise} + */ function updateTemplateFiles(dictionary, destPath) { const readmePath = path.join(destPath, 'README.md'); const packagePath = path.join(destPath, 'package.json'); @@ -52,6 +74,10 @@ function updateTemplateFiles(dictionary, destPath) { ]); } +/** + * The template handler + * @module template + */ module.exports = { updateFile, copyTemplate, diff --git a/src/utils/files.js b/src/utils/files.js index 4c53ebb..27c060c 100644 --- a/src/utils/files.js +++ b/src/utils/files.js @@ -4,6 +4,7 @@ const os = require('os'); /** * Resolve a path even if is using shell specific for home + * @method resolvePath * @param {String} originalPath The path to resolve * @return {String} The resolved path */ @@ -21,8 +22,10 @@ function resolvePath(originalPath) { /** * Read a file and translate to json + * @method readJsonFile * @param {String} file The path to the file * @return {Promise} The json object from the file + * @throws if the file can not be processed as json */ async function readJsonFile(file) { let json; @@ -39,8 +42,10 @@ async function readJsonFile(file) { /** * Copy a folder recursively + * @method copyDirRecursive * @param {String} [currentPath='./'] The folder path to copy * @param {String} [destPath='../new'] The destination path + * @return {Promise} */ async function copyDirRecursive(currentPath = './', destPath = '../new') { let dest = resolvePath(destPath); @@ -57,11 +62,11 @@ async function copyDirRecursive(currentPath = './', destPath = '../new') { // Read files in folder const files = await fs.readdir(current); - for(file of files) { - src = resolvePath(path.join(current, file)); + for(const file of files) { + const src = resolvePath(path.join(current, file)); dest = resolvePath(path.join(destPath, file)); - srcObj = await fs.lstat(src); + const srcObj = await fs.lstat(src); if (srcObj.isDirectory()) { // Recursive copy for folders await copyDirRecursive(src, dest); @@ -75,8 +80,9 @@ async function copyDirRecursive(currentPath = './', destPath = '../new') { /** * Delete a directory recursively + * @method deleteDirRecursive * @param {String} folderPath The path of the folder to be deleted - * @return {[type]} [description] + * @return {Promise} */ async function deleteDirRecursive(folderPath) { const dirPath = resolvePath(folderPath); @@ -90,10 +96,10 @@ async function deleteDirRecursive(folderPath) { const files = await fs.readdir(dirPath); - for(file of files){ + for (const file of files) { const curPath = resolvePath(path.join(dirPath, file)); - srcObj = await fs.lstat(curPath); + const srcObj = await fs.lstat(curPath); if (srcObj.isDirectory()) { await deleteDirRecursive(curPath); } else { // delete file @@ -105,6 +111,10 @@ async function deleteDirRecursive(folderPath) { console.log(`Folder ${dirPath} deleted`); } +/** + * Utilities for file system + * @module utils.files + */ module.exports = { copyDirRecursive, deleteDirRecursive, diff --git a/src/utils/process.js b/src/utils/process.js index c3add30..34785ab 100644 --- a/src/utils/process.js +++ b/src/utils/process.js @@ -2,18 +2,20 @@ const { exec, spawn } = require('child_process'); /** * Promisified exec + * @method execp * @see https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback - * @param {String} cmd The commando to be executed - * @param {String} cwd The current directoy where the the command should be executed - * @return {Promise} Promise object represents the exec of command + * @param {String} command The command to be executed + * @param {String} cwd The current working directoy where the the command + * should be executed + * @return {Promise} */ -function execp(cmd, cwd = null) { +function execp(command, cwd = null) { return new Promise((resolve, reject) => { - exec(cmd, { + exec(command, { cwd, }, (error, stdout) => { if (error) { - console.error(`There was an error with the command: ${cmd}`); + console.error(`There was an error with the command: ${command}`); reject(error); } resolve(stdout); @@ -23,6 +25,7 @@ function execp(cmd, cwd = null) { /** * Promisified spawn + * @method spawnp * @param {String} command command name * @param {string} args command arguments * @param {String} cwd working directory to run the commad diff --git a/src/utils/requests.js b/src/utils/requests.js index decb2c4..db0cd9b 100644 --- a/src/utils/requests.js +++ b/src/utils/requests.js @@ -2,11 +2,13 @@ const https = require('https'); /** * HTTP post method with json body and json response + * @method postReq * @param {Object} data The object with all the data to send * @param {String} url The http options * @param {Object} headers The headers for the request * @param {Boolean} jsonResponse If the response will be a json * @return {Promise} + * @throws if the request is not https */ function postReq(data, url, headers, jsonResponse = true) { const apiUrl = new URL(url); @@ -60,12 +62,14 @@ function postReq(data, url, headers, jsonResponse = true) { } /** -* HTTP delete method with json body and json response -* @param {Object} data The object with all the data to send -* @param {String} url The http options -* @param {Object} headers The headers for the request -* @param {Boolean} jsonResponse If the response will be a json -* @return {Promise} + * HTTP delete method with json body and json response + * @method deleteReq + * @param {Object} data The object with all the data to send + * @param {String} url The http options + * @param {Object} headers The headers for the request + * @param {Boolean} jsonResponse If the response will be a json + * @return {Promise} + * @throws if the request is not https */ function deleteReq(data, url, headers, jsonResponse = true) { const apiUrl = new URL(url); @@ -118,6 +122,10 @@ function deleteReq(data, url, headers, jsonResponse = true) { }); } +/** + * Utilites for https requests + * @module utils.requests + */ module.exports = { postReq, deleteReq, diff --git a/src/utils/string.js b/src/utils/string.js index e183b3b..a1e5f3f 100644 --- a/src/utils/string.js +++ b/src/utils/string.js @@ -2,6 +2,7 @@ const path = require('path'); /** * Replace a string using a given dictionary + * @method replaceByDictionary * @param {String} original The string to be replaced * @param {Object} dictionary A key-value dictionary * @return {String} The string with the replacements @@ -9,7 +10,7 @@ const path = require('path'); function replaceByDictionary(original, dictionary) { let processed = original; - for(key in dictionary){ + for (const key in dictionary) { processed = processed.replace(key, dictionary[key]); } @@ -18,6 +19,7 @@ function replaceByDictionary(original, dictionary) { /** * Create a normalized name based on the path + * @method normalizeName * @param {String} filepath The path * @return {String} A name normalized without blank spaces all lowercase */ @@ -25,7 +27,10 @@ function normalizeName(filepath) { return path.basename(filepath).toLowerCase().replace(/(\s|_)/g, '-'); } - +/** + * Utilites for strings + * @module utils.string + */ module.exports = { replaceByDictionary, normalizeName, From 95e438b6db6189e026ff429b8063a34bc3ca64e9 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 02:06:56 -0500 Subject: [PATCH 10/18] Fix some typos on test file names --- src/utils/process.js | 5 +++++ test/unit-tests/settings/index.test.js | 2 +- .../settings/{test-auth.json => test-settings.json} | 0 test/unit-tests/utils/files.test.js | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) rename test/unit-tests/settings/{test-auth.json => test-settings.json} (100%) diff --git a/src/utils/process.js b/src/utils/process.js index 34785ab..cb285f0 100644 --- a/src/utils/process.js +++ b/src/utils/process.js @@ -29,6 +29,7 @@ function execp(command, cwd = null) { * @param {String} command command name * @param {string} args command arguments * @param {String} cwd working directory to run the commad + * @return {Promise} */ async function spawnp(command, args, cwd) { const proc = spawn(command, args, { @@ -50,6 +51,10 @@ async function spawnp(command, args, cwd) { }); } +/** + * Utilities for processes + * @module utils.process + */ module.exports = { execp, spawnp, diff --git a/test/unit-tests/settings/index.test.js b/test/unit-tests/settings/index.test.js index afb049c..c76dddd 100644 --- a/test/unit-tests/settings/index.test.js +++ b/test/unit-tests/settings/index.test.js @@ -3,7 +3,7 @@ const should = require('chai').should(); const settings = require('../../../src/settings'); describe('Settings management', () => { - const filePath = 'test/unit-tests/auth/test-settings.json'; + const filePath = 'test/unit-tests/settings/test-settings.json'; before('load settings data', async () => { await settings.load(filePath); diff --git a/test/unit-tests/settings/test-auth.json b/test/unit-tests/settings/test-settings.json similarity index 100% rename from test/unit-tests/settings/test-auth.json rename to test/unit-tests/settings/test-settings.json diff --git a/test/unit-tests/utils/files.test.js b/test/unit-tests/utils/files.test.js index 28e6354..88d7566 100644 --- a/test/unit-tests/utils/files.test.js +++ b/test/unit-tests/utils/files.test.js @@ -10,7 +10,7 @@ const should = chai.should(); const utils = require('../../../src/utils'); describe('Utils for files', () => { - const jsonPath = 'test/unit-tests/settings/test-auth.json'; + const jsonPath = 'test/unit-tests/settings/test-settings.json'; const otherFile = 'test/unit-tests/utils/file.txt'; const tempFolder = path.resolve(path.join(os.homedir(), 'temp')); const testFolder = path.resolve(path.join(os.homedir(), 'temp', 'project')); From 9816ddbcf7f11c98c54dd59cfeac9624333e6e22 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 02:18:30 -0500 Subject: [PATCH 11/18] Fix README description for the settings auth data --- README.md | 24 ++++++++++-------------- scripts/install.js | 6 +++++- src/questionnaire/questions.js | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 194c758..caa71ee 100644 --- a/README.md +++ b/README.md @@ -84,20 +84,16 @@ If you are planning to allow this script to create your Github repositories, is 5. Open Terminal and add the Github token. ``` -# nano ~/create-nodejs-project.json - -{ - "github": [ - { - "user": "YOUR_USER", - "token": "YOUR_TOKEN" - }, - { - "user": "OTHER_USER", - "token": "OTHER_TOKEN" - } - ] -} +# nano /YOUR-NODE_MODULES-PATH/create-nodejs-project/create-nodejs-settings.json + +... +... + "githubAuth": { + "user": "YOUR_USER", + "token": "YOUR_TOKEN" + } +... +... ``` diff --git a/scripts/install.js b/scripts/install.js index 1bb9825..e454cc2 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -9,12 +9,16 @@ const settings = require('../src/settings'); let user; await settings.load(); + const authFileAnswers = await questions.promptSettingsFile(settings.settingsPath); + settings.settingsPath = authFileAnswers.settingsPath; + try { user = await settings.firstUser(); } catch (e) { // console.log('fixme'); } + const authUser = await questions.promptGithubUser(user.user || ''); const authToken = await questions.promptAuthToken(user.user || '', user.token || ''); @@ -24,5 +28,5 @@ const settings = require('../src/settings'); }; await settings.update(); - console.log('File created with your github details'); + console.log(`Your settings file was updated on ${settings.settingsPath}`); })(); diff --git a/src/questionnaire/questions.js b/src/questionnaire/questions.js index 0a56f37..a68f9db 100644 --- a/src/questionnaire/questions.js +++ b/src/questionnaire/questions.js @@ -133,14 +133,14 @@ async function promptSettingsFile(settingsPath) { { type: 'input', name: 'settingsPath', - message: 'What is the path for the create-nodejs-project.json file?', + message: 'What is the path for the create-nodejs-settings.json file?', default: settingsPath, validate: (ans) => { const path = utils.files.resolvePath(ans); if (path && fs.existsSync(path)) { return true; } - return 'You should introduce a real path for the create-nodejs-project.json'; + return 'You should introduce a real path for the create-nodejs-settings.json'; }, }, ]); From c2b3c72714a372ddd4e9fede5c68d1d3ba860c06 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 02:21:18 -0500 Subject: [PATCH 12/18] Reorder process for cleanup --- scripts/cleanup.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/cleanup.js b/scripts/cleanup.js index e49528d..23a2961 100644 --- a/scripts/cleanup.js +++ b/scripts/cleanup.js @@ -4,15 +4,11 @@ const utils = require('../src/utils'); async function cleanup(projectPath = 'a-demo-project') { await settings.load(); - const name = utils.string.normalizeName(projectPath); - // Remove test folder - console.log(`Deleting folder ${projectPath}`); - utils.files.deleteDirRecursive(projectPath); + await githubHandler.deleteRepo(name, settings.githubAuth.user, settings.githubAuth.token); - // Delete github project - githubHandler.deleteRepo(name, settings.githubAuth.user, settings.githubAuth.token); + utils.files.deleteDirRecursive(projectPath); } cleanup(process.argv[2]); From f9b5355f97f60510dff33e84fde63d0a88a3c24c Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 13:21:09 -0500 Subject: [PATCH 13/18] Making template path a setting --- create-nodejs-settings-example.json | 4 +++- src/project/index.js | 13 ++++++++++--- src/questionnaire/questions.js | 12 +++++++++++- src/settings/index.js | 10 +++++++--- test/unit-tests/settings/test-settings.json | 4 +++- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/create-nodejs-settings-example.json b/create-nodejs-settings-example.json index ef8dea5..636420f 100644 --- a/create-nodejs-settings-example.json +++ b/create-nodejs-settings-example.json @@ -31,8 +31,10 @@ "license": "GNU GPLv3", "version": "0.1.0" }, + "templates": [ + "nodejs-project", + ], "settingsPath": "/YOUR_PATH/create-nodejs-project/create-nodejs-settings.json", "templatesPath": "/YOUR_PATH/create-nodejs-project/templates", - "nodejsTemplatePath": "/YOUR_PATH/create-nodejs-project/templates/nodejs-project", "licensesPath": "/YOUR_PATH/create-nodejs-project/templates/licenses" } diff --git a/src/project/index.js b/src/project/index.js index 50079e7..d792006 100644 --- a/src/project/index.js +++ b/src/project/index.js @@ -1,4 +1,5 @@ const fs = require('fs').promises; +const path = require('path'); const questionnaire = require('../questionnaire'); const gitHandler = require('../gitHandler'); @@ -40,6 +41,7 @@ class Project { * @param {String} [path=''] The full path for the project folder * @param {String} [year=''] The year to be used on the license * @param {Array} [testPackages=[]] The list of the test packages selected + * @param {String} [template=''] The list of the test packages selected */ constructor({ name = '', @@ -66,9 +68,10 @@ class Project { }, issueTracker = '', isPrivate = false, - path = '', + thePath = '', year = '', testPackages = [], + theTemplate = '', }) { this.name = name; this.description = description; @@ -94,9 +97,10 @@ class Project { }; this.issueTracker = issueTracker; this.isPrivate = isPrivate; - this.path = path; + this.path = thePath; this.year = year || (new Date()).getFullYear(); this.testPackages = testPackages; + this.template = theTemplate; } /** @@ -207,7 +211,10 @@ class Project { * @return {Promise} */ async generateTemplateFiles() { - await template.copyTemplate(Project.settings.nodejsTemplatePath, this.path); + await template.copyTemplate( + path.join(Project.settings.templatesPath, this.template), + this.path + ); return Promise.all([ template.updateTemplateFiles(this.dictionary, this.path), diff --git a/src/questionnaire/questions.js b/src/questionnaire/questions.js index a68f9db..2b47577 100644 --- a/src/questionnaire/questions.js +++ b/src/questionnaire/questions.js @@ -12,11 +12,13 @@ const utils = require('../utils'); * @param {String} defaults.license The default license for the project * @param {String} defaults.gitUserName The git username setup for the project * @param {String} defaults.gitUserEmail The git username setup for the project + * @param {String} defaults.template The name for the default template * @param {Array} licenses The list of options for licenses * @param {Array} testingPkgs The list of options for testingPkgs + * @param {Array} templates The list of options for templates * @return {Promise} */ -async function promptProjectDetails(defaults, licenses, testingPkgs) { +async function promptProjectDetails(defaults, licenses, testingPkgs, templates) { return inquirer.prompt([ { type: 'input', @@ -25,6 +27,14 @@ async function promptProjectDetails(defaults, licenses, testingPkgs) { default: defaults.projectName, }, + { + type: 'list', + name: 'template', + message: 'What kind of project are you creating?', + choices: templates, + default: defaults.template, + }, + { type: 'input', name: 'description', diff --git a/src/settings/index.js b/src/settings/index.js index 6da0a9d..cd99fa5 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -36,13 +36,16 @@ class Settings { 'MIT License', 'ISC License', ], + templates = [ + 'nodejs-project', + ], settingsPath = SETTINGS_PATH, templatesPath = path.resolve(path.join(__dirname, '..', '..', 'templates')), - nodejsTemplatePath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'nodejs-project')), licensesPath = path.resolve(path.join(__dirname, '..', '..', 'templates', 'licenses')), defaults = { license: 'GNU GPLv3', version: '0.1.0', + template: 'nodejs-project', }, githubAuth = { user: 'YOUR_USER', @@ -59,10 +62,11 @@ class Settings { this.defaults = { license: defaults.license, version: defaults.version, + template: defaults.template, }; + this.templates = templates; this.settingsPath = settingsPath; this.templatesPath = templatesPath; - this.nodejsTemplatePath = nodejsTemplatePath; this.licensesPath = licensesPath; } @@ -98,7 +102,7 @@ class Settings { this.licenses = json.licenses; this.settingsPath = json.settingsPath; this.templatesPath = json.templatesPath; - this.nodejsTemplatePath = json.nodejsTemplatePath; + this.templates = json.templates; this.licensesPath = json.licensesPath; } diff --git a/test/unit-tests/settings/test-settings.json b/test/unit-tests/settings/test-settings.json index ef8dea5..4bfd0c3 100644 --- a/test/unit-tests/settings/test-settings.json +++ b/test/unit-tests/settings/test-settings.json @@ -31,8 +31,10 @@ "license": "GNU GPLv3", "version": "0.1.0" }, + "templates": [ + "nodejs-project" + ], "settingsPath": "/YOUR_PATH/create-nodejs-project/create-nodejs-settings.json", "templatesPath": "/YOUR_PATH/create-nodejs-project/templates", - "nodejsTemplatePath": "/YOUR_PATH/create-nodejs-project/templates/nodejs-project", "licensesPath": "/YOUR_PATH/create-nodejs-project/templates/licenses" } From efb62b24c365a32b9ef85589933ad59ca62ac700 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Thu, 31 Jan 2019 13:30:52 -0500 Subject: [PATCH 14/18] Fix generation of settings file during install --- scripts/install.js | 9 ++++++++- src/questionnaire/index.js | 7 ++++++- src/settings/index.js | 1 - 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/install.js b/scripts/install.js index e454cc2..0f36e81 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -1,3 +1,5 @@ +const fs = require('fs').promises; + const questions = require('../src/questionnaire/questions'); const settings = require('../src/settings'); @@ -7,7 +9,12 @@ const settings = require('../src/settings'); */ (async () => { let user; - await settings.load(); + try { + await fs.access(settings.settingsPath); + await settings.load(); + } catch (e) { + settings.update(); + } const authFileAnswers = await questions.promptSettingsFile(settings.settingsPath); settings.settingsPath = authFileAnswers.settingsPath; diff --git a/src/questionnaire/index.js b/src/questionnaire/index.js index 256234c..fb4e3d5 100644 --- a/src/questionnaire/index.js +++ b/src/questionnaire/index.js @@ -20,7 +20,12 @@ async function run(name, settings) { let currentAuthUser; let currentToken; - const resp = await questions.promptProjectDetails(name, settings.licenses, settings.testingPkgs); + const resp = await questions.promptProjectDetails( + name, + settings.licenses, + settings.testingPkgs, + settings.templates + ); if (!resp.useGithub) { remoteAnswers = await questions.promptGitRemoteDetails(); diff --git a/src/settings/index.js b/src/settings/index.js index cd99fa5..f261e52 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -10,7 +10,6 @@ const SETTINGS_PATH = path.resolve(path.join(__dirname, '..', '..', 'create-node * @class Settings */ class Settings { - constructor({ lintPkgs = [ 'eslint', From 73643f8771257adca4e30a6ac3114243af7738be Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Fri, 1 Feb 2019 13:23:35 -0500 Subject: [PATCH 15/18] Adding travis and update some things on readme --- .travis.yml | 4 ++++ README.md | 20 +++++++++++--------- templates/nodejs-project/README.md | 4 +++- templates/nodejs-project/package.json | 2 +- 4 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..64a2f6b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "iojs" + - "10" diff --git a/README.md b/README.md index caa71ee..5a06f35 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Node.js Project Initializer -[![License][license-image]][license-url] [![version][npm-image]][npm-url] +[![License][license-image]][license-url] [![version][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] An [npm initializer][npm/init] to scaffold a node project and include basic tools like lint, testing, etc. @@ -34,11 +34,10 @@ npm init nodejs-project path/to/new/project ## What it does 1. Create the folder for the new project -1. Guide you through a questionnarie to setup the project +1. Guide you through a questionnaire to setup the project 2. Initialize a git repository 3. Copy the template files (src, eslintrc, gitignore, readme, etc) -4. Can create a Github repository -5. Handle the Github tokens for multiple accounts/users +4. Create a Github repository 5. Install eslint dependencies 5. Install the selected testing dependencies 6. Generate package.json with all the project details @@ -47,22 +46,22 @@ npm init nodejs-project path/to/new/project ## About this package -The motivation started as a **DRY** thing. +Every time that I start a new project in Node.js, I hate to go to other project folder, copy files like eslintrc, editorconfig; install the same dependencies, create folder structure, etc. -I'm not expert with NodeJS, but every time that I start a new project, I hate to go to other project, copy files like eslintrc, editorconfig, install the same dependencies, create folder structure, etc. +With this in mind, the motivation to build this package started as a **DRY** (Do not repeat yourself) thing. -So, the idea is to have an automated way to initialize new NodeJS projects and with this have a new folder with everything ready to work in what really matters. +This package is intended to automated the initialization of new Node.js projects and with this have a new folder with everything ready to work, basically an scaffolding tool. ## Future features 1. Unit testing -7. Options to create the project with params instead of questionnaire +7. Options to create the project with parameters instead of questionnaire 10. A good error handler 11. Color for the console messages 12. Improve the template structure (the one that is generated in the new project) to include unit test 18. Option to questionnaire with all the default values -2. Logic to handle multiple auth files and multiple github accounts +2. Logic to handle multiple authentication files and multiple Github accounts ## Configure Github Authentication @@ -105,3 +104,6 @@ If you are planning to allow this script to create your Github repositories, is [npm-image]: https://img.shields.io/npm/v/create-nodejs-project.svg?style=for-the-badge&logo=npm [npm/init]: https://docs.npmjs.com/cli/init#description + +[downloads-url]: https://www.npmjs.com/package/create-nodejs-project +[downloads-image]: https://img.shields.io/npm/dt/create-nodejs-project.svg?style=for-the-badge diff --git a/templates/nodejs-project/README.md b/templates/nodejs-project/README.md index 966b3d2..aa8a800 100644 --- a/templates/nodejs-project/README.md +++ b/templates/nodejs-project/README.md @@ -27,4 +27,6 @@ --- -Made with :heart: by [PROJECT_AUTHOR_NAME](PROJECT_AUTHOR_URL) using [node-project initializer](https://github.com/nmicht/create-node-project) +Made with :heart: by [PROJECT_AUTHOR_NAME](PROJECT_AUTHOR_URL). + +This project was bootstrapped with [nodejs-project initializer](https://github.com/nmicht/create-nodejs-project) diff --git a/templates/nodejs-project/package.json b/templates/nodejs-project/package.json index 8bfe94a..ef4afd6 100644 --- a/templates/nodejs-project/package.json +++ b/templates/nodejs-project/package.json @@ -8,7 +8,7 @@ "license": "PROJECT_LICENSE", "private": PROJECT_PRIVATE, "engines": { - "node": ">=10.9.0" + "node": ">=10.12.0" }, "scripts": { "start": "node ./src/index.js" From e34e003be85942389ecf9b2c3e39c51180fb4f65 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Fri, 1 Feb 2019 13:38:23 -0500 Subject: [PATCH 16/18] Fix scripts order --- package.json | 3 ++- scripts/install.js | 26 +------------------------- scripts/setup.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 scripts/setup.js diff --git a/package.json b/package.json index 7b0f12d..127663e 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,9 @@ "private": false, "scripts": { "postinstall": "node --no-warnings scripts/install.js", - "start": "node --no-warnings src/index.js", + "setup": "node --no-warnings scripts/setup.js", "cleanup": "node --no-warnings scripts/cleanup.js", + "start": "node --no-warnings src/index.js", "test": "mocha" }, "engines": { diff --git a/scripts/install.js b/scripts/install.js index 0f36e81..3c5da47 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -1,39 +1,15 @@ const fs = require('fs').promises; -const questions = require('../src/questionnaire/questions'); const settings = require('../src/settings'); /** - * Install function for the package, it set up the github auth details - * TODO Consider the case for a previous auth file with different tokens + * Install function for the package, it set up all the settings details */ (async () => { - let user; try { await fs.access(settings.settingsPath); await settings.load(); } catch (e) { settings.update(); } - - const authFileAnswers = await questions.promptSettingsFile(settings.settingsPath); - settings.settingsPath = authFileAnswers.settingsPath; - - try { - user = await settings.firstUser(); - } catch (e) { - // console.log('fixme'); - } - - - const authUser = await questions.promptGithubUser(user.user || ''); - const authToken = await questions.promptAuthToken(user.user || '', user.token || ''); - - settings.githubAuth = { - user: authUser.github.user, - token: authToken.github.token, - }; - - await settings.update(); - console.log(`Your settings file was updated on ${settings.settingsPath}`); })(); diff --git a/scripts/setup.js b/scripts/setup.js new file mode 100644 index 0000000..0f36e81 --- /dev/null +++ b/scripts/setup.js @@ -0,0 +1,39 @@ +const fs = require('fs').promises; + +const questions = require('../src/questionnaire/questions'); +const settings = require('../src/settings'); + +/** + * Install function for the package, it set up the github auth details + * TODO Consider the case for a previous auth file with different tokens + */ +(async () => { + let user; + try { + await fs.access(settings.settingsPath); + await settings.load(); + } catch (e) { + settings.update(); + } + + const authFileAnswers = await questions.promptSettingsFile(settings.settingsPath); + settings.settingsPath = authFileAnswers.settingsPath; + + try { + user = await settings.firstUser(); + } catch (e) { + // console.log('fixme'); + } + + + const authUser = await questions.promptGithubUser(user.user || ''); + const authToken = await questions.promptAuthToken(user.user || '', user.token || ''); + + settings.githubAuth = { + user: authUser.github.user, + token: authToken.github.token, + }; + + await settings.update(); + console.log(`Your settings file was updated on ${settings.settingsPath}`); +})(); From 529204c077f338481e3cc86ff2ca898aac26b69c Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Fri, 1 Feb 2019 13:39:31 -0500 Subject: [PATCH 17/18] Update node.js version for CI --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 64a2f6b..4555503 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: node_js node_js: - - "iojs" - "10" From 23eb505ba3c0db1f810d26709472aa2394735509 Mon Sep 17 00:00:00 2001 From: Mihelle Torres Date: Fri, 1 Feb 2019 14:05:10 -0500 Subject: [PATCH 18/18] v1.0.0 --- CHANGELOG.md | 5 +++++ README.md | 11 +++++++++-- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a16bd..b86dffe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.0.0 +* Settings is a global object handle from an accessible json file. +* Includes some unit tests +* Added CI with travis + ## 0.2.0 * Generate license file diff --git a/README.md b/README.md index 5a06f35..a215a39 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Node.js Project Initializer -[![License][license-image]][license-url] [![version][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] +[![License][license-image]][license-url] [![version][npm-image]][npm-url] [![coverage][coverage-image]][coverage-url] [![downloads][downloads-image]][downloads-url] An [npm initializer][npm/init] to scaffold a node project and include basic tools like lint, testing, etc. @@ -22,7 +22,11 @@ An [npm initializer][npm/init] to scaffold a node project and include basic tool npm install -g create-nodejs-project ``` -2. You will be prompted for your Github information +2. Run the setup configuration +``` +npm setup +``` +You will be prompted for your Github information If you do not have the information at the moment, you can keep it empty. In order to create projects with Github integration, you will need to add the authentication information later. See [Github Auth](#configure-Github-authentication) @@ -107,3 +111,6 @@ If you are planning to allow this script to create your Github repositories, is [downloads-url]: https://www.npmjs.com/package/create-nodejs-project [downloads-image]: https://img.shields.io/npm/dt/create-nodejs-project.svg?style=for-the-badge + +[coverage-url]: https://coveralls.io/github/nmicht/create-nodejs-project?branch=master +[coverage-image]: https://img.shields.io/coveralls/github/nmicht/create-nodejs-project.svg?style=for-the-badge diff --git a/package-lock.json b/package-lock.json index 7ae1c22..0a951f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "create-nodejs-project", - "version": "0.2.0", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 127663e..6e53479 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "create-nodejs-project", - "version": "0.2.0", + "version": "1.0.0", "description": "An npm initializer to scaffold a node project and include basic tools like lint, testing, etc.", "main": "src/index.js", "bin": "src/index.js",