Skip to content

Commit 6624b8b

Browse files
committed
feat(developer): use git's last commit date for keyboard_info
1 parent b87667a commit 6624b8b

File tree

4 files changed

+71
-3
lines changed

4 files changed

+71
-3
lines changed

developer/src/kmc-keyboard-info/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export interface KeyboardInfoSources {
5151

5252
/** The source package filename and relative path (.kps) */
5353
kpsFilename: string;
54+
55+
/** Last modification date for files in the project folder 'YYYY-MM-DDThh:mm:ssZ' */
56+
lastCommitDate: string;
5457
};
5558

5659
export class KeyboardInfoCompiler {
@@ -164,8 +167,8 @@ export class KeyboardInfoCompiler {
164167

165168
this.fillLanguages(keyboard_info, kmpJsonData);
166169

167-
// TODO: use: TZ=UTC0 git log -1 --no-merges --date=format:%Y-%m-%dT%H:%M:%SZ --format=%ad
168-
keyboard_info.lastModifiedDate = (new Date).toISOString();
170+
// If a last commit date is not given, then just use the current time
171+
keyboard_info.lastModifiedDate = sources.lastCommitDate ?? (new Date).toISOString();
169172

170173
keyboard_info.packageFilename = this.callbacks.path.basename(sources.kmpFilename);
171174

developer/src/kmc/src/commands/buildClasses/BuildKeyboardInfo.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { KeyboardInfoCompiler } from '@keymanapp/kmc-keyboard-info';
55
import { loadProject } from '../../util/projectLoader.js';
66
import { InfrastructureMessages } from '../../messages/infrastructureMessages.js';
77
import { calculateSourcePath } from '../../util/calculateSourcePath.js';
8+
import { getLastGitCommitDate } from '../../util/getLastGitCommitDate.js';
89

910
export class BuildKeyboardInfo extends BuildActivity {
1011
public get name(): string { return 'Keyboard metadata'; }
@@ -43,13 +44,15 @@ export class BuildKeyboardInfo extends BuildActivity {
4344

4445

4546
const jsFilename = project.resolveOutputFilePath(keyboard, KeymanFileTypes.Source.KeymanKeyboard, KeymanFileTypes.Binary.WebKeyboard);
47+
const lastCommitDate = getLastGitCommitDate(callbacks.path.dirname(project.resolveInputFilePath(metadata)));
4648

4749
const compiler = new KeyboardInfoCompiler(callbacks);
4850
const data = compiler.writeMergedKeyboardInfoFile({
4951
kmpFilename: project.resolveOutputFilePath(kps, KeymanFileTypes.Source.Package, KeymanFileTypes.Binary.Package),
5052
kpsFilename: project.resolveInputFilePath(kps),
5153
jsFilename: fs.existsSync(jsFilename) ? jsFilename : undefined,
52-
sourcePath: calculateSourcePath(infile)
54+
sourcePath: calculateSourcePath(infile),
55+
lastCommitDate
5356
});
5457

5558
if(data == null) {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { execFileSync } from 'child_process';
2+
3+
/**
4+
* Returns the date and time of the last commit from git for the passed in path
5+
* @param path Path for which to retrieve the last commit message
6+
* @returns string, in RFC3339, 'YYYY-MM-DDThh:nn:ssZ'
7+
*/
8+
export function getLastGitCommitDate(path: string): string {
9+
// TZ=UTC0 git log -1 --no-merges --date=format:%Y-%m-%dT%H:%M:%SZ --format=%ad
10+
let result = null;
11+
12+
try {
13+
result = execFileSync('git', [
14+
'log', // git log
15+
'-1', // one commit only
16+
'--no-merges', // we're only interested in 'real' commits
17+
'--date=format:%Y-%m-%dT%H:%M:%SZ', // format the date in our expected RFC3339 format
18+
'--format=%ad' // emit only the commit date
19+
], {
20+
env: { ...process.env, TZ: 'TZ0' }, // use UTC timezone, not local
21+
encoding: 'utf-8', // force a string result rather than Buffer
22+
windowsHide: true, // on windows, we may need this to suppress a console window popup
23+
cwd: path, // path to run git from
24+
stdio: ['pipe', 'pipe', 'pipe'] // all output via pipe, so we don't get git errors on console
25+
});
26+
} catch (e) {
27+
// If git is not available, or the file is not in-repo, then it is probably
28+
// fine to just silently return null, as the only machines where this is
29+
// critical are the CI machines where we build and deploy .keyboard_info
30+
// files, and where git will always be available. It would be possible to
31+
// have this raise an error in CI environments, but the chance of error
32+
// seems low.
33+
return null;
34+
}
35+
36+
result = result.trim();
37+
38+
// We'll only return the result if it walks like a date, swims like a date,
39+
// and quacks like a date.
40+
if (!result.match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$/)) {
41+
return null;
42+
}
43+
44+
return result;
45+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { assert } from 'chai';
2+
import 'mocha';
3+
import { makePathToFixture } from './helpers/index.js';
4+
import { getLastGitCommitDate } from '../src/util/getLastGitCommitDate.js';
5+
6+
describe('getLastGitCommitDate', function () {
7+
it('should return a valid date for a folder in this repo', async function() {
8+
const path = makePathToFixture('.');
9+
const date = getLastGitCommitDate(path);
10+
assert.match(date, /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$/);
11+
});
12+
13+
it('should return null for a folder outside the repo', async function() {
14+
const date = getLastGitCommitDate('/');
15+
assert.isNull(date);
16+
});
17+
});

0 commit comments

Comments
 (0)