diff --git a/v1/lib/core/__tests__/utils.test.js b/v1/lib/core/__tests__/utils.test.js index 02182eed7fe4..79f0128efb0b 100644 --- a/v1/lib/core/__tests__/utils.test.js +++ b/v1/lib/core/__tests__/utils.test.js @@ -7,6 +7,7 @@ const path = require('path'); const fs = require('fs'); +const shell = require('shelljs'); const utils = require('../utils'); const blogPostWithTruncateContents = fs.readFileSync( @@ -96,6 +97,40 @@ describe('utils', () => { fs.writeFileSync(tempFilePath, 'Lorem ipsum :)'); expect(utils.getGitLastUpdated(tempFilePath)).toBeNull(); fs.unlinkSync(tempFilePath); + + // test renaming and moving file + + const tempFilePath2 = path.join(__dirname, '__fixtures__', '.temp2'); + const tempFilePath3 = path.join( + __dirname, + '__fixtures__', + 'test', + '.temp3', + ); + + // create new file + shell.exec = jest.fn(() => ({ + stdout: + '1539502055\n' + + '\n' + + ' create mode 100644 v1/lib/core/__tests__/__fixtures__/.temp2\n', + })); + const createTime = utils.getGitLastUpdated(tempFilePath2); + expect(typeof createTime).toBe('string'); + + // rename / move the file + shell.exec = jest.fn(() => ({ + stdout: + '1539502056\n' + + '\n' + + ' rename v1/lib/core/__tests__/__fixtures__/{.temp2 => test/.temp3} (100%)\n' + + '1539502055\n' + + '\n' + + ' create mode 100644 v1/lib/core/__tests__/__fixtures__/.temp2\n', + })); + const lastUpdateTime = utils.getGitLastUpdated(tempFilePath3); + // should only consider file content change + expect(lastUpdateTime).toEqual(createTime); }); test('idx', () => { diff --git a/v1/lib/core/utils.js b/v1/lib/core/utils.js index 602eea58b69e..0a09cc848323 100644 --- a/v1/lib/core/utils.js +++ b/v1/lib/core/utils.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -const spawn = require('cross-spawn'); +const shell = require('shelljs'); const TRUNCATE_MARKER = //; @@ -38,10 +38,34 @@ function idx(target, keyPaths) { ); } +function isNormalInteger(str) { + return /^\d+$/.test(str); +} + function getGitLastUpdated(filepath) { - const timeSpan = spawn - .sync('git', ['log', '-1', '--format=%ct', filepath]) - .stdout.toString('utf-8'); + // To differentiate between content change and file renaming / moving, use --summary + // To follow the file history until before it is moved (when we create new version), use + // --follow + const silentState = shell.config.silent; // save old silent state + shell.config.silent = true; + const result = shell + .exec(`git log --follow --summary --format=%ct ${filepath}`) + .stdout.trim(); + shell.config.silent = silentState; + + // Format the log results to be ['1234567', 'rename ...', '1234566', 'move ...', '1234565', '1234564'] + const records = result + .toString('utf-8') + .replace(/\n\s*\n/g, '\n') + .split('\n') + .filter(String); + + const timeSpan = records.find((item, index, arr) => { + const isTimestamp = isNormalInteger(item); + const isLastTwoItem = index + 2 >= arr.length; + const nextItemIsTimestamp = isNormalInteger(arr[index + 1]); + return isTimestamp && (isLastTwoItem || nextItemIsTimestamp); + }); if (timeSpan) { const date = new Date(parseInt(timeSpan, 10) * 1000); return date.toLocaleString();