Skip to content

Commit 1c49f65

Browse files
authored
Merge branch 'vNext' into vkombov/update-batch-editing-remote-paging-sample-15
2 parents 7a01261 + b9680ef commit 1c49f65

10 files changed

Lines changed: 331 additions & 1 deletion

File tree

.hooks/prepare-commit-msg

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
4+
var validate = require('./scripts/validate'),
5+
fs = require('fs');
6+
7+
var options = {
8+
style: "default"
9+
};
10+
11+
var text = fs.readFileSync(process.argv[2]).toString();
12+
13+
var errors = [];
14+
errors = validate(text, options, errors);
15+
16+
if (errors.length > 0) {
17+
process.stdout.write(errors[0].toString());
18+
process.exitCode = 1;
19+
}

.hooks/scripts/common.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
module.exports = {
4+
matchType: (types, line) => {
5+
return types.some(function(type) {
6+
if (line.startsWith(type)) {
7+
return true;
8+
}
9+
10+
return false;
11+
});
12+
},
13+
14+
errorFactory: (prefix, message, additionalParams) => {
15+
var result = '';
16+
if (prefix) {
17+
result = prefix;
18+
}
19+
20+
result += message;
21+
22+
if (additionalParams) {
23+
result += additionalParams;
24+
}
25+
26+
return result;
27+
},
28+
29+
errorMessages: {
30+
MESSAGE_SHOULD_START_WITH_TYPE: 'Message should start with one of the following types:\n',
31+
NEED_OPENING_PARENTHESIS: 'Need an opening parenthesis right after the type: (',
32+
TYPE_WAS_EMPTY: '<type> was empty, it must be one of these: \n',
33+
TYPE_WAS_INVALID: '<type> was invalid, It has to be one of these:\n',
34+
NEED_CLOSING_PARENTHESIS: 'Need a closing parenthesis after scope declaration: <scope>")"',
35+
SCOPE_WAS_EMPTY: "<scope> cannot be empty!",
36+
NEED_A_COLON: "Need a colon after the closing parenthesis: ):",
37+
NEED_SPACE_AND_SUBJECT: 'Need a space and <subject> after colon: ": <subject>"',
38+
SUBJECT_WAS_EMPTY: '<subject> must not be empty',
39+
WRONG_REVERT_STRUCT: 'If this is a revert of a previous commit, please write:\n',
40+
UNDEFINED_OF_COMMIT_MSG: 'Commit message is undefined, abort with error',
41+
MSG_IS_NOT_A_STRING: 'Commit message is not a string, abort with error',
42+
MSG_IS_EMPTY: 'Commit message is empty, abort with error'
43+
}
44+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict';
2+
3+
var matchType = require('../common').matchType,
4+
errorFactory = require('../common').errorFactory,
5+
errMessages = require('../common').errorMessages;
6+
7+
module.exports = (lines, options, errors) => {
8+
var scheme = '<type>(<scope>): <subject> <#issue|optional>';
9+
var prefix = `First line must be ${scheme}\n`;
10+
11+
var line = lines[0];
12+
if (line.startsWith('revert: ')) {
13+
line = line.replace(/^revert: /, '');
14+
prefix = `First line must be revert: ${scheme}\n`;
15+
} else if (line.startsWith('revert')) {
16+
errors.push(errorFactory(errMessages.WRONG_REVERT_STRUCT, 'revert: ' + scheme));
17+
18+
return;
19+
}
20+
21+
if (!matchType(options.types, line)) {
22+
errors.push(errorFactory(prefix, errMessages.MESSAGE_SHOULD_START_WITH_TYPE, options.types.join(', ')));
23+
24+
return;
25+
}
26+
27+
if (line.indexOf('(') === -1) {
28+
errors.push(errorFactory(prefix, errMessages.NEED_OPENING_PARENTHESIS));
29+
30+
return;
31+
}
32+
33+
var type = line.replace(/\(.*/, '');
34+
if (options.types.indexOf(type) === -1) {
35+
errors.push(errorFactory(prefix, errMessages.TYPE_WAS_INVALID, options.types.join(', ')));
36+
37+
return;
38+
}
39+
40+
if (line.indexOf(')') === -1) {
41+
errors.push(errorFactory(prefix, errMessages.NEED_CLOSING_PARENTHESIS));
42+
43+
return;
44+
}
45+
46+
var scope = line.slice(line.indexOf('(') + 1, line.indexOf(')'));
47+
if (scope.length === 0) {
48+
errors.push(errorFactory(prefix, errMessages.SCOPE_WAS_EMPTY));
49+
}
50+
51+
if (line.indexOf(type + '(' + scope + '):') === - 1) {
52+
errors.push(errorFactory(prefix, errMessages.NEED_A_COLON));
53+
54+
return;
55+
}
56+
57+
var subject = line.split(':')[1];
58+
if (subject === "" || !subject.startsWith(' ')) {
59+
errors.push(errorFactory(prefix, errMessages.NEED_SPACE_AND_SUBJECT));
60+
61+
return;
62+
}
63+
64+
subject = subject.trim();
65+
66+
if (subject.length === 0) {
67+
errors.push(errorFactory(errMessages.SUBJECT_WAS_EMPTY));
68+
69+
return;
70+
}
71+
72+
if (subject.length < options.subjectLimits) {
73+
errors.push(`<subject> should contains at least ${options.subjectLimits} characters`);
74+
}
75+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
5+
var defaults = {
6+
default: {
7+
style: 'default',
8+
subjectLimits: 15,
9+
lineLimits: {
10+
firstLine: 80,
11+
otherLine: 80,
12+
},
13+
issuePattern: '(#)[0-9]+',
14+
typesWithMandatoryIssue: [],
15+
guidelinesUrl: 'https://bit.ly/angular-guidelines',
16+
types: [
17+
'feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'build', 'ci', 'revert'
18+
],
19+
},
20+
oldMessagePath: path.join('.git', 'COMMIT_EDITMSG_OLD')
21+
}
22+
23+
module.exports = defaults;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
var matchType = require('../common').matchType,
4+
errorFactory = require('../common').errorFactory;
5+
6+
module.exports = (lines, options, errors) => {
7+
var ticket = new RegExp(options.issuePattern);
8+
var whetherIssueIsMandatory = false,
9+
wheterMatchAnyIssueRef = false;
10+
11+
12+
if (matchType(options.typesWithMandatoryIssue, lines[0])) {
13+
whetherIssueIsMandatory = true;
14+
}
15+
16+
lines.forEach((line) => {
17+
line = line.trim();
18+
if (line === "") {
19+
return;
20+
}
21+
22+
if (ticket.test(line)) {
23+
wheterMatchAnyIssueRef = true;
24+
return;
25+
}
26+
});
27+
28+
if (whetherIssueIsMandatory && !wheterMatchAnyIssueRef) {
29+
errors.push(errorFactory(
30+
`The issue reference for (${options.typesWithMandatoryIssue.join(', ')}) types is mandatory!\n`,
31+
"Please add at least one related issue. E.g: Closes #31, Closes #45"));
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
module.exports = (lines, options, errors) => {
4+
var limits = options.lineLimits;
5+
lines.forEach((line, index) => {
6+
line = line.trim();
7+
if (index === 0) {
8+
if (line.length === 0) {
9+
errors.push('First line of commit message must not be empty!');
10+
} else if (line.length > limits.firstLine) {
11+
errors.push(`First line of commit message must be no logner than ${limits.firstLine} characters!`);
12+
}
13+
} else if (index === 1 && line.length > 0) {
14+
errors.push('Second line must be always empty!');
15+
} else if (line.length > limits.otherLine) {
16+
errors.push(
17+
`Commit message line ${index + 1} is too long: ${line.length}, only ${limits.otherLine} are allowed.
18+
The line is: ${line.substring(0, 20)} [...]!`
19+
);
20+
}
21+
});
22+
}

.hooks/scripts/validate.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
var defaultTemp = require('./templates/default'),
4+
commitValidator = require('./templateValidators/default-style-validator'),
5+
lineLimits = require('./utils/line-limits'),
6+
issuesValidator = require('./utils/issue-validator'),
7+
semver = require('semver'),
8+
errMessages = require('./common').errorMessages,
9+
errorFactory = require('./common').errorFactory;
10+
11+
module.exports = (message, options, errors) => {
12+
message = message.trim();
13+
if (message === undefined) {
14+
errors.push(errMessages.UNDEFINED_OF_COMMIT_MSG);
15+
} else if (!(typeof message === 'string' || message instanceof String)) {
16+
errors.push(errMessages.MSG_IS_NOT_A_STRING);
17+
} else if (message.length === 0) {
18+
errors.push(errMessages.MSG_IS_EMPTY);
19+
}
20+
21+
var lines = message.split('\n');
22+
if (semver.valid(lines[0])) {
23+
return [];
24+
}
25+
26+
if(lines[0].toLocaleLowerCase().startsWith("merge")) {
27+
return [];
28+
}
29+
30+
// Get the default template if the style property matches
31+
if (defaultTemp[options.style]) {
32+
options = defaultTemp[options.style];
33+
}
34+
35+
// Get the lineLimits options from the default
36+
// if the template is custom and there is no lineLimits declared.
37+
if (!options.lineLimits) {
38+
options.lineLimits = defaultTemp["default"].lineLimits;
39+
}
40+
41+
if (!options.lineLimits.firstLine) {
42+
options.lineLimits.firstLine = defaultTemp["default"].lineLimits.firstLine;
43+
}
44+
45+
if (!options.lineLimits.otherLine) {
46+
options.lineLimits.otherLine = defaultTemp["default"].lineLimits.otherLine;
47+
}
48+
49+
if(!options.type) {
50+
options.types = defaultTemp["default"].types;
51+
}
52+
53+
lineLimits(lines, options, errors);
54+
commitValidator(lines, options, errors);
55+
issuesValidator(lines, options, errors);
56+
57+
return errors;
58+
}
59+

gulpfile.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,58 @@ let repositoryfyAngularDemos;
236236
let repositoryfyAngularDemosLob;
237237
let repositoryfyAngularDemosCrm;
238238

239+
const copyGitHooks = async (cb) => {
240+
241+
if (process.env.AZURE_PIPELINES || process.env.TRAVIS || process.env.CI || !fs.existsSync('.git')) {
242+
return;
243+
}
244+
245+
const gitHooksDir = './.git/hooks/';
246+
const defaultCopyHookDir = gitHooksDir + 'scripts/';
247+
const dirs = [
248+
gitHooksDir,
249+
defaultCopyHookDir,
250+
defaultCopyHookDir + 'templates',
251+
defaultCopyHookDir + 'templateValidators',
252+
defaultCopyHookDir + 'utils'
253+
];
254+
255+
dirs.forEach((dir) => {
256+
if (!fs.existsSync(dir)) {
257+
fs.mkdir(dir, (err) => {
258+
if (err) {
259+
throw err;
260+
}
261+
});
262+
}
263+
});
264+
265+
const defaultHookDir = './.hooks/scripts/';
266+
267+
fs.copyFileSync(defaultHookDir + 'templates/default.js',
268+
defaultCopyHookDir + 'templates/default.js');
269+
270+
fs.copyFileSync(defaultHookDir + 'templateValidators/default-style-validator.js',
271+
defaultCopyHookDir + 'templateValidators/default-style-validator.js');
272+
273+
fs.copyFileSync(defaultHookDir + 'utils/issue-validator.js',
274+
defaultCopyHookDir + 'utils/issue-validator.js');
275+
276+
fs.copyFileSync(defaultHookDir + 'utils/line-limits.js',
277+
defaultCopyHookDir + 'utils/line-limits.js');
278+
279+
fs.copyFileSync(defaultHookDir + 'common.js',
280+
defaultCopyHookDir + 'common.js');
281+
282+
fs.copyFileSync(defaultHookDir + 'validate.js',
283+
defaultCopyHookDir + 'validate.js');
284+
285+
fs.copyFileSync('./.hooks/prepare-commit-msg',
286+
'./.git/hooks/prepare-commit-msg');
287+
288+
return await cb();
289+
};
290+
239291
const cleanupAngularDemos = (cb) => {
240292
fsExtra.removeSync(submodule + "/angular-demos");
241293
fsExtra.mkdirSync(submodule + "/angular-demos");
@@ -257,3 +309,4 @@ const cleanupAngularDemosCrm = (cb) => {
257309
exports.repositoryfyAngularDemos = repositoryfyAngularDemos = gulp.series(cleanupAngularDemos, processDemosWithScss);
258310
exports.repositoryfyAngularDemosLob = repositoryfyAngularDemosLob = gulp.series(cleanupAngularDemosLob, processDemosLobWithScss);
259311
exports.repositoryfyAngularDemosCrm = repositoryfyAngularDemosCrm = gulp.series(cleanupAngularDemosCrm, processDemosCrmWithScss);
312+
exports.copyGitHooks = copyGitHooks;

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"repositoryfyAngularDemosCrm": "gulp repositoryfyAngularDemosCrm",
3737
"repositoryfyAngularDemosCrm:prod": "gulp repositoryfyAngularDemosCrm --configuration production",
3838
"build:stats": "ng build --stats-json",
39-
"analyze": "webpack-bundle-analyzer dist/app/stats.json"
39+
"analyze": "webpack-bundle-analyzer dist/app/stats.json",
40+
"postinstall": "gulp copyGitHooks"
4041
},
4142
"repository": {
4243
"type": "git",

0 commit comments

Comments
 (0)