@eclipse-glsp/cli 1.1.0-next.e31f2e5.119 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -1
- package/lib/app.d.ts.map +1 -1
- package/lib/app.js +3 -1
- package/lib/app.js.map +1 -1
- package/lib/commands/check-header.d.ts +24 -0
- package/lib/commands/check-header.d.ts.map +1 -0
- package/lib/commands/check-header.js +290 -0
- package/lib/commands/check-header.js.map +1 -0
- package/lib/commands/coverage-report.js +26 -3
- package/lib/commands/coverage-report.js.map +1 -1
- package/lib/commands/release/common.d.ts +1 -1
- package/lib/commands/release/common.d.ts.map +1 -1
- package/lib/commands/release/common.js +41 -15
- package/lib/commands/release/common.js.map +1 -1
- package/lib/commands/release/release-client.d.ts.map +1 -1
- package/lib/commands/release/release-client.js +29 -8
- package/lib/commands/release/release-client.js.map +1 -1
- package/lib/commands/release/release-eclipse-integration.js +24 -1
- package/lib/commands/release/release-eclipse-integration.js.map +1 -1
- package/lib/commands/release/release-java-server.js +25 -2
- package/lib/commands/release/release-java-server.js.map +1 -1
- package/lib/commands/release/release-server-node.js +24 -1
- package/lib/commands/release/release-server-node.js.map +1 -1
- package/lib/commands/release/release-theia-integration.d.ts.map +1 -1
- package/lib/commands/release/release-theia-integration.js +26 -14
- package/lib/commands/release/release-theia-integration.js.map +1 -1
- package/lib/commands/release/release-vscode-integration.js +25 -2
- package/lib/commands/release/release-vscode-integration.js.map +1 -1
- package/lib/commands/release/release.d.ts +2 -2
- package/lib/commands/release/release.d.ts.map +1 -1
- package/lib/commands/release/release.js +51 -11
- package/lib/commands/release/release.js.map +1 -1
- package/lib/util/command-util.d.ts +5 -9
- package/lib/util/command-util.d.ts.map +1 -1
- package/lib/util/command-util.js +31 -7
- package/lib/util/command-util.js.map +1 -1
- package/lib/util/git-util.d.ts +43 -4
- package/lib/util/git-util.d.ts.map +1 -1
- package/lib/util/git-util.js +151 -39
- package/lib/util/git-util.js.map +1 -1
- package/lib/util/logger.d.ts +21 -7
- package/lib/util/logger.d.ts.map +1 -1
- package/lib/util/logger.js +29 -13
- package/lib/util/logger.js.map +1 -1
- package/lib/util/validation-util.d.ts +1 -0
- package/lib/util/validation-util.d.ts.map +1 -1
- package/lib/util/validation-util.js +40 -6
- package/lib/util/validation-util.js.map +1 -1
- package/package.json +28 -27
- package/src/app.ts +4 -1
- package/src/commands/check-header.ts +355 -0
- package/src/commands/release/common.ts +7 -7
- package/src/commands/release/release-client.ts +6 -10
- package/src/commands/release/release-java-server.ts +1 -1
- package/src/commands/release/release-theia-integration.ts +6 -18
- package/src/commands/release/release-vscode-integration.ts +2 -1
- package/src/commands/release/release.ts +34 -14
- package/src/util/command-util.ts +9 -16
- package/src/util/git-util.ts +128 -38
- package/src/util/logger.ts +36 -17
- package/src/util/validation-util.ts +17 -4
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eclipse-glsp/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "CLI Tooling & scripts for GLSP components",
|
|
5
|
-
"license": "(EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0)",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"eclipse",
|
|
8
7
|
"tsconfig"
|
|
9
8
|
],
|
|
10
|
-
"author": {
|
|
11
|
-
"name": "Eclipse GLSP"
|
|
12
|
-
},
|
|
13
9
|
"homepage": "https://www.eclipse.org/glsp/",
|
|
10
|
+
"bugs": "https://github.com/eclipse-glsp/glsp/issues",
|
|
14
11
|
"repository": {
|
|
15
12
|
"type": "git",
|
|
16
13
|
"url": "https://github.com/eclipse-glsp/glsp.git"
|
|
17
14
|
},
|
|
18
|
-
"
|
|
15
|
+
"license": "(EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0)",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Eclipse GLSP"
|
|
18
|
+
},
|
|
19
19
|
"contributors": [
|
|
20
20
|
{
|
|
21
21
|
"name": "Eclipse GLSP Project",
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
"url": "https://projects.eclipse.org/projects/ecd.glsp"
|
|
24
24
|
}
|
|
25
25
|
],
|
|
26
|
+
"bin": {
|
|
27
|
+
"glsp": "bin/glsp"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"src",
|
|
31
|
+
"bin",
|
|
32
|
+
"lib"
|
|
33
|
+
],
|
|
26
34
|
"scripts": {
|
|
27
35
|
"build": "tsc -b",
|
|
28
36
|
"clean": "rimraf lib tsconfig.tsbuildinfo",
|
|
@@ -32,31 +40,24 @@
|
|
|
32
40
|
"start": "node --enable-source-maps lib/app.js",
|
|
33
41
|
"watch": "tsc -w"
|
|
34
42
|
},
|
|
35
|
-
"publishConfig": {
|
|
36
|
-
"access": "public"
|
|
37
|
-
},
|
|
38
43
|
"dependencies": {
|
|
39
|
-
"commander": "^
|
|
40
|
-
"
|
|
44
|
+
"commander": "^10.0.1",
|
|
45
|
+
"glob": "^10.3.10",
|
|
46
|
+
"node-fetch": "^2.6.11",
|
|
41
47
|
"readline-sync": "^1.4.10",
|
|
42
|
-
"semver": "^7.
|
|
43
|
-
"shelljs": "0.8.5"
|
|
48
|
+
"semver": "^7.5.1",
|
|
49
|
+
"shelljs": "^0.8.5"
|
|
44
50
|
},
|
|
45
51
|
"devDependencies": {
|
|
46
|
-
"@eclipse-glsp/config": "
|
|
47
|
-
"@types/
|
|
48
|
-
"@types/
|
|
49
|
-
"@types/
|
|
50
|
-
"@types/
|
|
51
|
-
"
|
|
52
|
+
"@eclipse-glsp/config": "~2.0.0",
|
|
53
|
+
"@types/glob": "^8.1.0",
|
|
54
|
+
"@types/node-fetch": "^2.6.6",
|
|
55
|
+
"@types/readline-sync": "^1.4.5",
|
|
56
|
+
"@types/semver": "^7.5.3",
|
|
57
|
+
"@types/shelljs": "^0.8.13"
|
|
52
58
|
},
|
|
53
|
-
"
|
|
54
|
-
"
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
55
61
|
},
|
|
56
|
-
"
|
|
57
|
-
"src",
|
|
58
|
-
"bin",
|
|
59
|
-
"lib"
|
|
60
|
-
],
|
|
61
|
-
"gitHead": "e31f2e57b5be8c784247c469669ed2a20ec548ee"
|
|
62
|
+
"gitHead": "de11704de0f39591d2a991c3956df4e0ce88d451"
|
|
62
63
|
}
|
package/src/app.ts
CHANGED
|
@@ -14,15 +14,18 @@
|
|
|
14
14
|
*
|
|
15
15
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
16
16
|
********************************************************************************/
|
|
17
|
+
import { CheckHeaderCommand } from './commands/check-header';
|
|
17
18
|
import { CoverageReportCommand } from './commands/coverage-report';
|
|
18
19
|
import { ReleaseCommand } from './commands/release/release';
|
|
19
20
|
import { baseCommand } from './util/command-util';
|
|
21
|
+
|
|
20
22
|
export const COMMAND_VERSION = '1.1.0-next';
|
|
21
23
|
|
|
22
24
|
const app = baseCommand() //
|
|
23
25
|
.version(COMMAND_VERSION)
|
|
24
26
|
.name('glsp')
|
|
27
|
+
.addCommand(CoverageReportCommand)
|
|
25
28
|
.addCommand(ReleaseCommand)
|
|
26
|
-
.addCommand(
|
|
29
|
+
.addCommand(CheckHeaderCommand);
|
|
27
30
|
|
|
28
31
|
app.parse(process.argv);
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2022-2023 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
/* eslint-disable max-len */
|
|
17
|
+
import { Option } from 'commander';
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import { glob } from 'glob';
|
|
20
|
+
import * as minimatch from 'minimatch';
|
|
21
|
+
import * as readline from 'readline-sync';
|
|
22
|
+
import * as sh from 'shelljs';
|
|
23
|
+
import { baseCommand, configureShell, getShellConfig } from '../util/command-util';
|
|
24
|
+
import {
|
|
25
|
+
getChangesOfLastCommit,
|
|
26
|
+
getFirstCommit,
|
|
27
|
+
getFirstModificationDate,
|
|
28
|
+
getInitialCommit,
|
|
29
|
+
getLastModificationDate,
|
|
30
|
+
getUncommittedChanges
|
|
31
|
+
} from '../util/git-util';
|
|
32
|
+
|
|
33
|
+
import { LOGGER } from '../util/logger';
|
|
34
|
+
import { validateGitDirectory } from '../util/validation-util';
|
|
35
|
+
import path = require('path');
|
|
36
|
+
export interface HeaderCheckOptions {
|
|
37
|
+
type: CheckType;
|
|
38
|
+
exclude: string[];
|
|
39
|
+
fileExtensions: string[];
|
|
40
|
+
json: boolean;
|
|
41
|
+
excludeDefaults: boolean;
|
|
42
|
+
autoFix: boolean;
|
|
43
|
+
severity: Severity;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const checkTypes = ['full', 'changes', 'lastCommit'] as const;
|
|
47
|
+
type CheckType = typeof checkTypes[number];
|
|
48
|
+
|
|
49
|
+
const severityTypes = ['error', 'warn', 'ok'] as const;
|
|
50
|
+
|
|
51
|
+
type Severity = typeof severityTypes[number];
|
|
52
|
+
|
|
53
|
+
const DEFAULT_EXCLUDES = ['**/@(node_modules|lib|dist|bundle)/**'];
|
|
54
|
+
const YEAR_RANGE_REGEX = /\d{4}(?:-d{4})?/g;
|
|
55
|
+
const HEADER_PATTERN = 'Copyright \\([cC]\\) \\d{4}(-d{4})?';
|
|
56
|
+
const AUTO_FIX_MESSAGE = 'Fix copyright header violations';
|
|
57
|
+
|
|
58
|
+
export const CheckHeaderCommand = baseCommand() //
|
|
59
|
+
.name('checkHeaders')
|
|
60
|
+
.description('Validates the copyright year range of license header files')
|
|
61
|
+
.argument('<rootDir>', 'The starting directory for the check', validateGitDirectory)
|
|
62
|
+
.addOption(
|
|
63
|
+
new Option(
|
|
64
|
+
'-t, --type <type>',
|
|
65
|
+
'The scope of the check. In addition to a full recursive check, is also possible to only' +
|
|
66
|
+
' consider pending changes or the last commit'
|
|
67
|
+
)
|
|
68
|
+
.choices(checkTypes)
|
|
69
|
+
.default('full')
|
|
70
|
+
)
|
|
71
|
+
.option('-f, --fileExtensions <extensions...>', 'File extensions that should be checked', ['ts', 'tsx'])
|
|
72
|
+
.addOption(
|
|
73
|
+
new Option(
|
|
74
|
+
'-e, --exclude <exclude...>',
|
|
75
|
+
'File patterns that should be excluded from the check. New exclude patterns are added to the default patterns'
|
|
76
|
+
).default([], `[${DEFAULT_EXCLUDES}]`)
|
|
77
|
+
)
|
|
78
|
+
.option(
|
|
79
|
+
'--no-exclude-defaults',
|
|
80
|
+
'Disables the default excludes patterns. Only explicitly passed exclude patterns (-e, --exclude) are considered'
|
|
81
|
+
)
|
|
82
|
+
.option('-j, --json', 'Also persist validation results as json file', false)
|
|
83
|
+
.addOption(
|
|
84
|
+
new Option('-s, --severity <severity>', 'The severity of validation results that should be printed.')
|
|
85
|
+
.choices(severityTypes)
|
|
86
|
+
.default('error', '"error" (only)')
|
|
87
|
+
)
|
|
88
|
+
.option('-a, --autoFix', 'Auto apply & commit fixes without prompting the user', false)
|
|
89
|
+
.action(checkHeaders);
|
|
90
|
+
|
|
91
|
+
export function checkHeaders(rootDir: string, options: HeaderCheckOptions): void {
|
|
92
|
+
configureShell({ silent: true, fatal: true });
|
|
93
|
+
|
|
94
|
+
if (options.excludeDefaults) {
|
|
95
|
+
options.exclude.push(...DEFAULT_EXCLUDES);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
sh.cd(rootDir);
|
|
99
|
+
const files = getFiles(rootDir, options);
|
|
100
|
+
LOGGER.info(`Check copy right headers of ${files.length} files`);
|
|
101
|
+
if (files.length === 0) {
|
|
102
|
+
LOGGER.info('Check completed');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const results = validate(rootDir, files, options);
|
|
106
|
+
handleValidationResults(rootDir, results, options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getFiles(rootDir: string, options: HeaderCheckOptions): string[] {
|
|
110
|
+
const includePattern = `**/*.@(${options.fileExtensions.join('|')})`;
|
|
111
|
+
const excludePattern = options.exclude;
|
|
112
|
+
|
|
113
|
+
if (options.type === 'full') {
|
|
114
|
+
return glob.sync(includePattern, {
|
|
115
|
+
cwd: rootDir,
|
|
116
|
+
ignore: excludePattern
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let changedFiles = options.type === 'changes' ? getUncommittedChanges(rootDir) : getChangesOfLastCommit(rootDir);
|
|
121
|
+
changedFiles = changedFiles.filter(minimatch.filter(includePattern));
|
|
122
|
+
|
|
123
|
+
excludePattern.forEach(pattern => {
|
|
124
|
+
changedFiles = changedFiles.filter(minimatch.filter(`!${pattern}`));
|
|
125
|
+
});
|
|
126
|
+
return changedFiles.filter(file => fs.existsSync(file));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function validate(rootDir: string, files: string[], options: HeaderCheckOptions): ValidationResult[] {
|
|
130
|
+
// Derives all files with valid headers, their copyright years and all files with no or invalid headers
|
|
131
|
+
const filesWithHeader = sh.grep('-l', HEADER_PATTERN, files).stdout.trim().split('\n');
|
|
132
|
+
const copyrightYears = sh
|
|
133
|
+
.grep(HEADER_PATTERN, files)
|
|
134
|
+
.stdout.trim()
|
|
135
|
+
.split('\n')
|
|
136
|
+
.map(line => line.match(YEAR_RANGE_REGEX)!.map(string => Number.parseInt(string, 10)));
|
|
137
|
+
const noHeaders = files.filter(file => !filesWithHeader.includes(file));
|
|
138
|
+
|
|
139
|
+
const results: ValidationResult[] = [];
|
|
140
|
+
|
|
141
|
+
const allFilesLength = files.length;
|
|
142
|
+
|
|
143
|
+
// Create validation results for all files with no or invalid headers
|
|
144
|
+
const noHeadersLength = noHeaders.length;
|
|
145
|
+
if (noHeadersLength > 0) {
|
|
146
|
+
LOGGER.info(`Found ${noHeadersLength} files with no (or an invalid) copyright header`);
|
|
147
|
+
}
|
|
148
|
+
noHeaders.forEach((file, i) => {
|
|
149
|
+
printFileProgress(i + 1, allFilesLength, `Validating ${file}`);
|
|
150
|
+
results.push({ file: path.resolve(rootDir, file), violation: 'noOrMissingHeader', severity: 'error' });
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Performance optimization: avoid retrieving the dates for each individual file by precalculating the endYear if possible.
|
|
154
|
+
let defaultEndYear: number | undefined;
|
|
155
|
+
if (options.type === 'changes') {
|
|
156
|
+
defaultEndYear = new Date().getFullYear();
|
|
157
|
+
} else if (options.type === 'lastCommit') {
|
|
158
|
+
defaultEndYear = getLastModificationDate(undefined, rootDir)?.getFullYear();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Create validation results for all files with valid headers
|
|
162
|
+
filesWithHeader.forEach((file, i) => {
|
|
163
|
+
printFileProgress(i + 1 + noHeadersLength, allFilesLength, `Validating ${file}`);
|
|
164
|
+
|
|
165
|
+
const result: DateValidationResult = {
|
|
166
|
+
currentStartYear: copyrightYears[i].shift()!,
|
|
167
|
+
expectedStartYear: getFirstModificationDate(file, rootDir, AUTO_FIX_MESSAGE)!.getFullYear(),
|
|
168
|
+
currentEndYear: copyrightYears[i].shift(),
|
|
169
|
+
expectedEndYear: defaultEndYear ?? getLastModificationDate(file, rootDir, AUTO_FIX_MESSAGE)!.getFullYear(),
|
|
170
|
+
file,
|
|
171
|
+
severity: 'ok',
|
|
172
|
+
violation: 'none'
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
if (result.expectedStartYear === result.expectedEndYear) {
|
|
176
|
+
validateSingleYear(result);
|
|
177
|
+
} else {
|
|
178
|
+
validateTimePeriod(result);
|
|
179
|
+
}
|
|
180
|
+
results.push(result);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
results.sort((a, b) => a.file.localeCompare(b.file));
|
|
184
|
+
|
|
185
|
+
process.stdout.clearLine(0);
|
|
186
|
+
return results;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function validateSingleYear(result: DateValidationResult): void {
|
|
190
|
+
const { currentStartYear, expectedStartYear, currentEndYear } = result;
|
|
191
|
+
result.violation = 'invalidCopyrightYear';
|
|
192
|
+
result.severity = 'error';
|
|
193
|
+
|
|
194
|
+
if (!currentEndYear) {
|
|
195
|
+
if (currentStartYear === expectedStartYear) {
|
|
196
|
+
result.violation = 'none';
|
|
197
|
+
result.severity = 'ok';
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Cornercase: For files of the initial contribution the copyright header predates the first git modification date.
|
|
203
|
+
// => declare as warning if not part of the initial contribution.
|
|
204
|
+
if (expectedStartYear === currentEndYear && currentStartYear < expectedStartYear) {
|
|
205
|
+
if (getFirstCommit(result.file) === getInitialCommit()) {
|
|
206
|
+
result.violation = 'none';
|
|
207
|
+
result.severity = 'ok';
|
|
208
|
+
} else {
|
|
209
|
+
result.severity = 'warn';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function validateTimePeriod(result: DateValidationResult): void {
|
|
215
|
+
const { currentStartYear, expectedStartYear, expectedEndYear, currentEndYear } = result;
|
|
216
|
+
|
|
217
|
+
result.violation = 'incorrectCopyrightPeriod';
|
|
218
|
+
result.severity = 'error';
|
|
219
|
+
if (!currentEndYear) {
|
|
220
|
+
result.severity = 'error';
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (currentStartYear === expectedStartYear && currentEndYear === expectedEndYear) {
|
|
225
|
+
result.violation = 'none';
|
|
226
|
+
result.severity = 'ok';
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Cornercase: For files of the initial contribution the copyright header predates the first git modification date.
|
|
231
|
+
// => declare as warning if not part of the initial contribution.
|
|
232
|
+
if (currentEndYear === expectedEndYear && currentStartYear < expectedEndYear) {
|
|
233
|
+
if (getFirstCommit(result.file) === getInitialCommit()) {
|
|
234
|
+
result.violation = 'none';
|
|
235
|
+
result.severity = 'ok';
|
|
236
|
+
} else {
|
|
237
|
+
result.severity = 'warn';
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function printFileProgress(currentFileCount: number, maxFileCount: number, message: string, clear = true): void {
|
|
243
|
+
if (clear) {
|
|
244
|
+
process.stdout.clearLine(0);
|
|
245
|
+
process.stdout.cursorTo(0);
|
|
246
|
+
}
|
|
247
|
+
process.stdout.write(`[${currentFileCount} of ${maxFileCount}] ${message}`);
|
|
248
|
+
if (!clear) {
|
|
249
|
+
process.stdout.write('\n');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function handleValidationResults(rootDir: string, results: ValidationResult[], options: HeaderCheckOptions): void {
|
|
254
|
+
LOGGER.newLine();
|
|
255
|
+
LOGGER.info(`Header validation for ${results.length} files completed`);
|
|
256
|
+
const violations = results.filter(result => result.severity === 'error');
|
|
257
|
+
// Adjust results to print based on configured severity level
|
|
258
|
+
let toPrint = results;
|
|
259
|
+
if (options.severity === 'error') {
|
|
260
|
+
toPrint = violations;
|
|
261
|
+
} else if (options.severity === 'warn') {
|
|
262
|
+
toPrint = results.filter(result => result.severity !== 'ok');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
LOGGER.info(`Found ${toPrint.length} copyright header violations:`);
|
|
266
|
+
LOGGER.newLine();
|
|
267
|
+
|
|
268
|
+
toPrint.forEach((result, i) => LOGGER.info(`${i + 1}. `, result.file, ':', toPrintMessage(result)));
|
|
269
|
+
|
|
270
|
+
LOGGER.newLine();
|
|
271
|
+
|
|
272
|
+
if (options.json) {
|
|
273
|
+
fs.writeFileSync(path.join(rootDir, 'headerCheck.json'), JSON.stringify(results, undefined, 2));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (violations.length > 0 && (options.autoFix || readline.keyInYN('Do you want automatically fix copyright year range violations?'))) {
|
|
277
|
+
const toFix = violations.filter(
|
|
278
|
+
violation => violation.severity === 'error' && isDateValidationResult(violation)
|
|
279
|
+
) as DateValidationResult[];
|
|
280
|
+
fixViolations(rootDir, toFix, options);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
LOGGER.info('Check completed');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function toPrintMessage(result: ValidationResult): string {
|
|
287
|
+
const colors: Record<Severity, string> = {
|
|
288
|
+
error: '\x1b[31m',
|
|
289
|
+
warn: '\x1b[33m',
|
|
290
|
+
ok: '\x1b[32m'
|
|
291
|
+
} as const;
|
|
292
|
+
|
|
293
|
+
if (
|
|
294
|
+
isDateValidationResult(result) &&
|
|
295
|
+
(result.violation === 'incorrectCopyrightPeriod' || result.violation === 'invalidCopyrightYear')
|
|
296
|
+
) {
|
|
297
|
+
const expected =
|
|
298
|
+
result.expectedStartYear !== result.expectedEndYear
|
|
299
|
+
? `${result.expectedStartYear}-${result.expectedEndYear}`
|
|
300
|
+
: result.expectedStartYear.toString();
|
|
301
|
+
const actual = result.currentEndYear ? `${result.currentStartYear}-${result.currentEndYear}` : result.currentStartYear.toString();
|
|
302
|
+
const message = result.violation === 'incorrectCopyrightPeriod' ? 'Invalid copyright period' : 'Invalid copyright year';
|
|
303
|
+
return `${colors[result.severity]} ${message}! Expected '${expected}' but is '${actual}'`;
|
|
304
|
+
} else if (result.violation === 'noOrMissingHeader') {
|
|
305
|
+
return `${colors[result.severity]} No or invalid copyright header!`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return `${colors[result.severity]} OK`;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function fixViolations(rootDir: string, violations: DateValidationResult[], options: HeaderCheckOptions): void {
|
|
312
|
+
LOGGER.newLine();
|
|
313
|
+
violations.forEach((violation, i) => {
|
|
314
|
+
printFileProgress(i + 1, violations.length, `Fix ${violation.file}`, false);
|
|
315
|
+
const fixedStartYear =
|
|
316
|
+
violation.currentStartYear < violation.expectedStartYear ? violation.currentStartYear : violation.expectedStartYear;
|
|
317
|
+
|
|
318
|
+
const currentRange = `${violation.currentStartYear}${violation.currentEndYear ? '-' + violation.currentEndYear : ''}`;
|
|
319
|
+
|
|
320
|
+
let fixedRange = `${fixedStartYear}`;
|
|
321
|
+
if (violation.expectedEndYear !== violation.expectedStartYear || fixedStartYear !== violation.expectedStartYear) {
|
|
322
|
+
fixedRange = `${fixedStartYear}-${violation.expectedEndYear}`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
sh.sed('-i', RegExp('Copyright \\([cC]\\) ' + currentRange), `Copyright (c) ${fixedRange}`, violation.file);
|
|
326
|
+
});
|
|
327
|
+
LOGGER.newLine();
|
|
328
|
+
if (options.autoFix || readline.keyInYN('Do you want to create a commit for the fixed files?')) {
|
|
329
|
+
LOGGER.newLine();
|
|
330
|
+
const files = violations.map(violation => violation.file).join(' ');
|
|
331
|
+
sh.exec(`git add ${files}`, getShellConfig());
|
|
332
|
+
sh.exec(`git commit -m "${AUTO_FIX_MESSAGE}"`);
|
|
333
|
+
LOGGER.newLine();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Helper types
|
|
338
|
+
interface ValidationResult {
|
|
339
|
+
file: string;
|
|
340
|
+
severity: Severity;
|
|
341
|
+
violation: Violation;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
interface DateValidationResult extends ValidationResult {
|
|
345
|
+
currentStartYear: number;
|
|
346
|
+
expectedStartYear: number;
|
|
347
|
+
currentEndYear?: number;
|
|
348
|
+
expectedEndYear: number;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function isDateValidationResult(object: ValidationResult): object is DateValidationResult {
|
|
352
|
+
return 'currentStartYear' in object && 'expectedStartYear' in object && 'expectedEndYear' in object;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
type Violation = 'none' | 'noOrMissingHeader' | 'incorrectCopyrightPeriod' | 'invalidCopyrightYear';
|
|
@@ -21,7 +21,7 @@ import * as readline from 'readline-sync';
|
|
|
21
21
|
import * as semver from 'semver';
|
|
22
22
|
import * as sh from 'shelljs';
|
|
23
23
|
import { fatalExec, getShellConfig } from '../../util/command-util';
|
|
24
|
-
import {
|
|
24
|
+
import { getLatestGithubRelease, getLatestTag, hasGitChanges, isGitRepository } from '../../util/git-util';
|
|
25
25
|
import { LOGGER } from '../../util/logger';
|
|
26
26
|
import { validateVersion } from '../../util/validation-util';
|
|
27
27
|
|
|
@@ -134,8 +134,8 @@ export function checkoutAndCd(options: ReleaseOptions): string {
|
|
|
134
134
|
sh.exec(`gh repo clone ${ghUrl}`, getShellConfig());
|
|
135
135
|
LOGGER.debug(`Successfully cloned to ${directory}`);
|
|
136
136
|
sh.cd(directory);
|
|
137
|
-
if (options.
|
|
138
|
-
sh.exec(`git
|
|
137
|
+
if (options.branch !== 'master' && options.branch !== 'main') {
|
|
138
|
+
sh.exec(`git checkout ${options.branch} `);
|
|
139
139
|
}
|
|
140
140
|
return sh.pwd();
|
|
141
141
|
}
|
|
@@ -175,7 +175,7 @@ export function publish(repositoryPath: string, options: ReleaseOptions): void {
|
|
|
175
175
|
throw new Error('Publish failed. The repository has pending changes');
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
const latestReleaseTag =
|
|
178
|
+
const latestReleaseTag = getLatestGithubRelease();
|
|
179
179
|
const localTag = getLatestTag();
|
|
180
180
|
validateTag(latestReleaseTag, localTag);
|
|
181
181
|
const preRelease = options.releaseType === 'rc' || localTag.includes('-');
|
|
@@ -186,7 +186,7 @@ function doPublish(tag: string, preRelease: boolean, latestRelease: string, draf
|
|
|
186
186
|
fatalExec(`git push origin HEAD:${tag}`, 'Could not push release branch to Github', getShellConfig({ silent: false }));
|
|
187
187
|
fatalExec(`git push origin tag ${tag}`, 'Could not push tag to Github', getShellConfig({ silent: false }));
|
|
188
188
|
const version = tagToVersion(tag);
|
|
189
|
-
const titleSuffix = preRelease ? `
|
|
189
|
+
const titleSuffix = preRelease ? ` Candidate ${version.substring(version.lastIndexOf('-RC') + 3)}` : '';
|
|
190
190
|
const title = `${version.replace(/-.*/, '')} Release${titleSuffix} `;
|
|
191
191
|
sh.exec(
|
|
192
192
|
`gh release create ${tag} -t "${title}" --notes-start-tag ${latestRelease} --generate-notes ${draft ? '-d' : ''} ${
|
|
@@ -257,8 +257,8 @@ export function asMvnVersion(version: string): string {
|
|
|
257
257
|
return mavenVersion;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
export async function
|
|
261
|
-
LOGGER.debug(`Check
|
|
260
|
+
export async function checkIfNpmVersionIsNew(pckgName: string, newVersion: string): Promise<void> {
|
|
261
|
+
LOGGER.debug(`Check that the release version is new i.e. does not exist on npm: ${newVersion}`);
|
|
262
262
|
|
|
263
263
|
const response = await fetch(`https://registry.npmjs.org/${pckgName}/${newVersion}`);
|
|
264
264
|
const data = await response.json();
|
|
@@ -16,15 +16,13 @@
|
|
|
16
16
|
import * as sh from 'shelljs';
|
|
17
17
|
import { LOGGER } from '../../util/logger';
|
|
18
18
|
import {
|
|
19
|
-
asMvnVersion,
|
|
20
|
-
checkJavaServerVersion,
|
|
21
19
|
checkoutAndCd,
|
|
22
20
|
commitAndTag,
|
|
23
21
|
lernaSetVersion,
|
|
24
22
|
publish,
|
|
25
23
|
ReleaseOptions,
|
|
26
24
|
updateLernaForDryRun,
|
|
27
|
-
|
|
25
|
+
updateVersion,
|
|
28
26
|
yarnInstall
|
|
29
27
|
} from './common';
|
|
30
28
|
|
|
@@ -34,7 +32,7 @@ export async function releaseClient(options: ReleaseOptions): Promise<void> {
|
|
|
34
32
|
LOGGER.info('Prepare glsp-client release');
|
|
35
33
|
LOGGER.debug('Release options: ', options.version);
|
|
36
34
|
REPO_ROOT = checkoutAndCd(options);
|
|
37
|
-
|
|
35
|
+
updateExternalGLSPDependencies(options.version);
|
|
38
36
|
generateChangeLog();
|
|
39
37
|
lernaSetVersion(REPO_ROOT, options.version);
|
|
40
38
|
build();
|
|
@@ -45,12 +43,10 @@ export async function releaseClient(options: ReleaseOptions): Promise<void> {
|
|
|
45
43
|
publish(REPO_ROOT, options);
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
LOGGER.info('Update example server
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
sh.cd(`${REPO_ROOT}/examples/workflow-glsp/scripts`);
|
|
53
|
-
updateServerConfig('config.json', mvnVersion, false);
|
|
46
|
+
function updateExternalGLSPDependencies(version: string): void {
|
|
47
|
+
LOGGER.info('Update external GLSP dependencies (workflow example server)');
|
|
48
|
+
sh.cd(REPO_ROOT);
|
|
49
|
+
updateVersion({ name: '@eclipse-glsp-examples/workflow-server-bundled', version });
|
|
54
50
|
}
|
|
55
51
|
|
|
56
52
|
function generateChangeLog(): void {
|
|
@@ -67,7 +67,7 @@ function build(): void {
|
|
|
67
67
|
LOGGER.info('Build M2 & P2');
|
|
68
68
|
LOGGER.debug('M2');
|
|
69
69
|
fatalExec('mvn clean install -Pm2', 'M2 build failed', getShellConfig({ silent: false }));
|
|
70
|
-
|
|
70
|
+
LOGGER.newLine();
|
|
71
71
|
LOGGER.debug('P2');
|
|
72
72
|
fatalExec('mvn clean install -Pp2', 'P2 build failed', getShellConfig({ silent: false }));
|
|
73
73
|
}
|
|
@@ -17,15 +17,12 @@
|
|
|
17
17
|
import * as sh from 'shelljs';
|
|
18
18
|
import { LOGGER } from '../../util/logger';
|
|
19
19
|
import {
|
|
20
|
-
asMvnVersion,
|
|
21
20
|
checkoutAndCd,
|
|
22
21
|
commitAndTag,
|
|
23
|
-
isExistingMavenVersion,
|
|
24
22
|
lernaSetVersion,
|
|
25
23
|
publish,
|
|
26
24
|
ReleaseOptions,
|
|
27
25
|
updateLernaForDryRun,
|
|
28
|
-
updateServerConfig,
|
|
29
26
|
updateVersion,
|
|
30
27
|
yarnInstall
|
|
31
28
|
} from './common';
|
|
@@ -37,7 +34,6 @@ export async function releaseTheiaIntegration(options: ReleaseOptions): Promise<
|
|
|
37
34
|
LOGGER.debug('Release options: ', options);
|
|
38
35
|
REPO_ROOT = checkoutAndCd(options);
|
|
39
36
|
updateExternalGLSPDependencies(options.version);
|
|
40
|
-
await updateDownloadServerScript(options.version);
|
|
41
37
|
generateChangeLog();
|
|
42
38
|
lernaSetVersion(REPO_ROOT, options.version);
|
|
43
39
|
build();
|
|
@@ -49,21 +45,13 @@ export async function releaseTheiaIntegration(options: ReleaseOptions): Promise<
|
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
function updateExternalGLSPDependencies(version: string): void {
|
|
52
|
-
LOGGER.info('Update external GLSP dependencies (Client and workflow example)');
|
|
48
|
+
LOGGER.info('Update external GLSP dependencies (Client and workflow example & server)');
|
|
53
49
|
sh.cd(REPO_ROOT);
|
|
54
|
-
updateVersion(
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const mvnVersion = asMvnVersion(version);
|
|
60
|
-
if (!isExistingMavenVersion('org.eclipse.glsp', 'org.eclipse.glsp.server', mvnVersion)) {
|
|
61
|
-
LOGGER.warn(`No Java GLSP server with version ${mvnVersion} found on maven central!. Please release a new Java GLSP Server version
|
|
62
|
-
before publishing this release!`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
sh.cd(`${REPO_ROOT}/examples/workflow-theia/src/node`);
|
|
66
|
-
updateServerConfig('server-config.json', mvnVersion, false);
|
|
50
|
+
updateVersion(
|
|
51
|
+
{ name: '@eclipse-glsp/client', version },
|
|
52
|
+
{ name: '@eclipse-glsp-examples/workflow-glsp', version },
|
|
53
|
+
{ name: '@eclipse-glsp-examples/workflow-server', version }
|
|
54
|
+
);
|
|
67
55
|
}
|
|
68
56
|
|
|
69
57
|
function build(): void {
|
|
@@ -50,7 +50,8 @@ function updateExternalGLSPDependencies(version: string): void {
|
|
|
50
50
|
updateVersion(
|
|
51
51
|
{ name: '@eclipse-glsp/protocol', version },
|
|
52
52
|
{ name: '@eclipse-glsp/client', version },
|
|
53
|
-
{ name: '@eclipse-glsp-examples/workflow-glsp', version }
|
|
53
|
+
{ name: '@eclipse-glsp-examples/workflow-glsp', version },
|
|
54
|
+
{ name: '@eclipse-glsp-examples/workflow-server', version }
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
57
|
|