@atlaskit/dependency-version-analytics 0.4.1 → 1.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/CHANGELOG.md +12 -0
- package/dist/cjs/cli.js +4 -18
- package/dist/cjs/commands/populate-historic-data/index.js +0 -3
- package/dist/cjs/commands/populate-historic-data/lib/dependency-store.js +24 -141
- package/dist/cjs/commands/populate-historic-data/package.js +3 -27
- package/dist/cjs/commands/populate-historic-data/product.js +15 -88
- package/dist/cjs/commands/populate-historic-data/util/generate-csv.js +4 -16
- package/dist/cjs/index.js +0 -2
- package/dist/cjs/util/analytics.js +0 -38
- package/dist/cjs/util/assert.js +0 -1
- package/dist/cjs/util/env-with-guard.js +0 -2
- package/dist/cjs/util/get-file-history-from-git.js +0 -5
- package/dist/cjs/util/get-package-version-history.js +0 -6
- package/dist/cjs/util/git.js +20 -58
- package/dist/cjs/util/statlas.js +0 -25
- package/dist/cjs/util/yarn.js +0 -32
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/cli.js +4 -8
- package/dist/es2019/commands/populate-historic-data/lib/dependency-store.js +24 -73
- package/dist/es2019/commands/populate-historic-data/package.js +0 -8
- package/dist/es2019/commands/populate-historic-data/product.js +4 -22
- package/dist/es2019/commands/populate-historic-data/util/generate-csv.js +2 -9
- package/dist/es2019/util/analytics.js +4 -19
- package/dist/es2019/util/env-with-guard.js +0 -1
- package/dist/es2019/util/get-file-history-from-git.js +2 -3
- package/dist/es2019/util/get-package-version-history.js +0 -4
- package/dist/es2019/util/git.js +29 -24
- package/dist/es2019/util/statlas.js +0 -6
- package/dist/es2019/util/yarn.js +2 -11
- package/dist/es2019/version.json +1 -1
- package/dist/esm/cli.js +6 -12
- package/dist/esm/commands/populate-historic-data/lib/dependency-store.js +27 -131
- package/dist/esm/commands/populate-historic-data/package.js +3 -20
- package/dist/esm/commands/populate-historic-data/product.js +15 -72
- package/dist/esm/commands/populate-historic-data/util/generate-csv.js +4 -13
- package/dist/esm/util/analytics.js +2 -28
- package/dist/esm/util/env-with-guard.js +0 -1
- package/dist/esm/util/get-file-history-from-git.js +2 -3
- package/dist/esm/util/get-package-version-history.js +0 -4
- package/dist/esm/util/git.js +21 -50
- package/dist/esm/util/statlas.js +0 -19
- package/dist/esm/util/yarn.js +0 -19
- package/dist/esm/version.json +1 -1
- package/package.json +4 -4
- package/report.api.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
-
|
|
3
2
|
/** Workspace code */
|
|
3
|
+
|
|
4
4
|
import debugModule from 'debug';
|
|
5
5
|
import semver from 'semver';
|
|
6
6
|
import { getWorkspacePaths, getWorkspaceGlobs } from '../../../util/yarn';
|
|
@@ -9,7 +9,6 @@ import { DEP_TYPES } from '../../../constants';
|
|
|
9
9
|
import { assert } from '../../../util/assert';
|
|
10
10
|
import micromatch from 'micromatch';
|
|
11
11
|
const debug = debugModule('atlaskit:dependency');
|
|
12
|
-
|
|
13
12
|
/**
|
|
14
13
|
* Stores the state of atlaskit dependencies in a repository
|
|
15
14
|
*/
|
|
@@ -19,132 +18,108 @@ export class DependencyStore {
|
|
|
19
18
|
/** Mapping of workspaces to their dependency map. Each dependency in their map links to an entry in `dependencies` */
|
|
20
19
|
|
|
21
20
|
/** Set of workspace globs. Used to verify that a package.json is a valid workspace */
|
|
21
|
+
|
|
22
22
|
constructor(cwd = process.cwd()) {
|
|
23
23
|
_defineProperty(this, "dependencies", {});
|
|
24
|
-
|
|
25
24
|
_defineProperty(this, "workspaces", {});
|
|
26
|
-
|
|
27
25
|
_defineProperty(this, "workspaceGlobs", new Set());
|
|
28
|
-
|
|
29
26
|
_defineProperty(this, "initialised", false);
|
|
30
|
-
|
|
31
27
|
this.cwd = cwd;
|
|
32
28
|
}
|
|
33
|
-
/** Scans the repo for dependencies at the specified git ref and return the flattened dependency map */
|
|
34
|
-
|
|
35
29
|
|
|
30
|
+
/** Scans the repo for dependencies at the specified git ref and return the flattened dependency map */
|
|
36
31
|
async initialise(gitRef) {
|
|
37
32
|
if (gitRef) {
|
|
38
33
|
await this.resetStore(gitRef);
|
|
39
34
|
}
|
|
40
|
-
|
|
41
35
|
this.initialised = true;
|
|
42
36
|
return this.getFlattenedDeps();
|
|
43
37
|
}
|
|
38
|
+
|
|
44
39
|
/** Updates the repo dependency store based on the changes in `logItem`.
|
|
45
40
|
* Returns the updated flattened dependencies
|
|
46
41
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
42
|
async update(logItem) {
|
|
50
43
|
this.assertInitialised();
|
|
51
44
|
const hash = logItem.hash;
|
|
52
45
|
assert(!!logItem.diff, `Diff must exist in log ${logItem} ${hash}`);
|
|
53
46
|
const changedPackageJsons = logItem.diff.files.filter(f => f.file === 'package.json' || f.file.endsWith('/package.json')).map(f => f.file);
|
|
54
47
|
const didRootPackageJsonChange = !!changedPackageJsons.find(file => file === 'package.json');
|
|
55
|
-
|
|
56
48
|
if (didRootPackageJsonChange) {
|
|
57
49
|
const workspaceGlobs = await getWorkspaceGlobs(hash, this.cwd);
|
|
58
50
|
const globsChanged = workspaceGlobs !== null && (this.workspaceGlobs.size !== workspaceGlobs.size || [...this.workspaceGlobs].some(glob => !workspaceGlobs.has(glob)));
|
|
59
|
-
|
|
60
51
|
if (globsChanged) {
|
|
61
52
|
debug(`Workspace globs changed: ${[...workspaceGlobs]}. Resetting store.`);
|
|
62
53
|
await this.resetStore(hash);
|
|
63
54
|
return this.getFlattenedDeps();
|
|
64
55
|
}
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
const changedWorkspaces = micromatch(changedPackageJsons, [...this.workspaceGlobs]);
|
|
68
|
-
debug(`Updating changed workspaces@${hash}: ${changedWorkspaces}`);
|
|
69
|
-
// remove older workspaces that are no longer valid
|
|
58
|
+
debug(`Updating changed workspaces@${hash}: ${changedWorkspaces}`);
|
|
70
59
|
|
|
60
|
+
// Iterate over all changed package.jsons rather than only valid workspaces so that we can
|
|
61
|
+
// remove older workspaces that are no longer valid
|
|
71
62
|
for (const workspacePath of changedPackageJsons) {
|
|
72
63
|
let workspaceDeps = await this.getWorkspaceDependencies(hash, workspacePath);
|
|
73
64
|
const validWorkspace = changedWorkspaces.includes(workspacePath);
|
|
74
|
-
|
|
75
65
|
if (!validWorkspace && !this.workspaces[workspacePath]) {
|
|
76
66
|
// Ignore package.jsons that aren't a valid workspace and weren't valid previously
|
|
77
67
|
continue;
|
|
78
|
-
}
|
|
79
|
-
|
|
68
|
+
}
|
|
80
69
|
|
|
70
|
+
// For workspaces that are no longer a valid workspace but were previously, explicitly remove them
|
|
81
71
|
const noLongerWorkspace = !validWorkspace && this.workspaces[workspacePath];
|
|
82
|
-
|
|
83
72
|
if (workspaceDeps == null || noLongerWorkspace) {
|
|
84
73
|
// If workspaceDeps is undefined, package.json existed but JSON was invalid
|
|
85
74
|
// Else if workspaceDeps is null, package.json doesn't exist and has hence been deleted
|
|
86
75
|
if (workspaceDeps === undefined) {
|
|
87
76
|
console.error(`Error parsing metadata for workspace ${workspacePath}@${hash}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
}
|
|
78
|
+
// set the workspaceDeps to empty here explicitly to remove any deleted workspaces
|
|
91
79
|
workspaceDeps = {};
|
|
92
80
|
}
|
|
93
|
-
|
|
94
81
|
this.updateWorkspaces(workspacePath, workspaceDeps);
|
|
95
82
|
}
|
|
96
|
-
|
|
97
83
|
return this.getFlattenedDeps();
|
|
98
84
|
}
|
|
85
|
+
|
|
99
86
|
/** Retrieve a flattened list of p repo dependencies.
|
|
100
87
|
* If multiple versions of a dependency exist, the lowest version is returned.
|
|
101
88
|
* If the dependency is listed under multiple dependency types, 'dependencies' is prioritised over 'devDependencies'
|
|
102
89
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
90
|
getFlattenedDeps() {
|
|
106
91
|
const deps = Object.entries(this.dependencies).filter(([, versions]) => versions.length > 0).map(([depName, versions]) => [depName, DependencyStore.getMinimumVersion(versions, depName)]);
|
|
107
92
|
return fromEntries(deps);
|
|
108
93
|
}
|
|
109
|
-
|
|
110
94
|
assertInitialised() {
|
|
111
95
|
if (!this.initialised) {
|
|
112
96
|
throw new Error('Class must be initialised first with `.initialise()`');
|
|
113
97
|
}
|
|
114
98
|
}
|
|
115
|
-
/** Scans all workspaces in repo and rebuilds dependency store */
|
|
116
|
-
|
|
117
99
|
|
|
100
|
+
/** Scans all workspaces in repo and rebuilds dependency store */
|
|
118
101
|
async resetStore(gitRef) {
|
|
119
102
|
this.dependencies = {};
|
|
120
103
|
this.workspaces = {};
|
|
121
104
|
const workspaceGlobs = await getWorkspaceGlobs(gitRef, this.cwd);
|
|
122
|
-
|
|
123
105
|
if (workspaceGlobs !== null) {
|
|
124
106
|
this.workspaceGlobs = workspaceGlobs;
|
|
125
107
|
}
|
|
126
|
-
|
|
127
108
|
const workspacePaths = await getWorkspacePaths(gitRef, this.workspaceGlobs, this.cwd);
|
|
128
109
|
debug(`Workspace paths: ${workspacePaths}`);
|
|
129
|
-
|
|
130
110
|
for (const wsPath of workspacePaths) {
|
|
131
111
|
if (this.workspaces[wsPath]) {
|
|
132
112
|
throw new Error(`Duplicate workspace path found: ${wsPath}`);
|
|
133
113
|
}
|
|
134
|
-
|
|
135
114
|
const workspaceDeps = await this.getWorkspaceDependencies(gitRef, wsPath);
|
|
136
|
-
|
|
137
115
|
if (workspaceDeps == null) {
|
|
138
116
|
continue;
|
|
139
117
|
}
|
|
140
|
-
|
|
141
118
|
this.updateWorkspaces(wsPath, workspaceDeps);
|
|
142
119
|
}
|
|
143
120
|
}
|
|
144
|
-
|
|
145
121
|
async getWorkspaceDependencies(hash, workspacePath) {
|
|
146
122
|
let file;
|
|
147
|
-
|
|
148
123
|
try {
|
|
149
124
|
file = await showFile(hash, workspacePath, {
|
|
150
125
|
cwd: this.cwd
|
|
@@ -153,46 +128,37 @@ export class DependencyStore {
|
|
|
153
128
|
debug(`Could not show file ${workspacePath}@${hash}`);
|
|
154
129
|
return null;
|
|
155
130
|
}
|
|
156
|
-
|
|
157
131
|
let json;
|
|
158
|
-
|
|
159
132
|
try {
|
|
160
133
|
json = JSON.parse(file);
|
|
161
134
|
} catch (e) {
|
|
162
135
|
console.error(`Error parsing JSON - "${file}"@${hash}`);
|
|
163
136
|
return undefined;
|
|
164
137
|
}
|
|
165
|
-
|
|
166
138
|
let workspaceDeps = {};
|
|
167
|
-
|
|
168
139
|
for (const {
|
|
169
140
|
packageJsonKey,
|
|
170
141
|
depTypeName
|
|
171
142
|
} of DEP_TYPES) {
|
|
172
143
|
const wsDeps = DependencyStore.getAkDependencies(json[packageJsonKey] || {}, depTypeName);
|
|
173
|
-
workspaceDeps = {
|
|
144
|
+
workspaceDeps = {
|
|
145
|
+
...workspaceDeps,
|
|
174
146
|
...wsDeps
|
|
175
147
|
};
|
|
176
148
|
}
|
|
177
|
-
|
|
178
149
|
return workspaceDeps;
|
|
179
150
|
}
|
|
180
|
-
|
|
181
151
|
updateWorkspaces(workspacePath, workspaceDeps) {
|
|
182
152
|
debug(`Updating workspace ${workspacePath}`);
|
|
183
|
-
|
|
184
153
|
if (!this.workspaces[workspacePath]) {
|
|
185
154
|
this.workspaces[workspacePath] = {};
|
|
186
155
|
}
|
|
187
|
-
|
|
188
156
|
const prevWorkspaceDeps = this.workspaces[workspacePath];
|
|
189
|
-
|
|
190
157
|
for (const depName of Object.keys(prevWorkspaceDeps)) {
|
|
191
158
|
if (!workspaceDeps[depName]) {
|
|
192
159
|
this.removeDependency(workspacePath, depName, prevWorkspaceDeps[depName]);
|
|
193
160
|
}
|
|
194
161
|
}
|
|
195
|
-
|
|
196
162
|
for (const [depName, {
|
|
197
163
|
version,
|
|
198
164
|
type
|
|
@@ -200,25 +166,20 @@ export class DependencyStore {
|
|
|
200
166
|
this.addDependency(workspacePath, depName, version, type);
|
|
201
167
|
}
|
|
202
168
|
}
|
|
203
|
-
|
|
204
169
|
addDependency(workspacePath, depName, version, type) {
|
|
205
170
|
if (!this.dependencies[depName]) {
|
|
206
171
|
debug(`Adding new dep ${depName}`);
|
|
207
172
|
this.dependencies[depName] = [];
|
|
208
173
|
}
|
|
209
|
-
|
|
210
174
|
const prevEntry = this.workspaces[workspacePath][depName];
|
|
211
175
|
const existingEntry = this.dependencies[depName].find(entry => entry.version === version && entry.type === type);
|
|
212
|
-
|
|
213
176
|
if (existingEntry && existingEntry === prevEntry) {
|
|
214
177
|
// We haven't added or updated the dep, exit early
|
|
215
178
|
return;
|
|
216
179
|
}
|
|
217
|
-
|
|
218
180
|
if (prevEntry) {
|
|
219
181
|
this.removeDependency(workspacePath, depName, prevEntry);
|
|
220
182
|
}
|
|
221
|
-
|
|
222
183
|
if (existingEntry) {
|
|
223
184
|
existingEntry.workspaces.add(workspacePath);
|
|
224
185
|
this.workspaces[workspacePath][depName] = existingEntry;
|
|
@@ -233,39 +194,33 @@ export class DependencyStore {
|
|
|
233
194
|
this.workspaces[workspacePath][depName] = newEntry;
|
|
234
195
|
}
|
|
235
196
|
}
|
|
236
|
-
|
|
237
197
|
removeDependency(workspacePath, depName, depEntry) {
|
|
238
198
|
debug(`${depName} removed from ${workspacePath}`);
|
|
239
199
|
assert(depEntry && depEntry.workspaces, `Dep entry should exist for ${depName}`);
|
|
240
200
|
depEntry.workspaces.delete(workspacePath);
|
|
241
|
-
|
|
242
201
|
if (depEntry.workspaces.size === 0) {
|
|
243
202
|
debug(`No more workspaces depend on ${depName}@${depEntry.version} as a ${depEntry.type}, deleting`);
|
|
244
203
|
this.dependencies[depName] = this.dependencies[depName].filter(entry => entry !== depEntry);
|
|
245
204
|
}
|
|
246
205
|
}
|
|
247
|
-
|
|
248
206
|
static getAkDependencies(depMap, type) {
|
|
249
|
-
return fromEntries(Object.entries(depMap).filter(
|
|
207
|
+
return fromEntries(Object.entries(depMap).filter(
|
|
208
|
+
// Ignore suffixed `--next` deps in jira used for independent upgrades
|
|
250
209
|
([name]) => name.includes('@atlaskit') && !name.endsWith('--next')).map(([name, version]) => [DependencyStore.transformDepName(name), {
|
|
251
210
|
version: DependencyStore.transformDepVersion(version),
|
|
252
211
|
type
|
|
253
212
|
}]));
|
|
254
213
|
}
|
|
255
|
-
|
|
256
214
|
static getMinimumVersion(versions, depName) {
|
|
257
|
-
const depOrder = ['dependency', 'peerDependency', 'devDependency', 'optionalDependency'];
|
|
258
|
-
|
|
215
|
+
const depOrder = ['dependency', 'peerDependency', 'devDependency', 'optionalDependency'];
|
|
216
|
+
// Sort deps before devDeps and then take the lowest version
|
|
259
217
|
const sorted = versions.sort((a, b) => {
|
|
260
218
|
const depSort = depOrder.indexOf(a.type) - depOrder.indexOf(b.type);
|
|
261
|
-
|
|
262
219
|
if (depSort !== 0) {
|
|
263
220
|
return depSort;
|
|
264
221
|
}
|
|
265
|
-
|
|
266
222
|
const aVersion = semver.coerce(a.version);
|
|
267
223
|
const bVersion = semver.coerce(b.version);
|
|
268
|
-
|
|
269
224
|
if (!aVersion) {
|
|
270
225
|
console.error(`Invalid version ${depName}@${a.version}`);
|
|
271
226
|
return 1;
|
|
@@ -273,37 +228,33 @@ export class DependencyStore {
|
|
|
273
228
|
console.error(`Invalid version ${depName}@${b.version}`);
|
|
274
229
|
return -1;
|
|
275
230
|
}
|
|
276
|
-
|
|
277
231
|
return semver.compare(aVersion, bVersion);
|
|
278
232
|
});
|
|
279
|
-
|
|
280
233
|
if (sorted.length > 1) {
|
|
281
|
-
debug(`Multiple versions found for ${depName}: ${JSON.stringify(sorted.map(depInfo => ({
|
|
234
|
+
debug(`Multiple versions found for ${depName}: ${JSON.stringify(sorted.map(depInfo => ({
|
|
235
|
+
...depInfo,
|
|
282
236
|
workspaces: [...depInfo.workspaces]
|
|
283
237
|
})))}`);
|
|
284
238
|
}
|
|
285
|
-
|
|
286
239
|
return sorted[0];
|
|
287
240
|
}
|
|
288
|
-
|
|
289
241
|
static transformDepName(name) {
|
|
290
242
|
// Treat `--current` as the standard dependency
|
|
291
243
|
return name.replace(/--current$/, '');
|
|
292
244
|
}
|
|
245
|
+
|
|
293
246
|
/* Coerce non-standard versions to a semver version.
|
|
294
247
|
* This essentially ignores everything up until the first number and then tries to parse a version
|
|
295
248
|
* out of that.
|
|
296
249
|
* Used to yarn alias versions used by jira's independent upgrades, e.g. npm:@atlaskit/button@^15.0.8
|
|
297
250
|
*/
|
|
298
|
-
|
|
299
|
-
|
|
300
251
|
static transformDepVersion(version) {
|
|
301
252
|
const parts = version.split('@');
|
|
302
253
|
return parts[parts.length - 1];
|
|
303
254
|
}
|
|
255
|
+
}
|
|
304
256
|
|
|
305
|
-
|
|
306
|
-
|
|
257
|
+
// Object.fromEntries polyfill, remove when upgraded to node 10
|
|
307
258
|
function fromEntries(iterable) {
|
|
308
259
|
return [...iterable].reduce((obj, {
|
|
309
260
|
0: key,
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
import getPackageVersionHistory from '../../util/get-package-version-history';
|
|
3
3
|
import { createUpgradeEvent, sendAnalytics } from '../../util/analytics';
|
|
4
|
-
|
|
5
4
|
const createAnalyticsEvents = (packageName, packageVersionHistory, since) => {
|
|
6
5
|
const sortedPackageVersionHistory = Object.entries(packageVersionHistory).filter(([version]) => semver.valid(version)).sort((a, b) => Number(new Date(a[1])) - Number(new Date(b[1])));
|
|
7
6
|
const upgradeEvents = sortedPackageVersionHistory.map(([version, time], i) => {
|
|
8
7
|
if (since && Number(new Date(time)) <= Number(new Date(since))) {
|
|
9
8
|
return null;
|
|
10
9
|
}
|
|
11
|
-
|
|
12
10
|
const previousVersion = sortedPackageVersionHistory[i - 1] && sortedPackageVersionHistory[i - 1][0];
|
|
13
11
|
return createUpgradeEvent(packageName, version, previousVersion, time, {
|
|
14
12
|
historical: true
|
|
@@ -16,25 +14,19 @@ const createAnalyticsEvents = (packageName, packageVersionHistory, since) => {
|
|
|
16
14
|
}).filter(e => e != null);
|
|
17
15
|
return upgradeEvents;
|
|
18
16
|
};
|
|
19
|
-
|
|
20
17
|
export default async function populatePackage(flags) {
|
|
21
18
|
if (!flags.pkg.startsWith('@atlaskit/')) {
|
|
22
19
|
throw new Error(`Package must start with '@atlaskit/'`);
|
|
23
20
|
}
|
|
24
|
-
|
|
25
21
|
const packageVersionHistory = await getPackageVersionHistory(flags.pkg);
|
|
26
|
-
|
|
27
22
|
if (flags.since && Number.isNaN(Number(new Date(flags.since)))) {
|
|
28
23
|
throw new Error(`'since' flag is an invalid date`);
|
|
29
24
|
}
|
|
30
|
-
|
|
31
25
|
const analyticsEvents = createAnalyticsEvents(flags.pkg, packageVersionHistory, flags.since);
|
|
32
|
-
|
|
33
26
|
if (flags.dryRun) {
|
|
34
27
|
console.log(JSON.stringify(analyticsEvents));
|
|
35
28
|
return analyticsEvents;
|
|
36
29
|
}
|
|
37
|
-
|
|
38
30
|
await sendAnalytics(analyticsEvents, {
|
|
39
31
|
dev: flags.dev,
|
|
40
32
|
limit: flags.limit,
|
|
@@ -6,7 +6,6 @@ import * as statlas from '../../util/statlas';
|
|
|
6
6
|
import { generateCSV } from './util/generate-csv';
|
|
7
7
|
import { assert } from '../../util/assert';
|
|
8
8
|
import { DependencyStore } from './lib/dependency-store';
|
|
9
|
-
|
|
10
9
|
const getUpgradeEventsFromPkgChange = (oldDeps, newDeps, {
|
|
11
10
|
date,
|
|
12
11
|
commitHash
|
|
@@ -15,9 +14,9 @@ const getUpgradeEventsFromPkgChange = (oldDeps, newDeps, {
|
|
|
15
14
|
version,
|
|
16
15
|
type
|
|
17
16
|
}]) => {
|
|
18
|
-
const prevDep = oldDeps[name];
|
|
17
|
+
const prevDep = oldDeps[name];
|
|
18
|
+
// Only treat a dependency as previous if the dependency type matches
|
|
19
19
|
// Otherwise, we want separate add/remove events
|
|
20
|
-
|
|
21
20
|
const prevVersion = prevDep && prevDep.type === type ? prevDep.version : undefined;
|
|
22
21
|
return createUpgradeEvent(name, version, prevVersion, date, {
|
|
23
22
|
commitHash,
|
|
@@ -27,7 +26,8 @@ const getUpgradeEventsFromPkgChange = (oldDeps, newDeps, {
|
|
|
27
26
|
}).filter(e => e != null);
|
|
28
27
|
const removeEvents = Object.entries(oldDeps).filter(([name, {
|
|
29
28
|
type
|
|
30
|
-
}]) =>
|
|
29
|
+
}]) =>
|
|
30
|
+
// Treat the same dep under a different dependency type as a new dep
|
|
31
31
|
newDeps[name] == null || newDeps[name].type !== type).map(([name, {
|
|
32
32
|
version,
|
|
33
33
|
type
|
|
@@ -40,7 +40,6 @@ const getUpgradeEventsFromPkgChange = (oldDeps, newDeps, {
|
|
|
40
40
|
}).filter(e => e != null);
|
|
41
41
|
return [...addOrUpgradeEvents, ...removeEvents];
|
|
42
42
|
};
|
|
43
|
-
|
|
44
43
|
const getEventsFromHistory = async (packageChangesLog, prevRunHash, {
|
|
45
44
|
cwd
|
|
46
45
|
}) => {
|
|
@@ -49,14 +48,11 @@ const getEventsFromHistory = async (packageChangesLog, prevRunHash, {
|
|
|
49
48
|
assert(packageChangesLog.all.length > 0, '');
|
|
50
49
|
let dependencyStore = new DependencyStore(cwd);
|
|
51
50
|
let dependencies = await dependencyStore.initialise(prevRunHash);
|
|
52
|
-
|
|
53
51
|
for (let i = 0; i < packageChangesLog.all.length; i++) {
|
|
54
52
|
let item = packageChangesLog.all[i];
|
|
55
|
-
|
|
56
53
|
if (allPackageChanges.length > 0) {
|
|
57
54
|
dependencies = allPackageChanges[allPackageChanges.length - 1].akDeps;
|
|
58
55
|
}
|
|
59
|
-
|
|
60
56
|
const newDependencies = await dependencyStore.update(item);
|
|
61
57
|
const packageChange = {
|
|
62
58
|
date: new Date(item.date).toISOString(),
|
|
@@ -66,69 +62,56 @@ const getEventsFromHistory = async (packageChangesLog, prevRunHash, {
|
|
|
66
62
|
date: packageChange.date,
|
|
67
63
|
commitHash: item.hash
|
|
68
64
|
});
|
|
69
|
-
|
|
70
65
|
if (upgradeEvents.length > 0) {
|
|
71
66
|
allUpgradeEvents.push(...upgradeEvents);
|
|
72
67
|
allPackageChanges.push(packageChange);
|
|
73
68
|
}
|
|
74
69
|
}
|
|
75
|
-
|
|
76
70
|
return {
|
|
77
71
|
allPackageChanges,
|
|
78
72
|
allUpgradeEvents
|
|
79
73
|
};
|
|
80
74
|
};
|
|
81
|
-
|
|
82
75
|
async function getSinceRef(flags) {
|
|
83
76
|
if (flags.statlas) {
|
|
84
77
|
const meta = await statlas.getMeta(flags.product);
|
|
85
|
-
|
|
86
78
|
if (!meta || !meta.lastRunHash) {
|
|
87
79
|
throw new Error(chalk.red(`Missing or invalid metadata file for ${flags.product}. Must use --reset for populating from start of history`));
|
|
88
80
|
}
|
|
89
|
-
|
|
90
81
|
return meta.lastRunHash;
|
|
91
82
|
} else {
|
|
92
83
|
const tag = flags.tag || DEFAULT_TAG;
|
|
93
84
|
await refetchTag(tag);
|
|
94
85
|
const tagExists = await doesTagExist(tag);
|
|
95
|
-
|
|
96
86
|
if (!tagExists) {
|
|
97
87
|
throw new Error(chalk.red(`Tag '${tag}' does not exist. Must use --reset for populating from start of history.`));
|
|
98
88
|
}
|
|
99
|
-
|
|
100
89
|
return tag;
|
|
101
90
|
}
|
|
102
91
|
}
|
|
103
|
-
|
|
104
92
|
export default async function populateProduct(flags) {
|
|
105
93
|
const cwd = flags.cwd || process.cwd();
|
|
106
94
|
const sinceRef = flags.reset ? undefined : await getSinceRef(flags);
|
|
107
95
|
const log = await getChangesSince(sinceRef);
|
|
108
|
-
|
|
109
96
|
if (log.all.length === 0) {
|
|
110
97
|
console.log(`No package.json changes found since '${sinceRef}'.`);
|
|
111
98
|
return;
|
|
112
99
|
}
|
|
113
|
-
|
|
114
100
|
const {
|
|
115
101
|
allPackageChanges,
|
|
116
102
|
allUpgradeEvents
|
|
117
103
|
} = await getEventsFromHistory(log, sinceRef, {
|
|
118
104
|
cwd
|
|
119
105
|
});
|
|
120
|
-
|
|
121
106
|
if (flags.csv) {
|
|
122
107
|
const csv = generateCSV(allPackageChanges);
|
|
123
108
|
console.log(csv);
|
|
124
109
|
return;
|
|
125
110
|
}
|
|
126
|
-
|
|
127
111
|
if (flags.dryRun) {
|
|
128
112
|
console.log(JSON.stringify(allUpgradeEvents));
|
|
129
113
|
return;
|
|
130
114
|
}
|
|
131
|
-
|
|
132
115
|
if (allUpgradeEvents.length > 0) {
|
|
133
116
|
await sendAnalytics(allUpgradeEvents, {
|
|
134
117
|
dev: flags.dev,
|
|
@@ -139,7 +122,6 @@ export default async function populateProduct(flags) {
|
|
|
139
122
|
} else {
|
|
140
123
|
console.log(`Found no AK dependency changes since last run from ref "${sinceRef}"'`);
|
|
141
124
|
}
|
|
142
|
-
|
|
143
125
|
if (flags.statlas) {
|
|
144
126
|
// Upload latest commit to statlas
|
|
145
127
|
const currentCommit = await getHash('HEAD');
|
|
@@ -8,16 +8,14 @@ export const generateCSV = packageChanges => {
|
|
|
8
8
|
version
|
|
9
9
|
}]) => {
|
|
10
10
|
let depColumnIndex = csvData.findIndex(item => item[0] === name);
|
|
11
|
-
|
|
12
11
|
if (depColumnIndex === -1) {
|
|
13
12
|
depColumnIndex = csvData.push([name]) - 1;
|
|
14
|
-
}
|
|
15
|
-
|
|
13
|
+
}
|
|
16
14
|
|
|
15
|
+
// console.log(csvData)
|
|
17
16
|
csvData[depColumnIndex][currentRow] = version;
|
|
18
17
|
});
|
|
19
18
|
});
|
|
20
|
-
|
|
21
19
|
for (let i = 0; i < csvData.length; i++) {
|
|
22
20
|
for (let j = 0; j < csvData.length; j++) {
|
|
23
21
|
if (typeof csvData[i][j] !== 'string') {
|
|
@@ -25,23 +23,18 @@ export const generateCSV = packageChanges => {
|
|
|
25
23
|
csvData[i][j] = '';
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
|
-
|
|
29
26
|
if (i !== 0 && csvData[0].length < csvData[i].length) {}
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
const csvStrings = [];
|
|
33
29
|
csvData.forEach(column => {
|
|
34
30
|
if (!column) {
|
|
35
31
|
return;
|
|
36
32
|
}
|
|
37
|
-
|
|
38
33
|
for (let rowIndex = 0; rowIndex < csvData[0].length; rowIndex++) {
|
|
39
34
|
const rowItem = column[rowIndex] || '';
|
|
40
|
-
|
|
41
35
|
if (typeof csvStrings[rowIndex] !== 'string') {
|
|
42
36
|
csvStrings[rowIndex] = '';
|
|
43
37
|
}
|
|
44
|
-
|
|
45
38
|
csvStrings[rowIndex] += `"${rowItem}",`;
|
|
46
39
|
}
|
|
47
40
|
});
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
// @ts-ignore
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
/* eslint-disable-next-line import/no-unresolved */
|
|
6
|
-
|
|
7
6
|
import { analyticsClient } from '@atlassiansox/analytics-node-client';
|
|
8
7
|
import { version as packageVersion } from '../version.json';
|
|
9
|
-
|
|
10
8
|
function getUpgradeType(version, previousVersion) {
|
|
11
9
|
if (previousVersion == null && version != null) {
|
|
12
10
|
return 'add';
|
|
@@ -15,12 +13,10 @@ function getUpgradeType(version, previousVersion) {
|
|
|
15
13
|
} else if (previousVersion != null && version != null && previousVersion !== version) {
|
|
16
14
|
const coercedPrevious = semver.coerce(previousVersion);
|
|
17
15
|
const coercedNew = semver.coerce(version);
|
|
18
|
-
|
|
19
16
|
if (coercedNew == null) {
|
|
20
17
|
console.error(`Found invalid version "${version}", skipping`);
|
|
21
18
|
return null;
|
|
22
19
|
}
|
|
23
|
-
|
|
24
20
|
if (coercedPrevious != null && semver.lt(coercedNew, coercedPrevious)) {
|
|
25
21
|
return 'downgrade';
|
|
26
22
|
} else {
|
|
@@ -30,36 +26,27 @@ function getUpgradeType(version, previousVersion) {
|
|
|
30
26
|
return null;
|
|
31
27
|
}
|
|
32
28
|
}
|
|
33
|
-
|
|
34
29
|
function getUpgradeSubType(version, previousVersion) {
|
|
35
30
|
let upgradeSubType = null;
|
|
36
|
-
|
|
37
31
|
if (version == null || previousVersion == null) {
|
|
38
32
|
return upgradeSubType;
|
|
39
33
|
}
|
|
40
|
-
|
|
41
34
|
const parsedOld = semver.coerce(previousVersion);
|
|
42
35
|
const parsedNew = semver.coerce(version);
|
|
43
|
-
|
|
44
36
|
if (parsedOld && parsedNew) {
|
|
45
37
|
upgradeSubType = semver.diff(parsedOld.version, parsedNew.version);
|
|
46
38
|
}
|
|
47
|
-
|
|
48
39
|
return upgradeSubType;
|
|
49
40
|
}
|
|
50
|
-
|
|
51
41
|
export function createUpgradeEvent(name, version, previousVersion, date, optionalArgs = {}) {
|
|
52
42
|
if (Number.isNaN(Date.parse(date))) {
|
|
53
43
|
throw new Error(`Invalid date: '${date}'`);
|
|
54
44
|
}
|
|
55
|
-
|
|
56
45
|
const upgradeType = getUpgradeType(version, previousVersion);
|
|
57
|
-
|
|
58
46
|
if (!upgradeType) {
|
|
59
47
|
// Not an upgrade for this dependency, return null
|
|
60
48
|
return null;
|
|
61
49
|
}
|
|
62
|
-
|
|
63
50
|
const upgradeSubType = getUpgradeSubType(version, previousVersion);
|
|
64
51
|
const eventVersion = upgradeType !== 'remove' ? version : previousVersion;
|
|
65
52
|
const parsedVersion = semver.coerce(eventVersion);
|
|
@@ -88,7 +75,6 @@ export async function sendAnalytics(analyticsEvents, {
|
|
|
88
75
|
env: dev ? 'dev' : 'prod',
|
|
89
76
|
product: product
|
|
90
77
|
});
|
|
91
|
-
|
|
92
78
|
if (!skipPrompt) {
|
|
93
79
|
const answers = await inquirer.prompt([{
|
|
94
80
|
type: 'confirm',
|
|
@@ -96,13 +82,11 @@ export async function sendAnalytics(analyticsEvents, {
|
|
|
96
82
|
message: `Are you sure you want to send ${eventsToSend.length} historical analytics events to '${analyticsEnv}' env for product '${product}?`,
|
|
97
83
|
default: false
|
|
98
84
|
}]);
|
|
99
|
-
|
|
100
85
|
if (!answers.continue) {
|
|
101
86
|
console.log('Aborting');
|
|
102
87
|
process.exit(0);
|
|
103
88
|
}
|
|
104
89
|
}
|
|
105
|
-
|
|
106
90
|
try {
|
|
107
91
|
const promises = await Promise.all(eventsToSend.map(event => {
|
|
108
92
|
return client.sendTrackEvent({
|
|
@@ -112,7 +96,8 @@ export async function sendAnalytics(analyticsEvents, {
|
|
|
112
96
|
source: '@atlaskit/dependency-version-analytics',
|
|
113
97
|
action: 'upgraded',
|
|
114
98
|
actionSubject: 'akDependency',
|
|
115
|
-
attributes: {
|
|
99
|
+
attributes: {
|
|
100
|
+
...event
|
|
116
101
|
},
|
|
117
102
|
origin: 'console',
|
|
118
103
|
platform: 'bot'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { exec } from 'child_process';
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
2
|
|
|
3
|
+
// Lock files tend to be huge
|
|
3
4
|
const FiveMBBuffer = 1024 * 5000;
|
|
4
5
|
export default function getFileHistoryFromGit(fileName) {
|
|
5
6
|
return new Promise((resolve, reject) => {
|
|
@@ -9,11 +10,9 @@ export default function getFileHistoryFromGit(fileName) {
|
|
|
9
10
|
if (error) {
|
|
10
11
|
reject(error);
|
|
11
12
|
}
|
|
12
|
-
|
|
13
13
|
if (stderr) {
|
|
14
14
|
reject(stderr);
|
|
15
15
|
}
|
|
16
|
-
|
|
17
16
|
resolve(stdout);
|
|
18
17
|
});
|
|
19
18
|
});
|
|
@@ -5,19 +5,15 @@ export default function getPackageVersionHistory(packageName) {
|
|
|
5
5
|
if (error) {
|
|
6
6
|
reject(error);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
8
|
if (stderr) {
|
|
10
9
|
reject(stderr);
|
|
11
10
|
}
|
|
12
|
-
|
|
13
11
|
let json;
|
|
14
|
-
|
|
15
12
|
try {
|
|
16
13
|
json = JSON.parse(stdout).data;
|
|
17
14
|
} catch (e) {
|
|
18
15
|
reject(`Error parsing json output: ${e}`);
|
|
19
16
|
}
|
|
20
|
-
|
|
21
17
|
resolve(json);
|
|
22
18
|
});
|
|
23
19
|
});
|