Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Allow user to specify path to custom README template #68

Merged
merged 13 commits into from
Jun 23, 2019
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@
"test",
"ideas"
]
},
{
"login": "hgb123",
"name": "Bao Ho",
"avatar_url": "https://avatars0.githubusercontent.com/u/18468577?v=4",
"profile": "https://github.com/hgb123",
"contributions": [
"code",
"test"
]
}
],
"contributorsPerLine": 7,
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Feel free to check [issues page](https://github.com/kefranabg/readme-md-generato
<td align="center"><a href="https://github.com/samit4me"><img src="https://avatars3.githubusercontent.com/u/3248531?v=4" width="75px;" alt="Samuel Sharpe"/><br /><sub><b>Samuel Sharpe</b></sub></a><br /><a href="https://github.com/kefranabg/readme-md-generator/commits?author=samit4me" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/apatrascu"><img src="https://avatars3.githubusercontent.com/u/1193770?v=4" width="75px;" alt="Alecsandru Patrascu"/><br /><sub><b>Alecsandru Patrascu</b></sub></a><br /><a href="https://github.com/kefranabg/readme-md-generator/commits?author=apatrascu" title="Code">💻</a></td>
<td align="center"><a href="http://milad.nekofar.com"><img src="https://avatars3.githubusercontent.com/u/147401?v=4" width="75px;" alt="Milad Nekofar"/><br /><sub><b>Milad Nekofar</b></sub></a><br /><a href="https://github.com/kefranabg/readme-md-generator/commits?author=nekofar" title="Code">💻</a> <a href="https://github.com/kefranabg/readme-md-generator/commits?author=nekofar" title="Tests">⚠️</a> <a href="#ideas-nekofar" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/hgb123"><img src="https://avatars0.githubusercontent.com/u/18468577?v=4" width="75px;" alt="Bao Ho"/><br /><sub><b>Bao Ho</b></sub></a><br /><a href="https://github.com/kefranabg/readme-md-generator/commits?author=hgb123" title="Code">💻</a> <a href="https://github.com/kefranabg/readme-md-generator/commits?author=hgb123" title="Tests">⚠️</a></td>
</tr>
</table>

Expand Down
4 changes: 2 additions & 2 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ const askQuestions = async (projectInfos, skipQuestions) => {
*
* @param {Object} args
*/
const mainProcess = async ({ template, yes }) => {
const mainProcess = async ({ templatePath, yes }) => {
const projectInformations = await infos.getProjectInfos()
const answersContext = await cli.askQuestions(projectInformations, yes)
const readmeContent = await readme.buildReadmeContent(
answersContext,
template
templatePath
)

await readme.writeReadme(readmeContent)
Expand Down
10 changes: 5 additions & 5 deletions src/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('cli', () => {
})

it('should call main functions with correct args', async () => {
const template = 'default'
const templatePath = 'default'
const projectInformations = { name: 'readme-md-generator' }
const readmeContent = 'content'
projectInfos.getProjectInfos = jest.fn(() =>
Expand All @@ -67,7 +67,7 @@ describe('cli', () => {
readme.writeReadme = jest.fn()
utils.showEndMessage = jest.fn()

await cli.mainProcess({ template })
await cli.mainProcess({ templatePath })

expect(projectInfos.getProjectInfos).toHaveBeenCalledTimes(1)
expect(cli.askQuestions).toHaveBeenNthCalledWith(
Expand All @@ -78,19 +78,19 @@ describe('cli', () => {
expect(readme.buildReadmeContent).toHaveBeenNthCalledWith(
1,
answersContext,
template
templatePath
)
expect(readme.writeReadme).toHaveBeenNthCalledWith(1, readmeContent)
expect(utils.showEndMessage).toHaveBeenCalledTimes(1)
})

it('should forward --yes option to askQuestions', async () => {
const template = 'default'
const templatePath = 'default'
const projectInformations = { name: 'readme-md-generator' }
const skipQuestions = true
utils.showEndMessage = jest.fn()

await cli.mainProcess({ template, yes: skipQuestions })
await cli.mainProcess({ templatePath, yes: skipQuestions })

expect(cli.askQuestions).toHaveBeenNthCalledWith(
1,
Expand Down
9 changes: 8 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const yargs = require('yargs')

const { mainProcess } = require('./cli')
const { getReadmeTemplatePath } = require('./readme')

yargs
.usage('Usage: $0 <command> [options]')
Expand All @@ -14,8 +15,14 @@ yargs
desc: 'The name of template you want to use',
default: 'default'
}),
args => mainProcess(args)
args => {
const templatePath = getReadmeTemplatePath(args)
mainProcess({ templatePath, yes: args.yes })
}
)
.string('p')
.alias('p', 'path')
.describe('path', 'Path to your own template')
.boolean('yes')
.alias('y', 'yes')
.describe('yes', 'Use default values for all fields')
Expand Down
42 changes: 33 additions & 9 deletions src/readme.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const ejs = require('ejs')
const path = require('path')
const ora = require('ora')
const { promisify } = require('util')
const getYear = require('date-fns/get_year')
const fs = require('fs')
const path = require('path')

const README_PATH = 'README.md'

Expand Down Expand Up @@ -43,17 +43,13 @@ const getReadmeTemplate = async templatePath => {
}

/**
* Build README content with the given answersContext and templateName
* Build README content with the given context and templatePath
*
* @param {Object} context
* @param {string} templateName
* @param {string} templatePath
*/
const buildReadmeContent = async (context, templateName) => {
const buildReadmeContent = async (context, templatePath) => {
const currentYear = getYear(new Date())
const templatePath = path.resolve(
__dirname,
`../templates/${templateName}.md`
)
const template = await getReadmeTemplate(templatePath)

return ejs.render(template, {
Expand All @@ -63,8 +59,36 @@ const buildReadmeContent = async (context, templateName) => {
})
}

/**
* Get path to the readme template
*
* @param {string} availableTemplate
* @param {string} customTemplate
*/
const getReadmeTemplatePath = args => {
const spinner = ora('Resolving README template path').start()

const { template: availableTemplate, path: customTemplate } = args

const templatePath =
customTemplate ||
path.resolve(__dirname, `../templates/${availableTemplate}.md`)

try {
fs.lstatSync(templatePath).isFile()
hgb123 marked this conversation as resolved.
Show resolved Hide resolved
} catch (err) {
spinner.fail(`The template path ${templatePath} is not valid.`)
throw err
}

spinner.succeed('README template path resolved')

return templatePath
}

module.exports = {
writeReadme,
buildReadmeContent,
README_PATH
README_PATH,
getReadmeTemplatePath
}
77 changes: 72 additions & 5 deletions src/readme.spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
const fs = require('fs')
const ora = require('ora')
const path = require('path')

jest.mock('ora')

const { writeReadme, buildReadmeContent, README_PATH } = require('./readme')
const {
writeReadme,
buildReadmeContent,
README_PATH,
getReadmeTemplatePath
} = require('./readme')

describe('readme', () => {
const succeed = jest.fn()
Expand Down Expand Up @@ -63,7 +69,7 @@ describe('readme', () => {
})

describe('buildReadmeContent', () => {
const templateName = 'default'
const templatePath = path.resolve(__dirname, `../templates/default.md`)
const context = {
isGithubRepos: true,
repositoryUrl: 'https://github.com/kefranabg/readme-md-generator',
Expand Down Expand Up @@ -98,7 +104,7 @@ describe('readme', () => {
})

it('should call ora with correct parameters in success case', async () => {
await buildReadmeContent(context, templateName)
await buildReadmeContent(context, templatePath)

expect(ora).toHaveBeenCalledTimes(1)
expect(ora).toHaveBeenCalledWith('Loading README template')
Expand All @@ -107,7 +113,7 @@ describe('readme', () => {
})

it('should return readme template content', async () => {
const result = await buildReadmeContent(context, templateName)
const result = await buildReadmeContent(context, templatePath)

expect(result).toMatchSnapshot()
})
Expand All @@ -118,7 +124,7 @@ describe('readme', () => {
})

try {
await buildReadmeContent(context, templateName)
await buildReadmeContent(context, templatePath)
// eslint-disable-next-line no-empty
} catch (err) {}

Expand All @@ -128,4 +134,65 @@ describe('readme', () => {
expect(fail).toHaveBeenCalledWith('README template loading fail')
})
})

describe('getReadmeTemplatePath', () => {
it('should return default template path if customTemplate is undefined', () => {
const args = { template: 'default' }
const actualResult = getReadmeTemplatePath(args)
const expectedResult = path.resolve(__dirname, `../templates/default.md`)

expect(actualResult).toEqual(expectedResult)
})

it('should return custom template path if customTemplate is defined', () => {
const customTemplatePath = path.resolve(
__dirname,
`../templates/default.md`
)
const args = { template: 'default', path: customTemplatePath }
const expectedResult = customTemplatePath
const actualResult = getReadmeTemplatePath(args)

expect(actualResult).toEqual(expectedResult)
})

it('should throw an error if customTemplate is defined but invalid', () => {
const args = { template: 'default', path: 'wrong path' }

expect(() => getReadmeTemplatePath(args)).toThrow()
})

it('should call ora with correct parameters in fail case', async () => {
const args = { template: 'default', path: 'wrong path' }

try {
getReadmeTemplatePath(args)
// eslint-disable-next-line no-empty
} catch (err) {}

expect(ora).toHaveBeenNthCalledWith(1, 'Resolving README template path')
expect(fail).toHaveBeenNthCalledWith(
1,
'The template path wrong path is not valid.'
)
})

it('should call ora with correct parameters in success case', async () => {
const args = {
template: 'default',
path: path.resolve(__dirname, `../templates/default.md`)
}

try {
getReadmeTemplatePath(args)
// eslint-disable-next-line no-empty
} catch (err) {}

expect(ora).toHaveBeenNthCalledWith(1, 'Resolving README template path')
expect(succeed).toHaveBeenNthCalledWith(
1,
'README template path resolved'
)
})
})
})