Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

## Version History

### v9.9.0

- :rocket: Standardize Handlebar Variables

### v9.8.0

- :tada: Update CFN-Config to latest version which supports regions created after 2022
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,4 @@ for complete information on tag formatting.
}, "Client", "<another tag>"]
}
```

7 changes: 6 additions & 1 deletion lib/artifacts/docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ function single(creds, image) {
});

image = Handlebars.compile(image)({
project: creds.repo ,
rootStackName: `${creds.repo}-${creds.stack}`,
fullStackName: `${creds.repo}-${creds.name}`,
accountId: creds._accountId,
stack: creds.stack,
region: creds.region,
project: creds.repo,
gitsha: creds.sha
});

Expand Down
1 change: 1 addition & 0 deletions lib/artifacts/s3.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function single(creds, object) {
rootStackName: `${creds.repo}-${creds.stack}`,
fullStackName: `${creds.repo}-${creds.name}`,
accountId: creds._accountId,
stack: creds.stack,
region: creds.region,
project: creds.repo,
gitsha: creds.sha
Expand Down
6 changes: 6 additions & 0 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ export default class Credentials {
creds.tags = creds.tags.concat(creds.dotdeploy.tags || []);
}

// Load GitHub polling configuration
creds.githubPolling = {
timeout: 30 * 60 * 1000, // 30 minutes default
interval: 30 * 1000 // 30 seconds default
};

creds.aws = {};

try {
Expand Down
69 changes: 63 additions & 6 deletions lib/gh.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import fs from 'fs';
import fs from 'node:fs';
import ora from 'ora';
import Git from './git.js';

Expand Down Expand Up @@ -48,7 +48,15 @@ export default class GH {
success = 'failed';
}

await this.status();
// Poll GitHub status checks before proceeding with deployment
if (this.context.force !== true) {
try {
await this.pollStatusChecks(this.context.githubPolling);
} catch (err) {
console.error(`Status Check Polling Failed: ${err.message}`);
process.exit(1);
}
}

if (this.context.deployment) {
return await this.deployment_update(stack, success);
Expand All @@ -66,9 +74,9 @@ export default class GH {
}

async status() {
const res = await fetch(this.url + `/repos/${this.context.owner}/${this.repo}/commits/${this.context.sha}/status`, {
const res = await fetch(this.url + `/repos/${this.context.owner}/${this.repo}/commits/${this.context.sha}/check-runs`, {
method: 'GET',
headers: this.headers,
headers: this.headers
});

const body = await res.json();
Expand All @@ -80,10 +88,59 @@ export default class GH {
console.error(body);
throw new Error('Could not list status checks');
}
} else {
if (body.state === 'pending') {
}

return body;
}

/**
* Poll GitHub status checks until they pass or fail
*
* @param {Object} options - Polling options
* @param {number} options.timeout - Timeout in milliseconds (default: 30 minutes)
* @param {number} options.interval - Poll interval in milliseconds (default: 30 seconds)
* @returns {Promise<boolean>} - True if checks pass, throws error if they fail
*/
async pollStatusChecks(options = {}) {
const timeout = options.timeout || 30 * 60 * 1000; // 30 minutes default
const interval = options.interval || 30 * 1000; // 30 seconds default
const startTime = Date.now();

const progress = ora(`GitHub Status Checks: ${this.context.sha}`).start();

try {
while (Date.now() - startTime < timeout) {
try {
const status = await this.status();

progress.text = `GitHub Status Checks: (${status.check_runs?.length || 0} checks)`;

const completed = status.check_runs?.filter((s) => s.status === 'completed') || [];

if (completed.length === status.check_runs?.length) {
progress.succeed();
return;
};

await new Promise((resolve) => setTimeout(resolve, interval));
} catch (error) {
if (error.message.includes('Status checks failed') || error.message.includes('encountered errors')) {
throw error; // Re-throw status check failures
}

progress.text = `GitHub Status Checks: Error - ${error.message}`;
await new Promise((resolve) => setTimeout(resolve, interval));
}
}

progress.fail(`GitHub Status Checks: Timeout after ${timeout / 1000 / 60} minutes`);
throw new Error(`❌ Timeout waiting for status checks to complete after ${timeout / 1000 / 60} minutes`);
} catch (error) {
// Ensure we clean up the spinner if it's still running
if (progress.isSpinning) {
progress.fail('GitHub Status Checks: Failed');
}
throw error;
}
}

Expand Down
Loading
Loading