@generacy-ai/generacy-plugin-cloud-build 0.0.0-preview-20260304013206

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 (83) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +228 -0
  3. package/dist/auth/auth-provider.d.ts +26 -0
  4. package/dist/auth/auth-provider.d.ts.map +1 -0
  5. package/dist/auth/auth-provider.js +72 -0
  6. package/dist/auth/auth-provider.js.map +1 -0
  7. package/dist/auth/types.d.ts +26 -0
  8. package/dist/auth/types.d.ts.map +1 -0
  9. package/dist/auth/types.js +5 -0
  10. package/dist/auth/types.js.map +1 -0
  11. package/dist/client.d.ts +43 -0
  12. package/dist/client.d.ts.map +1 -0
  13. package/dist/client.js +87 -0
  14. package/dist/client.js.map +1 -0
  15. package/dist/config/schema.d.ts +73 -0
  16. package/dist/config/schema.d.ts.map +1 -0
  17. package/dist/config/schema.js +32 -0
  18. package/dist/config/schema.js.map +1 -0
  19. package/dist/config/types.d.ts +30 -0
  20. package/dist/config/types.d.ts.map +1 -0
  21. package/dist/config/types.js +11 -0
  22. package/dist/config/types.js.map +1 -0
  23. package/dist/errors.d.ts +75 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +144 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/index.d.ts +25 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +22 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/operations/artifacts.d.ts +35 -0
  32. package/dist/operations/artifacts.d.ts.map +1 -0
  33. package/dist/operations/artifacts.js +168 -0
  34. package/dist/operations/artifacts.js.map +1 -0
  35. package/dist/operations/builds.d.ts +91 -0
  36. package/dist/operations/builds.d.ts.map +1 -0
  37. package/dist/operations/builds.js +397 -0
  38. package/dist/operations/builds.js.map +1 -0
  39. package/dist/operations/logs.d.ts +56 -0
  40. package/dist/operations/logs.d.ts.map +1 -0
  41. package/dist/operations/logs.js +207 -0
  42. package/dist/operations/logs.js.map +1 -0
  43. package/dist/operations/triggers.d.ts +76 -0
  44. package/dist/operations/triggers.d.ts.map +1 -0
  45. package/dist/operations/triggers.js +308 -0
  46. package/dist/operations/triggers.js.map +1 -0
  47. package/dist/plugin.d.ts +156 -0
  48. package/dist/plugin.d.ts.map +1 -0
  49. package/dist/plugin.js +270 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/dist/streaming/log-stream.d.ts +34 -0
  52. package/dist/streaming/log-stream.d.ts.map +1 -0
  53. package/dist/streaming/log-stream.js +89 -0
  54. package/dist/streaming/log-stream.js.map +1 -0
  55. package/dist/streaming/types.d.ts +27 -0
  56. package/dist/streaming/types.d.ts.map +1 -0
  57. package/dist/streaming/types.js +6 -0
  58. package/dist/streaming/types.js.map +1 -0
  59. package/dist/types/artifacts.d.ts +46 -0
  60. package/dist/types/artifacts.d.ts.map +1 -0
  61. package/dist/types/artifacts.js +6 -0
  62. package/dist/types/artifacts.js.map +1 -0
  63. package/dist/types/builds.d.ts +134 -0
  64. package/dist/types/builds.d.ts.map +1 -0
  65. package/dist/types/builds.js +5 -0
  66. package/dist/types/builds.js.map +1 -0
  67. package/dist/types/logs.d.ts +18 -0
  68. package/dist/types/logs.d.ts.map +1 -0
  69. package/dist/types/logs.js +5 -0
  70. package/dist/types/logs.js.map +1 -0
  71. package/dist/types/triggers.d.ts +71 -0
  72. package/dist/types/triggers.d.ts.map +1 -0
  73. package/dist/types/triggers.js +5 -0
  74. package/dist/types/triggers.js.map +1 -0
  75. package/dist/utils/retry.d.ts +41 -0
  76. package/dist/utils/retry.d.ts.map +1 -0
  77. package/dist/utils/retry.js +107 -0
  78. package/dist/utils/retry.js.map +1 -0
  79. package/dist/utils/validation.d.ts +53 -0
  80. package/dist/utils/validation.d.ts.map +1 -0
  81. package/dist/utils/validation.js +75 -0
  82. package/dist/utils/validation.js.map +1 -0
  83. package/package.json +58 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Artifact operations for the Cloud Build plugin.
