@teambit/snapping 1.0.107 → 1.0.108

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.
Files changed (39) hide show
  1. package/components-have-issues.ts +39 -0
  2. package/dist/flattened-edges.d.ts +1 -1
  3. package/dist/generate-comp-from-scope.d.ts +1 -1
  4. package/dist/snap-cmd.js +1 -1
  5. package/dist/snap-cmd.js.map +1 -1
  6. package/dist/snap-distance-cmd.d.ts +15 -0
  7. package/dist/snap-distance-cmd.js +44 -0
  8. package/dist/snap-distance-cmd.js.map +1 -0
  9. package/dist/snap-from-scope.cmd.d.ts +3 -3
  10. package/dist/snap-from-scope.cmd.js +1 -2
  11. package/dist/snap-from-scope.cmd.js.map +1 -1
  12. package/dist/snapping.main.runtime.d.ts +7 -7
  13. package/dist/snapping.main.runtime.js +21 -22
  14. package/dist/snapping.main.runtime.js.map +1 -1
  15. package/dist/snapping.spec.js +2 -2
  16. package/dist/snapping.spec.js.map +1 -1
  17. package/dist/tag-cmd.js +1 -1
  18. package/dist/tag-cmd.js.map +1 -1
  19. package/dist/tag-from-scope.cmd.d.ts +1 -1
  20. package/dist/tag-model-component.d.ts +4 -4
  21. package/dist/tag-model-component.js +11 -14
  22. package/dist/tag-model-component.js.map +1 -1
  23. package/flattened-edges.ts +189 -0
  24. package/generate-comp-from-scope.ts +124 -0
  25. package/index.ts +8 -0
  26. package/package.json +28 -37
  27. package/reset-cmd.ts +70 -0
  28. package/snap-cmd.ts +195 -0
  29. package/snap-distance-cmd.ts +29 -0
  30. package/snap-from-scope.cmd.ts +155 -0
  31. package/snapping.aspect.ts +5 -0
  32. package/snapping.main.runtime.ts +1331 -0
  33. package/snapping.spec.ts +52 -0
  34. package/tag-cmd.ts +360 -0
  35. package/tag-from-scope.cmd.ts +258 -0
  36. package/tag-model-component.ts +641 -0
  37. package/tsconfig.json +16 -21
  38. package/types/asset.d.ts +15 -3
  39. /package/dist/{preview-1703590665075.js → preview-1703647408454.js} +0 -0
