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

[OC-28] Cli init allows for --templateType to be npm module #480

Merged
merged 20 commits into from
Jul 27, 2017

Conversation

nickbalestra
Copy link
Contributor

If the templatetype passed to the init comand is not 'jade' or 'handlebars' (default) but a valid oc-template module, the cli will download it and use it to generate boilerplate.

Example of boilerplate code used by the cli to generate a component

  • Coded to easily add yarn in the future 😍 (not yet supported)
  • Don't install template if already available on local dev registry
  • Use boilerplate code hosted template
  • add readme into boilerplates
  • logger dependcy injection
  • unit tests

A couple of extra notes:
For the moment templates defines "compileDependencies" in their package.json. Those are required and will be installed in order to compile template-specific components and therefore templates to work rely on being initialized through the oc init command. The rationale was to avoid having to install all such dependencies on the registry or in places where are not needed at all. Down-size is that for a component creator point of view the api is not too ergonomic as it won't be possible to simply create a component with the right template type and dependencies to work without running oc init or manually installing compileDependencies. To address this in the near future we might split templates in two modules, a client modules and a compile module.

@matteofigus
Copy link
Member

I'm not sure what's happening with appveyor. When I click details, it goes to a different PR

@matteofigus matteofigus changed the title [GPT-537]Cli init allows for --templateType to be npm module [GPT-537] Cli init allows for --templateType to be npm module May 11, 2017
Copy link
Member

@matteofigus matteofigus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First round of reviews. There are many minor things but the overall structure seems ok and I think tests cover the
various scenarios quite well 👍

const logger = config.logger;

