Skip to content

Commit 71f77a4

Browse files
Merge pull request #5 from WarpBuilds/feat/multi-profile-support
2 parents 0288f15 + b751d23 commit 71f77a4

File tree

9 files changed

+6355
-4355
lines changed

9 files changed

+6355
-4355
lines changed

.github/workflows/debug.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ jobs:
3030
push: false
3131
# platforms: linux/amd64,linux/arm64
3232
platforms: linux/amd64
33-
profile-name: dev-eph
33+
profile-name: test-dev,dev-eph
34+
timeout: 40000
3435

3536

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ inputs:
115115
description: "The API key for the WarpBuild API. This is not required in case of using WarpBuild runners"
116116
required: false
117117
profile-name:
118-
description: "The profile name to use for the WarpBuild Docker Builders"
118+
description: "The profile names to use for the WarpBuild Docker Builders, comma separated list of profile names to be attempted in order"
119119
required: true
120120
timeout:
121121
description: "The timeout(in ms) to wait for the Docker Builders to be ready. By default, it is 10 minutes"

dist/index.js

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/licenses.txt

Lines changed: 70 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export interface Inputs {
4242
ulimit: string[];
4343
'github-token': string;
4444
apiKey: string;
45-
profileName: string;
45+
profileNames: string;
4646
timeout: string;
4747
}
4848

@@ -82,7 +82,7 @@ export async function getInputs(): Promise<Inputs> {
8282
ulimit: Util.getInputList('ulimit', {ignoreComma: true}),
8383
'github-token': core.getInput('github-token'),
8484
apiKey: core.getInput('api-key'),
85-
profileName: core.getInput('profile-name'),
85+
profileNames: core.getInput('profile-name'),
8686
timeout: core.getInput('timeout')
8787
};
8888
}

