feat: last updated time in docs (#913)

* Adding last updated time for docs

* Making file path general and other suggested changes

* Checking if time returned is null due to absence of git or some other issue

* Adding option to enable/disable update time feature and test-doc

* Adding simple unit tests for getGitUpdateTime()

* nits & rewrote failing test

* consistent test naming

* Adding optional updateEnableTime in documentation

* package-lock & yarn.lock
This commit is contained in:
Shubham Bansal 2018-08-29 18:45:18 +05:30 committed by Endilie Yacop Sucipto
parent 5542ace288
commit 1a572757f1
10 changed files with 170 additions and 14 deletions

View file

@ -16,7 +16,8 @@ const DocsSidebar = require('./DocsSidebar.js');
const OnPageNav = require('./nav/OnPageNav.js');
const Site = require('./Site.js');
const translation = require('../server/translation.js');
const {idx} = require('./utils.js');
const docs = require('../server/docs.js');
const {idx, getGitLastUpdated} = require('./utils.js');
// component used to generate whole webpage for docs, including sidebar/header/footer
class DocsLayout extends React.Component {
@ -43,6 +44,12 @@ class DocsLayout extends React.Component {
if (this.props.Doc) {
DocComponent = this.props.Doc;
}
let updateTime;
if (this.props.config.enableUpdateTime) {
const filepath = docs.getFilePath(metadata);
updateTime = getGitLastUpdated(filepath);
}
const title =
idx(i18n, ['localized-strings', 'docs', id, 'title']) || defaultTitle;
const hasOnPageNav = this.props.config.onPageNav === 'separate';
@ -100,6 +107,13 @@ class DocsLayout extends React.Component {
</a>
)}
</div>
{this.props.config.enableUpdateTime &&
updateTime && (
<p style={{fontSize: '12px', textAlign: 'right'}}>
<strong>Last updated: </strong>
{updateTime}
</p>
)}
</Container>
{hasOnPageNav && (
<nav className="onPageNav">

View file

@ -0,0 +1,5 @@
---
title: Don't edit this
---
Do not edit this file

View file

@ -72,4 +72,29 @@ describe('utils', () => {
expect(utils.removeExtension('/docs/test')).toBe('/docs/test');
expect(utils.removeExtension('pages.js')).toBe('pages');
});
test('getGitLastUpdated', () => {
// existing test file in repository with git timestamp
const existingFilePath = path.join(__dirname, '__fixtures__', 'test.md');
const gitLastUpdated = utils.getGitLastUpdated(existingFilePath);
expect(typeof gitLastUpdated).toBe('string');
expect(Date.parse(gitLastUpdated)).not.toBeNaN();
expect(gitLastUpdated).not.toBeNull();
// non existing file
const nonExistingFilePath = path.join(
__dirname,
'__fixtures__',
'.nonExisting'
);
expect(utils.getGitLastUpdated(null)).toBeNull();
expect(utils.getGitLastUpdated(undefined)).toBeNull();
expect(utils.getGitLastUpdated(nonExistingFilePath)).toBeNull();
// temporary created file that has no git timestamp
const tempFilePath = path.join(__dirname, '__fixtures__', '.temp');
fs.writeFileSync(tempFilePath, 'Lorem ipsum :)');
expect(utils.getGitLastUpdated(tempFilePath)).toBeNull();
fs.unlinkSync(tempFilePath);
});
});

View file

@ -4,6 +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 TRUNCATE_MARKER = /<!--\s*truncate\s*-->/;
@ -32,9 +33,21 @@ function idx(target, path) {
return path.reduce((obj, key) => obj && obj[key], target);
}
function getGitLastUpdated(filepath) {
const timeSpan = spawn
.sync('git', ['log', '-1', '--format=%ct', filepath])
.stdout.toString('utf-8');
if (timeSpan) {
const date = new Date(parseInt(timeSpan, 10) * 1000);
return date.toLocaleString();
}
return null;
}
module.exports = {
blogPostHasTruncateMarker,
extractBlogPostBeforeTruncate,
getGitLastUpdated,
getPath,
removeExtension,
idx,

View file

@ -15,7 +15,7 @@ const readMetadata = require('./readMetadata.js');
const {insertTOC} = require('../core/toc.js');
const {getPath} = require('../core/utils.js');
function getFile(metadata) {
function getFilePath(metadata) {
if (!metadata) {
return null;
}
@ -31,6 +31,14 @@ function getFile(metadata) {
} else {
file = join(CWD, '..', readMetadata.getDocsPath(), metadata.source);
}
return file;
}
function getFile(metadata) {
if (!metadata) {
return null;
}
const file = getFilePath(metadata);
if (!fs.existsSync(file)) {
return null;
}
@ -123,6 +131,7 @@ function getRedirectMarkup(metadata) {
module.exports = {
getMarkup,
getFile,
getFilePath,
getRedirectMarkup,
mdToHtmlify,
replaceAssetsLink,