try {
const bluprinting = new Spinner(`Blueprinting component...`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to the shared strings?


fs.writeJsonSync(componentPath + '/package.json', packageContent);
bluprinting.stop();
logger.log(`${colors.green('✔')} Files created at ${componentPath}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for this one

logger.log(`${colors.green('✔')} Files created at ${componentPath}`);
return callback(null, { ok: true });
} catch (error) {
return callback(`Blueprinting failed. Please open an issue on ${templatePackage.bugs.url} with the following information: ${error}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this one

creating.start();
fs.ensureDirSync(componentPath);
creating.stop(true);
logger.log(`${colors.green('✔')} Created directory "${componentName}"`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

createComponentDir(config);

try {
// If template available in the dev registry, generate boilerplate out of its blueprint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever this comment is trying to tell me, I don't understand it :D Can you be more clear about what this is doing?

const pathDir = '../../components/base-component-' + templateType,
baseComponentDir = path.resolve(__dirname, pathDir),
npmIgnorePath = path.resolve(__dirname, pathDir + '/.npmignore');
// LEGACY TEMPLATES
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to own file like init-legacy-templates.js so that we can make this comment redundant?

@@ -19,7 +19,7 @@ module.exports = function(dependencies){

callback = wrapCliCallback(callback);

local.init(componentName, templateType, (err) => {
local.init(componentName, templateType, { logger: logger }, err => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ logger } ?

});
it('should correctly invoke ensureDirSync', () => {
expect(deps['fs-extra'].ensureDirSync.calledWith(
config.componentPath
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personal preference, I like repetition on tests to improve readability. I prefer to read that's called with path/to/component over the config, so that if I scroll a lot in the bottom, each tests still tells me what this is doing by looking at it instead of scrolling back up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im fine either way

}
};

const initPackage = injectr('../../src/cli/domain/init-template/initPackage.js', deps, {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a minor one, but I think we usually follow conventions of init-package for filenames. Are you able to bring all the new files in this PR back to follow the same convention?

it('should return the unaltered package name if alrady given', () => {
expect(getPackageName('oc-template-jade')).to.equal('oc-template-jade');
expect(getPackageName('are-we-there-yet-1.1.2.tgz')).to.equal('are-we-there-yet');
expect(getPackageName('oc-template-jade@next')).to.equal('oc-template-jade');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well done on testing all of these scenarios

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😎

@nickbalestra
Copy link
Contributor Author

@matteofigus I've change pr base so that now this will merge to master (as the templates branch was already been merged). Addressed all the previous points, rebased and improved it a bit further.

Copy link
Member

@matteofigus matteofigus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a second round of review. There may be more to come but I think this is good to start

installCompiler: (compiler, fromLocal) =>
`Installing ${compiler} from ${fromLocal ? 'local' : 'npm'}...`,
installCompilerSuccess: (template, compiler, version) =>
`${colors.green('✔')} Installed ${compiler} [${template.replace(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think template.replace is not something I would put here. I prefer this to have simple text replacements and this to be done to however calls this (template should already be without -compiler)

@@ -0,0 +1,20 @@
module.exports = (logger, componentName, componentPath) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use a multiline template literal and actually move this to the resources file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause multiline is space sensitive, it will look a bit ugly on that file. I've commited it so that you can see. I think is ok for now as we need to rethink that part anyway.

const {
componentName,
templateType,
logger = console,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger will be sent by the facade, so we don't need to fallback to console

logger = console,
cli = 'npm'
} = options;
const componentPath = path.join(process.cwd(), componentName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we generate componentPath in the facade, and pass it through each call? so that process-cwd() is not repeated in multiple places.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually happen in one place. The other calls to process-cwd() are for different matters (local compiler, resolve for path being passed for template). But agree on hoisting it up in the facade. 👍


module.exports = function(options) {
const { cli, componentPath } = options;
spawn.sync(cli, ['init', '--yes'], { cwd: componentPath });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the point on abstracting cli into a separate variable if we support only npm? I would rather explicitly have npm here and abstract only if we add support to yarn or other tools in the future.


fs.copySync(baseComponentFiles, componentPath);

const componentPackage = require(componentPath + '/package.json');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use readJsonSync as you are requiring something and then overriding its own cache by changing the file immediately after...

});

scaffold.stop();
// logger.log(strings.messages.cli.scaffoldSuccess(componentPath));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this comment?

fs.outputJsonSync(componentPath, component, { spaces: 2 });

return callback(null, { ok: true });
initTemplate({ componentName, templateType, logger }, callback);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initTemplate looks asynchronous to me. So this try/catch should be converted to an async callback check

@@ -135,9 +138,24 @@ module.exports = {
},
messages: {
cli: {
installCompiler: (compiler, fromLocal) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we keep those alphabetic. Perhaps first all lower case (new format) then all upper case (old format to be converted to new)

`${colors.green('✔')} Files created at ${componentPath}`,
creatingDir: () => `Creating directory...`,
createdDir: dirName =>
`${colors.green('✔')} Created directory "${dirName}"`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I like the ${colors.green('✔')} been here. The responsibility of this file should not be to have colors. I would rather create a new method in the logger, like logger.okV('message') which does this for you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll suggest we do this afterward as we rethink/rearchitect the facade part

@nickbalestra
Copy link
Contributor Author

nickbalestra commented Jul 24, 2017

@matteofigus Thanks for the great review/comments.
After our conversation, aside addressing the review, couple of things extras:

  • move all the logging/ui into the facade - To be done in a follow-up PR
  • removed support for path being passed for templates.
  • removed spinner support (so that everything is a bit simpler yet, we can do some follow-up PR when we address the facade/cliUX system)
  • addressed all of the previous comments

@nickbalestra nickbalestra force-pushed the GPT-537 branch 2 times, most recently from 8fb76ee to 490fadb Compare July 24, 2017 23:06
shrinkwrap

ora replacement

blueprint and error handling

shwrinkrap

test wip

dependency injection for logger

fixed init.js tests

init-template cleanup
Copy link
Member

@matteofigus matteofigus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple of little things. Also, can you qa doing oc init hello jade|handlebars to test if all works without breaking changes compared to the past? (testing that then both dev and publish work as expected)? Thanks

describe('when invoked', () => {
const options = {
componentPath: 'path/to/component',
cli: 'npm'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this line

describe('when invoked', () => {
const config = {
templateType: 'oc-template-jade',
cli: 'npm',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

templateType: 'oc-template-jade',
cli: 'npm',
componentPath: 'path/to/component',
local: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

componentName,
logger,
componentPath,
compiler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetic

templateType,
compiler,
componentPath,
logger
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetic

componentPath,
compiler,
compilerPath,
logger
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetic

templateType,
logger,
componentPath,
compiler: `${templateType}-compiler`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetic

@nickbalestra
Copy link
Contributor Author

@matteofigus addressed the reviewed points. Some context for you when you'll review it again:

I've QA the following scenarios (both with the compiler already installed on the dev registry or not):

  • oc init myComponent -> will setup oc-template-handlebars (work both init & dev, therefore publish)
  • oc init myComponent handlebars -> will setup oc-template-handlebars (work both init & dev, therefore publish)
  • oc init myComponent jade -> will setup oc-template-jade (work both init & dev, therefore publish)
  • oc init myComponent oc-template-handlebars/jade -> will setup oc-template-handlebars/jade (work both init & dev, therefore publish)

All seems good now

@matteofigus
Copy link
Member

LGTM. Let's merge and release tomorrow first thing 👍

@matteofigus matteofigus changed the title [GPT-537] Cli init allows for --templateType to be npm module [OC-28] Cli init allows for --templateType to be npm module Jul 27, 2017
@matteofigus matteofigus merged commit 343900e into master Jul 27, 2017
@matteofigus matteofigus deleted the GPT-537 branch July 27, 2017 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants