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

feat(sub-directory): add -s, --sub-directory option #32

Closed
wants to merge 11 commits into from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ $ changelog -h
-x, --exclude <types> exclude selected commit types (comma separated)
-f, --file [file] file to write to, defaults to ./CHANGELOG.md, use - for stdout
-u, --repo-url [url] specify the repo URL for commit links, defaults to checking the package.json
-s, --sub-directory <path> specify an explicit relatvie path to a sub-directory
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like the alignment here is also a bit off. Can you generate the help and just replace the whole help text to make sure it's exactly as it would be outputted?


```

Expand Down
13 changes: 9 additions & 4 deletions bin/generate
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ var File = require('../lib/file');

CLI.parse(process.argv);

return Bluebird.all([
Changelog.generate(CLI),
File.readIfExists(CLI.file)
])
return File.normalizeFilePath(CLI.file, CLI.subDirectory)
.then(function (normalizedPath) {
CLI.file = normalizedPath;

return Bluebird.all([
Changelog.generate(CLI),
File.readIfExists(CLI.file)
]);
})
.spread(function (newLogs, oldLogs) {
return File.writeToFile(CLI.file, newLogs + oldLogs);
})
Expand Down
3 changes: 2 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ module.exports = CLI
.option('-t, --tag <range>', 'generate from specific tag or range (e.g. v1.2.3 or v1.2.3..v1.2.4)')
.option('-x, --exclude <types>', 'exclude selected commit types (comma separated)', list)
.option('-f, --file [file]', 'file to write to, defaults to ./CHANGELOG.md, use - for stdout', './CHANGELOG.md')
.option('-u, --repo-url [url]', 'specify the repo URL for commit links, defaults to checking the package.json');
.option('-u, --repo-url [url]', 'specify the repo URL for commit links, defaults to checking the package.json')
.option('-s, --sub-directory <path>', 'specify an explicit relatvie path to a sub-directory');
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you make the description specify a path to be passed into git log? And then maybe add a subsection within ## Usage in the README titled ### Sub-directory under ### Recommended to explain the nuances with how --file is relative from --sub-directory since it is a bit nuanced?

24 changes: 24 additions & 0 deletions lib/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var Bluebird = require('bluebird');
var Fs = Bluebird.promisifyAll(require('fs'));
var Path = Bluebird.promisifyAll(require('path'));
Copy link
Contributor

Choose a reason for hiding this comment

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

We're not using any async functions in path so we don't have to promisify it.


var STDOUT_PATH = '-';

Expand Down Expand Up @@ -42,3 +43,26 @@ exports.writeToFile = function (path, data) {
}
});
};

/**
* Normalize the input/output file path according to a sub-directory if needed
* @param {String} file - path of the input/ouput file
* @param {String|null} subDirectory - an explicit path to a sub-directory if given
* @returns {Promise}
*/
exports.normalizeFilePath = function (file, subDirectory) {
return Bluebird.resolve()
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't look like anything in this function is actually asynchronous so you don't have to make it return a promise. It should make the implementation a bit simpler.

.then(function () {
if (!subDirectory) {
return file;
}

file = Path.normalize(file);

if (Path.dirname(file) === '.') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry for not replying on the issue earlier, but I think the desired behavior of how -f and -s will work together will be to always have it be relative from the subdirectory. I think that will give the most options for where the file should go. For example, in the current implementation, I'm not sure there's any way to write the file to root directory of the repo (I tried CHANGELOG.md, ../CHANGELOG.md, ./../CHANGELOG.md).

And since this is a completely new feature, we don't have to worry about backwards compatibility as long as we don't affect the current functionality. So we should pick what makes the most sense and provides the greatest control.

return Path.join(subDirectory, file);
}

return file;
});
};
8 changes: 7 additions & 1 deletion lib/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ exports.getCommits = function (options) {
revisions = tag ? tag + '..HEAD' : '';
}

var gitLogCommand = 'git log -E --format=' + FORMAT + ' ' + revisions;

if (options.subDirectory) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like if you do git log -- ., it behaves the same way as git log, so it might simplify the logic if you make the default value of subDirectory . in lib/cli.js.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The combination of using default value for 'subDirectory' and discarding all the explicit path handling - make this PR way simpler 😅
Liked it way better though 👍

gitLogCommand += ' -- ' + options.subDirectory;
}

return CP.execAsync(
'git log -E --format=' + FORMAT + ' ' + revisions,
gitLogCommand,
{
maxBuffer: Number.MAX_SAFE_INTEGER
}
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var Writer = require('./writer');
* @param {Boolean} options.major - whether it should be a major changelog
* @param {String} options.repoUrl - repo URL that will be used when linking commits
* @param {Array} options.exclude - exclude listed commit types (e.g. ['chore', 'style', 'refactor'])
* @param {String} options.subDirectory - specify an explicit relatvie path to a sub-directory
* @returns {Promise<String>} the \n separated changelog string
*/
exports.generate = function (options) {
Expand Down
68 changes: 68 additions & 0 deletions test/file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var Sinon = require('sinon');

var File = require('../lib/file');

var DEFAULT_FILE = './CHANGELOG.md';
var NONEXISTENT = Path.resolve(__dirname, '../fake-file.txt');
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you align the equal signs within this block of vars?

var README = Path.resolve(__dirname, '../README.md');
var STDOUT_FD = 1;
Expand Down Expand Up @@ -79,4 +80,71 @@ describe('file', function () {

});

describe('normalizePath', function () {

it('default output, no sub-directory given => CHANGELOG.md in current directory', function () {
return File.normalizeFilePath(DEFAULT_FILE)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(DEFAULT_FILE);
});
});

it('default name, with sub-directory given => CHANGELOG.md in sub directory', function () {
var subDirectory = 'subdirectory';

return File.normalizeFilePath(DEFAULT_FILE, subDirectory)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(Path.join(subDirectory, DEFAULT_FILE));
});
});

it('explicit name, no sub-directory given => explicit name in current directory', function () {
var someFile = 'SOMEFILE.md';

return File.normalizeFilePath(someFile)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(someFile);
});
});

it('explicit name, with sub-directory given => explicit name in sub directory', function () {
var subDirectory = 'subdirectory';
var someFile = 'SOMEFILE.md';

return File.normalizeFilePath(someFile, subDirectory)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(Path.join(subDirectory, someFile));
});
});

it('default name, with deep-sub-directory given => CHANGELOG.md in deep-sub directory', function () {
var subDirectory = Path.join('path', 'to', 'subdirectory');

return File.normalizeFilePath(DEFAULT_FILE, subDirectory)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(Path.join(subDirectory, DEFAULT_FILE));
});
});

it('explicit output path, without sub-directory given => explicit output path', function () {
var explicitPath = Path.join('path', 'to', DEFAULT_FILE);

return File.normalizeFilePath(explicitPath)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(explicitPath);
});
});

it('explicit output path, with sub-directory given => explicit output path', function () {
var explicitPath = Path.join('path', 'to', DEFAULT_FILE);
var subDirectory = Path.join('some', 'other', 'directory');

return File.normalizeFilePath(explicitPath, subDirectory)
.then(function (normalizedPath) {
Expect(normalizedPath).to.eql(explicitPath);
});
});

});

});
26 changes: 26 additions & 0 deletions test/git.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,32 @@ describe('git', function () {
});
});

it('uses subDirectory for filtering git log command when `-s` / `--sub-directory` option was used', function () {
Sinon.stub(CP, 'execAsync')
.onFirstCall().returns(Bluebird.resolve('1.2.3.4'))
.onSecondCall().returns(Bluebird.resolve(VALID_COMMITS));

var subDirectory = 'subdirectory';

return Git.getCommits({ subDirectory: subDirectory })
.then(function () {
CP.execAsync.secondCall.calledWithMatch(new RegExp('-- ' + subDirectory + '$'));
CP.execAsync.restore();
});
});

it('git log command does not filter path when `-s` / `--sub-directory` option was not used', function () {
Sinon.stub(CP, 'execAsync')
.onFirstCall().returns(Bluebird.resolve('1.2.3.4'))
.onSecondCall().returns(Bluebird.resolve(VALID_COMMITS));

return Git.getCommits()
.then(function () {
CP.execAsync.secondCall.notCalledWithMatch(/-- /);
CP.execAsync.restore();
});
});

});

});