3
+ *
4
+ * Handles:
5
+ * - Listing build artifacts
6
+ * - Downloading artifacts (Buffer mode for ≤100MB)
7
+ * - Streaming artifacts (ReadableStream for large files)
8
+ */
9
+ import { MAX_ARTIFACT_SIZE_BYTES } from '../types/artifacts.js';
10
+ import { NotFoundError, ValidationError, CloudBuildError } from '../errors.js';
11
+ import { mapApiError } from '../client.js';
12
+ export class ArtifactOperations {
13
+ cloudBuildClient;
14
+ storage;
15
+ config;
16
+ logger;
17
+ constructor(cloudBuildClient, storage, config, logger) {
18
+ this.cloudBuildClient = cloudBuildClient;
19
+ this.storage = storage;
20
+ this.config = config;
21
+ this.logger = logger;
22
+ }
23
+ /**
24
+ * List artifacts for a build.
25
+ */
26
+ async listArtifacts(buildId) {
27
+ this.logger.debug({ buildId }, 'Listing artifacts');
28
+ try {
29
+ // Get the build to find artifact information
30
+ const [build] = await this.cloudBuildClient.getBuild({
31
+ projectId: this.config.projectId,
32
+ id: buildId,
33
+ });
34
+ if (!build) {
35
+ throw new NotFoundError('Build', buildId);
36
+ }
37
+ // Get artifacts from build results and config
38
+ const artifacts = [];
39
+ // Check for object artifacts
40
+ const artifactConfig = build.artifacts?.objects;
41
+ if (artifactConfig?.location && artifactConfig?.paths) {
42
+ const bucketMatch = artifactConfig.location.match(/^gs:\/\/([^/]+)(?:\/(.*))?$/);
43
+ if (bucketMatch) {
44
+ const bucketName = bucketMatch[1];
45
+ const prefix = bucketMatch[2] || '';
46
+ if (bucketName) {
47
+ const bucket = this.storage.bucket(bucketName);
48
+ for (const pathPattern of artifactConfig.paths) {
49
+ const fullPrefix = prefix ? `${prefix}/${pathPattern.replace(/\*\*?/g, '')}` : pathPattern.replace(/\*\*?/g, '');
50
+ const [files] = await bucket.getFiles({
51
+ prefix: fullPrefix,
52
+ });
53
+ for (const file of files) {
54
+ const [metadata] = await file.getMetadata();
55
+ artifacts.push({
56
+ path: file.name,
57
+ bucket: bucketName,
58
+ size: parseInt(metadata.size) || 0,
59
+ contentType: metadata.contentType ?? undefined,
60
+ generation: metadata.generation?.toString(),
61
+ md5Hash: metadata.md5Hash ?? undefined,
62
+ crc32c: metadata.crc32c ?? undefined,
63
+ updated: new Date(metadata.updated),
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ // Also check explicit artifact bucket in config
71
+ if (this.config.artifactBucket) {
72
+ const bucket = this.storage.bucket(this.config.artifactBucket);
73
+ const buildPrefix = `builds/${buildId}/`;
74
+ const [files] = await bucket.getFiles({ prefix: buildPrefix });
75
+ for (const file of files) {
76
+ // Avoid duplicates
77
+ if (artifacts.some(a => a.path === file.name && a.bucket === this.config.artifactBucket)) {
78
+ continue;
79
+ }
80
+ const [metadata] = await file.getMetadata();
81
+ artifacts.push({
82
+ path: file.name,
83
+ bucket: this.config.artifactBucket,
84
+ size: parseInt(metadata.size) || 0,
85
+ contentType: metadata.contentType ?? undefined,
86
+ generation: metadata.generation?.toString(),
87
+ md5Hash: metadata.md5Hash ?? undefined,
88
+ crc32c: metadata.crc32c ?? undefined,
89
+ updated: new Date(metadata.updated),
90
+ });
91
+ }
92
+ }
93
+ return artifacts;
94
+ }
95
+ catch (error) {
96
+ if (error instanceof NotFoundError || error instanceof CloudBuildError) {
97
+ throw error;
98
+ }
99
+ throw mapApiError(error, { buildId });
100
+ }
101
+ }
102
+ /**
103
+ * Download an artifact as a Buffer.
104
+ * Throws if artifact exceeds 100MB.
105
+ */
106
+ async getArtifact(buildId, path) {
107
+ this.logger.debug({ buildId, path }, 'Getting artifact');
108
+ // Find the artifact to get its metadata
109
+ const artifacts = await this.listArtifacts(buildId);
110
+ const artifact = artifacts.find(a => a.path === path || a.path.endsWith(`/${path}`));
111
+ if (!artifact) {
112
+ throw new NotFoundError('Artifact', path);
113
+ }
114
+ // Check size limit
115
+ if (artifact.size > MAX_ARTIFACT_SIZE_BYTES) {
116
+ throw new ValidationError(`Artifact size (${artifact.size} bytes) exceeds maximum of ${MAX_ARTIFACT_SIZE_BYTES} bytes. Use getArtifactStream() for large files.`, 'size');
117
+ }
118
+ try {
119
+ const bucket = this.storage.bucket(artifact.bucket);
120
+ const file = bucket.file(artifact.path);
121
+ const [contents] = await file.download();
122
+ return contents;
123
+ }
124
+ catch (error) {
125
+ throw mapApiError(error, { buildId, path });
126
+ }
127
+ }
128
+ /**
129
+ * Download an artifact as a ReadableStream.
130
+ * Use for large files that exceed the 100MB Buffer limit.
131
+ */
132
+ async getArtifactStream(buildId, path) {
133
+ this.logger.debug({ buildId, path }, 'Getting artifact stream');
134
+ // Find the artifact
135
+ const artifacts = await this.listArtifacts(buildId);
136
+ const artifact = artifacts.find(a => a.path === path || a.path.endsWith(`/${path}`));
137
+ if (!artifact) {
138
+ throw new NotFoundError('Artifact', path);
139
+ }
140
+ try {
141
+ const bucket = this.storage.bucket(artifact.bucket);
142
+ const file = bucket.file(artifact.path);
143
+ // Create a Node.js readable stream
144
+ const nodeStream = file.createReadStream();
145
+ // Convert Node.js stream to Web ReadableStream
146
+ return new ReadableStream({
147
+ start(controller) {
148
+ nodeStream.on('data', (chunk) => {
149
+ controller.enqueue(new Uint8Array(chunk));
150
+ });
151
+ nodeStream.on('end', () => {
152
+ controller.close();
153
+ });
154
+ nodeStream.on('error', (error) => {
155
+ controller.error(error);
156
+ });
157
+ },
158
+ cancel() {
159
+ nodeStream.destroy();
160
+ },
161
+ });
162
+ }
163
+ catch (error) {
164
+ throw mapApiError(error, { buildId, path });
165
+ }
166
+ }
167
+ }
168
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/operations/artifacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Build operations for the Cloud Build plugin.
3
+ *
4
+ * Handles:
5
+ * - Build triggering (triggerBuild, runBuild)
6
+ * - Build monitoring (getBuild, listBuilds)
7
+ * - Build lifecycle (cancelBuild, retryBuild)
8
+ */
9
+ import type { CloudBuildClient } from '@google-cloud/cloudbuild';
10
+ import type { Logger } from 'pino';
11
+ import type { CloudBuildConfig } from '../config/types.js';
12
+ import type { Build, BuildConfig, BuildFilter, BuildSource, PaginatedResult } from '../types/builds.js';
13
+ export declare class BuildOperations {
14
+ private readonly client;
15
+ private readonly config;
16
+ private readonly logger;
17
+ constructor(client: CloudBuildClient, config: CloudBuildConfig, logger: Logger);
18
+ /**
19
+ * Trigger a build from an existing trigger.
20
+ */
21
+ triggerBuild(triggerId: string, source?: BuildSource): Promise<Build>;
22
+ /**
23
+ * Run a build from inline configuration.
24
+ */
25
+ runBuild(buildConfig: BuildConfig): Promise<Build>;
26
+ /**
27
+ * Get a single build by ID.
28
+ */
29
+ getBuild(buildId: string): Promise<Build>;
30
+ /**
31
+ * List builds with optional filtering.
32
+ */
33
+ listBuilds(filter?: BuildFilter): Promise<PaginatedResult<Build>>;
34
+ /**
35
+ * Cancel a running build.
36
+ */
37
+ cancelBuild(buildId: string): Promise<void>;
38
+ /**
39
+ * Retry a failed build.
40
+ */
41
+ retryBuild(buildId: string): Promise<Build>;
42
+ /**
43
+ * Execute operation with retry logic.
44
+ */
45
+ private withRetry;
46
+ /**
47
+ * Build filter string for API request.
48
+ */
49
+ private buildFilterString;
50
+ /**
51
+ * Map Google Cloud Build source to API request format.
52
+ */
53
+ private mapSourceToRequest;
54
+ /**
55
+ * Map Google Cloud Build to plugin Build type.
56
+ */
57
+ private mapBuild;
58
+ /**
59
+ * Map build status enum.
60
+ */
61
+ private mapStatus;
62
+ /**
63
+ * Map build step.
64
+ */
65
+ private mapStep;
66
+ /**
67
+ * Map build step status.
68
+ */
69
+ private mapStepStatus;
70
+ /**
71
+ * Map build results.
72
+ */
73
+ private mapResults;
74
+ /**
75
+ * Map source from API response.
76
+ */
77
+ private mapSource;
78
+ /**
79
+ * Map time span.
80
+ */
81
+ private mapTimeSpan;
82
+ /**
83
+ * Convert protobuf timestamp to Date.
84
+ */
85
+ private toDate;
86
+ /**
87
+ * Calculate build duration in seconds.
88
+ */
89
+ private calculateDuration;
90
+ }
91
+ //# sourceMappingURL=builds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builds.d.ts","sourceRoot":"","sources":["../../src/operations/builds.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,WAAW,EAKX,eAAe,EAGhB,MAAM,oBAAoB,CAAC;AAW5B,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM;IAGjC;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;IA0B3E;;OAEG;IACG,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;IA+CxD;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAwB/C;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAwBvE;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAejD;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAkBjD;;OAEG;YACW,SAAS;IAUvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+BzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuB1B;;OAEG;IACH,OAAO,CAAC,QAAQ;IAuBhB;;OAEG;IACH,OAAO,CAAC,SAAS;IA6BjB;;OAEG;IACH,OAAO,CAAC,OAAO;IAkBf;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,UAAU;IAclB;;OAEG;IACH,OAAO,CAAC,SAAS;IAuBjB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,MAAM;IAQd;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAQ1B"}
@@ -0,0 +1,397 @@
1
+ /**
2
+ * Build operations for the Cloud Build plugin.
3
+ *
4
+ * Handles:
5
+ * - Build triggering (triggerBuild, runBuild)
6
+ * - Build monitoring (getBuild, listBuilds)
7
+ * - Build lifecycle (cancelBuild, retryBuild)
8
+ */
9
+ import { NotFoundError, ValidationError } from '../errors.js';
10
+ import { mapApiError } from '../client.js';
11
+ import { withRetry, shouldRetryError } from '../utils/retry.js';
12
+ export class BuildOperations {
13
+ client;
14
+ config;
15
+ logger;
16
+ constructor(client, config, logger) {
17
+ this.client = client;
18
+ this.config = config;
19
+ this.logger = logger;
20
+ }
21
+ /**
22
+ * Trigger a build from an existing trigger.
23
+ */
24
+ async triggerBuild(triggerId, source) {
25
+ this.logger.debug({ triggerId, source }, 'Triggering build');
26
+ try {
27
+ const [operation] = await this.withRetry(() => this.client.runBuildTrigger({
28
+ projectId: this.config.projectId,
29
+ triggerId,
30
+ source: source?.repoSource ? {
31
+ projectId: source.repoSource.projectId,
32
+ repoName: source.repoSource.repoName,
33
+ branchName: source.repoSource.branchName,
34
+ tagName: source.repoSource.tagName,
35
+ commitSha: source.repoSource.commitSha,
36
+ dir: source.repoSource.dir,
37
+ } : undefined,
38
+ }));
39
+ const [response] = await operation.promise();
40
+ return this.mapBuild(response);
41
+ }
42
+ catch (error) {
43
+ throw mapApiError(error, { triggerId });
44
+ }
45
+ }
46
+ /**
47
+ * Run a build from inline configuration.
48
+ */
49
+ async runBuild(buildConfig) {
50
+ if (!buildConfig.steps || buildConfig.steps.length === 0) {
51
+ throw new ValidationError('At least one build step is required', 'steps');
52
+ }
53
+ this.logger.debug({ stepCount: buildConfig.steps.length }, 'Running build');
54
+ try {
55
+ const [operation] = await this.withRetry(() => this.client.createBuild({
56
+ projectId: this.config.projectId,
57
+ build: {
58
+ steps: buildConfig.steps.map(step => ({
59
+ name: step.name,
60
+ entrypoint: step.entrypoint,
61
+ args: step.args,
62
+ dir: step.dir,
63
+ env: step.env,
64
+ secretEnv: step.secretEnv,
65
+ waitFor: step.waitFor,
66
+ timeout: step.timeout ? { seconds: parseInt(step.timeout) } : undefined,
67
+ script: step.script,
68
+ })),
69
+ source: buildConfig.source ? this.mapSourceToRequest(buildConfig.source) : undefined,
70
+ timeout: buildConfig.timeout ? { seconds: parseInt(buildConfig.timeout) } : undefined,
71
+ substitutions: buildConfig.substitutions,
72
+ tags: buildConfig.tags,
73
+ serviceAccount: buildConfig.serviceAccount,
74
+ logsBucket: buildConfig.logsBucket,
75
+ artifacts: buildConfig.artifacts ? {
76
+ images: buildConfig.artifacts.images,
77
+ objects: buildConfig.artifacts.objects ? {
78
+ location: buildConfig.artifacts.objects.location,
79
+ paths: buildConfig.artifacts.objects.paths,
80
+ } : undefined,
81
+ } : undefined,
82
+ },
83
+ }));
84
+ const [response] = await operation.promise();
85
+ return this.mapBuild(response);
86
+ }
87
+ catch (error) {
88
+ throw mapApiError(error);
89
+ }
90
+ }
91
+ /**
92
+ * Get a single build by ID.
93
+ */
94
+ async getBuild(buildId) {
95
+ this.logger.debug({ buildId }, 'Getting build');
96
+ try {
97
+ const [build] = await this.withRetry(() => this.client.getBuild({
98
+ projectId: this.config.projectId,
99
+ id: buildId,
100
+ }));
101
+ if (!build) {
102
+ throw new NotFoundError('Build', buildId);
103
+ }
104
+ return this.mapBuild(build);
105
+ }
106
+ catch (error) {
107
+ if (error instanceof NotFoundError) {
108
+ throw error;
109
+ }
110
+ throw mapApiError(error, { buildId });
111
+ }
112
+ }
113
+ /**
114
+ * List builds with optional filtering.
115
+ */
116
+ async listBuilds(filter) {
117
+ this.logger.debug({ filter }, 'Listing builds');
118
+ try {
119
+ const filterString = this.buildFilterString(filter);
120
+ const [builds, , response] = await this.withRetry(() => this.client.listBuilds({
121
+ projectId: this.config.projectId,
122
+ filter: filterString || undefined,
123
+ pageSize: filter?.pageSize ?? 50,
124
+ pageToken: filter?.pageToken,
125
+ }));
126
+ return {
127
+ items: builds.map(build => this.mapBuild(build)),
128
+ nextPageToken: response?.nextPageToken ?? undefined,
129
+ };
130
+ }
131
+ catch (error) {
132
+ throw mapApiError(error);
133
+ }
134
+ }
135
+ /**
136
+ * Cancel a running build.
137
+ */
138
+ async cancelBuild(buildId) {
139
+ this.logger.debug({ buildId }, 'Cancelling build');
140
+ try {
141
+ await this.withRetry(() => this.client.cancelBuild({
142
+ projectId: this.config.projectId,
143
+ id: buildId,
144
+ }));
145
+ }
146
+ catch (error) {
147
+ throw mapApiError(error, { buildId });
148
+ }
149
+ }
150
+ /**
151
+ * Retry a failed build.
152
+ */
153
+ async retryBuild(buildId) {
154
+ this.logger.debug({ buildId }, 'Retrying build');
155
+ try {
156
+ const [operation] = await this.withRetry(() => this.client.retryBuild({
157
+ projectId: this.config.projectId,
158
+ id: buildId,
159
+ }));
160
+ const [response] = await operation.promise();
161
+ return this.mapBuild(response);
162
+ }
163
+ catch (error) {
164
+ throw mapApiError(error, { buildId });
165
+ }
166
+ }
167
+ /**
168
+ * Execute operation with retry logic.
169
+ */
170
+ async withRetry(operation) {
171
+ return withRetry(operation, {
172
+ ...this.config.retry,
173
+ shouldRetry: shouldRetryError,
174
+ onRetry: (error, attempt, delayMs) => {
175
+ this.logger.warn({ error, attempt, delayMs }, 'Retrying operation');
176
+ },
177
+ });
178
+ }
179
+ /**
180
+ * Build filter string for API request.
181
+ */
182
+ buildFilterString(filter) {
183
+ if (!filter)
184
+ return '';
185
+ const parts = [];
186
+ if (filter.status) {
187
+ const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
188
+ const statusFilter = statuses.map(s => `status="${s}"`).join(' OR ');
189
+ parts.push(`(${statusFilter})`);
190
+ }
191
+ if (filter.triggerId) {
192
+ parts.push(`build_trigger_id="${filter.triggerId}"`);
193
+ }
194
+ if (filter.startTime?.after) {
195
+ parts.push(`create_time>="${filter.startTime.after.toISOString()}"`);
196
+ }
197
+ if (filter.startTime?.before) {
198
+ parts.push(`create_time<="${filter.startTime.before.toISOString()}"`);
199
+ }
200
+ if (filter.tags && filter.tags.length > 0) {
201
+ const tagFilter = filter.tags.map(t => `tags="${t}"`).join(' OR ');
202
+ parts.push(`(${tagFilter})`);
203
+ }
204
+ return parts.join(' AND ');
205
+ }
206
+ /**
207
+ * Map Google Cloud Build source to API request format.
208
+ */
209
+ mapSourceToRequest(source) {
210
+ return {
211
+ storageSource: source.storageSource ? {
212
+ bucket: source.storageSource.bucket,
213
+ object: source.storageSource.object,
214
+ generation: source.storageSource.generation,
215
+ } : undefined,
216
+ repoSource: source.repoSource ? {
217
+ projectId: source.repoSource.projectId,
218
+ repoName: source.repoSource.repoName,
219
+ branchName: source.repoSource.branchName,
220
+ tagName: source.repoSource.tagName,
221
+ commitSha: source.repoSource.commitSha,
222
+ dir: source.repoSource.dir,
223
+ } : undefined,
224
+ gitSource: source.gitSource ? {
225
+ url: source.gitSource.url,
226
+ revision: source.gitSource.revision,
227
+ dir: source.gitSource.dir,
228
+ } : undefined,
229
+ };
230
+ }
231
+ /**
232
+ * Map Google Cloud Build to plugin Build type.
233
+ */
234
+ mapBuild(raw) {
235
+ return {
236
+ id: raw.id ?? '',
237
+ projectId: raw.projectId ?? this.config.projectId,
238
+ status: this.mapStatus(raw.status),
239
+ statusDetail: raw.statusDetail ?? undefined,
240
+ source: raw.source ? this.mapSource(raw.source) : undefined,
241
+ steps: (raw.steps ?? []).map(step => this.mapStep(step)),
242
+ results: raw.results ? this.mapResults(raw.results) : undefined,
243
+ createTime: this.toDate(raw.createTime) ?? new Date(),
244
+ startTime: this.toDate(raw.startTime),
245
+ finishTime: this.toDate(raw.finishTime),
246
+ duration: this.calculateDuration(raw),
247
+ timeout: raw.timeout?.seconds ? `${raw.timeout.seconds}s` : undefined,
248
+ logUrl: raw.logUrl ?? undefined,
249
+ logsBucket: raw.logsBucket ?? undefined,
250
+ buildTriggerId: raw.buildTriggerId ?? undefined,
251
+ substitutions: raw.substitutions,
252
+ tags: raw.tags,
253
+ serviceAccount: raw.serviceAccount ?? undefined,
254
+ };
255
+ }
256
+ /**
257
+ * Map build status enum.
258
+ */
259
+ mapStatus(status) {
260
+ if (status === null || status === undefined)
261
+ return 'STATUS_UNKNOWN';
262
+ const statusMap = {
263
+ 0: 'STATUS_UNKNOWN',
264
+ 1: 'PENDING',
265
+ 2: 'QUEUED',
266
+ 3: 'WORKING',
267
+ 4: 'SUCCESS',
268
+ 5: 'FAILURE',
269
+ 6: 'INTERNAL_ERROR',
270
+ 7: 'TIMEOUT',
271
+ 8: 'CANCELLED',
272
+ 9: 'EXPIRED',
273
+ 'STATUS_UNKNOWN': 'STATUS_UNKNOWN',
274
+ 'PENDING': 'PENDING',
275
+ 'QUEUED': 'QUEUED',
276
+ 'WORKING': 'WORKING',
277
+ 'SUCCESS': 'SUCCESS',
278
+ 'FAILURE': 'FAILURE',
279
+ 'INTERNAL_ERROR': 'INTERNAL_ERROR',
280
+ 'TIMEOUT': 'TIMEOUT',
281
+ 'CANCELLED': 'CANCELLED',
282
+ 'EXPIRED': 'EXPIRED',
283
+ };
284
+ return statusMap[status] ?? 'STATUS_UNKNOWN';
285
+ }
286
+ /**
287
+ * Map build step.
288
+ */
289
+ mapStep(step) {
290
+ return {
291
+ id: step.id ?? undefined,
292
+ name: step.name ?? '',
293
+ entrypoint: step.entrypoint ?? undefined,
294
+ args: step.args,
295
+ dir: step.dir ?? undefined,
296
+ env: step.env,
297
+ secretEnv: step.secretEnv,
298
+ waitFor: step.waitFor,
299
+ timeout: step.timeout?.seconds ? `${step.timeout.seconds}s` : undefined,
300
+ status: this.mapStepStatus(step.status),
301
+ timing: step.timing ? this.mapTimeSpan(step.timing) : undefined,
302
+ pullTiming: step.pullTiming ? this.mapTimeSpan(step.pullTiming) : undefined,
303
+ script: step.script ?? undefined,
304
+ };
305
+ }
306
+ /**
307
+ * Map build step status.
308
+ */
309
+ mapStepStatus(status) {
310
+ if (status === null || status === undefined)
311
+ return 'STATUS_UNKNOWN';
312
+ const statusMap = {
313
+ 0: 'STATUS_UNKNOWN',
314
+ 1: 'PENDING',
315
+ 2: 'QUEUED',
316
+ 3: 'WORKING',
317
+ 4: 'SUCCESS',
318
+ 5: 'FAILURE',
319
+ 6: 'INTERNAL_ERROR',
320
+ 7: 'TIMEOUT',
321
+ 8: 'CANCELLED',
322
+ };
323
+ return statusMap[status] ?? 'STATUS_UNKNOWN';
324
+ }
325
+ /**
326
+ * Map build results.
327
+ */
328
+ mapResults(results) {
329
+ return {
330
+ images: results.images?.map(img => ({
331
+ name: img.name ?? '',
332
+ digest: img.digest ?? '',
333
+ pushTiming: img.pushTiming ? this.mapTimeSpan(img.pushTiming) : undefined,
334
+ })),
335
+ buildStepImages: results.buildStepImages,
336
+ artifactManifest: results.artifactManifest ?? undefined,
337
+ numArtifacts: results.numArtifacts ? Number(results.numArtifacts) : undefined,
338
+ artifactTiming: results.artifactTiming ? this.mapTimeSpan(results.artifactTiming) : undefined,
339
+ };
340
+ }
341
+ /**
342
+ * Map source from API response.
343
+ */
344
+ mapSource(source) {
345
+ return {
346
+ storageSource: source.storageSource ? {
347
+ bucket: source.storageSource.bucket ?? '',
348
+ object: source.storageSource.object ?? '',
349
+ generation: source.storageSource.generation?.toString(),
350
+ } : undefined,
351
+ repoSource: source.repoSource ? {
352
+ projectId: source.repoSource.projectId ?? undefined,
353
+ repoName: source.repoSource.repoName ?? '',
354
+ branchName: source.repoSource.branchName ?? undefined,
355
+ tagName: source.repoSource.tagName ?? undefined,
356
+ commitSha: source.repoSource.commitSha ?? undefined,
357
+ dir: source.repoSource.dir ?? undefined,
358
+ } : undefined,
359
+ gitSource: source.gitSource ? {
360
+ url: source.gitSource.url ?? '',
361
+ revision: source.gitSource.revision ?? undefined,
362
+ dir: source.gitSource.dir ?? undefined,
363
+ } : undefined,
364
+ };
365
+ }
366
+ /**
367
+ * Map time span.
368
+ */
369
+ mapTimeSpan(span) {
370
+ return {
371
+ startTime: this.toDate(span.startTime) ?? new Date(),
372
+ endTime: this.toDate(span.endTime) ?? new Date(),
373
+ };
374
+ }
375
+ /**
376
+ * Convert protobuf timestamp to Date.
377
+ */
378
+ toDate(timestamp) {
379
+ if (!timestamp?.seconds)
380
+ return undefined;
381
+ const seconds = typeof timestamp.seconds === 'object'
382
+ ? Number(timestamp.seconds.toString())
383
+ : Number(timestamp.seconds);
384
+ return new Date(seconds * 1000 + (timestamp.nanos ?? 0) / 1000000);
385
+ }
386
+ /**
387
+ * Calculate build duration in seconds.
388
+ */
389
+ calculateDuration(build) {
390
+ const startTime = this.toDate(build.startTime);
391
+ const finishTime = this.toDate(build.finishTime);
392
+ if (!startTime || !finishTime)
393
+ return undefined;
394
+ return Math.round((finishTime.getTime() - startTime.getTime()) / 1000);
395
+ }
396
+ }
397
+ //# sourceMappingURL=builds.js.map