Skip to content

Commit 08f8a70

Browse files
Add runbook name field (#1560)
<!-- Ensure the title clearly reflects what was changed. Provide a clear and concise description of the changes made. The PR should only contain the changes related to the issue, and no other unrelated changes. --> Part of OPS-2931
1 parent fc1bc0f commit 08f8a70

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { DocumentIdentifier } from '@aws-sdk/client-ssm';
2+
import { BlockPropValueSchema, Property } from '@openops/blocks-framework';
3+
import { amazonAuth } from '../auth';
4+
import { DocumentOwner } from './document-owner';
5+
import { getSsmDocuments } from './get-ssm-documents';
6+
7+
export const runbookNameProperty = Property.Dropdown({
8+
displayName: 'Runbook',
9+
description: 'Select an SSM Automation document (runbook).',
10+
required: true,
11+
refreshers: ['auth', 'owner', 'region'],
12+
options: async ({ auth, owner, region }) => {
13+
const awsAuth = auth as BlockPropValueSchema<typeof amazonAuth>;
14+
if (!awsAuth) {
15+
return {
16+
disabled: true,
17+
options: [],
18+
placeholder: 'Please authenticate first',
19+
};
20+
}
21+
22+
const awsRegion = (region || awsAuth.defaultRegion) as string;
23+
if (!awsRegion) {
24+
return {
25+
disabled: true,
26+
options: [],
27+
placeholder: 'Please provide a region',
28+
};
29+
}
30+
31+
try {
32+
const docs = await getSsmDocuments({
33+
auth: awsAuth,
34+
region: awsRegion,
35+
owner: owner as DocumentOwner,
36+
});
37+
38+
return {
39+
disabled: false,
40+
options: docs
41+
.filter((d: DocumentIdentifier) => Boolean(d.Name))
42+
.map((d) => ({
43+
label: d.Name!,
44+
value: d.Name!,
45+
})),
46+
};
47+
} catch (error) {
48+
return {
49+
disabled: true,
50+
options: [],
51+
placeholder: 'Failed to load runbooks',
52+
error: String(error),
53+
};
54+
}
55+
},
56+
});
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { DocumentIdentifier } from '@aws-sdk/client-ssm';
2+
3+
const getSsmDocuments = jest.fn();
4+
jest.mock('../../../src/lib/aws/ssm/get-ssm-documents', () => ({
5+
getSsmDocuments: (...args: any[]) => getSsmDocuments(...args),
6+
}));
7+
8+
import type { PropertyContext } from '@openops/blocks-framework';
9+
import { runbookNameProperty } from '../../../src/lib/aws/ssm/runbook-name-property';
10+
11+
describe('runbookNameProperty.options', () => {
12+
const ctx = {} as PropertyContext;
13+
beforeEach(() => {
14+
jest.clearAllMocks();
15+
});
16+
17+
test('returns disabled with placeholder when auth is missing', async () => {
18+
const res = await runbookNameProperty.options(
19+
{ auth: undefined, owner: undefined, region: 'us-east-1' },
20+
ctx,
21+
);
22+
23+
expect(res).toEqual({
24+
disabled: true,
25+
options: [],
26+
placeholder: 'Please authenticate first',
27+
});
28+
29+
expect(getSsmDocuments).not.toHaveBeenCalled();
30+
});
31+
32+
test('returns disabled with placeholder when region is missing and no defaultRegion', async () => {
33+
const auth = {};
34+
35+
const res = await runbookNameProperty.options(
36+
{ auth, owner: undefined, region: undefined },
37+
ctx,
38+
);
39+
40+
expect(res).toEqual({
41+
disabled: true,
42+
options: [],
43+
placeholder: 'Please provide a region',
44+
});
45+
46+
expect(getSsmDocuments).not.toHaveBeenCalled();
47+
});
48+
49+
test('uses provided region over auth.defaultRegion and maps docs to options', async () => {
50+
const auth = { defaultRegion: 'us-west-2' };
51+
const owner = 'Self';
52+
const region = 'us-east-1';
53+
54+
const docs: Partial<DocumentIdentifier>[] = [
55+
{ Name: 'AWS-RunShellScript' },
56+
{ Name: 'MyCustomRunbook' },
57+
];
58+
getSsmDocuments.mockResolvedValueOnce(docs);
59+
60+
const res = await runbookNameProperty.options({ auth, owner, region }, ctx);
61+
62+
expect(getSsmDocuments).toHaveBeenCalledTimes(1);
63+
expect(getSsmDocuments).toHaveBeenCalledWith({
64+
auth,
65+
region,
66+
owner,
67+
});
68+
69+
expect(res).toEqual({
70+
disabled: false,
71+
options: [
72+
{ label: 'AWS-RunShellScript', value: 'AWS-RunShellScript' },
73+
{ label: 'MyCustomRunbook', value: 'MyCustomRunbook' },
74+
],
75+
});
76+
});
77+
78+
test('uses auth.defaultRegion when region arg is missing', async () => {
79+
const auth = { defaultRegion: 'eu-central-1' };
80+
const owner = 'Amazon';
81+
82+
getSsmDocuments.mockResolvedValueOnce([]);
83+
84+
const res = await runbookNameProperty.options(
85+
{ auth, owner, region: undefined },
86+
ctx,
87+
);
88+
89+
expect(getSsmDocuments).toHaveBeenCalledWith({
90+
auth,
91+
region: 'eu-central-1',
92+
owner,
93+
});
94+
expect(res).toEqual({ disabled: false, options: [] });
95+
});
96+
97+
test('returns disabled with error and placeholder when getSsmDocuments throws', async () => {
98+
const auth = { defaultRegion: 'eu-west-1' };
99+
const err = new Error('boom');
100+
getSsmDocuments.mockRejectedValueOnce(err);
101+
102+
const res = await runbookNameProperty.options(
103+
{ auth, owner: undefined, region: undefined },
104+
ctx,
105+
);
106+
107+
expect(res).toEqual({
108+
disabled: true,
109+
options: [],
110+
placeholder: 'Failed to load runbooks',
111+
error: String(err),
112+
});
113+
});
114+
});

0 commit comments

Comments
 (0)