Skip to content

Commit

Permalink
build: test action (#459)
Browse files Browse the repository at this point in the history
* build: test action

* feat: changes

* build: test

* chore: te

* build: wildcard

* build: tes

* test: t

* chore: te

* chore: t

* ci: tt

* ci: t

* ci: t

* ci: test internal action

* ci: try remove unnecessary actions

* ci: fix args

* ci: try to avoid bundling action

* ci: only build since main

* ci: try to figure out what main is

* ci: improve debugging experience

* ci: fix build

* ci: try trigger on pull request only

* ci: try trigger

* ci: update logging

* ci: test deploy app

* ci: test

* ci: update action

* ci: t

* ci: t

* ci: update logging

* ci: update turbo json

* ci: tes

* ci: messing with args

* ci:

* ci:

t

* ci:

* ci:

* ci:

* ci:

* ci:

* ci:

* ci: update action

* ci: install tsc global in gh action

* ci: try debug

* ci: update script

* ci: 💚

* ci: test

* ci:

* ci: 💚 finally fixed it

* ci:

* ci:

* ci:

* ci:

* ci:

* ci: update with token

* ci:

* ci: add content type to headers

* ci: read pr from github action

* ci: update pr label

* ci: rename workflows and actions to something reasonable

* ci: fix pr label

* ci: test publishing

* ci: test checks with label

* ci: update tsconfig.json

* ci: github event test

* ci: remove log
  • Loading branch information
Gustav-Eikaas committed Aug 11, 2023
1 parent 3c244d1 commit 27e80a3
Show file tree
Hide file tree
Showing 26 changed files with 614 additions and 28 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/pr-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: 'Deploy PR build'
on:
pull_request:
branches:
- main

permissions: write-all
jobs:
aquire-token:
if: contains(github.event.pull_request.labels.*.name, 'QA Required')
runs-on: ubuntu-latest
steps:
- name: 'Login to Azure'
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
allow-no-subscriptions: true

- name: 'Obtain token for upload'
shell: bash
run: echo "FUSION_TOKEN=$(az account get-access-token --resource '${{ secrets.AZURE_RESOURCE_ID }}' | jq '.accessToken')" >> $GITHUB_ENV

- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # Required to fetch range

- name: Install Dependencies
run: npm i -g pnpm typescript && pnpm i

- name: Build monorepo
run: pnpm ci:build

- name: 'Deploy affected apps to Fusion'
shell: bash
run: npx turbo run pr:deploy --since origin/main -- --token ${{ env.FUSION_TOKEN }} --pr ${{ github.event.number }}
3 changes: 2 additions & 1 deletion apps/handover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"scripts": {
"dev": "fusion-framework-cli app dev",
"build": "tsc -b -f",
"shipit": "npx ts-node --esm ../../cli/src/main.ts release"
"shipit": "npx ts-node --esm ../../cli/src/main.ts release",
"pr:deploy": "npx ts-node --esm ../../github-action/src/releasePr.ts release"
},
"dependencies": {
"@cc-components/handoverapp": "workspace:^",
Expand Down
3 changes: 2 additions & 1 deletion apps/workorder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"dev": "fusion-framework-cli app dev",
"build": "tsc -b -f",
"shipit": "npx ts-node --esm ../../cli/src/main.ts release"
"shipit": "npx ts-node --esm ../../cli/src/main.ts release",
"pr:deploy": "npx ts-node --esm ../../github-action/src/releasePr.ts release"
},
"dependencies": {
"@cc-components/shared": "workspace:^",
Expand Down
1 change: 1 addition & 0 deletions apps/workorder/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ const WorkorderApp = () => {
};

export const render = createRender(WorkorderApp, configure, 'Workorder');

export default render;
1 change: 1 addition & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"build": "tsc -b -f"
},
"dependencies": {
"@actions/http-client": "^2.1.1",
"adm-zip": "^0.5.10",
"commander": "^10.0.1",
"open": "^9.1.0",
Expand Down
58 changes: 58 additions & 0 deletions cli/src/commands/releasePr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { zipBundle } from './zip-bundle.js';
import { makeManifest } from './make-app-manifest.js';
import { FusionEnvironment, deployApp } from '../utils/deployApp.js';
import { logBundleSize } from '../utils/logBundleSize.js';
import { bundleApp } from '../utils/bundleApp.js';
import { compileApp } from '../utils/compile.js';
import ora from 'ora';
import { downloadCIBundle } from './download_zip_bundle.js';
import { parsePackageJson } from '../utils/parsePackageJson.js';
import { chdir, cwd } from 'process';
import { execSync } from 'child_process';

export async function releasePr() {
compileApp();

await ensureProjectBuilds();

//Vite build
await prepareBundle('ci');

// Create manifest
makeManifest('./package.json');

//Log bundle size
logBundleSize();

//zip bundle
zipBundle();

//upload to fdev
await deployApp('ci');
}

async function prepareBundle(env: FusionEnvironment) {
const { name } = parsePackageJson();
if (!name) {
throw new Error('Missing name in package.json');
}
switch (env) {
case 'ci':
case 'fqa':
return bundleApp();

case 'fprd':
console.log('Download ci bundle');
return downloadCIBundle(name);
}
}

async function ensureProjectBuilds() {
const spinner = ora('Building project').start();
const appDir = cwd();
const rootDir = '../../';
chdir(rootDir);
execSync(`pnpm ci:build`);
chdir(appDir);
spinner.stop();
}
19 changes: 19 additions & 0 deletions github-action/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "github-action",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"adm-zip": "^0.5.10",
"commander": "11.0.0"
}
}
12 changes: 12 additions & 0 deletions github-action/src/parsePackageJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import fs from 'fs';

