Skip to content

Commit 5314496

Browse files
committed
fix(nx-fly-deployment-action): failed deployment should fail workflow
closed COD-215
1 parent 09e438d commit 5314496

5 files changed

Lines changed: 50 additions & 10 deletions

File tree

packages/nx-fly-deployment-action/action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ outputs:
8484
skipped:
8585
description: >
8686
A list of project names that were skipped for some reason.
87+
failed:
88+
description: >
89+
A list of project names that failed to deploy.
8790
deployed:
8891
description: >
8992
JSON object containing the deployed project names and their urls.

packages/nx-fly-deployment-action/src/lib/main.spec.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,12 @@ describe('main', () => {
138138
},
139139
{ action: 'destroy', app: 'api-one-app' },
140140
{ action: 'destroy', app: 'api-two-app' },
141-
{ action: 'skip', appOrProject: 'web-one', reason: 'failed' },
142-
{ action: 'skip', appOrProject: 'web-two', reason: 'outdated' }
141+
{
142+
action: 'failed',
143+
appOrProject: 'web-two',
144+
error: 'deployment error'
145+
},
146+
{ action: 'skip', appOrProject: 'web-one', reason: 'outdated' }
143147
]
144148
};
145149
flyDeploymentMock.mockResolvedValue(result);
@@ -154,10 +158,12 @@ describe('main', () => {
154158
'api-one-app',
155159
'api-two-app'
156160
]);
157-
expect(setOutputMock).toHaveBeenCalledWith('skipped', [
158-
'web-one',
159-
'web-two'
160-
]);
161+
expect(setOutputMock).toHaveBeenCalledWith('skipped', ['web-one']);
162+
expect(setOutputMock).toHaveBeenCalledWith('failed', ['web-two']);
163+
164+
expect(setFailedMock).toHaveBeenCalledWith(
165+
'Deployment failed for 1 project(s):\nweb-two: deployment error'
166+
);
161167
});
162168

163169
it('should handle errors', async () => {

packages/nx-fly-deployment-action/src/lib/main.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,32 @@ export async function run(): Promise<void> {
5454
'skipped',
5555
projects.filter((p) => p.action === 'skip').map((p) => p.appOrProject)
5656
);
57+
// Output: List of failed project names
58+
core.setOutput(
59+
'failed',
60+
projects.filter((p) => p.action === 'failed').map((p) => p.appOrProject)
61+
);
5762
// Output: Record of deployed project names and urls
5863
core.setOutput(
5964
'deployed',
6065
projects
6166
.filter((p) => p.action === 'deploy')
6267
.reduce((acc, p) => ({ ...acc, [`${p.name}`]: p.url }), {})
6368
);
69+
70+
// Fail the action if any deployments failed
71+
const failedProjects = projects.filter((p) => p.action === 'failed');
72+
if (failedProjects.length > 0) {
73+
const failedList = failedProjects
74+
.map(
75+
(p) =>
76+
`${p.appOrProject}: ${'error' in p ? p.error : 'Unknown error'}`
77+
)
78+
.join('\n');
79+
core.setFailed(
80+
`Deployment failed for ${failedProjects.length} project(s):\n${failedList}`
81+
);
82+
}
6483
} catch (error) {
6584
if (error instanceof Error) {
6685
core.setFailed(error.message);

packages/nx-fly-deployment-action/src/lib/schemas/action-outputs.schema.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { EnvironmentSchema } from '@codeware/core/actions';
22
import { z } from 'zod';
33

4-
export const ActionSchema = z.enum(['deploy', 'destroy', 'skip']);
4+
export const ActionSchema = z.enum(['deploy', 'destroy', 'failed', 'skip']);
55

66
const FlyAppNameSchema = z.object({
77
app: z.string({ description: 'App name' }).min(1, 'An app name is required')
@@ -27,6 +27,17 @@ const ActionDestroySchema = FlyAppNameSchema.merge(
2727
})
2828
);
2929

30+
// 'failed' action requires an app or project name and an error message
31+
const ActionFailedSchema = z.object({
32+
action: z.literal(ActionSchema.enum.failed),
33+
appOrProject: z
34+
.string({ description: 'App or project name' })
35+
.min(1, 'An app or project name is required'),
36+
error: z
37+
.string({ description: 'Error message' })
38+
.min(1, 'An error message is required')
39+
});
40+
3041
// 'skip' action requires an app or project name and a reason
3142
const ActionSkipSchema = z.object({
3243
action: z.literal(ActionSchema.enum.skip),
@@ -42,6 +53,7 @@ const ActionSkipSchema = z.object({
4253
const ProjectSchema = z.discriminatedUnion('action', [
4354
ActionDeploySchema,
4455
ActionDestroySchema,
56+
ActionFailedSchema,
4557
ActionSkipSchema
4658
]);
4759

packages/nx-fly-deployment-action/src/lib/utils/run-deploy-apps.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,14 @@ export const runDeployApps = async (options: {
167167
} catch (error) {
168168
const msg = error instanceof Error ? error.message : String(error);
169169

170-
core.warning(
170+
core.error(
171171
`[${projectName}] ❌ Failed to deploy project${tenantLabel}: ${msg}`
172172
);
173173

174174
projects.push({
175175
appOrProject: tenantId ? `${projectName} (${tenantId})` : projectName,
176-
action: 'skip',
177-
reason: `Failed to deploy project${tenantLabel}`
176+
action: 'failed',
177+
error: msg
178178
});
179179
}
180180
}

0 commit comments

Comments
 (0)