@@ -0,0 +1,641 @@
1
+ import mapSeries from 'p-map-series';
2
+ import fetch from 'node-fetch';
3
+ import R from 'ramda';
4
+ import { isEmpty } from 'lodash';
5
+ import { ReleaseType } from 'semver';
6
+ import { v4 } from 'uuid';
7
+ import { BitError } from '@teambit/bit-error';
8
+ import * as globalConfig from '@teambit/legacy/dist/api/consumer/lib/global-config';
9
+ import { Scope } from '@teambit/legacy/dist/scope';
10
+ import { ComponentID, ComponentIdList } from '@teambit/component-id';
11
+ import {
12
+ BuildStatus,
13
+ CFG_USER_EMAIL_KEY,
14
+ CFG_USER_NAME_KEY,
15
+ CFG_USER_TOKEN_KEY,
16
+ getCloudDomain,
17
+ Extensions,
18
+ } from '@teambit/legacy/dist/constants';
19
+ import { CURRENT_SCHEMA } from '@teambit/legacy/dist/consumer/component/component-schema';
20
+ import { linkToNodeModulesByComponents } from '@teambit/workspace.modules.node-modules-linker';
21
+ import ConsumerComponent from '@teambit/legacy/dist/consumer/component/consumer-component';
22
+ import Consumer from '@teambit/legacy/dist/consumer/consumer';
23
+ import { NewerVersionFound } from '@teambit/legacy/dist/consumer/exceptions';
24
+ import { Component } from '@teambit/component';
25
+ import deleteComponentsFiles from '@teambit/legacy/dist/consumer/component-ops/delete-component-files';
26
+ import logger from '@teambit/legacy/dist/logger/logger';
27
+ import { sha1 } from '@teambit/legacy/dist/utils';
28
+ import { AutoTagResult, getAutoTagInfo } from '@teambit/legacy/dist/scope/component-ops/auto-tag';
29
+ import { getValidVersionOrReleaseType } from '@teambit/legacy/dist/utils/semver-helper';
30
+ import { BuilderMain, OnTagOpts } from '@teambit/builder';
31
+ import { Log } from '@teambit/legacy/dist/scope/models/version';
32
+ import {
33
+ MessagePerComponent,
34
+ MessagePerComponentFetcher,
35
+ } from '@teambit/legacy/dist/scope/component-ops/message-per-component';
36
+ import { ModelComponent } from '@teambit/legacy/dist/scope/models';
37
+ import { DependencyResolverMain } from '@teambit/dependency-resolver';
38
+ import { ScopeMain, StagedConfig } from '@teambit/scope';
39
+ import { Workspace } from '@teambit/workspace';
40
+ import { SnappingMain, TagDataPerComp } from './snapping.main.runtime';
41
+
42
+ export type onTagIdTransformer = (id: ComponentID) => ComponentID | null;
43
+
44
+ export type BasicTagSnapParams = {
45
+ message: string;
46
+ skipTests?: boolean;
47
+ build?: boolean;
48
+ ignoreBuildErrors?: boolean;
49
+ rebuildDepsGraph?: boolean;
50
+ };
51
+
52
+ export type BasicTagParams = BasicTagSnapParams & {
53
+ ignoreNewestVersion?: boolean;
54
+ skipAutoTag?: boolean;
55
+ soft?: boolean;
56
+ persist: boolean;
57
+ disableTagAndSnapPipelines?: boolean;
58
+ preReleaseId?: string;
59
+ editor?: string;
60
+ unmodified?: boolean;
61
+ };
62
+
63
+ function updateDependenciesVersions(
64
+ componentsToTag: ConsumerComponent[],
65
+ dependencyResolver: DependencyResolverMain
66
+ ): void {
67
+ const getNewDependencyVersion = (id: ComponentID): ComponentID | null => {
68
+ const foundDependency = componentsToTag.find((component) => component.id.isEqualWithoutVersion(id));
69
+ return foundDependency ? id.changeVersion(foundDependency.version) : null;
70
+ };
71
+ const changeExtensionsVersion = (component: ConsumerComponent): void => {
72
+ component.extensions.forEach((ext) => {
73
+ if (ext.extensionId) {
74
+ const newDepId = getNewDependencyVersion(ext.extensionId);
75
+ if (newDepId) ext.extensionId = newDepId;
76
+ }
77
+ });
78
+ };
79
+
80
+ componentsToTag.forEach((oneComponentToTag) => {
81
+ oneComponentToTag.getAllDependencies().forEach((dependency) => {
82
+ const newDepId = getNewDependencyVersion(dependency.id);
83
+ if (newDepId) dependency.id = newDepId;
84
+ });
85
+ changeExtensionsVersion(oneComponentToTag);
86
+ // @ts-ignore
87
+ oneComponentToTag = dependencyResolver.updateDepsOnLegacyTag(oneComponentToTag, getNewDependencyVersion.bind(this));
88
+ });
89
+ }
90
+
91
+ function setHashes(componentsToTag: ConsumerComponent[]): void {
92
+ componentsToTag.forEach((componentToTag) => {
93
+ componentToTag.setNewVersion(sha1(v4()));
94
+ });
95
+ }
96
+
97
+ async function setFutureVersions(
98
+ componentsToTag: ConsumerComponent[],
99
+ scope: Scope,
100
+ releaseType: ReleaseType | undefined,
101
+ exactVersion: string | null | undefined,
102
+ persist: boolean,
103
+ autoTagIds: ComponentIdList,
104
+ ids: ComponentIdList,
105
+ incrementBy?: number,
106
+ preReleaseId?: string,
107
+ soft?: boolean,
108
+ tagDataPerComp?: TagDataPerComp[]
109
+ ): Promise<void> {
110
+ const isPreReleaseLike = releaseType
111
+ ? ['prerelease', 'premajor', 'preminor', 'prepatch'].includes(releaseType)
112
+ : false;
113
+ await Promise.all(
114
+ componentsToTag.map(async (componentToTag) => {
115
+ const isAutoTag = autoTagIds.hasWithoutVersion(componentToTag.id);
116
+ const modelComponent = await scope.sources.findOrAddComponent(componentToTag);
117
+ const nextVersion = componentToTag.componentMap?.nextVersion?.version;
118
+ const getNewVersion = (): string => {
119
+ if (tagDataPerComp) {
120
+ const tagData = tagDataPerComp.find((t) => t.componentId.isEqualWithoutVersion(componentToTag.id));
121
+ if (!tagData) throw new Error(`tag-data is missing for ${componentToTag.id.toStringWithoutVersion()}`);
122
+ if (!tagData.versionToTag)
123
+ throw new Error(`tag-data.TagResults is missing for ${componentToTag.id.toStringWithoutVersion()}`);
124
+ const exactVersionOrReleaseType = getValidVersionOrReleaseType(tagData.versionToTag);
125
+ return modelComponent.getVersionToAdd(
126
+ exactVersionOrReleaseType.releaseType,
127
+ exactVersionOrReleaseType.exactVersion,
128
+ incrementBy,
129
+ tagData.prereleaseId
130
+ );
131
+ }
132
+ if (nextVersion && persist) {
133
+ const exactVersionOrReleaseType = getValidVersionOrReleaseType(nextVersion);
134
+ return modelComponent.getVersionToAdd(
135
+ exactVersionOrReleaseType.releaseType,
136
+ exactVersionOrReleaseType.exactVersion,
137
+ undefined,
138
+ componentToTag.componentMap?.nextVersion?.preRelease
139
+ );
140
+ }
141
+ if (isAutoTag) {
142
+ // auto-tag always bumped as patch unless it's pre-release
143
+ if (isPreReleaseLike) {
144
+ return soft
145
+ ? (releaseType as string)
146
+ : modelComponent.getVersionToAdd(releaseType, exactVersion, incrementBy, preReleaseId);
147
+ }
148
+ return soft ? 'patch' : modelComponent.getVersionToAdd('patch', undefined, incrementBy, preReleaseId);
149
+ }
150
+ const versionByEnteredId = getVersionByEnteredId(ids, componentToTag, modelComponent);
151
+ return soft
152
+ ? versionByEnteredId || exactVersion || (releaseType as string)
153
+ : versionByEnteredId || modelComponent.getVersionToAdd(releaseType, exactVersion, incrementBy, preReleaseId);
154
+ };
155
+ const newVersion = getNewVersion();
156
+ componentToTag.setNewVersion(newVersion);
157
+ })
158
+ );
159
+ }
160
+
161
+ function getVersionByEnteredId(
162
+ enteredIds: ComponentIdList,
163
+ component: ConsumerComponent,
164
+ modelComponent: ModelComponent
165
+ ): string | undefined {
166
+ const enteredId = enteredIds.searchWithoutVersion(component.id);
167
+ if (enteredId && enteredId.hasVersion()) {
168
+ const exactVersionOrReleaseType = getValidVersionOrReleaseType(enteredId.version as string);
169
+ return modelComponent.getVersionToAdd(
170
+ exactVersionOrReleaseType.releaseType,
171
+ exactVersionOrReleaseType.exactVersion
172
+ );
173
+ }
174
+ return undefined;
175
+ }
176
+
177
+ export async function tagModelComponent({
178
+ workspace,
179
+ scope,
180
+ snapping,
181
+ builder,
182
+ consumerComponents,
183
+ ids,
184
+ tagDataPerComp,
185
+ populateArtifactsFrom,
186
+ message,
187
+ editor,
188
+ exactVersion,
189
+ releaseType,
190
+ preReleaseId,
191
+ ignoreNewestVersion = false,
192
+ skipTests = false,
193
+ skipAutoTag,
194
+ soft,
195
+ build,
196
+ persist,
197
+ isSnap = false,
198
+ disableTagAndSnapPipelines,
199
+ ignoreBuildErrors,
200
+ rebuildDepsGraph,
201
+ incrementBy,
202
+ packageManagerConfigRootDir,
203
+ dependencyResolver,
204
+ copyLogFromPreviousSnap = false,
205
+ exitOnFirstFailedTask = false,
206
+ }: {
207
+ workspace?: Workspace;
208
+ scope: ScopeMain;
209
+ snapping: SnappingMain;
210
+ builder: BuilderMain;
211
+ consumerComponents: ConsumerComponent[];
212
+ ids: ComponentIdList;
213
+ tagDataPerComp?: TagDataPerComp[];
214
+ populateArtifactsFrom?: ComponentID[];
215
+ copyLogFromPreviousSnap?: boolean;
216
+ exactVersion?: string | null | undefined;
217
+ releaseType?: ReleaseType;
218
+ incrementBy?: number;
219
+ isSnap?: boolean;
220
+ packageManagerConfigRootDir?: string;
221
+ dependencyResolver: DependencyResolverMain;
222
+ exitOnFirstFailedTask?: boolean;
223
+ } & BasicTagParams): Promise<{
224
+ taggedComponents: ConsumerComponent[];
225
+ autoTaggedResults: AutoTagResult[];
226
+ publishedPackages: string[];
227
+ stagedConfig?: StagedConfig;
228
+ removedComponents?: ComponentIdList;
229
+ }> {
230
+ const consumer = workspace?.consumer;
231
+ const legacyScope = scope.legacyScope;
232
+ const consumerComponentsIdsMap = {};
233
+ // Concat and unique all the dependencies from all the components so we will not import
234
+ // the same dependency more then once, it's mainly for performance purpose
235
+ consumerComponents.forEach((consumerComponent) => {
236
+ const componentIdString = consumerComponent.id.toString();
237
+ // Store it in a map so we can take it easily from the sorted array which contain only the id
238
+ consumerComponentsIdsMap[componentIdString] = consumerComponent;
239
+ });
240
+ const componentsToTag: ConsumerComponent[] = R.values(consumerComponentsIdsMap); // consumerComponents unique
241
+ const idsToTag = ComponentIdList.fromArray(componentsToTag.map((c) => c.id));
242
+ // ids without versions are new. it's impossible that tagged (and not-modified) components has
243
+ // them as dependencies.
244
+ const idsToTriggerAutoTag = idsToTag.filter((id) => id.hasVersion());
245
+ const autoTagData =
246
+ skipAutoTag || !consumer ? [] : await getAutoTagInfo(consumer, ComponentIdList.fromArray(idsToTriggerAutoTag));
247
+ const autoTagComponents = autoTagData.map((autoTagItem) => autoTagItem.component);
248
+ const autoTagComponentsFiltered = autoTagComponents.filter((c) => !idsToTag.has(c.id));
249
+ const autoTagIds = ComponentIdList.fromArray(autoTagComponentsFiltered.map((autoTag) => autoTag.id));
250
+ const allComponentsToTag = [...componentsToTag, ...autoTagComponentsFiltered];
251
+
252
+ const messagesFromEditorFetcher = new MessagePerComponentFetcher(idsToTag, autoTagIds);
253
+ const getMessagePerId = async () => {
254
+ if (editor) return messagesFromEditorFetcher.getMessagesFromEditor(legacyScope.tmp, editor);
255
+ if (tagDataPerComp) return tagDataPerComp.map((t) => ({ id: t.componentId, msg: t.message || message }));
256
+ return [];
257
+ };
258
+ const messagePerId = await getMessagePerId();
259
+
260
+ // check for each one of the components whether it is using an old version
261
+ if (!ignoreNewestVersion && !isSnap) {
262
+ const newestVersionsP = allComponentsToTag.map(async (component) => {
263
+ if (component.componentFromModel) {
264
+ // otherwise it's a new component, so this check is irrelevant
265
+ const modelComponent = await legacyScope.getModelComponentIfExist(component.id);
266
+ if (!modelComponent) throw new BitError(`component ${component.id} was not found in the model`);
267
+ if (!modelComponent.listVersions().length) return null; // no versions yet, no issues.
268
+ const latest = modelComponent.getHeadRegardlessOfLaneAsTagOrHash();
269
+ if (latest !== component.version) {
270
+ return {
271
+ componentId: component.id.toStringWithoutVersion(),
272
+ currentVersion: component.version,
273
+ latestVersion: latest,
274
+ };
275
+ }
276
+ }
277
+ return null;
278
+ });
279
+ const newestVersions = await Promise.all(newestVersionsP);
280
+ const newestVersionsWithoutEmpty = newestVersions.filter((newest) => newest);
281
+ if (!isEmpty(newestVersionsWithoutEmpty)) {
282
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
283
+ throw new NewerVersionFound(newestVersionsWithoutEmpty);
284
+ }
285
+ }
286
+
287
+ logger.debugAndAddBreadCrumb('tag-model-components', 'sequentially persist all components');
288
+ setCurrentSchema(allComponentsToTag);
289
+ // go through all components and find the future versions for them
290
+ isSnap
291
+ ? setHashes(allComponentsToTag)
292
+ : await setFutureVersions(
293
+ allComponentsToTag,
294
+ legacyScope,
295
+ releaseType,
296
+ exactVersion,
297
+ persist,
298
+ autoTagIds,
299
+ ids,
300
+ incrementBy,
301
+ preReleaseId,
302
+ soft,
303
+ tagDataPerComp
304
+ );
305
+ // go through all dependencies and update their versions
306
+ updateDependenciesVersions(allComponentsToTag, dependencyResolver);
307
+
308
+ await addLogToComponents(componentsToTag, autoTagComponents, persist, message, messagePerId, copyLogFromPreviousSnap);
309
+ // don't move it down. otherwise, it'll be empty and we don't know which components were during merge.
310
+ // (it's being deleted in snapping.main.runtime - `_addCompToObjects` method)
311
+ const unmergedComps = workspace ? await workspace.listComponentsDuringMerge() : [];
312
+ let stagedConfig;
313
+ if (soft) {
314
+ if (!consumer) throw new Error(`unable to soft-tag without consumer`);
315
+ consumer.updateNextVersionOnBitmap(allComponentsToTag, preReleaseId);
316
+ } else {
317
+ await snapping._addFlattenedDependenciesToComponents(allComponentsToTag, rebuildDepsGraph);
318
+ await snapping.throwForDepsFromAnotherLane(allComponentsToTag);
319
+ if (!build) emptyBuilderData(allComponentsToTag);
320
+ addBuildStatus(allComponentsToTag, BuildStatus.Pending);
321
+ await addComponentsToScope(legacyScope, snapping, allComponentsToTag, Boolean(build), consumer, tagDataPerComp);
322
+
323
+ if (workspace) {
324
+ const modelComponents = await Promise.all(
325
+ allComponentsToTag.map((c) => {
326
+ return c.modelComponent || legacyScope.getModelComponent(c.id);
327
+ })
328
+ );
329
+ stagedConfig = await updateComponentsVersions(workspace, modelComponents);
330
+ }
331
+ }
332
+
333
+ const publishedPackages: string[] = [];
334
+ let harmonyComps: Component[] = [];
335
+ if (build) {
336
+ const onTagOpts: OnTagOpts = {
337
+ disableTagAndSnapPipelines,
338
+ throwOnError: true,
339
+ forceDeploy: ignoreBuildErrors,
340
+ isSnap,
341
+ populateArtifactsFrom,
342
+ };
343
+ const seedersOnly = !workspace; // if tag from scope, build only the given components
344
+ const isolateOptions = { packageManagerConfigRootDir, seedersOnly };
345
+ const builderOptions = { exitOnFirstFailedTask, skipTests };
346
+
347
+ const componentsToBuild = allComponentsToTag.filter((c) => !c.isRemoved());
348
+ if (componentsToBuild.length) {
349
+ await scope.reloadAspectsWithNewVersion(componentsToBuild);
350
+ harmonyComps = await (workspace || scope).getManyByLegacy(componentsToBuild);
351
+ const { builderDataMap } = await builder.tagListener(harmonyComps, onTagOpts, isolateOptions, builderOptions);
352
+ const buildResult = scope.builderDataMapToLegacyOnTagResults(builderDataMap);
353
+
354
+ snapping._updateComponentsByTagResult(componentsToBuild, buildResult);
355
+ publishedPackages.push(...snapping._getPublishedPackages(componentsToBuild));
356
+ addBuildStatus(componentsToBuild, BuildStatus.Succeed);
357
+ await mapSeries(componentsToBuild, (consumerComponent) => snapping._enrichComp(consumerComponent));
358
+ }
359
+ }
360
+
361
+ let removedComponents: ComponentIdList | undefined;
362
+ if (!soft) {
363
+ removedComponents = await removeDeletedComponentsFromBitmap(allComponentsToTag, workspace);
364
+ await legacyScope.objects.persist();
365
+ await removeMergeConfigFromComponents(unmergedComps, allComponentsToTag, workspace);
366
+ if (workspace) {
367
+ await linkToNodeModulesByComponents(
368
+ harmonyComps.length ? harmonyComps : await workspace.scope.getManyByLegacy(allComponentsToTag),
369
+ workspace
370
+ );
371
+ }
372
+ }
373
+
374
+ return {
375
+ taggedComponents: componentsToTag,
376
+ autoTaggedResults: autoTagData,
377
+ publishedPackages,
378
+ stagedConfig,
379
+ removedComponents,
380
+ };
381
+ }
382
+
383
+ async function removeDeletedComponentsFromBitmap(
384
+ comps: ConsumerComponent[],
385
+ workspace?: Workspace
386
+ ): Promise<ComponentIdList | undefined> {
387
+ if (!workspace) {
388
+ return undefined;
389
+ }
390
+ const removedComps = comps.filter((comp) => comp.isRemoved());
391
+ if (!removedComps.length) return undefined;
392
+ const compBitIdsToRemove = ComponentIdList.fromArray(removedComps.map((c) => c.id));
393
+ await deleteComponentsFiles(workspace.consumer, compBitIdsToRemove);
394
+ await workspace.consumer.cleanFromBitMap(compBitIdsToRemove);
395
+
396
+ return compBitIdsToRemove;
397
+ }
398
+
399
+ async function removeMergeConfigFromComponents(
400
+ unmergedComps: ComponentID[],
401
+ components: ConsumerComponent[],
402
+ workspace?: Workspace
403
+ ) {
404
+ if (!workspace || !unmergedComps.length) {
405
+ return;
406
+ }
407
+ const configMergeFile = workspace.getConflictMergeFile();
408
+
409
+ unmergedComps.forEach((compId) => {
410
+ const isNowSnapped = components.find((c) => c.id.isEqualWithoutVersion(compId));
411
+ if (isNowSnapped) {
412
+ configMergeFile.removeConflict(compId.toStringWithoutVersion());
413
+ }
414
+ });
415
+ const currentlyUnmerged = workspace ? await workspace.listComponentsDuringMerge() : [];
416
+ if (configMergeFile.hasConflict() && currentlyUnmerged.length) {
417
+ // it's possible that "workspace" section is still there. but if all "unmerged" are now merged,
418
+ // then, it's safe to delete the file.
419
+ await configMergeFile.write();
420
+ } else {
421
+ await configMergeFile.delete();
422
+ }
423
+ }
424
+
425
+ async function addComponentsToScope(
426
+ scope: Scope,
427
+ snapping: SnappingMain,
428
+ components: ConsumerComponent[],
429
+ shouldValidateVersion: boolean,
430
+ consumer?: Consumer,
431
+ tagDataPerComp?: TagDataPerComp[]
432
+ ) {
433
+ const lane = await scope.getCurrentLaneObject();
434
+ if (consumer) {
435
+ await mapSeries(components, async (component) => {
436
+ await snapping._addCompToObjects({
437
+ source: component,
438
+ consumer,
439
+ lane,
440
+ shouldValidateVersion,
441
+ });
442
+ });
443
+ } else {
444
+ await mapSeries(components, async (component) => {
445
+ const results = await snapping._addCompFromScopeToObjects(component, lane);
446
+
447
+ // in case "tagData.isNew", the version object has "parents" that should not be there.
448
+ // they got created as a workaround to generate a new component from the scope without having a workspace.
449
+ const tagData = tagDataPerComp?.find((t) => t.componentId.isEqualWithoutVersion(component.id));
450
+ if (tagData?.isNew) results.version.removeAllParents();
451
+ });
452
+ }
453
+ }
454
+
455
+ /**
456
+ * otherwise, tagging without build will have the old build data of the previous snap/tag.
457
+ * in case we currently build, it's ok to leave the data as is, because it'll be overridden anyway.
458
+ */
459
+ function emptyBuilderData(components: ConsumerComponent[]) {
460
+ components.forEach((component) => {
461
+ component.extensions = component.extensions.clone();
462
+ const existingBuilder = component.extensions.findCoreExtension(Extensions.builder);
463
+ if (existingBuilder) existingBuilder.data = {};
464
+ });
465
+ }
466
+
467
+ async function addLogToComponents(
468
+ components: ConsumerComponent[],
469
+ autoTagComps: ConsumerComponent[],
470
+ persist: boolean,
471
+ message: string,
472
+ messagePerComponent: MessagePerComponent[],
473
+ copyLogFromPreviousSnap = false
474
+ ) {
475
+ // @ts-ignore this happens when running `bit tag -m ""`.
476
+ if (message === true) {
477
+ message = '';
478
+ }
479
+ const basicLog = await getBasicLog();
480
+ const getLog = (component: ConsumerComponent): Log => {
481
+ const nextVersion = persist ? component.componentMap?.nextVersion : null;
482
+ const msgFromEditor = messagePerComponent.find((item) => item.id.isEqualWithoutVersion(component.id))?.msg;
483
+ if (copyLogFromPreviousSnap) {
484
+ const currentLog = component.log;
485
+ if (!currentLog) {
486
+ throw new Error(
487
+ `addLogToComponents is set copyLogFromPreviousSnap: true, but it is unable to find log in the previous snap`
488
+ );
489
+ }
490
+ currentLog.message = msgFromEditor || message || currentLog.message;
491
+ currentLog.date = basicLog.date;
492
+ return currentLog;
493
+ }
494
+
495
+ return {
496
+ username: nextVersion?.username || basicLog.username,
497
+ email: nextVersion?.email || basicLog.email,
498
+ message: nextVersion?.message || msgFromEditor || message,
499
+ date: basicLog.date,
500
+ };
501
+ };
502
+
503
+ components.forEach((component) => {
504
+ component.log = getLog(component);
505
+ });
506
+ autoTagComps.forEach((autoTagComp) => {
507
+ autoTagComp.log = getLog(autoTagComp);
508
+ const defaultMsg = 'bump dependencies versions';
509
+ if (message) {
510
+ autoTagComp.log.message += ` (${defaultMsg})`;
511
+ } else if (!autoTagComp.log.message) {
512
+ autoTagComp.log.message = defaultMsg;
513
+ }
514
+ });
515
+ }
516
+
517
+ export async function getBasicLog(): Promise<Log> {
518
+ const username = (await getBitCloudUsername()) || (await globalConfig.get(CFG_USER_NAME_KEY));
519
+ const email = await globalConfig.get(CFG_USER_EMAIL_KEY);
520
+ return {
521
+ username,
522
+ email,
523
+ message: '',
524
+ date: Date.now().toString(),
525
+ };
526
+ }
527
+
528
+ export async function getBitCloudUsername(): Promise<string | undefined> {
529
+ const token = await globalConfig.get(CFG_USER_TOKEN_KEY);
530
+ if (!token) return '';
531
+ try {
532
+ const res = await fetch(`https://api.${getCloudDomain()}/user`, {
533
+ headers: {
534
+ Authorization: `Bearer ${token}`,
535
+ 'Content-Type': 'application/json',
536
+ },
537
+ });
538
+ const object = await res.json();
539
+ const user = object.payload;
540
+ const username = user.username;
541
+ return username;
542
+ } catch (error) {
543
+ return undefined;
544
+ }
545
+ }
546
+
547
+ export type BitCloudUser = {
548
+ username?: string;
549
+ name?: string;
550
+ displayName?: string;
551
+ profileImage?: string;
552
+ };
553
+
554
+ export async function getBitCloudUser(): Promise<BitCloudUser | undefined> {
555
+ const token = await globalConfig.get(CFG_USER_TOKEN_KEY);
556
+ if (!token) return undefined;
557
+
558
+ try {
559
+ const res = await fetch(`https://api.${getCloudDomain()}/user`, {
560
+ headers: {
561
+ Authorization: `Bearer ${token}`,
562
+ 'Content-Type': 'application/json',
563
+ },
564
+ });
565
+ const object = await res.json();
566
+ const user = object.payload;
567
+
568
+ return {
569
+ ...user,
570
+ };
571
+ } catch (error) {
572
+ return undefined;
573
+ }
574
+ }
575
+
576
+ function setCurrentSchema(components: ConsumerComponent[]) {
577
+ components.forEach((component) => {
578
+ component.schema = CURRENT_SCHEMA;
579
+ });
580
+ }
581
+
582
+ function addBuildStatus(components: ConsumerComponent[], buildStatus: BuildStatus) {
583
+ components.forEach((component) => {
584
+ component.buildStatus = buildStatus;
585
+ });
586
+ }
587
+
588
+ export async function updateComponentsVersions(
589
+ workspace: Workspace,
590
+ components: Array<ModelComponent>,
591
+ isTag = true
592
+ ): Promise<StagedConfig> {
593
+ const consumer = workspace.consumer;
594
+ const currentLane = consumer.getCurrentLaneId();
595
+ const stagedConfig = await workspace.scope.getStagedConfig();
596
+ const isAvailableOnMain = async (
597
+ component: ModelComponent | ConsumerComponent,
598
+ id: ComponentID
599
+ ): Promise<boolean> => {
600
+ if (currentLane.isDefault()) {
601
+ return true;
602
+ }
603
+ if (!id.hasVersion()) {
604
+ // component was unsnapped on the current lane and is back to a new component
605
+ return true;
606
+ }
607
+ const modelComponent =
608
+ component instanceof ModelComponent ? component : await consumer.scope.getModelComponent(component.id);
609
+ return modelComponent.hasHead();
610
+ };
611
+
612
+ const updateVersions = async (modelComponent: ModelComponent) => {
613
+ const id: ComponentID = modelComponent.toBitIdWithLatestVersionAllowNull();
614
+ consumer.bitMap.updateComponentId(id, undefined, undefined, true);
615
+ const availableOnMain = await isAvailableOnMain(modelComponent, id);
616
+ if (!availableOnMain) {
617
+ consumer.bitMap.setOnLanesOnly(id, true);
618
+ }
619
+ const componentMap = consumer.bitMap.getComponent(id);
620
+ const compId = await workspace.resolveComponentId(id);
621
+ // it can be either a tag/snap or reset.
622
+ if (isTag) {
623
+ const config = componentMap.config;
624
+ stagedConfig.addComponentConfig(compId, config);
625
+ consumer.bitMap.removeConfig(id);
626
+ const hash = modelComponent.getRef(id.version as string);
627
+ if (!hash) throw new Error(`updateComponentsVersions: unable to find a hash for ${id.toString()}`);
628
+ workspace.scope.legacyScope.stagedSnaps.addSnap(hash?.toString());
629
+ } else if (!componentMap.config) {
630
+ componentMap.config = stagedConfig.getConfigPerId(compId);
631
+ }
632
+ componentMap.clearNextVersion();
633
+ };
634
+ // important! DO NOT use Promise.all here! otherwise, you're gonna enter into a whole world of pain.
635
+ // imagine tagging comp1 with auto-tagged comp2, comp1 package.json is written while comp2 is
636
+ // trying to get the dependencies of comp1 using its package.json.
637
+ await mapSeries(components, updateVersions);
638
+ await workspace.scope.legacyScope.stagedSnaps.write();
639
+
640
+ return stagedConfig;
641
+ }
package/tsconfig.json CHANGED
@@ -1,38 +1,33 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "lib": [
4
- "es2019",
5
- "DOM",
6
- "ES6",
7
- "DOM.Iterable",
8
- "ScriptHost"
4
+ "esnext",
5
+ "dom",
6
+ "dom.Iterable"
9
7
  ],
