@teambit/builder 0.0.565 → 0.0.569

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.
@@ -0,0 +1,52 @@
1
+ export type ArtifactDefinition = {
2
+ /**
3
+ * name of the artifact.
4
+ * e.g. a project might utilize two different artifacts for the same typescript compiler, one
5
+ * that generates ES5 files and another for ES6, this prop helps to distinguish between the two.
6
+ */
7
+ name: string;
8
+
9
+ /**
10
+ * aspect id that created the artifact. sometimes it's not the same as the task.id.
11
+ * e.g. teambit.compilation/compiler executes teambit.typescript/typescript code that generates dists artifacts
12
+ * the generatedBy in this case is the teambit.typescript/typescript while the task.id is
13
+ * teambit.compilation/compiler
14
+ */
15
+ generatedBy?: string;
16
+
17
+ /**
18
+ * description of the artifact.
19
+ */
20
+ description?: string;
21
+
22
+ /**
23
+ * glob patterns of files to include upon artifact creation. minimatch is used to match the patterns.
24
+ * e.g. ['*.ts', '!foo.ts'] matches all ts files but ignores foo.ts.
25
+ */
26
+ globPatterns: string[];
27
+
28
+ /**
29
+ * define the root directory for reading the artifacts from the capsule file system.
30
+ * the rootDir must be unique per artifacts, otherwise we risk overriding data between artifacts.
31
+ */
32
+ rootDir?: string;
33
+
34
+ /**
35
+ * adds a directory prefix for all artifact files.
36
+ */
37
+ dirPrefix?: string;
38
+
39
+ /**
40
+ * determine the context of the artifact.
41
+ * default artifact context is `component`.
42
+ * "env" is useful when the same file is generated for all components, for example, "preview"
43
+ * task may create the same webpack file for all components of that env.
44
+ */
45
+ context?: 'component' | 'env';
46
+
47
+ /**
48
+ * storage resolver. can be used to replace where artifacts are stored.
49
+ * default resolver persists artifacts on scope. (not recommended for large files!)
50
+ */
51
+ storageResolver?: string;
52
+ };
@@ -0,0 +1,116 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ import { ScopeMain } from '@teambit/scope';
4
+ import { ComponentID } from '@teambit/component-id';
5
+ import pMapSeries from 'p-map-series';
6
+ import minimatch from 'minimatch';
7
+ import { ArtifactFiles, ArtifactObject } from '@teambit/legacy/dist/consumer/component/sources/artifact-files';
8
+ import { BuilderMain } from '../builder.main.runtime';
9
+ import { ArtifactsOpts } from './artifacts.cmd';
10
+
11
+ export type ExtractorResult = {
12
+ id: ComponentID;
13
+ artifacts: ExtractorArtifactResult[];
14
+ };
15
+
16
+ export type ExtractorArtifactResult = {
17
+ aspectId: string;
18
+ taskName: string;
19
+ files: string[];
20
+ };
21
+
22
+ export type ExtractorResultGrouped = {
23
+ id: ComponentID;
24
+ artifacts: { [aspectId: string]: ExtractorArtifactResult[] };
25
+ };
26
+
27
+ type ArtifactObjectsPerId = {
28
+ id: ComponentID;
29
+ artifacts: ArtifactObject[];
30
+ };
31
+
32
+ export class ArtifactExtractor {
33
+ constructor(
34
+ private scope: ScopeMain,
35
+ private builder: BuilderMain,
36
+ private patterns: string[],
37
+ private options: ArtifactsOpts
38
+ ) {}
39
+
40
+ async list(): Promise<ExtractorResult[]> {
41
+ const components = await this.scope.byPattern(this.patterns);
42
+ const artifactObjectsPerId: ArtifactObjectsPerId[] = components.map((component) => {
43
+ return {
44
+ id: component.id,
45
+ artifacts: this.builder.getArtifacts(component) || [],
46
+ };
47
+ });
48
+ this.filterByOptions(artifactObjectsPerId);
49
+ await this.saveFilesInFileSystemIfAsked(artifactObjectsPerId);
50
+
51
+ return this.artifactsObjectsToExtractorResults(artifactObjectsPerId);
52
+ }
53
+
54
+ groupResultsByAspect(extractorResult: ExtractorResult[]) {
55
+ return extractorResult.map((result) => {
56
+ const artifacts = result.artifacts.reduce((acc, current) => {
57
+ (acc[current.aspectId] ||= []).push(current);
58
+ return acc;
59
+ }, {});
60
+ return { id: result.id, artifacts };
61
+ });
62
+ }
63
+
64
+ private async saveFilesInFileSystemIfAsked(artifactObjectsPerId: ArtifactObjectsPerId[]) {
65
+ const outDir = this.options.outDir;
66
+ if (!outDir) {
67
+ return;
68
+ }
69
+ // @todo: optimize this to first import all missing hashes.
70
+ await pMapSeries(artifactObjectsPerId, async ({ id, artifacts }) => {
71
+ const vinyls = await Promise.all(
72
+ artifacts.map((artifactObject) =>
73
+ artifactObject.files.getVinylsAndImportIfMissing(id.scope as string, this.scope.legacyScope)
74
+ )
75
+ );
76
+ const flattenedVinyls = vinyls.flat();
77
+ const compPath = path.join(outDir, id.toStringWithoutVersion());
78
+ await Promise.all(flattenedVinyls.map((vinyl) => fs.outputFile(path.join(compPath, vinyl.path), vinyl.contents)));
79
+ });
80
+ }
81
+
82
+ private artifactsObjectsToExtractorResults(artifactObjectsPerId: ArtifactObjectsPerId[]): ExtractorResult[] {
83
+ return artifactObjectsPerId.map(({ id, artifacts }) => {
84
+ const results: ExtractorArtifactResult[] = artifacts.map((artifact) => {
85
+ return {
86
+ aspectId: artifact.task.id,
87
+ taskName: artifact.task.name || artifact.generatedBy,
88
+ files: artifact.files.refs.map((ref) => ref.relativePath),
89
+ };
90
+ });
91
+ return {
92
+ id,
93
+ artifacts: results,
94
+ };
95
+ });
96
+ }
97
+
98
+ private filterByOptions(artifactObjectsPerId: ArtifactObjectsPerId[]) {
99
+ const { aspect, task, files } = this.options;
100
+ artifactObjectsPerId.forEach((item) => {
101
+ item.artifacts = item.artifacts.filter((artifact) => {
102
+ if (aspect && aspect !== artifact.task.id) return false;
103
+ if (task && task !== artifact.task.name) return false;
104
+ return true;
105
+ });
106
+ if (files) {
107
+ item.artifacts.forEach((artifact) => {
108
+ const refs = artifact.files.refs.filter((ref) => minimatch(ref.relativePath, files));
109
+ artifact.files = new ArtifactFiles([], [], refs);
110
+ });
111
+ // remove artifacts with no files
112
+ item.artifacts = item.artifacts.filter((artifact) => artifact.files.refs.length);
113
+ }
114
+ });
115
+ }
116
+ }
@@ -0,0 +1,119 @@
1
+ import { join } from 'path';
2
+ import globby from 'globby';
3
+ import { flatten } from 'lodash';
4
+ import { ArtifactFiles } from '@teambit/legacy/dist/consumer/component/sources/artifact-files';
5
+ import { Component, ComponentMap } from '@teambit/component';
6
+ import type { StorageResolverSlot } from '../builder.main.runtime';
7
+ import { ArtifactDefinition } from './artifact-definition';
8
+ import { DefaultResolver, StorageResolver } from '../storage';
9
+ import { ArtifactList } from './artifact-list';
10
+ import { Artifact } from './artifact';
11
+ import type { BuildContext, BuildTask } from '../build-task';
12
+ import { CapsuleNotFound } from '../exceptions';
13
+
14
+ export const DEFAULT_CONTEXT = 'component';
15
+
16
+ export type ArtifactMap = ComponentMap<ArtifactList>;
17
+
18
+ export class ArtifactFactory {
19
+ constructor(private storageResolverSlot: StorageResolverSlot) {}
20
+
21
+ private getResolver(resolvers: StorageResolver[], name?: string) {
22
+ const defaultResolver = new DefaultResolver();
23
+ const userResolver = resolvers.find((resolver) => resolver.name === name);
24
+ return userResolver || defaultResolver;
25
+ }
26
+
27
+ private resolvePaths(root: string, def: ArtifactDefinition): string[] {
28
+ const patternsFlattened = flatten(def.globPatterns);
29
+ const paths = globby.sync(patternsFlattened, { cwd: root });
30
+ return paths;
31
+ }
32
+
33
+ private getArtifactContextPath(context: BuildContext, component: Component, def: ArtifactDefinition) {
34
+ const artifactContext = this.getArtifactContext(def);
35
+ if (artifactContext === 'component') {
36
+ const capsulePath = context.capsuleNetwork.graphCapsules.getCapsule(component.id)?.path;
37
+ if (!capsulePath) throw new CapsuleNotFound(component.id);
38
+ return capsulePath;
39
+ }
40
+
41
+ return context.capsuleNetwork.capsulesRootDir;
42
+ }
43
+
44
+ private getArtifactContext(def: ArtifactDefinition) {
45
+ return def.context || DEFAULT_CONTEXT;
46
+ }
47
+
48
+ createFromComponent(
49
+ context: BuildContext,
50
+ component: Component,
51
+ def: ArtifactDefinition,
52
+ task: BuildTask
53
+ ): Artifact | undefined {
54
+ const storageResolver = this.getStorageResolver(def);
55
+ const rootDir = this.getArtifactContextPath(context, component, def);
56
+ const paths = this.resolvePaths(this.getRootDir(rootDir, def), def);
57
+ if (!paths || !paths.length) {
58
+ return undefined;
59
+ }
60
+ return new Artifact(def, storageResolver, new ArtifactFiles(paths), rootDir, task);
61
+ }
62
+
63
+ private getStorageResolver(def: ArtifactDefinition) {
64
+ const storageResolvers = this.storageResolverSlot.values();
65
+ return this.getResolver(storageResolvers, def.storageResolver);
66
+ }
67
+
68
+ private toComponentMap(context: BuildContext, artifactMap: [string, Artifact][]) {
69
+ return ComponentMap.as<ArtifactList>(context.components, (component) => {
70
+ const id = component.id.toString();
71
+ const artifacts = artifactMap.filter(([targetId]) => targetId === id).map(([, artifact]) => artifact);
72
+
73
+ return new ArtifactList(artifacts);
74
+ });
75
+ }
76
+
77
+ private getRootDir(rootDir: string, def: ArtifactDefinition) {
78
+ if (!def.rootDir) return rootDir;
79
+ return join(rootDir, def.rootDir);
80
+ }
81
+
82
+ /**
83
+ * generate artifacts from a build context according to the spec defined in the artifact definitions.
84
+ */
85
+ generate(context: BuildContext, defs: ArtifactDefinition[], task: BuildTask): ComponentMap<ArtifactList> {
86
+ const tupleArr: [string, Artifact][] = [];
87
+
88
+ defs.forEach((def) => {
89
+ const artifactContext = this.getArtifactContext(def);
90
+ if (artifactContext === 'env') {
91
+ const capsuleDir = context.capsuleNetwork.capsulesRootDir;
92
+ const rootDir = this.getRootDir(capsuleDir, def);
93
+ const paths = this.resolvePaths(rootDir, def);
94
+ if (paths && paths.length) {
95
+ const artifact = new Artifact(
96
+ def,
97
+ this.getStorageResolver(def),
98
+ new ArtifactFiles(this.resolvePaths(rootDir, def)),
99
+ rootDir,
100
+ task
101
+ );
102
+
103
+ return context.components.forEach((component) => {
104
+ tupleArr.push([component.id.toString(), artifact]);
105
+ });
106
+ }
107
+ }
108
+
109
+ return context.components.forEach((component) => {
110
+ const artifact = this.createFromComponent(context, component, def, task);
111
+ if (artifact) {
112
+ tupleArr.push([component.id.toString(), artifact]);
113
+ }
114
+ });
115
+ });
116
+
117
+ return this.toComponentMap(context, tupleArr);
118
+ }
119
+ }
@@ -0,0 +1,64 @@
1
+ import { Component } from '@teambit/component';
2
+ import type { ArtifactObject } from '@teambit/legacy/dist/consumer/component/sources/artifact-files';
3
+ import type { Artifact } from './artifact';
4
+
5
+ export type ResolverMap = { [key: string]: Artifact[] };
6
+
7
+ export class ArtifactList {
8
+ constructor(readonly artifacts: Artifact[]) {}
9
+
10
+ /**
11
+ * return an array of artifact objects.
12
+ */
13
+ toArray() {
14
+ return this.artifacts;
15
+ }
16
+
17
+ /**
18
+ * group artifacts by the storage resolver.
19
+ */
20
+ groupByResolver(): ResolverMap {
21
+ const resolverMap: ResolverMap = {};
22
+ this.artifacts.forEach((artifact) => {
23
+ const storageResolver = artifact.storageResolver;
24
+ const resolverArray = resolverMap[storageResolver.name];
25
+ if (!resolverArray) {
26
+ resolverMap[storageResolver.name] = [artifact];
27
+ return;
28
+ }
29
+ if (resolverArray.length) {
30
+ resolverMap[storageResolver.name].push(artifact);
31
+ }
32
+ });
33
+
34
+ return resolverMap;
35
+ }
36
+
37
+ toObject(): ArtifactObject[] {
38
+ return this.artifacts.map((artifact) => artifact.toObject());
39
+ }
40
+
41
+ groupByTaskId() {
42
+ return this.artifacts.reduce((acc: { [key: string]: Artifact }, artifact) => {
43
+ const taskId = artifact.task.aspectId;
44
+ acc[taskId] = artifact;
45
+ return acc;
46
+ }, {});
47
+ }
48
+
49
+ /**
50
+ * store all artifacts using the configured storage resolvers.
51
+ */
52
+ async store(component: Component) {
53
+ const byResolvers = this.groupByResolver();
54
+ const promises = Object.keys(byResolvers).map(async (key) => {
55
+ const artifacts = byResolvers[key];
56
+ if (!artifacts.length) return;
57
+ const storageResolver = artifacts[0].storageResolver;
58
+ const artifactList = new ArtifactList(artifacts);
59
+ await storageResolver.store(component, artifactList);
60
+ });
61
+
62
+ return Promise.all(promises);
63
+ }
64
+ }
@@ -0,0 +1,81 @@
1
+ import type { ArtifactFiles, ArtifactObject } from '@teambit/legacy/dist/consumer/component/sources/artifact-files';
2
+ import type { BuildTask } from '../build-task';
3
+ import type { StorageResolver } from '../storage';
4
+ import type { ArtifactDefinition } from './artifact-definition';
5
+
6
+ export class Artifact {
7
+ constructor(
8
+ /**
9
+ * definition of the artifact.
10
+ */
11
+ readonly def: ArtifactDefinition,
12
+
13
+ /**
14
+ * storage resolver. can be used to replace where artifacts are stored.
15
+ */
16
+ readonly storageResolver: StorageResolver,
17
+
18
+ readonly files: ArtifactFiles,
19
+
20
+ /**
21
+ * join this with `this.paths` to get the absolute paths
22
+ */
23
+ readonly rootDir: string,
24
+
25
+ /**
26
+ * the declaring task.
27
+ * todo: change this to taskDescriptor that has only the metadata of the task, so it could be
28
+ * saved into the model.
29
+ */
30
+ readonly task: BuildTask,
31
+
32
+ /**
33
+ * timestamp of the artifact creation.
34
+ */
35
+ readonly timestamp: number = Date.now()
36
+ ) {}
37
+
38
+ get storage() {
39
+ return this.storageResolver;
40
+ }
41
+
42
+ /**
43
+ * name of the artifact.
44
+ */
45
+ get name(): string {
46
+ return this.def.name;
47
+ }
48
+
49
+ /**
50
+ * description of the artifact.
51
+ */
52
+ get description() {
53
+ return this.def.description;
54
+ }
55
+
56
+ /**
57
+ * aspect id (string) that generated the artifact
58
+ */
59
+ get generatedBy(): string {
60
+ return this.def.generatedBy || this.task.aspectId;
61
+ }
62
+
63
+ /**
64
+ * archive all artifact files into a tar.
65
+ */
66
+ tar() {}
67
+
68
+ toObject(): ArtifactObject {
69
+ return {
70
+ name: this.name,
71
+ description: this.description,
72
+ generatedBy: this.generatedBy,
73
+ storage: this.storageResolver.name,
74
+ task: {
75
+ id: this.task.aspectId,
76
+ name: this.task.name,
77
+ },
78
+ files: this.files,
79
+ };
80
+ }
81
+ }
@@ -0,0 +1,68 @@
1
+ import { Command, CommandOptions } from '@teambit/cli';
2
+ import chalk from 'chalk';
3
+ import { ScopeMain } from '@teambit/scope';
4
+ import { BuilderMain } from '../builder.main.runtime';
5
+ import { ArtifactExtractor, ExtractorArtifactResult, ExtractorResultGrouped } from './artifact-extractor';
6
+
7
+ const INDENT_TITLE = ' '.repeat(2);
8
+ const INDENT_SUB_TITLE = ' '.repeat(4);
9
+ const INDENT_FILES = ' '.repeat(6);
10
+
11
+ export type ArtifactsOpts = {
12
+ aspect?: string;
13
+ task?: string;
14
+ files?: string;
15
+ outDir?: string;
16
+ };
17
+
18
+ export class ArtifactsCmd implements Command {
19
+ name = 'artifacts <pattern...>';
20
+ shortDescription = 'EXPERIMENTAL. list and download components artifacts';
21
+ description = `EXPERIMENTAL. list and download components artifacts.
22
+ artifacts are created on isolated capsules during tag or snap commands.
23
+ example of artifacts are dists files generated by a compiler, a JUnit.xml file generated by a tester
24
+ and a package.tgz file generated by pkg aspect.
25
+ `;
26
+ alias = '';
27
+ group = 'development';
28
+ options = [
29
+ ['', 'aspect <aspect-id>', 'show/download only artifacts generated by this aspect-id'],
30
+ ['', 'task <task-id>', 'show/download only artifacts generated by this task-id'],
31
+ [
32
+ '',
33
+ 'files <glob>',
34
+ 'show/download only artifacts matching the given files or the glob pattern (wrap glob patterns in quotes)',
35
+ ],
36
+ ['', 'out-dir <string>', 'download the files to the specified dir'],
37
+ ] as CommandOptions;
38
+
39
+ constructor(private builder: BuilderMain, private scope: ScopeMain) {}
40
+
41
+ async report([userPattern]: [string[]], artifactsOpts: ArtifactsOpts): Promise<string> {
42
+ const artifactExtractor = new ArtifactExtractor(this.scope, this.builder, userPattern, artifactsOpts);
43
+ const list = await artifactExtractor.list();
44
+ const grouped = artifactExtractor.groupResultsByAspect(list);
45
+ const outputArtifacts = (aspectId: string, artifactData: ExtractorArtifactResult[]) => {
46
+ const title = chalk.green(aspectId);
47
+ const artifactDataStr = artifactData
48
+ .map((artifact) => {
49
+ const subTitle = chalk.white(artifact.taskName);
50
+ const files = artifact.files.map((f) => INDENT_FILES + chalk.dim(f)).join('\n');
51
+ return `${INDENT_SUB_TITLE}${subTitle}\n${files}`;
52
+ })
53
+ .join('\n');
54
+ return `${INDENT_TITLE}${title}\n${artifactDataStr}`;
55
+ };
56
+ const outputResult = (result: ExtractorResultGrouped) => {
57
+ const idStr = chalk.cyan(result.id.toString());
58
+ const artifacts = Object.keys(result.artifacts)
59
+ .map((aspectId) => outputArtifacts(aspectId, result.artifacts[aspectId]))
60
+ .join('\n\n');
61
+ return `${idStr}\n${artifacts}`;
62
+ };
63
+ const footer = artifactsOpts.outDir
64
+ ? chalk.green('\n\nThe above files were saved successfully to the file system')
65
+ : '';
66
+ return grouped.map(outputResult).join('\n\n') + footer;
67
+ }
68
+ }
@@ -0,0 +1,12 @@
1
+ import type { AspectDescriptor } from '@teambit/aspect-loader';
2
+ import { AbstractVinyl } from '@teambit/legacy/dist/consumer/component/sources';
3
+
4
+ export class ExtensionArtifact {
5
+ constructor(readonly files: AbstractVinyl[], readonly extensionDescriptor: AspectDescriptor) {}
6
+
7
+ toObject() {
8
+ return {
9
+ extensionDescriptor: this.extensionDescriptor,
10
+ };
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ export { ArtifactDefinition } from './artifact-definition';
2
+ export { ExtensionArtifact } from './extension-artifact';
3
+ export { Artifact } from './artifact';
4
+ export { ArtifactList } from './artifact-list';
5
+ export { ArtifactFactory, ArtifactMap } from './artifact-factory';
@@ -0,0 +1,163 @@
1
+ import { EnvDefinition, EnvService, ExecutionContext } from '@teambit/envs';
2
+ import React from 'react';
3
+ import { ScopeMain } from '@teambit/scope';
4
+ import { Text, Newline } from 'ink';
5
+ import { Logger } from '@teambit/logger';
6
+ import { IsolatorMain } from '@teambit/isolator';
7
+ import { Component } from '@teambit/component';
8
+ import { BuildPipe } from './build-pipe';
9
+ import { TaskResultsList } from './task-results-list';
10
+ import { TaskSlot } from './builder.main.runtime';
11
+ import { BuildContext, BuildTaskHelper } from './build-task';
12
+ import { ArtifactFactory } from './artifact';
13
+ import { calculatePipelineOrder } from './build-pipeline-order';
14
+ import { BuilderAspect } from './builder.aspect';
15
+
16
+ export type BuildServiceResults = {
17
+ id: string;
18
+ buildResults: TaskResultsList;
19
+ components: Component[];
20
+ errors?: [];
21
+ };
22
+
23
+ export type BuilderServiceOptions = { seedersOnly?: boolean; tasks?: string[]; skipTests?: boolean };
24
+
25
+ export type EnvsBuildContext = { [envId: string]: BuildContext };
26
+
27
+ const pipeNames = {
28
+ getBuildPipe: 'build',
29
+ getTagPipe: 'tag',
30
+ getSnapPipe: 'snap',
31
+ };
32
+
33
+ type PipeName = 'build' | 'tag' | 'snap';
34
+
35
+ export type BuilderDescriptor = Array<{ pipeName: PipeName; tasks: string[] }>;
36
+
37
+ type PipeFunctionNames = keyof typeof pipeNames;
38
+ export class BuilderService implements EnvService<BuildServiceResults, BuilderDescriptor> {
39
+ name = 'builder';
40
+
41
+ constructor(
42
+ /**
43
+ * isolator extension.
44
+ */
45
+ private isolator: IsolatorMain,
46
+
47
+ /**
48
+ * logger extension.
49
+ */
50
+ private logger: Logger,
51
+
52
+ /**
53
+ * task slot (e.g tasks registered by other extensions.).
54
+ */
55
+ private taskSlot: TaskSlot,
56
+
57
+ /**
58
+ * a method with such name should be implemented on the env in order to run the pipe tasks.
59
+ */
60
+ private pipeNameOnEnv: PipeFunctionNames,
61
+
62
+ /**
63
+ * pipe name to display on the console during the execution
64
+ */
65
+ private displayPipeName: string,
66
+ private artifactFactory: ArtifactFactory,
67
+ private scope: ScopeMain
68
+ ) {}
69
+
70
+ /**
71
+ * runs all tasks for all envs
72
+ */
73
+ async runOnce(envsExecutionContext: ExecutionContext[], options: BuilderServiceOptions): Promise<TaskResultsList> {
74
+ const envs = envsExecutionContext.map((executionContext) => executionContext.envDefinition);
75
+ const tasksQueue = calculatePipelineOrder(
76
+ this.taskSlot,
77
+ envs,
78
+ this.pipeNameOnEnv,
79
+ options.tasks,
80
+ options.skipTests
81
+ );
82
+ tasksQueue.validate();
83
+ this.logger.info(`going to run tasks in the following order:\n${tasksQueue.toString()}`);
84
+ const title = `running ${this.displayPipeName} pipe for ${envs.length} environments, total ${tasksQueue.length} tasks`;
85
+ const longProcessLogger = this.logger.createLongProcessLogger(title);
86
+ this.logger.consoleTitle(title);
87
+ const envsBuildContext: EnvsBuildContext = {};
88
+ await Promise.all(
89
+ envsExecutionContext.map(async (executionContext) => {
90
+ const componentIds = executionContext.components.map((component) => component.id);
91
+ const capsuleNetwork = await this.isolator.isolateComponents(componentIds, {
92
+ getExistingAsIs: true,
93
+ seedersOnly: options.seedersOnly,
94
+ });
95
+ this.logger.console(
96
+ `generated graph for env "${executionContext.id}", seeders total: ${capsuleNetwork.seedersCapsules.length}, graph total: ${capsuleNetwork.graphCapsules.length}`
97
+ );
98
+ const buildContext = Object.assign(executionContext, {
99
+ capsuleNetwork,
100
+ previousTasksResults: [],
101
+ });
102
+ envsBuildContext[executionContext.id] = buildContext;
103
+ })
104
+ );
105
+ const buildPipe = BuildPipe.from(tasksQueue, envsBuildContext, this.logger, this.artifactFactory);
106
+ const buildResults = await buildPipe.execute();
107
+ longProcessLogger.end();
108
+ buildResults.hasErrors() ? this.logger.consoleFailure() : this.logger.consoleSuccess();
109
+
110
+ return buildResults;
111
+ }
112
+
113
+ render(env: EnvDefinition) {
114
+ const pipes = this.getDescriptor(env);
115
+
116
+ return (
117
+ <Text key={BuilderAspect.id}>{pipes.map(({ pipeName, tasks }) => this.renderOnePipe(pipeName, tasks))}</Text>
118
+ );
119
+ }
120
+
121
+ private renderOnePipe(pipeName, tasks) {
122
+ if (!tasks || !tasks.length) return null;
123
+ return (
124
+ <Text key={pipeName}>
125
+ <Text underline color="green">
126
+ {pipeName} pipe
127
+ </Text>
128
+ <Newline />
129
+ <Text color="cyan">total {tasks.length} tasks are configured to be executed in the following order</Text>
130
+ <Newline />
131
+ {tasks.map((task, index) => (
132
+ <Text key={index}>
133
+ <Text>
134
+ {index + 1}. {task}
135
+ </Text>
136
+ <Newline />
137
+ </Text>
138
+ ))}
139
+ <Newline />
140
+ </Text>
141
+ );
142
+ }
143
+
144
+ getDescriptor(env: EnvDefinition) {
145
+ // @ts-ignore
146
+ const tasks = Object.keys(pipeNames).map((pipeFuncName: PipeFunctionNames) => {
147
+ const tasksQueue = this.getTasksNamesByPipeFunc(env, pipeFuncName);
148
+ return { pipeName: pipeNames[pipeFuncName], tasks: tasksQueue };
149
+ });
150
+ return tasks as BuilderDescriptor;
151
+ }
152
+
153
+ private getTasksNamesByPipeFunc(env: EnvDefinition, pipeFuncName: PipeFunctionNames): string[] {
154
+ const tasksQueue = calculatePipelineOrder(this.taskSlot, [env], pipeFuncName).map(({ task }) =>
155
+ BuildTaskHelper.serializeId(task)
156
+ );
157
+ return tasksQueue;
158
+ }
159
+
160
+ getCurrentPipeTasks(env: EnvDefinition) {
161
+ return this.getTasksNamesByPipeFunc(env, this.pipeNameOnEnv);
162
+ }
163
+ }
@@ -0,0 +1,7 @@
1
+ import { Component } from '@teambit/component';
2
+
3
+ export class ArtifactStorageError extends Error {
4
+ constructor(private originalError: Error, private component: Component) {
5
+ super(`failed to store artifacts for component ${component.id.toString()}`);
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ import { ComponentID } from '@teambit/component';
2
+
3
+ export class CapsuleNotFound extends Error {
4
+ constructor(private id: ComponentID) {
5
+ super(`unable to find capsule for component ${id.toString()}`);
6
+ }
7
+ }
@@ -0,0 +1,3 @@
1
+ export { InvalidTask } from './invalid-task';
2
+ export { CapsuleNotFound } from './capsule-not-found';
3
+ export { ArtifactStorageError } from './artifact-storage-error';
@@ -0,0 +1,7 @@
1
+ import { BitError } from '@teambit/bit-error';
2
+
3
+ export class InvalidTask extends BitError {
4
+ constructor(readonly taskAspectId: string, reason: string) {
5
+ super(`task of ${taskAspectId} is invalid, ${reason}`);
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teambit/builder",
3
- "version": "0.0.565",
3
+ "version": "0.0.569",
4
4
  "homepage": "https://bit.dev/teambit/pipelines/builder",
5
5
  "main": "dist/index.js",
6
6
  "componentId": {
7
7
  "scope": "teambit.pipelines",
8
8
  "name": "builder",
9
- "version": "0.0.565"
9
+ "version": "0.0.569"
10
10
  },
11
11
  "dependencies": {
12
12
  "p-map-series": "2.1.0",
@@ -22,18 +22,18 @@
22
22
  "globby": "11.0.1",
23
23
  "@babel/runtime": "7.12.18",
24
24
  "core-js": "^3.0.0",
25
- "@teambit/component": "0.0.565",
26
- "@teambit/envs": "0.0.565",
27
- "@teambit/logger": "0.0.477",
28
- "@teambit/tester": "0.0.565",
29
- "@teambit/isolator": "0.0.565",
30
- "@teambit/cli": "0.0.392",
31
- "@teambit/workspace": "0.0.565",
32
- "@teambit/aspect-loader": "0.0.565",
33
- "@teambit/graphql": "0.0.565",
34
- "@teambit/scope": "0.0.565",
35
- "@teambit/bit-error": "0.0.378",
36
- "@teambit/component-id": "0.0.382"
25
+ "@teambit/component": "0.0.569",
26
+ "@teambit/envs": "0.0.569",
27
+ "@teambit/logger": "0.0.481",
28
+ "@teambit/tester": "0.0.569",
29
+ "@teambit/isolator": "0.0.569",
30
+ "@teambit/cli": "0.0.395",
31
+ "@teambit/workspace": "0.0.569",
32
+ "@teambit/aspect-loader": "0.0.569",
33
+ "@teambit/graphql": "0.0.569",
34
+ "@teambit/scope": "0.0.569",
35
+ "@teambit/bit-error": "0.0.381",
36
+ "@teambit/component-id": "0.0.385"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/lodash": "4.14.165",
@@ -45,10 +45,10 @@
45
45
  "@types/jest": "^26.0.0",
46
46
  "@types/react-dom": "^17.0.5",
47
47
  "@types/node": "12.20.4",
48
- "@teambit/pipelines.aspect-docs.builder": "0.0.111"
48
+ "@teambit/pipelines.aspect-docs.builder": "0.0.115"
49
49
  },
50
50
  "peerDependencies": {
51
- "@teambit/legacy": "1.0.178",
51
+ "@teambit/legacy": "1.0.181",
52
52
  "react-dom": "^16.8.0 || ^17.0.0",
53
53
  "react": "^16.8.0 || ^17.0.0"
54
54
  },
@@ -76,27 +76,12 @@
76
76
  "react": "-"
77
77
  },
78
78
  "peerDependencies": {
79
- "@teambit/legacy": "1.0.178",
79
+ "@teambit/legacy": "1.0.181",
80
80
  "react-dom": "^16.8.0 || ^17.0.0",
81
81
  "react": "^16.8.0 || ^17.0.0"
82
82
  }
83
83
  }
84
84
  },
85
- "files": [
86
- "dist",
87
- "!dist/tsconfig.tsbuildinfo",
88
- "**/*.md",
89
- "**/*.mdx",
90
- "**/*.js",
91
- "**/*.json",
92
- "**/*.sass",
93
- "**/*.scss",
94
- "**/*.less",
95
- "**/*.css",
96
- "**/*.css",
97
- "**/*.jpeg",
98
- "**/*.gif"
99
- ],
100
85
  "private": false,
101
86
  "engines": {
102
87
  "node": ">=12.22.0"
@@ -0,0 +1 @@
1
+ export { PipelineResults } from './pipeline-results';
@@ -0,0 +1 @@
1
+ export class PipelineResults {}
@@ -0,0 +1,13 @@
1
+ import { Component } from '@teambit/component';
2
+ import { StorageResolver } from './storage-resolver';
3
+ import type { ArtifactList } from '../artifact';
4
+
5
+ export class DefaultResolver implements StorageResolver {
6
+ name = 'default';
7
+
8
+ async store(component: Component, artifactList: ArtifactList) {
9
+ artifactList.artifacts.forEach((artifact) => {
10
+ artifact.files.populateVinylsFromPaths(artifact.rootDir);
11
+ });
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ export { StorageResolver } from './storage-resolver';
2
+ export { DefaultResolver } from './default-resolver';
@@ -0,0 +1,40 @@
1
+ // import { S3 } from 'aws-sdk';
2
+ // import { Component, ComponentID } from '@teambit/component';
3
+ // import { StorageResolver } from './storage-resolver';
4
+ // import type { ArtifactList } from '../artifact';
5
+
6
+ // export class S3Resolver implements StorageResolver {
7
+ // name = 's3';
8
+ // // todo artifact map
9
+ // async store(component: Component, artifacts: ArtifactList) {
10
+ // // https://staoge.com/{compId}/aspectId/${path}
11
+ // const artifactsByTaskId = artifacts.groupByTaskId();
12
+ // const files = Object.entries(artifactsByTaskId).map(([taskId, artifact]) => {
13
+ // return artifact.paths.map((path) => this.buildKey(component.id, taskId, path));
14
+ // });
15
+ // // files file to upload
16
+ // }
17
+
18
+ // private buildKey(id: ComponentID, taskId: string, path: string) {
19
+ // return id.fullName;
20
+ // }
21
+
22
+ // private upload(key: string, body: string) {
23
+ // const s3 = this.getS3Client();
24
+ // s3.upload({
25
+ // Bucket: 'storage',
26
+ // Key: key,
27
+ // Body: body,
28
+ // });
29
+ // }
30
+
31
+ // private getS3Client() {
32
+ // //TODO: need to pass bithub token
33
+ // const s3 = new S3({
34
+ // accessKeyId: 'bit',
35
+ // secretAccessKey: process.env.BIT_DEV_TOKEN,
36
+ // endpoint: 'http://bit.test:5003',
37
+ // });
38
+ // return s3;
39
+ // }
40
+ // }
@@ -0,0 +1,18 @@
1
+ import { Component } from '@teambit/component';
2
+ import { ArtifactList } from '../artifact';
3
+
4
+ export type StoreResult = {
5
+ [path: string]: string;
6
+ };
7
+
8
+ export interface StorageResolver {
9
+ /**
10
+ * name of the storage resolver.
11
+ */
12
+ name: string;
13
+
14
+ /**
15
+ * store artifacts in the storage.
16
+ */
17
+ store(component: Component, artifacts: ArtifactList): Promise<void>;
18
+ }
@@ -0,0 +1,29 @@
1
+ declare module '*.png' {
2
+ const value: any;
3
+ export = value;
4
+ }
5
+ declare module '*.svg' {
6
+ import type { FunctionComponent, SVGProps } from 'react';
7
+
8
+ export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
9
+ const src: string;
10
+ export default src;
11
+ }
12
+
13
+ // @TODO Gilad
14
+ declare module '*.jpg' {
15
+ const value: any;
16
+ export = value;
17
+ }
18
+ declare module '*.jpeg' {
19
+ const value: any;
20
+ export = value;
21
+ }
22
+ declare module '*.gif' {
23
+ const value: any;
24
+ export = value;
25
+ }
26
+ declare module '*.bmp' {
27
+ const value: any;
28
+ export = value;
29
+ }
@@ -0,0 +1,42 @@
1
+ declare module '*.module.css' {
2
+ const classes: { readonly [key: string]: string };
3
+ export default classes;
4
+ }
5
+ declare module '*.module.scss' {
6
+ const classes: { readonly [key: string]: string };
7
+ export default classes;
8
+ }
9
+ declare module '*.module.sass' {
10
+ const classes: { readonly [key: string]: string };
11
+ export default classes;
12
+ }
13
+
14
+ declare module '*.module.less' {
15
+ const classes: { readonly [key: string]: string };
16
+ export default classes;
17
+ }
18
+
19
+ declare module '*.less' {
20
+ const classes: { readonly [key: string]: string };
21
+ export default classes;
22
+ }
23
+
24
+ declare module '*.css' {
25
+ const classes: { readonly [key: string]: string };
26
+ export default classes;
27
+ }
28
+
29
+ declare module '*.sass' {
30
+ const classes: { readonly [key: string]: string };
31
+ export default classes;
32
+ }
33
+
34
+ declare module '*.scss' {
35
+ const classes: { readonly [key: string]: string };
36
+ export default classes;
37
+ }
38
+
39
+ declare module '*.mdx' {
40
+ const component: any;
41
+ export default component;
42
+ }