Skip to content

Commit

Permalink
ci: migrate fusion app management v2 pipelines (#1165)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustav-Eikaas authored Nov 6, 2024
1 parent 65480d7 commit 1ce2cf7
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/manual-deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ jobs:
env:
#Public hosted runners has 16GB available (linux | windows runners)
NODE_OPTIONS: "--max_old_space_size=12288"
run: npx turbo run fprd:deploy --filter=${{inputs.appKey}} --concurrency 4 --token ${{ steps.get-fusion-token.outputs.token }} --ai '${{secrets.ai}}' --modelViewerConfig '${{vars.modelViewerConfig}}' --sha '${{github.sha}}'
run: npx turbo run fprd:deploy --filter='${{inputs.appKey}}' --concurrency 4 -- --token ${{ steps.get-fusion-token.outputs.token }} --ai '${{secrets.ai}}' --modelViewerConfig '${{vars.modelViewerConfig}}' --sha '${{github.sha}}'
10 changes: 7 additions & 3 deletions github-action/src/releaseMain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env node
import { HttpClient } from '@actions/http-client';
import { readdirSync } from 'fs';
import { Command } from 'commander';
import { setSecret, warning } from '@actions/core';
Expand All @@ -10,8 +11,9 @@ import { zipBundle } from './utils/zipBundle.js';
import { uploadBundle } from './utils/uploadBundle.js';
import { patchAppConfig } from './utils/patchAppConfig.js';
import { execSync } from 'child_process';
import { getVersion } from './utils/bumpVersion.js';

const prodUrl = 'https://fusion-s-portal-fprd.azurewebsites.net';
const prodUrl = 'https://apps.api.fusion.equinor.com';

const program = new Command();

Expand Down Expand Up @@ -47,6 +49,7 @@ program

await program.parseAsync();


export async function release(config: ReleaseArgs) {
const pkg = parsePackageJson();
if (!pkg.name) {
Expand All @@ -62,11 +65,12 @@ export async function release(config: ReleaseArgs) {

prepareBundle();

makeManifest('./package.json');
const version = await getVersion(prodUrl, config.token, pkg.name);
makeManifest('./package.json', version, config.sha);

const zipped = zipBundle();

await uploadBundle(prodUrl, config.token, pkg.name, zipped);
await uploadBundle(prodUrl, config.token, pkg.name, zipped, version);
await patchAppConfig(
{
ai: config.ai,
Expand Down
21 changes: 13 additions & 8 deletions github-action/src/releasePr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { zipBundle } from './utils/zipBundle.js';
import { uploadBundle } from './utils/uploadBundle.js';
import { patchAppConfig } from './utils/patchAppConfig.js';
import { execSync } from 'child_process';
import { getVersion } from './utils/bumpVersion.js';

const ciUrl = 'https://fusion-s-portal-ci.azurewebsites.net';
const ciUrl = 'https://apps.ci.api.fusion-dev.net';

const program = new Command();

Expand Down Expand Up @@ -49,15 +50,17 @@ await program.parseAsync();

export async function release(context: ReleaseArgs) {
prepareBundle();
makeManifest('./package.json');
const zipped = zipBundle();
const r = parsePackageJson();
if (!r.name) {
const pkg = parsePackageJson();
if (!pkg.name) {
throw new Error(
`No name in package json, cannot deploy unknown app at path ${process.cwd()}`
);
}
await uploadBundle(ciUrl, context.token, r.name, zipped);

const version = await getVersion(ciUrl, context.token, pkg.name);
makeManifest('./package.json', version, context.sha);
const zipped = zipBundle();
await uploadBundle(ciUrl, context.token, pkg.name, zipped, version);
await patchAppConfig(
{
ai: context.ai,
Expand All @@ -66,9 +69,11 @@ export async function release(context: ReleaseArgs) {
modelViewerConfig: JSON.parse(context.modelViewerConfig),
},
context.token,
r.name,
pkg.name,
ciUrl
);

execSync(`echo '## ${r.name}' >> $GITHUB_STEP_SUMMARY`);
execSync(`echo '## ${pkg.name}' >> $GITHUB_STEP_SUMMARY`);
}


23 changes: 23 additions & 0 deletions github-action/src/utils/bumpVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { HttpClient } from '@actions/http-client';

// We do not use semver and dont want to manually bump versions.
// For now we ask the server what the latest version is and bump the patch version
export async function getVersion(ciUrl: string, token: string, name: string) {
const client = new HttpClient();
const response = await client.get(`${ciUrl}/apps/${name}?api-version=1.0`, {
['Authorization']: `Bearer ${token}`,
});
const body = await response.readBody();
const json = JSON.parse(body);
const v = incrementPatchVersion(json.build.version);
return v;
}

function incrementPatchVersion(semver: string) {
const parts = semver.split('.');
if (parts.length !== 3) {
throw new Error('Invalid semver format: ' + semver);
}
const patch = parseInt(parts[2], 10) + 1;
return `${parts[0]}.${parts[1]}.${patch}`;
}
35 changes: 9 additions & 26 deletions github-action/src/utils/makeManifest.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,24 @@
import { parsePackageJson } from './parsePackageJson.js';
import fs from 'fs';
import { notice } from '@actions/core';

export function makeManifest(path: string) {
export function makeManifest(path: string, version: string, sha: string) {
// Create manifest
notice('making manifest');
const { version, name, ...maybe } = parsePackageJson(path);
const { name } = parsePackageJson(path);
if (!version || !name) {
throw new Error('Name or version missing in package.json');
}
const { major, minor, patch } = splitVersions(version);

/** Some app-manifests have custom short and displaynames */
const shortName = maybe?.['shortName'] ?? name;
const displayName = maybe?.['displayName'] ?? name[0].toUpperCase() + name.slice(1);

const manifest = {
name: displayName,
shortName: shortName,
key: name,
version: {
major: major,
minor: minor,
patch: patch,
},
//required
entryPoint: "app-bundle.js",
//required
version: version,
githubRepo: "https://github.com/equinor/cc-components",
timestamp: new Date().toISOString(),
commitSha: sha,
};

const data = JSON.stringify(manifest, null, 2);

fs.writeFileSync('./dist/app-manifest.json', data);
}

function splitVersions(version: string) {
const [major, minor, patch] = version.split('.');
return {
major,
minor,
patch,
};
}
4 changes: 2 additions & 2 deletions github-action/src/utils/patchAppConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function getAppConfig(token: string, appKey: string, url: string) {
['Content-Type']: 'application/json',
};

const res = await client.get(`${url}/api/apps/${appKey}/config`, headers);
const res = await client.get(`${url}/apps/${appKey}/builds/latest/config`, headers);
if (res.message.statusCode !== 200) {
logInfo(`Failed to fetch client config, Code: ${res.message.statusCode}`, 'Red');
throw new Error('Failed to fetch client config');
Expand Down Expand Up @@ -49,7 +49,7 @@ export async function patchAppConfig<T extends Record<PropertyKey, unknown> = {}

//patch
const patchResponse = await client.put(
`${url}/api/apps/${appKey}/config`,
`${url}/apps/${appKey}/builds/latest/config`,
JSON.stringify(existingConfig),
headers
);
Expand Down
53 changes: 19 additions & 34 deletions github-action/src/utils/uploadBundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,48 @@ export async function uploadBundle(
baseUrl: string,
token: string,
appKey: string,
zipped: AdmZip
zipped: AdmZip,
version: string
) {
const client = new HttpClient();

await ensureAppExists(baseUrl, token, appKey);

const headers: OutgoingHttpHeaders = {
['Authorization']: `Bearer ${token}`,
['Content-Type']: 'application/zip',
['Content-Disposition']: 'attachment; filename=bundle.zip',
};

const stream = Readable.from(zipped.toBuffer());

logInfo(`Sending payload to ${baseUrl}/bundles/apps/${appKey}`, "Green");
const r = await client.sendStream(
'POST',
`${baseUrl}/api/apps/${appKey}/versions`,
`${baseUrl}/bundles/apps/${appKey}`,
stream,
headers
);

notice(`bundle uploaded with status code ${r.message.statusCode}`);
if (r.message.statusCode !== 200) {
notice(`${appKey} bundle uploaded with status code ${r.message.statusCode}`);
if (r.message.statusCode !== 201) {
const body = await r.readBody()
logInfo(`Failed to upload ${appKey}, code: ${r.message.statusCode}`, 'Red');
logInfo(body, 'Red');
throw new Error('Bundle failed to upload, fatal error');
}

/** Publish bundle */
const publishResponse = await client.post(
`${baseUrl}/api/apps/${appKey}/publish`,
'',
headers
const publishResponse = await client.put(
`${baseUrl}/apps/${appKey}/tags/latest`,
JSON.stringify({ version: version }),
{
['Authorization']: `Bearer ${token}`,
["Content-Type"]: 'application/json',
}
);

if (publishResponse.message.statusCode !== 200) {
logInfo(`Failed to publish ${appKey}, code: ${r.message.statusCode}`, 'Red');
throw new Error(JSON.stringify(publishResponse.message));
logInfo(`Failed to publish ${appKey}, code: ${publishResponse.message.statusCode}`, 'Red');
const body = await publishResponse.readBody()
throw new Error(body)
}
logInfo(`Sucessfully published ${appKey}`, 'Green');
}

async function ensureAppExists(baseUrl: string, token: string, appKey: string) {
const client = new HttpClient();

const headers: OutgoingHttpHeaders = {
['Authorization']: `Bearer ${token}`,
['Content-Type']: 'application/zip',
};

const res = await client.get(
`${baseUrl}/api/admin/apps/${appKey}/versions?api-version=1.0`,
headers
);

if (res.message.statusCode === 404) {
logInfo(`Unknown app: ${appKey}`, 'Red');
throw new Error(
'App doesnt exist please use the manual create fusion app to create this app first'
);
}
}
5 changes: 2 additions & 3 deletions github-action/src/utils/zipBundle.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { resolve } from 'path';
import AdmZip from 'adm-zip';
import { notice } from '@actions/core';

export function zipBundle() {
// zip bundle
notice('zipping bundle');
const appManifestPath = resolve('./dist/app-manifest.json');
const bundlePath = resolve('./dist/app-bundle.js');
const packageJsonPath = resolve('./package.json');

var zip = new AdmZip();

//TODO: scan files in package.json
zip.addLocalFile(appManifestPath);
zip.addLocalFile(bundlePath);
zip.addLocalFile(packageJsonPath);

zip.writeZip('./dist/bundle.zip');
return zip;
Expand Down

0 comments on commit 1ce2cf7

Please sign in to comment.