10
- "target": "es2015",
11
- "module": "CommonJS",
12
- "jsx": "react",
13
- "allowJs": true,
14
- "composite": true,
8
+ "target": "es2020",
9
+ "module": "es2020",
10
+ "jsx": "react-jsx",
15
11
  "declaration": true,
16
12
  "sourceMap": true,
17
- "skipLibCheck": true,
18
13
  "experimentalDecorators": true,
19
- "outDir": "dist",
14
+ "skipLibCheck": true,
20
15
  "moduleResolution": "node",
21
16
  "esModuleInterop": true,
22
- "rootDir": ".",
23
17
  "resolveJsonModule": true,
24
- "emitDeclarationOnly": true,
25
- "emitDecoratorMetadata": true,
26
- "allowSyntheticDefaultImports": true,
27
- "strictPropertyInitialization": false,
28
- "strict": true,
29
- "noImplicitAny": false,
30
- "preserveConstEnums": true
18
+ "allowJs": true,
19
+ "outDir": "dist",
20
+ "emitDeclarationOnly": true
31
21
  },
32
22
  "exclude": [
23
+ "artifacts",
24
+ "public",
33
25
  "dist",
26
+ "node_modules",
27
+ "package.json",
34
28
  "esm.mjs",
35
- "package.json"
29
+ "**/*.cjs",
30
+ "./dist"
36
31
  ],
37
32
  "include": [
38
33
  "**/*",