src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ actionsToolkit.run(
3636

3737
remoteBuilders = new WarpBuildRemoteBuilders({
3838
apiKey: inputs.apiKey,
39-
profileName: inputs.profileName,
39+
profileNames: inputs.profileNames,
4040
timeout: parsedTimeout
4141
});
4242

@@ -255,7 +255,7 @@ actionsToolkit.run(
255255

256256
remoteBuilders = new WarpBuildRemoteBuilders({
257257
apiKey: inputs.apiKey,
258-
profileName: inputs.profileName,
258+
profileNames: inputs.profileNames,
259259
timeout: parsedTimeout
260260
});
261261

src/warpbuild.ts

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as core from '@actions/core';
99
const execAsync = promisify(exec);
1010

1111
interface BuilderConfig {
12-
profileName: string;
12+
profileNames: string;
1313
apiKey?: string;
1414
timeout?: number;
1515
}
@@ -39,19 +39,19 @@ interface CleanupState {
3939
}
4040

4141
export class WarpBuildRemoteBuilders {
42-
private readonly profileName: string;
42+
private readonly profileNames: string[];
4343
private readonly apiKey?: string;
4444
private readonly timeout: number;
4545
private readonly isWarpBuildRunner: boolean;
46-
private readonly scriptStartTime: number;
4746
private readonly apiDomain: string;
47+
private scriptStartTime: number;
4848
private builderName: string;
4949
private builderInstances: BuilderInstance[] = [];
5050
private certDirs: string[] = [];
5151
private assignmentPromise: Promise<void> | null = null;
5252

5353
constructor(config: BuilderConfig) {
54-
this.profileName = config.profileName;
54+
this.profileNames = config.profileNames.split(',');
5555
this.apiKey = config.apiKey;
5656
this.timeout = config.timeout || 600000; // Default timeout 600 seconds
5757
this.scriptStartTime = Date.now();
@@ -146,64 +146,71 @@ export class WarpBuildRemoteBuilders {
146146
let retryCount = 0;
147147
const staticWait = 10000; // 10 seconds
148148

149-
await core.group(`Assigning WarpBuild builders for profile ${this.profileName}`, async () => {
150-
while (this.checkGlobalTimeoutNotExceeded()) {
151-
retryCount++;
152-
153-
try {
154-
core.info(`Making API request to assign builder (attempt ${retryCount})...`);
155-
156-
const authHeader = this.isWarpBuildRunner ? `Bearer ${process.env.WARPBUILD_RUNNER_VERIFICATION_TOKEN}` : `Bearer ${this.apiKey}`;
157-
158-
const response = await fetch(assignBuilderEndpoint, {
159-
method: 'POST',
160-
headers: {
161-
'Content-Type': 'application/json',
162-
Authorization: authHeader
163-
},
164-
body: JSON.stringify({profile_name: this.profileName})
165-
});
166-
167-
if (!response.ok) {
168-
const statusCode = response.status;
169-
170-
const errorData = await response.json().catch(() => ({message: 'Unknown error'}));
171-
172-
// Determine if we should retry based on status code
173-
if (statusCode >= 500 || statusCode === 409 || statusCode === 429) {
174-
core.warning(`${errorData.description || errorData.message || 'Assign builder failed'}`);
175-
core.info(`Waiting ${staticWait / 1000} seconds before next attempt...`);
176-
await new Promise(resolve => setTimeout(resolve, staticWait));
177-
continue;
149+
await core.group(`Assigning WarpBuild builders for profile ${this.profileNames}`, async () => {
150+
for (const profileName of this.profileNames) {
151+
core.info(`Assigning builder for profile ${profileName}`);
152+
while (this.checkGlobalTimeoutNotExceeded()) {
153+
retryCount++;
154+
155+
try {
156+
core.info(`Making API request to assign builder (attempt ${retryCount})...`);
157+
158+
const authHeader = this.isWarpBuildRunner ? `Bearer ${process.env.WARPBUILD_RUNNER_VERIFICATION_TOKEN}` : `Bearer ${this.apiKey}`;
159+
160+
const response = await fetch(assignBuilderEndpoint, {
161+
method: 'POST',
162+
headers: {
163+
'Content-Type': 'application/json',
164+
Authorization: authHeader
165+
},
166+
body: JSON.stringify({profile_name: profileName.trim()})
167+
});
168+
169+
if (!response.ok) {
170+
const statusCode = response.status;
171+
172+
const errorData = await response.json().catch(() => ({message: 'Unknown error'}));
173+
174+
// Determine if we should retry based on status code
175+
if (statusCode >= 500 || statusCode === 409 || statusCode === 429) {
176+
core.warning(`${errorData.description || errorData.message || 'Assign builder failed'}`);
177+
core.info(`Waiting ${staticWait / 1000} seconds before next attempt...`);
178+
await new Promise(resolve => setTimeout(resolve, staticWait));
179+
continue;
180+
}
181+
182+
// Not a retriable error
183+
core.debug(`Error data: ${JSON.stringify(errorData)}`);
184+
throw new Error(`HTTP ${statusCode}: ${errorData.description || errorData.message || 'Unknown error'}`);
178185
}
179186

180-
// Not a retriable error
181-
core.debug(`Error data: ${JSON.stringify(errorData)}`);
182-
throw new Error(`HTTP ${statusCode}: ${errorData.description || errorData.message || 'Unknown error'}`);
183-
}
187+
const data = (await response.json()) as AssignBuilderResponse;
184188

185-
const data = (await response.json()) as AssignBuilderResponse;
189+
if (!data.builder_instances || data.builder_instances.length === 0) {
190+
throw new Error('No builder instances assigned');
191+
}
186192

187-
if (!data.builder_instances || data.builder_instances.length === 0) {
188-
throw new Error('No builder instances assigned');
189-
}
193+
core.info(`✓ Successfully assigned ${data.builder_instances.length} builder(s) after ${retryCount} attempts`);
194+
this.builderInstances = data.builder_instances;
195+
this.saveState();
196+
return;
197+
} catch (error) {
198+
if (error instanceof Error && error.message.startsWith('API Error:')) {
199+
throw error; // Re-throw non-retriable errors
200+
}
190201

191-
core.info(`✓ Successfully assigned ${data.builder_instances.length} builder(s) after ${retryCount} attempts`);
192-
this.builderInstances = data.builder_instances;
193-
this.saveState();
194-
return;
195-
} catch (error) {
196-
if (error instanceof Error && error.message.startsWith('API Error:')) {
197-
throw error; // Re-throw non-retriable errors
202+
core.warning(`Request error: ${error}`);
203+
core.info(`Waiting ${staticWait / 1000} seconds before next attempt...`);
204+
await new Promise(resolve => setTimeout(resolve, staticWait));
198205
}
199-
200-
core.warning(`Request error: ${error}`);
201-
core.info(`Waiting ${staticWait / 1000} seconds before next attempt...`);
202-
await new Promise(resolve => setTimeout(resolve, staticWait));
203206
}
207+
208+
//Reset script start time after each profile
209+
this.scriptStartTime = Date.now();
210+
core.info(`Timeout reached for profile ${profileName}`);
204211
}
205212

206-
throw new Error('Exceeded global timeout waiting for builder assignment');
213+
throw new Error('Exceeded global timeout waiting for builder assignment for all profiles');
207214
});
208215
}
209216

@@ -267,7 +274,7 @@ export class WarpBuildRemoteBuilders {
267274
* Validate required inputs
268275
*/
269276
private validateInputs(): void {
270-
if (!this.profileName) {
277+
if (!this.profileNames) {
271278
throw new Error('Profile name is required');
272279
}
273280

0 commit comments

Comments
 (0)