Skip to content

Commit c21e3e5

Browse files
feat: support building block run URL input with fallback to payload
- Add buildingBlockRunUrl input to action.yml for fetching building block run data - Update index.ts to handle both URL-based and payload-based inputs - URL-based input makes a GET request to fetch the building block run object - Maintains backward compatibility with existing buildingBlockRun payload input - Extract common logic for parsing building block run data from both sources - Add tests for building block run parsing from URL and payload sources
1 parent 09f870e commit c21e3e5

File tree

4 files changed

+253
-18
lines changed

4 files changed

+253
-18
lines changed

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ inputs:
55
description: 'The steps to register'
66
required: true
77
type: string
8+
buildingBlockRunUrl:
9+
description: 'URL to fetch the building block run object from (alternative to buildingBlockRun input via payload)'
10+
required: false
11+
type: string
812
outputs:
913
token_file:
1014
description: 'Path to the file containing the authentication token'

dist/main/index.js

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32289,16 +32289,71 @@ const os = __importStar(__nccwpck_require__(2037));
3228932289
async function run() {
3229032290
try {
3229132291
const stepsInput = core.getInput('steps');
32292+
const buildingBlockRunUrl = core.getInput('buildingBlockRunUrl');
3229232293
core.debug(`Steps Input: ${stepsInput}`);
32293-
// Extract buildingBlockRun from the GitHub event payload
32294-
const buildingBlockRun = github.context.payload.inputs.buildingBlockRun;
32295-
core.debug(`Building Block Run: ${buildingBlockRun}`);
32296-
// Decode and parse the buildingBlockRun input
32297-
const decodedBuildingBlockRun = Buffer.from(buildingBlockRun, 'base64').toString('utf-8');
32298-
const buildingBlockRunJson = JSON.parse(decodedBuildingBlockRun);
32299-
const bbRunUuid = buildingBlockRunJson.metadata.uuid;
32300-
const baseUrl = buildingBlockRunJson._links.meshstackBaseUrl.href;
32301-
const inputs = buildingBlockRunJson.spec.buildingBlock.spec.inputs;
32294+
core.debug(`Building Block Run URL: ${buildingBlockRunUrl}`);
32295+
let buildingBlockRunJson;
32296+
let bbRunUuid;
32297+
let baseUrl;
32298+
let inputs;
32299+
// Determine input source: URL or payload
32300+
if (buildingBlockRunUrl) {
32301+
// Fetch building block run from URL
32302+
core.debug('Using buildingBlockRunUrl input');
32303+
// Read token from file for authorization
32304+
const tempDir = process.env.RUNNER_TEMP || os.tmpdir();
32305+
const tokenFilePath = path.join(tempDir, 'meshstack_token.json');
32306+
if (!fs.existsSync(tokenFilePath)) {
32307+
throw new Error(`Token file does not exist at ${tokenFilePath}`);
32308+
}
32309+
const tokenData = JSON.parse(fs.readFileSync(tokenFilePath, 'utf8'));
32310+
const token = tokenData.token;
32311+
if (!token) {
32312+
throw new Error('Token not found in token file');
32313+
}
32314+
core.debug(`Token: ${token}`);
32315+
// Fetch the building block run from the URL
32316+
const headers = {
32317+
'Accept': 'application/vnd.meshcloud.api.meshbuildingblockrun.v1.hal+json',
32318+
'Authorization': `Bearer ${token}`
32319+
};
32320+
try {
32321+
const response = await axios_1.default.get(buildingBlockRunUrl, { headers });
32322+
buildingBlockRunJson = response.data;
32323+
core.debug(`Fetched Building Block Run: ${JSON.stringify(buildingBlockRunJson)}`);
32324+
}
32325+
catch (fetchError) {
32326+
if (axios_1.default.isAxiosError(fetchError)) {
32327+
if (fetchError.response) {
32328+
core.error(`Failed to fetch building block run: ${JSON.stringify(fetchError.response.data)}`);
32329+
core.error(`Status code: ${fetchError.response.status}`);
32330+
}
32331+
else {
32332+
core.error(`Fetch error message: ${fetchError.message}`);
32333+
}
32334+
}
32335+
else {
32336+
core.error(`Unexpected error during fetch: ${fetchError}`);
32337+
}
32338+
throw fetchError;
32339+
}
32340+
}
32341+
else {
32342+
// Use buildingBlockRun from GitHub event payload
32343+
core.debug('Using buildingBlockRun from GitHub event payload');
32344+
const buildingBlockRun = github.context.payload.inputs.buildingBlockRun;
32345+
core.debug(`Building Block Run: ${buildingBlockRun}`);
32346+
if (!buildingBlockRun) {
32347+
throw new Error('Neither buildingBlockRunUrl input nor buildingBlockRun payload provided');
32348+
}
32349+
// Decode and parse the buildingBlockRun input
32350+
const decodedBuildingBlockRun = Buffer.from(buildingBlockRun, 'base64').toString('utf-8');
32351+
buildingBlockRunJson = JSON.parse(decodedBuildingBlockRun);
32352+
}
32353+
// Extract common data from buildingBlockRunJson
32354+
bbRunUuid = buildingBlockRunJson.metadata.uuid;
32355+
baseUrl = buildingBlockRunJson._links.meshstackBaseUrl.href;
32356+
inputs = buildingBlockRunJson.spec.buildingBlock.spec.inputs;
3230232357
core.debug(`Base URL: ${baseUrl}`);
3230332358
core.debug(`BB Run UUID: ${bbRunUuid}`);
3230432359
// Extract additional inputs

src/index.ts

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,80 @@ import * as os from 'os';
88
async function run() {
99
try {
1010
const stepsInput = core.getInput('steps');
11+
const buildingBlockRunUrl = core.getInput('buildingBlockRunUrl');
1112

1213
core.debug(`Steps Input: ${stepsInput}`);
14+
core.debug(`Building Block Run URL: ${buildingBlockRunUrl}`);
15+
16+
let buildingBlockRunJson: any;
17+
let bbRunUuid: string;
18+
let baseUrl: string;
19+
let inputs: any[];
20+
21+
// Determine input source: URL or payload
22+
if (buildingBlockRunUrl) {
23+
// Fetch building block run from URL
24+
core.debug('Using buildingBlockRunUrl input');
25+
26+
// Read token from file for authorization
27+
const tempDir = process.env.RUNNER_TEMP || os.tmpdir();
28+
const tokenFilePath = path.join(tempDir, 'meshstack_token.json');
29+
30+
if (!fs.existsSync(tokenFilePath)) {
31+
throw new Error(`Token file does not exist at ${tokenFilePath}`);
32+
}
33+
34+
const tokenData = JSON.parse(fs.readFileSync(tokenFilePath, 'utf8'));
35+
const token = tokenData.token;
36+
37+
if (!token) {
38+
throw new Error('Token not found in token file');
39+
}
40+
41+
core.debug(`Token: ${token}`);
42+
43+
// Fetch the building block run from the URL
44+
const headers = {
45+
'Accept': 'application/vnd.meshcloud.api.meshbuildingblockrun.v1.hal+json',
46+
'Authorization': `Bearer ${token}`
47+
};
48+
49+
try {
50+
const response = await axios.get(buildingBlockRunUrl, { headers });
51+
buildingBlockRunJson = response.data;
52+
core.debug(`Fetched Building Block Run: ${JSON.stringify(buildingBlockRunJson)}`);
53+
} catch (fetchError) {
54+
if (axios.isAxiosError(fetchError)) {
55+
if (fetchError.response) {
56+
core.error(`Failed to fetch building block run: ${JSON.stringify(fetchError.response.data)}`);
57+
core.error(`Status code: ${fetchError.response.status}`);
58+
} else {
59+
core.error(`Fetch error message: ${fetchError.message}`);
60+
}
61+
} else {
62+
core.error(`Unexpected error during fetch: ${fetchError}`);
63+
}
64+
throw fetchError;
65+
}
66+
} else {
67+
// Use buildingBlockRun from GitHub event payload
68+
core.debug('Using buildingBlockRun from GitHub event payload');
69+
const buildingBlockRun = github.context.payload.inputs.buildingBlockRun;
70+
core.debug(`Building Block Run: ${buildingBlockRun}`);
1371

14-
// Extract buildingBlockRun from the GitHub event payload
15-
const buildingBlockRun = github.context.payload.inputs.buildingBlockRun;
16-
core.debug(`Building Block Run: ${buildingBlockRun}`);
72+
if (!buildingBlockRun) {
73+
throw new Error('Neither buildingBlockRunUrl input nor buildingBlockRun payload provided');
74+
}
75+
76+
// Decode and parse the buildingBlockRun input
77+
const decodedBuildingBlockRun = Buffer.from(buildingBlockRun, 'base64').toString('utf-8');
78+
buildingBlockRunJson = JSON.parse(decodedBuildingBlockRun);
79+
}
1780

18-
// Decode and parse the buildingBlockRun input
19-
const decodedBuildingBlockRun = Buffer.from(buildingBlockRun, 'base64').toString('utf-8');
20-
const buildingBlockRunJson = JSON.parse(decodedBuildingBlockRun);
21-
const bbRunUuid = buildingBlockRunJson.metadata.uuid;
22-
const baseUrl = buildingBlockRunJson._links.meshstackBaseUrl.href;
23-
const inputs = buildingBlockRunJson.spec.buildingBlock.spec.inputs;
81+
// Extract common data from buildingBlockRunJson
82+
bbRunUuid = buildingBlockRunJson.metadata.uuid;
83+
baseUrl = buildingBlockRunJson._links.meshstackBaseUrl.href;
84+
inputs = buildingBlockRunJson.spec.buildingBlock.spec.inputs;
2485

2586
core.debug(`Base URL: ${baseUrl}`);
2687
core.debug(`BB Run UUID: ${bbRunUuid}`);

tests/token.test.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,119 @@ describe('register-source token file reading', () => {
113113
assert(expectedPath.includes(tempDir));
114114
});
115115
});
116+
117+
describe('building block run parsing from URL vs payload', () => {
118+
const mockBuildingBlockRun = {
119+
kind: 'meshBuildingBlockRun',
120+
apiVersion: 'v1',
121+
metadata: {
122+
uuid: 'b3116611-e08b-4b00-91c5-10365b25a6ef'
123+
},
124+
spec: {
125+
runNumber: 1,
126+
buildingBlock: {
127+
uuid: '68ce5455-2a4a-4a4b-a324-6a6c18cab85a',
128+
spec: {
129+
displayName: 'block',
130+
workspaceIdentifier: 'my-workspace',
131+
projectIdentifier: 'my-project',
132+
fullPlatformIdentifier: 'my-platform.my-location',
133+
inputs: [
134+
{
135+
key: 'variable-name',
136+
value: 'some-value',
137+
type: 'STRING',
138+
isSensitive: false,
139+
isEnvironment: false
140+
}
141+
],
142+
parentBuildingBlocks: []
143+
}
144+
},
145+
buildingBlockDefinition: {
146+
uuid: 'b23cfb9a-6974-444f-9d33-62134a632373',
147+
spec: {
148+
version: 1,
149+
implementation: {
150+
type: 'TERRAFORM',
151+
terraformVersion: 'v1',
152+
repositoryUrl: 'https://example.com',
153+
async: true,
154+
useMeshHttpBackendFallback: false
155+
}
156+
}
157+
},
158+
behavior: 'APPLY'
159+
},
160+
status: 'IN_PROGRESS',
161+
_links: {
162+
self: {
163+
href: 'https://mesh-backend-url/api/meshobjects/meshbuildingblockruns/b3116611-e08b-4b00-91c5-10365b25a6ef'
164+
},
165+
registerSource: {
166+
href: 'https://mesh-backend-url/api/meshobjects/meshbuildingblockruns/b3116611-e08b-4b00-91c5-10365b25a6ef/status/source'
167+
},
168+
updateSource: {
169+
href: 'https://mesh-backend-url/api/meshobjects/meshbuildingblockruns/b3116611-e08b-4b00-91c5-10365b25a6ef/status/source/{sourceId}',
170+
templated: true
171+
},
172+
meshstackBaseUrl: {
173+
href: 'https://mesh-backend-url'
174+
}
175+
}
176+
};
177+
178+
it('should extract uuid from building block run', () => {
179+
const uuid = mockBuildingBlockRun.metadata.uuid;
180+
assert.strictEqual(uuid, 'b3116611-e08b-4b00-91c5-10365b25a6ef');
181+
});
182+
183+
it('should extract base URL from building block run', () => {
184+
const baseUrl = mockBuildingBlockRun._links.meshstackBaseUrl.href;
185+
assert.strictEqual(baseUrl, 'https://mesh-backend-url');
186+
});
187+
188+
it('should extract inputs from building block spec', () => {
189+
const inputs = mockBuildingBlockRun.spec.buildingBlock.spec.inputs;
190+
assert.strictEqual(inputs.length, 1);
191+
assert.strictEqual(inputs[0].key, 'variable-name');
192+
assert.strictEqual(inputs[0].value, 'some-value');
193+
});
194+
195+
it('should encode building block run as base64 for payload', () => {
196+
const encoded = Buffer.from(JSON.stringify(mockBuildingBlockRun)).toString('base64');
197+
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
198+
const parsed = JSON.parse(decoded);
199+
200+
assert.strictEqual(parsed.metadata.uuid, mockBuildingBlockRun.metadata.uuid);
201+
assert.strictEqual(parsed._links.meshstackBaseUrl.href, mockBuildingBlockRun._links.meshstackBaseUrl.href);
202+
});
203+
204+
it('should handle multiple inputs in building block spec', () => {
205+
const multiInputRun = {
206+
...mockBuildingBlockRun,
207+
spec: {
208+
...mockBuildingBlockRun.spec,
209+
buildingBlock: {
210+
...mockBuildingBlockRun.spec.buildingBlock,
211+
spec: {
212+
...mockBuildingBlockRun.spec.buildingBlock.spec,
213+
inputs: [
214+
{ key: 'input1', value: 'value1', type: 'STRING', isSensitive: false, isEnvironment: false },
215+
{ key: 'input2', value: 'value2', type: 'STRING', isSensitive: false, isEnvironment: false },
216+
{ key: 'input3', value: 'value3', type: 'STRING', isSensitive: false, isEnvironment: false }
217+
]
218+
}
219+
}
220+
}
221+
};
222+
223+
const inputs = multiInputRun.spec.buildingBlock.spec.inputs;
224+
assert.strictEqual(inputs.length, 3);
225+
assert.strictEqual(inputs[0].key, 'input1');
226+
assert.strictEqual(inputs[1].key, 'input2');
227+
assert.strictEqual(inputs[2].key, 'input3');
228+
});
229+
});
116230
});
231+

0 commit comments

Comments
 (0)