@appland/scanner 1.88.1 → 1.88.2
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/CHANGELOG.md +7 -0
- package/built/cli/scan/watchScan.js +2 -2
- package/built/cli.js +10 -2
- package/package.json +2 -2
- package/built/telemetry.d.ts +0 -50
- package/built/telemetry.js +0 -394
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [@appland/scanner-v1.88.2](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.88.1...@appland/scanner-v1.88.2) (2025-10-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **scanner:** Update to @appland/telemetry ([1672e65](https://github.com/getappmap/appmap-js/commit/1672e651d5119d5779c797f8013b079d9087fc81))
|
|
7
|
+
|
|
1
8
|
# [@appland/scanner-v1.88.1](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.88.0...@appland/scanner-v1.88.1) (2025-05-22)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -45,7 +45,7 @@ const node_util_1 = require("node:util");
|
|
|
45
45
|
const formatReport_1 = require("./formatReport");
|
|
46
46
|
const scanner_1 = __importDefault(require("./scanner"));
|
|
47
47
|
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
48
|
-
const telemetry_1 =
|
|
48
|
+
const telemetry_1 = require("@appland/telemetry");
|
|
49
49
|
const events_1 = __importDefault(require("events"));
|
|
50
50
|
const isAncestorPath_1 = __importDefault(require("../../util/isAncestorPath"));
|
|
51
51
|
const util_1 = require("util");
|
|
@@ -139,7 +139,7 @@ class Watcher {
|
|
|
139
139
|
yield ((_a = this.appmapWatcher) === null || _a === void 0 ? void 0 : _a.close());
|
|
140
140
|
this.appmapWatcher = undefined;
|
|
141
141
|
console.warn('File watching disabled.');
|
|
142
|
-
telemetry_1.
|
|
142
|
+
telemetry_1.Telemetry.sendEvent({
|
|
143
143
|
name: `scan:watcher_error:enospc`,
|
|
144
144
|
properties: {
|
|
145
145
|
errorMessage: error.message,
|
package/built/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const command_1 = __importDefault(require("./cli/scan/command"));
|
|
|
9
9
|
const util_1 = require("./rules/lib/util");
|
|
10
10
|
const errors_1 = require("./errors");
|
|
11
11
|
const exitCode_1 = require("./cli/exitCode");
|
|
12
|
-
const telemetry_1 =
|
|
12
|
+
const telemetry_1 = require("@appland/telemetry");
|
|
13
13
|
const models_1 = require("@appland/models");
|
|
14
14
|
const sqlWarning_1 = __importDefault(require("./sqlWarning"));
|
|
15
15
|
function errorInfo(err) {
|
|
@@ -29,8 +29,16 @@ function handleError(err) {
|
|
|
29
29
|
};
|
|
30
30
|
if (label === 'error')
|
|
31
31
|
telemetry.properties.errorStack = err.stack;
|
|
32
|
-
telemetry_1.
|
|
32
|
+
telemetry_1.Telemetry.sendEvent(telemetry);
|
|
33
33
|
}
|
|
34
|
+
telemetry_1.Telemetry.configure({
|
|
35
|
+
product: {
|
|
36
|
+
name: '@appland/scanner',
|
|
37
|
+
// Importing this would change the directory structure of our build, so we use require
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
39
|
+
version: require('../package.json').version,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
34
42
|
(0, models_1.setSQLErrorHandler)(sqlWarning_1.default);
|
|
35
43
|
(0, yargs_1.default)(process.argv.slice(2))
|
|
36
44
|
.option('verbose', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appland/scanner",
|
|
3
|
-
"version": "1.88.
|
|
3
|
+
"version": "1.88.2",
|
|
4
4
|
"description": "Analyze AppMaps for code flaws",
|
|
5
5
|
"bin": "built/cli.js",
|
|
6
6
|
"main": "built/index.js",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"author": "AppLand, Inc.",
|
|
28
28
|
"license": "Commons Clause + MIT",
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@appland/appmap-agent-js": "^13.9.0",
|
|
31
30
|
"@semantic-release/changelog": "^6.0.1",
|
|
32
31
|
"@semantic-release/git": "^10.0.1",
|
|
33
32
|
"@types/async": "^3.2.12",
|
|
@@ -66,6 +65,7 @@
|
|
|
66
65
|
"@appland/models": "^2.10.0",
|
|
67
66
|
"@appland/openapi": "^1.7.0",
|
|
68
67
|
"@appland/sql-parser": "^1.5.0",
|
|
68
|
+
"@appland/telemetry": "^1.1.0",
|
|
69
69
|
"@types/cli-progress": "^3.9.2",
|
|
70
70
|
"ajv": "^8.8.2",
|
|
71
71
|
"applicationinsights": "^2.1.4",
|
package/built/telemetry.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { TelemetryClient } from 'applicationinsights';
|
|
3
|
-
import { PathLike } from 'fs';
|
|
4
|
-
declare class Session {
|
|
5
|
-
id: string;
|
|
6
|
-
expiration: number;
|
|
7
|
-
constructor();
|
|
8
|
-
static beyondExpiration(expiration: number): boolean;
|
|
9
|
-
static expirationFromNow(): number;
|
|
10
|
-
static newSessionId(): string;
|
|
11
|
-
touch(): void;
|
|
12
|
-
get valid(): boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface TelemetryData {
|
|
15
|
-
name: string;
|
|
16
|
-
properties?: Record<string, string | undefined>;
|
|
17
|
-
metrics?: Record<string, number | undefined>;
|
|
18
|
-
}
|
|
19
|
-
export interface TelemetryOptions {
|
|
20
|
-
includeEnvironment: boolean;
|
|
21
|
-
}
|
|
22
|
-
export default class Telemetry {
|
|
23
|
-
private static _session?;
|
|
24
|
-
private static _client?;
|
|
25
|
-
private static debug;
|
|
26
|
-
static readonly machineId: string;
|
|
27
|
-
static get enabled(): boolean;
|
|
28
|
-
static get session(): Session;
|
|
29
|
-
static get client(): TelemetryClient;
|
|
30
|
-
static sendEvent(data: TelemetryData, options?: TelemetryOptions): void;
|
|
31
|
-
static flush(exitCB: () => unknown): void;
|
|
32
|
-
}
|
|
33
|
-
export declare enum GitState {
|
|
34
|
-
NotInstalled = 0,
|
|
35
|
-
NoRepository = 1,
|
|
36
|
-
Ok = 2
|
|
37
|
-
}
|
|
38
|
-
export declare const GitRepositoryEnvKeys: readonly ["GITHUB_REPOSITORY", "CIRCLE_REPOSITORY_URL", "GIT_URL", "CI_REPOSITORY_URL"];
|
|
39
|
-
export declare const GitBranchEnvKeys: readonly ["GITHUB_REF_NAME", "CIRCLE_BRANCH", "GIT_BRANCH", "TRAVIS_BRANCH", "CI_COMMIT_REF_NAME"];
|
|
40
|
-
export declare const GitCommitEnvKeys: readonly ["GITHUB_SHA", "CIRCLE_SHA1", "GIT_COMMIT", "TRAVIS_COMMIT", "CI_COMMIT_SHA"];
|
|
41
|
-
declare class GitProperties {
|
|
42
|
-
static contributors(sinceDaysAgo: number, cwd?: PathLike): Promise<Array<string>>;
|
|
43
|
-
static repository(cwd?: PathLike): Promise<string | undefined>;
|
|
44
|
-
static branch(cwd?: PathLike): Promise<string | undefined>;
|
|
45
|
-
static commit(cwd?: PathLike): Promise<string | undefined>;
|
|
46
|
-
static state(cwd?: PathLike): Promise<GitState>;
|
|
47
|
-
static clearCache(): void;
|
|
48
|
-
}
|
|
49
|
-
export declare const Git: typeof GitProperties;
|
|
50
|
-
export {};
|
package/built/telemetry.js
DELETED
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
-
};
|
|
37
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.Git = exports.GitCommitEnvKeys = exports.GitBranchEnvKeys = exports.GitRepositoryEnvKeys = exports.GitState = void 0;
|
|
39
|
-
const os_1 = require("os");
|
|
40
|
-
const crypto_1 = require("crypto");
|
|
41
|
-
const os = __importStar(require("os"));
|
|
42
|
-
const read_pkg_up_1 = require("read-pkg-up");
|
|
43
|
-
const applicationinsights_1 = require("applicationinsights");
|
|
44
|
-
const conf_1 = __importDefault(require("conf"));
|
|
45
|
-
const child_process_1 = require("child_process");
|
|
46
|
-
const util_1 = require("util");
|
|
47
|
-
const exec = (0, util_1.promisify)(child_process_1.exec);
|
|
48
|
-
const { name, version } = (() => {
|
|
49
|
-
var _a;
|
|
50
|
-
const result = (_a = (0, read_pkg_up_1.sync)({ cwd: __dirname })) === null || _a === void 0 ? void 0 : _a.packageJson;
|
|
51
|
-
if (!result)
|
|
52
|
-
throw 'cannot find package.json';
|
|
53
|
-
return result;
|
|
54
|
-
})();
|
|
55
|
-
const config = new conf_1.default({
|
|
56
|
-
projectName: '@appland/appmap',
|
|
57
|
-
projectVersion: '0.0.1', // note this is actually config version
|
|
58
|
-
});
|
|
59
|
-
const invalidMacAddresses = new Set([
|
|
60
|
-
'00:00:00:00:00:00',
|
|
61
|
-
'ff:ff:ff:ff:ff:ff',
|
|
62
|
-
'ac:de:48:00:11:22',
|
|
63
|
-
]);
|
|
64
|
-
// This key is meant to be publically shared. However, I'm adding a simple
|
|
65
|
-
// obfuscation to mitigate key scraping bots on GitHub. The key is split on
|
|
66
|
-
// hypens and base64 encoded without padding.
|
|
67
|
-
// key.split('-').map((x) => x.toString('base64').replace(/=*/, ''))
|
|
68
|
-
const INSTRUMENTATION_KEY = ['NTBjMWE1YzI', 'NDliNA', 'NDkxMw', 'YjdjYw', 'ODZhNzhkNDA3NDVm']
|
|
69
|
-
.map((x) => Buffer.from(x, 'base64').toString('utf8'))
|
|
70
|
-
.join('-');
|
|
71
|
-
function getMachineId() {
|
|
72
|
-
const machineId = config.get('machineId');
|
|
73
|
-
if (machineId) {
|
|
74
|
-
return machineId;
|
|
75
|
-
}
|
|
76
|
-
let machineIdSource;
|
|
77
|
-
// Derive a machine ID from the first network interface
|
|
78
|
-
machineIdSource = Object.values((0, os_1.networkInterfaces)())
|
|
79
|
-
.flat()
|
|
80
|
-
.map((iface) => iface === null || iface === void 0 ? void 0 : iface.mac)
|
|
81
|
-
.filter((mac) => mac && !invalidMacAddresses.has(mac))
|
|
82
|
-
.shift();
|
|
83
|
-
if (!machineIdSource) {
|
|
84
|
-
// Fallback to a random string
|
|
85
|
-
machineIdSource = (0, crypto_1.randomBytes)(32);
|
|
86
|
-
}
|
|
87
|
-
const machineIdHash = (0, crypto_1.createHash)('sha256')
|
|
88
|
-
.update(machineIdSource)
|
|
89
|
-
.digest('hex');
|
|
90
|
-
config.set('machineId', machineIdHash);
|
|
91
|
-
return machineIdHash;
|
|
92
|
-
}
|
|
93
|
-
class Session {
|
|
94
|
-
constructor() {
|
|
95
|
-
const sessionId = config.get('sessionId');
|
|
96
|
-
const sessionExpiration = config.get('sessionExpiration');
|
|
97
|
-
if (sessionId && sessionExpiration && !Session.beyondExpiration(sessionExpiration)) {
|
|
98
|
-
this.id = sessionId;
|
|
99
|
-
this.expiration = sessionExpiration;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
this.id = Session.newSessionId();
|
|
103
|
-
this.expiration = Session.expirationFromNow();
|
|
104
|
-
config.set('sessionId', this.id);
|
|
105
|
-
config.set('sessionExpiration', this.expiration);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
static beyondExpiration(expiration) {
|
|
109
|
-
return expiration <= Date.now();
|
|
110
|
-
}
|
|
111
|
-
static expirationFromNow() {
|
|
112
|
-
return Date.now() + 1000 * 60 * 30;
|
|
113
|
-
}
|
|
114
|
-
static newSessionId() {
|
|
115
|
-
return (0, crypto_1.createHash)('sha256').update((0, crypto_1.randomBytes)(32)).digest('hex');
|
|
116
|
-
}
|
|
117
|
-
touch() {
|
|
118
|
-
this.expiration = Session.expirationFromNow();
|
|
119
|
-
config.set('sessionExpiration', this.expiration);
|
|
120
|
-
}
|
|
121
|
-
get valid() {
|
|
122
|
-
return !Session.beyondExpiration(this.expiration);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const propPrefix = name === '@appland/appmap' ? 'appmap.cli.' : name.replace('@', '').replace('/', '.') + '.';
|
|
126
|
-
/**
|
|
127
|
-
* Append the prefix to the name of each property and drop undefined values
|
|
128
|
-
*/
|
|
129
|
-
const transformProps = (obj) => {
|
|
130
|
-
const result = {};
|
|
131
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
132
|
-
if (v === undefined)
|
|
133
|
-
continue;
|
|
134
|
-
if (k.includes('.')) {
|
|
135
|
-
result[k] = v;
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
const prefixedKey = k.startsWith(propPrefix) ? k : `${propPrefix}${k}`;
|
|
139
|
-
result[prefixedKey] = v;
|
|
140
|
-
}
|
|
141
|
-
return result;
|
|
142
|
-
};
|
|
143
|
-
class Telemetry {
|
|
144
|
-
static get enabled() {
|
|
145
|
-
return process.env.APPMAP_TELEMETRY_DISABLED === undefined;
|
|
146
|
-
}
|
|
147
|
-
static get session() {
|
|
148
|
-
var _a;
|
|
149
|
-
if (!((_a = this._session) === null || _a === void 0 ? void 0 : _a.valid)) {
|
|
150
|
-
this._session = new Session();
|
|
151
|
-
}
|
|
152
|
-
return this._session;
|
|
153
|
-
}
|
|
154
|
-
static get client() {
|
|
155
|
-
if (!this._client) {
|
|
156
|
-
// Do not allow Application Insights to try and collect additional metadata
|
|
157
|
-
process.env.APPLICATION_INSIGHTS_NO_STATSBEAT = '1';
|
|
158
|
-
// Disable everything we can, we don't any additional collection from Application Insights.
|
|
159
|
-
(0, applicationinsights_1.setup)(INSTRUMENTATION_KEY)
|
|
160
|
-
.setAutoCollectRequests(false)
|
|
161
|
-
.setAutoCollectPerformance(false)
|
|
162
|
-
.setAutoCollectExceptions(false)
|
|
163
|
-
.setAutoCollectDependencies(false)
|
|
164
|
-
.setAutoCollectHeartbeat(false)
|
|
165
|
-
.setAutoDependencyCorrelation(false)
|
|
166
|
-
.setAutoCollectConsole(false)
|
|
167
|
-
.setInternalLogging(false, false)
|
|
168
|
-
.setSendLiveMetrics(false)
|
|
169
|
-
.setUseDiskRetryCaching(true);
|
|
170
|
-
const client = new applicationinsights_1.TelemetryClient(INSTRUMENTATION_KEY);
|
|
171
|
-
client.context.tags[client.context.keys.userId] = Telemetry.machineId;
|
|
172
|
-
client.context.tags[client.context.keys.sessionId] = Telemetry.session.id;
|
|
173
|
-
client.context.tags[client.context.keys.cloudRole] = name;
|
|
174
|
-
client.setAutoPopulateAzureProperties(false);
|
|
175
|
-
this._client = client;
|
|
176
|
-
}
|
|
177
|
-
return this._client;
|
|
178
|
-
}
|
|
179
|
-
static sendEvent(data, options = { includeEnvironment: false }) {
|
|
180
|
-
try {
|
|
181
|
-
const transformedProperties = transformProps(Object.assign({ version: version, args: process.argv.slice(1).join(' ') }, data.properties));
|
|
182
|
-
const transformedMetrics = transformProps(data.metrics || {});
|
|
183
|
-
const properties = Object.assign({ 'common.source': name, 'common.os': os.platform(), 'common.platformversion': os.release(), 'common.arch': os.arch(), 'appmap.cli.machineId': Telemetry.machineId, 'appmap.cli.sessionId': Telemetry.session.id }, transformedProperties);
|
|
184
|
-
if (options.includeEnvironment) {
|
|
185
|
-
properties['common.environmentVariables'] = Object.keys(process.env).sort().join(',');
|
|
186
|
-
}
|
|
187
|
-
const event = {
|
|
188
|
-
name: `${name}/${data.name}`,
|
|
189
|
-
measurements: transformedMetrics,
|
|
190
|
-
properties,
|
|
191
|
-
};
|
|
192
|
-
if (this.debug) {
|
|
193
|
-
console.log(JSON.stringify(event, null, 2));
|
|
194
|
-
}
|
|
195
|
-
if (this.enabled) {
|
|
196
|
-
Telemetry.client.trackEvent(event);
|
|
197
|
-
Telemetry.session.touch();
|
|
198
|
-
Telemetry.client.flush();
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (e) {
|
|
202
|
-
// Don't let telemetry fail the entire command
|
|
203
|
-
// Do nothing other than log for now, we can't do anything about it
|
|
204
|
-
if (this.debug) {
|
|
205
|
-
if (e instanceof Error) {
|
|
206
|
-
console.error(e.stack);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
console.error(e);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
static flush(exitCB) {
|
|
215
|
-
if (this.enabled) {
|
|
216
|
-
// Telemetry.client.flush is broken:
|
|
217
|
-
// https://github.com/microsoft/ApplicationInsights-node.js/issues/871 .
|
|
218
|
-
// As a result, we can fail to send telemetry data when exiting.
|
|
219
|
-
//
|
|
220
|
-
// If we got passed a callback, flush the data and wait for a second
|
|
221
|
-
// before calling it.
|
|
222
|
-
if (exitCB) {
|
|
223
|
-
Telemetry.client.flush();
|
|
224
|
-
setTimeout(exitCB, 1000);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
exitCB();
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
exports.default = Telemetry;
|
|
233
|
-
Telemetry.debug = process.env.APPMAP_TELEMETRY_DEBUG !== undefined;
|
|
234
|
-
Telemetry.machineId = getMachineId();
|
|
235
|
-
var GitState;
|
|
236
|
-
(function (GitState) {
|
|
237
|
-
GitState[GitState["NotInstalled"] = 0] = "NotInstalled";
|
|
238
|
-
GitState[GitState["NoRepository"] = 1] = "NoRepository";
|
|
239
|
-
GitState[GitState["Ok"] = 2] = "Ok";
|
|
240
|
-
})(GitState = exports.GitState || (exports.GitState = {}));
|
|
241
|
-
exports.GitRepositoryEnvKeys = [
|
|
242
|
-
'GITHUB_REPOSITORY',
|
|
243
|
-
'CIRCLE_REPOSITORY_URL',
|
|
244
|
-
'GIT_URL',
|
|
245
|
-
'CI_REPOSITORY_URL', // GitLab
|
|
246
|
-
];
|
|
247
|
-
exports.GitBranchEnvKeys = [
|
|
248
|
-
'GITHUB_REF_NAME',
|
|
249
|
-
'CIRCLE_BRANCH',
|
|
250
|
-
'GIT_BRANCH',
|
|
251
|
-
'TRAVIS_BRANCH',
|
|
252
|
-
'CI_COMMIT_REF_NAME', // GitLab
|
|
253
|
-
];
|
|
254
|
-
exports.GitCommitEnvKeys = [
|
|
255
|
-
'GITHUB_SHA',
|
|
256
|
-
'CIRCLE_SHA1',
|
|
257
|
-
'GIT_COMMIT',
|
|
258
|
-
'TRAVIS_COMMIT',
|
|
259
|
-
'CI_COMMIT_SHA', // GitLab
|
|
260
|
-
];
|
|
261
|
-
class GitProperties {
|
|
262
|
-
static contributors(sinceDaysAgo, cwd) {
|
|
263
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
264
|
-
const unixTimeNow = Math.floor(Number(new Date()) / 1000);
|
|
265
|
-
const unixTimeAgo = unixTimeNow - sinceDaysAgo * 24 * 60 * 60;
|
|
266
|
-
try {
|
|
267
|
-
const { stdout } = yield exec([
|
|
268
|
-
'git',
|
|
269
|
-
cwd && `-C ${cwd.toString()}`,
|
|
270
|
-
'--no-pager',
|
|
271
|
-
'log',
|
|
272
|
-
`--since=${unixTimeAgo}`,
|
|
273
|
-
'--format="%ae"',
|
|
274
|
-
].join(' '));
|
|
275
|
-
return [
|
|
276
|
-
...stdout
|
|
277
|
-
.trim()
|
|
278
|
-
.split('\n')
|
|
279
|
-
.reduce((acc, email) => {
|
|
280
|
-
acc.add(email);
|
|
281
|
-
return acc;
|
|
282
|
-
}, new Set()),
|
|
283
|
-
];
|
|
284
|
-
}
|
|
285
|
-
catch (_a) {
|
|
286
|
-
return [];
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
// Returns the repository URL, first by checking the environment, then by
|
|
291
|
-
// shelling out to git.
|
|
292
|
-
static repository(cwd) {
|
|
293
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
-
const envKey = exports.GitRepositoryEnvKeys.find((key) => process.env[key]);
|
|
295
|
-
if (envKey)
|
|
296
|
-
return process.env[envKey];
|
|
297
|
-
try {
|
|
298
|
-
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'config', '--get', 'remote.origin.url'].join(' '));
|
|
299
|
-
return stdout.trim();
|
|
300
|
-
}
|
|
301
|
-
catch (_a) {
|
|
302
|
-
return undefined;
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
// Returns the branch, first by checking the environment, then by
|
|
307
|
-
// shelling out to git.
|
|
308
|
-
static branch(cwd) {
|
|
309
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
-
const envKey = exports.GitBranchEnvKeys.find((key) => process.env[key]);
|
|
311
|
-
if (envKey)
|
|
312
|
-
return process.env[envKey];
|
|
313
|
-
try {
|
|
314
|
-
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'rev-parse', '--abbrev-ref', 'HEAD'].join(' '));
|
|
315
|
-
return stdout.trim();
|
|
316
|
-
}
|
|
317
|
-
catch (_a) {
|
|
318
|
-
return undefined;
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
// Returns the commit SHA, first by checking the environment, then by
|
|
323
|
-
// shelling out to git.
|
|
324
|
-
static commit(cwd) {
|
|
325
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
326
|
-
const envKey = exports.GitCommitEnvKeys.find((key) => process.env[key]);
|
|
327
|
-
if (envKey)
|
|
328
|
-
return process.env[envKey];
|
|
329
|
-
try {
|
|
330
|
-
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'rev-parse', 'HEAD'].join(' '));
|
|
331
|
-
return stdout.trim();
|
|
332
|
-
}
|
|
333
|
-
catch (_a) {
|
|
334
|
-
return undefined;
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
static state(cwd) {
|
|
339
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
340
|
-
return new Promise((resolve) => {
|
|
341
|
-
try {
|
|
342
|
-
const commandProcess = (0, child_process_1.spawn)('git', ['status', '--porcelain'], {
|
|
343
|
-
shell: true,
|
|
344
|
-
cwd: cwd === null || cwd === void 0 ? void 0 : cwd.toString(),
|
|
345
|
-
stdio: 'ignore',
|
|
346
|
-
timeout: 2000,
|
|
347
|
-
});
|
|
348
|
-
commandProcess.on('exit', (code) => {
|
|
349
|
-
switch (code) {
|
|
350
|
-
case 127:
|
|
351
|
-
return resolve(GitState.NotInstalled);
|
|
352
|
-
case 128:
|
|
353
|
-
return resolve(GitState.NoRepository);
|
|
354
|
-
default:
|
|
355
|
-
return resolve(GitState.Ok);
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
commandProcess.on('error', () => resolve(GitState.NotInstalled));
|
|
359
|
-
}
|
|
360
|
-
catch (_a) {
|
|
361
|
-
resolve(GitState.NotInstalled);
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
static clearCache() {
|
|
367
|
-
gitCache.clear();
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
const gitCache = new Map();
|
|
371
|
-
const noCacheList = ['clearCache'];
|
|
372
|
-
// GitProperties is available externally as Git.
|
|
373
|
-
// This export provides a simple caching layer around GitProperties to avoid
|
|
374
|
-
// excessive shelling out to git.
|
|
375
|
-
exports.Git = new Proxy(GitProperties, {
|
|
376
|
-
get(target, prop) {
|
|
377
|
-
if (!noCacheList.includes(prop.toString()) &&
|
|
378
|
-
typeof target[prop] === 'function') {
|
|
379
|
-
return new Proxy(target[prop], {
|
|
380
|
-
apply(target, thisArg, argArray) {
|
|
381
|
-
const cacheKey = `${prop.toString()}(${JSON.stringify(argArray)})`;
|
|
382
|
-
if (gitCache.has(cacheKey)) {
|
|
383
|
-
return gitCache.get(cacheKey);
|
|
384
|
-
}
|
|
385
|
-
/* eslint-disable-next-line @typescript-eslint/ban-types */
|
|
386
|
-
const result = Reflect.apply(target, thisArg, argArray);
|
|
387
|
-
gitCache.set(cacheKey, result);
|
|
388
|
-
return result;
|
|
389
|
-
},
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
return Reflect.get(target, prop);
|
|
393
|
-
},
|
|
394
|
-
});
|