export type PackageJson = {
name?: string;
version?: string;
type?: 'module' | 'commonjs';
} & Record<string, any>;

export function parsePackageJson(path: string = './package.json'): PackageJson {
const blob = fs.readFileSync(path);
return JSON.parse(blob.toString('utf-8'));
}
185 changes: 185 additions & 0 deletions github-action/src/releasePr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env node

import { Command } from 'commander';
import fs from 'fs';
import { execSync } from 'child_process';
import { parsePackageJson } from './parsePackageJson.js';
import { resolve } from 'path';
import AdmZip from 'adm-zip';
import { HttpClient } from '@actions/http-client';
import { OutgoingHttpHeaders } from 'http';
import { Readable } from 'stream';
import { notice, setSecret } from '@actions/core';

const program = new Command();

program.name('Release');

program
.command('release')
.option('-T, --token <token>', 'change the working directory')
.option('-pr --pr <pr>', 'Pr number')
.action(async (args) => {
if (!args.token) {
throw new Error('Missing az token');
}
setSecret(args.token);
release(args.token, args.pr);
});

await program.parseAsync();

export async function release(token: string, prNumber: string) {
// Vite build
notice('bundling application');
prepareBundle();

// Create manifest
notice('making manifest');
makeManifest('./package.json');

// zip bundle
notice('zipping bundle');
const zipped = zipBundle();

const r = parsePackageJson();
if (!r.name) {
throw new Error(
`No name in package json, cannot deploy unknown app at path ${process.cwd()}`
);
}

await uploadBundle(token, r.name, zipped, prNumber);
}

async function uploadBundle(
token: string,
appKey: string,
zipped: AdmZip,
prNumber: string
) {
const client = new HttpClient();

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

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

const r = await client.sendStream(
'POST',
`https://fusion-s-portal-ci.azurewebsites.net/api/apps/${appKey}/versions`,
stream,
headers
);

notice(`bundle uploaded with status code ${r.message.statusCode}`);
if (r.message.statusCode !== 200) {
throw new Error('Bundle failed to upload, fatal error');
}

/** Publish bundle */
const publishResponse = await client.post(
`https://fusion-s-portal-ci.azurewebsites.net/api/apps/${appKey}/publish`,
'',
headers
);
if (publishResponse.message.statusCode !== 200) {
throw new Error(JSON.stringify(publishResponse.message));
}

await patchWithPrNumber(prNumber, token, appKey);
}

function prepareBundle() {
const { name } = parsePackageJson();
if (!name) {
throw new Error('Missing name in package.json');
}
execSync('npx vite build --logLevel silent', { stdio: 'inherit' });
}

export function makeManifest(path: string) {
const { version, name, ...maybe } = 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,
},
};

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,
};
}

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

var zip = new AdmZip();

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

zip.writeZip('./dist/bundle.zip');
return zip;
}

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

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

//Download current config
const res = await client.get(
`https://fusion-s-portal-ci.azurewebsites.net/api/apps/${appKey}/config`,
headers
);
if (res.message.statusCode !== 200) {
throw new Error('Failed to fetch client config');
}
const config = JSON.parse(await res.readBody());
config.environment = { ...config.environment, pr: prNumber };
//append pr

//patch
const patchResponse = await client.put(
`https://fusion-s-portal-ci.azurewebsites.net/api/apps/${appKey}/config`,
JSON.stringify(config),
headers
);
if (patchResponse.message.statusCode !== 200) {
throw new Error(
`Failed to patch client config with pr number, ${await patchResponse.readBody()}`
);
}
}
19 changes: 19 additions & 0 deletions github-action/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "ESNext",
"module": "ESNext",
"lib": ["ES2022", "dom"],
"skipLibCheck": true,
"resolveJsonModule": true,
"skipDefaultLibCheck": true,
"allowSyntheticDefaultImports": true,
"outDir": "script"
},
"exclude": ["node_modules"]
}
6 changes: 6 additions & 0 deletions libs/handoverapp/src/lib/config/frameworkConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export const configure = async (config: IAppConfigurator, c: ComponentRenderArgs

const envConfig: HandoverEnvConfig = c.env.config?.environment as HandoverEnvConfig;

if (envConfig.pr) {
console.log(`Lets fucking go pr#${envConfig.pr}`);
console.log(`https://github.com/equinor/cc-components/pull/${envConfig.pr}`);
}

if (!envConfig.uri) {
throw new Error('Failed to load environemnt config for workorder');
}
Expand All @@ -37,4 +42,5 @@ export const configure = async (config: IAppConfigurator, c: ComponentRenderArgs
type HandoverEnvConfig = {
uri: string;
defaultScopes: string[];
pr?: string;
};
2 changes: 1 addition & 1 deletion libs/handoverapp/src/lib/config/gardenConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const useGardenConfig = (
customHeaderView: GardenHeader,
},
visuals: {
rowHeight: 30,
rowHeight: 31,
},
};
};
Loading

0 comments on commit 27e80a3

Please sign in to comment.