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

Change changelog task to for direct invocation from external command #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions blueprints/ember-cli-changelog/files/config/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ module.exports = {
// format: 'YYYY-MM-DD',
// timezone: 'America/Los_Angeles',

beforeCommit: function(project, versions) {
beforeCommit: function(project, tags) {
console.log(project);
return generateChangelog.call(project);
return generateChangelog(project, tags.latest, tags.next);
Copy link
Collaborator

Choose a reason for hiding this comment

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

The usage in this file was actually buggy, it was intended to be used this way:

beforeCommit: generateChangelog

We can account for separation of the tags in a wrapper function layer within either project if necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I updated this line so that it would reflect my other changes, but like I said before I'd like to avoid making the user add this to their config/release.js, so I think the issue is moot.

}
};
22 changes: 19 additions & 3 deletions lib/commands/changelog.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// jshint node:true
'use strict';

var SilentError = require('silent-error');
var chalk = require('chalk');
var generateChangelog = require('../tasks/changelog');

module.exports = {
Expand All @@ -11,9 +13,23 @@ module.exports = {

availableOptions: [],

anonymousOptions: [],
anonymousOptions: [
'<from-rev>',
'<release-name>',
],
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like you intend to invoke ember-cli-changelog from the command line. You can actually do this easier via good old require.

try {
  var generateChangelog = require('ember-cli-changelog/lib/tasks/release-with-changelog');
} catch (e) {
  throw new Error("Please ensure that you have installed ember-cli-changelog");
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, that's what I want to do, see this branch over on ember-cli-release.

The command args are separate from how release will use it, but are necessary to include if the task is to be self-contained, i.e. if these weren't provided on the command line, the config would have to be read in before the task is invoked.

This is part of a larger question I had about how you see the changelog command being used by itself. The way I understand it, there's two options:

  1. Suggest that ember changelog be set as the version hook of npm version, use the updated version as the new release/tag name and head option, leaving the user to specify what commit to start from.
  2. Assume changelog updates happen before version bump/tagging and use the package version as the start commit, leaving the user to specify the release/tag name.

Either way I think it requires the user to specify more information to the command. Hope I'm not missing something obvious.


run: function() {
return generateChangelog.call(this);
run: function(options, rawArgs) {
var fromRev = rawArgs.shift();
var releaseName = rawArgs.shift();

if (!fromRev) {
throw new SilentError("Changelog generation requires a valid starting git revision.");
}

if (!releaseName) {
throw new SilentError("Changelog generation requires specifying the name of the release.");
}

return generateChangelog(this.project, fromRev, releaseName);
}
};
10 changes: 5 additions & 5 deletions lib/helpers/create-updated-changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ var fs = require('fs');
var path = require('path');
var chalk = require('chalk');

module.exports = function(config, groups) {
var changelogPath = path.join(config.project.root, 'CHANGELOG.md');
var tmpPath = path.join(config.project.root, 'tmp/CHANGELOG-' + (new Date()).getTime() + '.md');
module.exports = function(project, config, groups) {
var changelogPath = path.join(project.root, 'CHANGELOG.md');
var tmpPath = path.join(project.root, 'tmp/CHANGELOG-' + (new Date()).getTime() + '.md');

var changes = generateChanges.call(this, config, groups);
var changes = generateChanges(config, groups);

if (fs.existsSync(changelogPath)) {
var file = fs.readFileSync(changelogPath).toString();
Expand All @@ -24,7 +24,7 @@ module.exports = function(config, groups) {

fs.writeFileSync(tmpPath, lines.join('\n'));
} else {
this.ui.writeLine(chalk.red("Error: CHANGELOG.md does not exist!"));
project.ui.writeLine(chalk.red("Error: CHANGELOG.md does not exist!"));
process.exit(1);
}

Expand Down
56 changes: 56 additions & 0 deletions lib/helpers/get-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// jshint node:true
'use strict';

var path = require('path');
var fs = require('fs');
var chalk = require('chalk');
var objectAssign = require('object-assign');
var readPackage = require('./read-package');
var getRepoInfo = require('./get-repo-info');

// Returns a config object augmented with user defined config options
module.exports = function getConfig(project) {
var pkg = readPackage(project.root);
var config = {
root: project.root,
version: pkg.version,
};

return getRepoInfo(project)
.then(function(repoInfo) {
// Add repo info to the config object
objectAssign(config, repoInfo);

config.hostIsGithub = repoInfo.service === 'github';
config.hostIsBitbucket = repoInfo.service === 'bitbucket';
config.hostIsCustom = repoInfo.service === 'custom';

return readConfig(project);
}).then(function(userConfig) {
// Add user config options to the config object
objectAssign(config, userConfig);

return config;
});
};

function readConfig(project) {
if (project._changelogConfig) {
return project._changelogConfig;
}
var configPath = path.join(project.root, 'config/changelog.js');
var config = {};

if (fs.existsSync(configPath)) {
config = require(configPath);
project._changelogConfig = config;

if (!config.head) {
config.head = 'master';
}

return config;
}

throw "Error: config/changelog.js is not defined. You may need to run `ember g ember-cli-changelog`.";
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

It appears you primarily moved this from tasks to helpers, could you do it in a way to preserve history so changes are more clear?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Dammit git. Yeah, I think it will work to do it in a rename commit and an update commit.

119 changes: 54 additions & 65 deletions lib/tasks/get-project.js → lib/helpers/get-repo-info.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*jshint node:true*/
'use strict';

var RSVP = require('rsvp');
var Promise = RSVP.Promise; // jshint ignore:line
var validUrl = require('valid-url');
var readPackage = require('./../helpers/read-package');
var updatePackage = require('./../helpers/update-package');
var getConfig = require('./get-config');
var Promise = RSVP.Promise; // jshint ignore:line

// expected repository url forms

Expand All @@ -21,62 +21,61 @@ var getConfig = require('./get-config');
// git@try.gogs.io:<org>/<project>.git
// https://try.gogs.io/<org>/<project>.git

module.exports = function getRepoInfo(project) {
return getRepoURL(project).then(function(link) {
var parts = link.split('/');
var projectName = parts.pop();
var org = parts.pop();
var service = getService(link);
if (projectName.indexOf('.git') !== -1) {
projectName = projectName.substr(0, projectName.indexOf('.git'));
}

return {
path: link,
organization: org,
name: projectName,
project: projectName,
service: service,
projectUrl: getUrlBase(link, service, org, projectName),
repositoryLink: link
};
});
};

module.exports = function() {
var pkg = readPackage.bind(this)();
var firstStep;
function getRepoURL(project) {
var pkg = readPackage(project.root);

if (!pkg.repository || (typeof pkg.repository !== 'string' && !pkg.repository.url)) {
firstStep = promptForRepoName.call(this)
return promptForRepoName(project)
.then(function(repositoryLink) {
updatePackage.call(this, {
updatePackage(project, {
repository: repositoryLink
});
return repositoryLink;
}.bind(this));
});
} else {
firstStep = Promise.resolve(pkg.repository.url || pkg.repository);
return Promise.resolve(pkg.repository.url || pkg.repository);
}
}

return firstStep
.then(function(link) {
var parts = link.split('/');
var project = parts.pop();
var org = parts.pop();
var service = getService(link);
if (project.indexOf('.git') !== -1) {
project = project.substr(0, project.indexOf('.git'));
}
var p = {
root: this.project.root,
path: link,
organization: org,
name: project,
project: this.project,
version: pkg.version,
service: service,
projectUrl: getUrlBase(link, service, org, project),
repositoryLink: link
};
var config = getConfig.call(this, p);

config.hostIsGithub = p.service === 'github';
config.hostIsBitbucket = p.service === 'bitbucket';
config.hostIsCustom = p.service === 'custom';

config.project = p;
return config;
}.bind(this));
};
function promptForRepoName(project) {
var promptOptions = {
message: "Your project's package.json file has a missing or empty 'repository'\n" +
"Please type or paste the link to the repository to continue.",
type: 'input',
name: 'repository'
};

function getService(link) {
if (link.indexOf('github.com') !== -1) {
return 'github';
}
if (link.indexOf('bitbucket.org') !== -1) {
return 'bitbucket';
}
return 'custom';
project.ui.writeLine("");
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks as though you've removed the "service" detection without replacing it elsewhere.

return project.ui.prompt(promptOptions)
.then(function(response) {
if (!validUrl.isUri(response.repository)) {
project.ui.writeError('Your answer does not appear to be a URL');
return promptForRepoName(project);
}
return response.repository;
});
}

function getUrlBase(link, service, org, project) {
Expand All @@ -102,22 +101,12 @@ function getUrlBase(link, service, org, project) {
return [base, org, project].join('/');
}


function promptForRepoName() {
var promptOptions = {
message: "Your project's package.json file has a missing or empty 'repository'\n" +
"Please type or paste the link to the repository to continue.",
type: 'input',
name: 'repository'
};

this.ui.writeLine("");
return this.ui.prompt(promptOptions)
.then(function(response) {
if (!validUrl.isUri(response.repository)) {
this.ui.writeError('Your answer does not appear to be a URL');
return promptForRepoName.call(this);
}
return response.repository;
}.bind(this));
function getService(link) {
if (link.indexOf('github.com') !== -1) {
return 'github';
}
if (link.indexOf('bitbucket.org') !== -1) {
return 'bitbucket';
}
return 'custom';
}
4 changes: 2 additions & 2 deletions lib/helpers/prompt-file-overwrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
var FileInfo = require('ember-cli/lib/models/file-info');
var fs = require('fs');

module.exports = function(config, files) {
module.exports = function(project, config, files) {
var info = new FileInfo({
action: 'write',
outputPath: files.originalPath,
displayPath: 'CHANGELOG.md',
inputPath: files.tmpPath,
ui: this.ui
ui: project.ui
});
var task = info.confirmOverwriteTask();
return task()
Expand Down
4 changes: 2 additions & 2 deletions lib/helpers/read-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ var path = require('path');
var fs = require('fs');
var jsonFile = require('jsonfile');

module.exports = function() {
var configPath = path.join(this.project.root, 'package.json');
module.exports = function(root) {
var configPath = path.join(root, 'package.json');
var opts;

if (fs.existsSync(configPath)) {
Expand Down
6 changes: 3 additions & 3 deletions lib/helpers/update-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ var jsonFile = require('jsonfile');
var objectAssign = require('object-assign');
var readPackage = require('./read-package');

module.exports = function(options) {
var configPath = path.join(this.project.root, 'package.json');
var opts = readPackage.call(this, configPath);
module.exports = function(project, options) {
var configPath = path.join(project.root, 'package.json');
var opts = readPackage(project.root);

objectAssign(opts, options);

Expand Down
35 changes: 18 additions & 17 deletions lib/tasks/changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@
'use strict';

var prepareCommits = require('../helpers/git/prepare-commits');
var getProject = require('./get-project');
var getConfig = require('../helpers/get-config');
var createUpdatedChangelog = require('../helpers/create-updated-changelog');
var promptFileOverwrite = require('../helpers/prompt-file-overwrite');
var defaultCommitFilter = require('../helpers/default-commit-filter');
var defaultCommitGroupSort = require('../helpers/default-commit-group-sort');
var defaultCommitFormatter = require('../helpers/default-commit-formatter');
var chalk = require('chalk');

module.exports = function() {
return getProject.call(this)
module.exports = function(project, fromRev, releaseName) {
// TODO: disambiguate this 'project' object from the ember-cli project instance
return getConfig(project)
.then(function(config) {
this.ui.writeLine(
project.ui.writeLine(
chalk.cyan("Generating Changes between ") +
chalk.yellow(config.base) +
chalk.yellow(fromRev) +
chalk.cyan(" and ") +
chalk.yellow(config.head) +
chalk.cyan(" for version ") +
chalk.yellow(config.versions.next));
chalk.yellow(releaseName));
if (config.hostIsGithub) {
this.ui.writeLine(chalk.yellow("Changes will only be generated based on commits" +
project.ui.writeLine(chalk.yellow("Changes will only be generated based on commits" +
" and tags already pushed to Github."));
}

var options = {
user: config.project.organization,
user: config.organization,
repo: config.hostIsGithub ? config.project.name : config.project.root,
base: config.base,
base: fromRev,
head: config.head
};

Expand Down Expand Up @@ -60,25 +61,25 @@ module.exports = function() {
})

// generate a new file
.then(createUpdatedChangelog.bind(this, config))
.then(createUpdatedChangelog.bind(null, project, config))

// prompt & overwrite
.then(promptFileOverwrite.bind(this, config))
.then(promptFileOverwrite.bind(null, project, config))

// alert finished
.then(function(status) {
if (status.action === 'overwrite') {
this.ui.writeLine(chalk.cyan('CHANGELOG.md updated for ' + config.versions.next));
project.ui.writeLine(chalk.cyan('CHANGELOG.md updated for ' + releaseName));
} else {
this.ui.writeLine(chalk.yellow('WARNING: Skipped CHANGELOG.md update for version ' + config.versions.next));
project.ui.writeLine(chalk.yellow('WARNING: Skipped CHANGELOG.md update for version ' + releaseName));
}
return true;
}.bind(this))
})

// catch errors
.catch(function(err) {
this.ui.writeError(err);
}.bind(this));
project.ui.writeError(err);
});

}.bind(this));
});
};
Loading