From b972ad05e495c7e951abf3ca4df0992c30c8df76 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 4 Feb 2025 11:27:31 -0500 Subject: [PATCH 1/4] feat: improve packing --- api/scripts/build.mjs | 65 +++++++++++++---------- api/src/graphql/generated/client/gql.ts | 4 +- api/src/graphql/generated/client/index.ts | 4 +- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/api/scripts/build.mjs b/api/scripts/build.mjs index 248ffabb6f..3654d55a9e 100755 --- a/api/scripts/build.mjs +++ b/api/scripts/build.mjs @@ -1,10 +1,13 @@ #!/usr/bin/env zx +import { cp, mkdir, writeFile } from 'fs/promises'; import { exit } from 'process'; -import { cd, $ } from 'zx'; + +import { $, cd } from 'zx'; import { getDeploymentVersion } from './get-deployment-version.mjs'; try { + // Enable colours in output process.env.FORCE_COLOR = '1'; @@ -12,20 +15,17 @@ try { process.env.WORKDIR ??= process.env.PWD; cd(process.env.WORKDIR); + await $`rm -rf ./deploy/*`; // Create deployment directories - ignore if they already exist - await $`mkdir -p ./deploy/release`; - await $`mkdir -p ./deploy/pre-pack`; - - await $`rm -rf ./deploy/release/*`; - await $`rm -rf ./deploy/pre-pack/*`; + await mkdir('./deploy/release', { recursive: true }); + await mkdir('./deploy/pre-pack', { recursive: true }); // Build Generated Types await $`npm run codegen`; await $`npm run build`; // Copy app files to plugin directory - await $`cp -r ./src/ ./deploy/pre-pack/src/`; - await $`cp -r ./dist/ ./deploy/pre-pack/dist/`; + await cp('./dist', './deploy/pre-pack/dist', { recursive: true }); // Copy environment to deployment directory const files = [ @@ -35,10 +35,10 @@ try { 'codegen.ts', 'ecosystem.config.json', 'vite.config.ts', - ] + ]; for (const file of files) { - await $`cp ./${file} ./deploy/pre-pack/${file}`; + await cp(`./${file}`, `./deploy/pre-pack/${file}`); } // Get package details @@ -49,28 +49,39 @@ try { const deploymentVersion = getDeploymentVersion(process.env, version); // Create deployment package.json - await $`echo ${JSON.stringify({ - ...rest, - name, - version: deploymentVersion, - })} > ./deploy/pre-pack/package.json`; - + await writeFile( + './deploy/pre-pack/package.json', + JSON.stringify( + { + name, + version: deploymentVersion, + ...rest, + }, + null, + 2 + ) + ); // # Create final tgz - await $`cp ./README.md ./deploy/pre-pack/`; + await cp('./README.md', './deploy/pre-pack/README.md'); + + await cp('./node_modules', './deploy/pre-pack/node_modules', { recursive: true }); + // Install production dependencies + + console.log('Installing dependencies...'); - await $`cp -r ./node_modules ./deploy/pre-pack/node_modules`; - // Install production dependencies - cd('./deploy/pre-pack'); + $.verbose = true; + await $`npm --prefix ./deploy/pre-pack prune --omit=dev`; + await $`npm --prefix ./deploy/pre-pack install --omit=dev`; - await $`npm prune --omit=dev`; - await $`npm install --omit=dev`; - await $`npm install github:unraid/libvirt`; + // Ensure that we don't have any dev dependencies left + console.log('Installed dependencies:'); + await $`npm --prefix ./deploy/pre-pack ls --omit=dev --depth=0`; - // Now we'll pack everything in the pre-pack directory - await $`tar -czf ../unraid-api-${deploymentVersion}.tgz .`; + console.log('Dependencies installed, packing...'); - // Move unraid-api.tgz to release directory - await $`mv ../unraid-api-${deploymentVersion}.tgz ../release`; + // Now we'll pack everything in the pre-pack directory to the release directory + await $`tar -czf ./deploy/release/unraid-api-${deploymentVersion}.tgz ./deploy/pre-pack/`; + console.log('Packing complete, build finished.'); } catch (error) { // Error with a command if (Object.keys(error).includes('stderr')) { diff --git a/api/src/graphql/generated/client/gql.ts b/api/src/graphql/generated/client/gql.ts index c01d48e701..3e879b5c8c 100644 --- a/api/src/graphql/generated/client/gql.ts +++ b/api/src/graphql/generated/client/gql.ts @@ -15,7 +15,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- */ const documents = { "\n mutation sendRemoteGraphQLResponse($input: RemoteGraphQLServerInput!) {\n remoteGraphQLResponse(input: $input)\n }\n": types.sendRemoteGraphQLResponseDocument, - "\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n": types.RemoteGraphQLEventFragmentFragmentDoc, + "\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n": types.RemoteGraphQLEventFragmentFragmentDoc, "\n subscription events {\n events {\n __typename\n ... on ClientConnectedEvent {\n connectedData: data {\n type\n version\n apiKey\n }\n connectedEvent: type\n }\n ... on ClientDisconnectedEvent {\n disconnectedData: data {\n type\n version\n apiKey\n }\n disconnectedEvent: type\n }\n ...RemoteGraphQLEventFragment\n }\n }\n": types.eventsDocument, }; @@ -40,7 +40,7 @@ export function graphql(source: "\n mutation sendRemoteGraphQLResponse($input /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n"): (typeof documents)["\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n"]; +export function graphql(source: "\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n"): (typeof documents)["\n fragment RemoteGraphQLEventFragment on RemoteGraphQLEvent {\n remoteGraphQLEventData: data {\n type\n body\n sha256\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/api/src/graphql/generated/client/index.ts b/api/src/graphql/generated/client/index.ts index 873144cb2c..6cf863446e 100644 --- a/api/src/graphql/generated/client/index.ts +++ b/api/src/graphql/generated/client/index.ts @@ -1,2 +1,2 @@ -export * from './fragment-masking.js'; -export * from './gql.js'; +export * from "./fragment-masking.js"; +export * from "./gql.js"; \ No newline at end of file From d509b2bdf7de1f4f8db1e258d122b7449823f9dc Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 4 Feb 2025 11:41:04 -0500 Subject: [PATCH 2/4] feat: log size and only tar files --- api/scripts/build.mjs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/api/scripts/build.mjs b/api/scripts/build.mjs index 3654d55a9e..5e1a74903b 100755 --- a/api/scripts/build.mjs +++ b/api/scripts/build.mjs @@ -1,5 +1,6 @@ #!/usr/bin/env zx -import { cp, mkdir, writeFile } from 'fs/promises'; +import { cp, mkdir, writeFile, stat } from 'fs/promises'; +import { pathExists } from 'fs-extra'; import { exit } from 'process'; import { $, cd } from 'zx'; @@ -7,7 +8,6 @@ import { $, cd } from 'zx'; import { getDeploymentVersion } from './get-deployment-version.mjs'; try { - // Enable colours in output process.env.FORCE_COLOR = '1'; @@ -80,8 +80,18 @@ try { console.log('Dependencies installed, packing...'); // Now we'll pack everything in the pre-pack directory to the release directory - await $`tar -czf ./deploy/release/unraid-api-${deploymentVersion}.tgz ./deploy/pre-pack/`; - console.log('Packing complete, build finished.'); + await cd('./deploy/pre-pack'); + const tarballPath = `../release/unraid-api-${deploymentVersion}.tgz`; + await $`tar -czf ${tarballPath} .`; + // Ensure the tarball exists + if (!(await pathExists(tarballPath))) { + console.error(`Failed to create tarball at ${tarballPath}`); + process.exit(1); + } + const packageSize = Math.round((await stat(tarballPath)).size / 1024 / 1024); + console.log( + `Package created at: ${tarballPath} with size ${packageSize} MB` + ); } catch (error) { // Error with a command if (Object.keys(error).includes('stderr')) { From 21906a4591f8e3a18feefbace7f5e3953fae6027 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 4 Feb 2025 11:58:00 -0500 Subject: [PATCH 3/4] feat: ignore generated code --- api/.eslintrc.ts | 1 + api/.prettierignore | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/api/.eslintrc.ts b/api/.eslintrc.ts index 138e5d54bb..a2930a3239 100644 --- a/api/.eslintrc.ts +++ b/api/.eslintrc.ts @@ -31,4 +31,5 @@ export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.r ], 'prettier/prettier': 'error', }, + ignores: ['src/graphql/generated/client/**/*'], }); diff --git a/api/.prettierignore b/api/.prettierignore index 29efe68b23..6ef230e8a2 100644 --- a/api/.prettierignore +++ b/api/.prettierignore @@ -1,4 +1,7 @@ !src/* # Downloaded Fixtures (For File Modifications) -src/unraid-api/unraid-file-modifier/modifications/__fixtures__/downloaded/* \ No newline at end of file +src/unraid-api/unraid-file-modifier/modifications/__fixtures__/downloaded/* + +# Generated Types +src/graphql/generated/client/*.ts From 835bc0418c80b8636b6ac0db6313fc7e6e99bab7 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 4 Feb 2025 12:05:13 -0500 Subject: [PATCH 4/4] fix: resource busy when removing all subdirectories --- api/scripts/build.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/scripts/build.mjs b/api/scripts/build.mjs index 5e1a74903b..7abc0b7842 100755 --- a/api/scripts/build.mjs +++ b/api/scripts/build.mjs @@ -15,7 +15,8 @@ try { process.env.WORKDIR ??= process.env.PWD; cd(process.env.WORKDIR); - await $`rm -rf ./deploy/*`; + await $`rm -rf ./deploy/release/*`; + await $`rm -rf ./deploy/pre-pack/*`; // Create deployment directories - ignore if they already exist await mkdir('./deploy/release', { recursive: true }); await mkdir('./deploy/pre-pack', { recursive: true });