Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions 7452: Bundling and uploading wasm file to GCS for function extension #4445

Merged
merged 7 commits into from
Oct 8, 2024

Conversation

saga-dasgupta
Copy link
Contributor

@saga-dasgupta saga-dasgupta commented Sep 12, 2024

Issue: https://github.com/Shopify/script-service/issues/7452

WHY are these changes introduced?

To have a consistent way of uploading and obtaining extension data is core using the App Module Framework.

WHAT is this pull request doing?

This PR adds the "bundling" feature to functions and sets the output path for compilation to the bundle directory to ensure the wasm file generated is zipped and uploaded to GCS like every other extension.

The deployment plan is:
This version of CLI goes out which bundles the wasm file and uploads it (existing wasm blob upload stays in place).
Then on Core's side we verify we are able to obtain the wasm content and upload it to our runtime-engine bucket. Then we come back here and delete the uploadWasmBlob path and in core we throw an error when we fail to upload. TLDR: existing upload path stays in place till we can verify new path works.

How to test your changes?

Tophat this normally from your local computer since core changes are out. Run cli for dev and deploy both for an app with functions

Post-release steps

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
  • Existing analytics will cater for this addition
  • PR includes analytics changes to measure impact

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

Copy link
Contributor

Thanks for your contribution!

Depending on what you are working on, you may want to request a review from a Shopify team:

  • Themes: @shopify/advanced-edits
  • UI extensions: @shopify/ui-extensions-cli
    • Checkout UI extensions: @shopify/checkout-ui-extensions-api-stewardship
  • Hydrogen: @shopify/hydrogen
  • Other: @shopify/app-inner-loop

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch 3 times, most recently from e0c4923 to 8c1179a Compare September 13, 2024 16:26
}

await this.build(options)

if (this.isFunctionExtension) {
await copyFile(this.outputPath, joinPath(bundleDirectory, extensionId, 'index.wasm'))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying the wasm file generated from the function's dist directory to the bundleDirectory for it to get zipped and uploaded later.

@@ -243,7 +243,7 @@ describe('deploy', () => {
expect(updateAppIdentifiers).toHaveBeenCalledOnce()
})

test('uploads the extension bundle with 1 function', async () => {
test('uploads the extension bundle with 1 function extension', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the test names consistent.

@@ -290,7 +290,7 @@ describe('deploy', () => {
],
developerPlatformClient,
extensionIds: {},
bundlePath: undefined,
bundlePath: expect.stringMatching(/bundle.zip$/),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundle path now has a zip file for functions' assets.

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch 4 times, most recently from 04ce5e5 to c5a48a8 Compare September 17, 2024 16:26
Copy link
Contributor

github-actions bot commented Sep 17, 2024

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
72.67% (-0.06% 🔻)
8540/11751
🟡 Branches
69.64% (-0.06% 🔻)
4196/6025
🟡 Functions
71.73% (+0.02% 🔼)
2207/3077
🟡 Lines
73.01% (-0.06% 🔻)
8084/11073
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / extension-instance.ts
84.85% (-0.55% 🔻)
74.29% (-0.95% 🔻)
90.91% (-0.4% 🔻)
86.29% (-0.43% 🔻)
🔴
... / extension.ts
54.55% (-0.72% 🔻)
50% 57.14%
55.81% (-0.94% 🔻)
🟢
... / upload.ts
80.87% (-3.91% 🔻)
75.41% (-4.59% 🔻)
84.21% (-1.16% 🔻)
81.37% (-4.11% 🔻)
🟢
... / ConcurrentOutput.tsx
98.39% (-1.61% 🔻)
90.91% (-4.55% 🔻)
100%
98.33% (-1.67% 🔻)

Test suite run success

1943 tests passing in 876 suites.

Report generated by 🧪jest coverage report action from 6834807

@saga-dasgupta saga-dasgupta marked this pull request as ready for review September 17, 2024 16:32
Copy link
Contributor

We detected some changes at either packages/*/src or packages/cli-kit/assets/cli-ruby/** and there are no updates in the .changeset.
If the changes are user-facing, run "pnpm changeset add" to track your changes and include them in the next release CHANGELOG.

Copy link
Contributor

@andrewhassan andrewhassan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great! My comments are mostly around Isaac's concerns 😄

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch 2 times, most recently from a53dfe6 to 16a1fca Compare September 20, 2024 20:27
if (extension.isJavaScript) {
await runCommandOrBuildJSFunction(extension, options)
} else {
await buildOtherFunction(extension, options)
}
if (fileExistsSync(extension.outputPath)) {
Copy link
Contributor Author

@saga-dasgupta saga-dasgupta Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to add this if condition because I see there are tests like succeeds when is a JS function and build command is not present so I assume thats the intention.

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch from 16a1fca to c1c12ea Compare September 20, 2024 20:40
@@ -141,11 +142,18 @@ export async function buildFunctionExtension(
}

try {
const bundlePath = joinPath(extension.outputPath.split('/').slice(0, -2).join('/'), 'index.wasm')
extension.outputPath = joinPath(extension.directory, joinPath('dist', 'function.wasm'))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This little dance avoids isFunctionExtension? in build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining why this step is necessary? I'm not totally following 🤔

Copy link
Contributor Author

@saga-dasgupta saga-dasgupta Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, outputPath ends up becoming <bundlepath>/dist/something.js and since <bundlepath>/dist/ does not exists it complains No such file or directory (remember that bundlePath is a /tmp directory). So, I essentially set it to the valid path that exists which is <extension directory>/dist.

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch 2 times, most recently from 4c9da9a to fc66510 Compare September 25, 2024 14:41
packages/app/src/cli/services/build/extension.ts Outdated Show resolved Hide resolved
@@ -141,11 +142,18 @@ export async function buildFunctionExtension(
}

try {
const bundlePath = joinPath(extension.outputPath.split('/').slice(0, -2).join('/'), 'index.wasm')
extension.outputPath = joinPath(extension.directory, joinPath('dist', 'function.wasm'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining why this step is necessary? I'm not totally following 🤔

Comment on lines 194 to 198
async deployConfig({
apiKey,
developerPlatformClient,
appConfiguration,
}: ExtensionDeployConfigOptions): Promise<{[key: string]: unknown} | undefined> {
if (this.isFunctionExtension) return this.functionDeployConfig({apiKey, developerPlatformClient, appConfiguration})
return this.commonDeployConfig(apiKey, appConfiguration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good!!!

I'll ask for one more change, since now deployConfig is basically doing nothing and just calling commonDeployConfig can we unify both?

Have a single deployConfig that does whatever commonDeployConfig does.
And update all calls to commonDeployConfig to call deployConfig instead. Should be straightforward :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, thanks for catching that, it was easy to fix!

Copy link
Contributor

@andrewhassan andrewhassan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't 🎩 but overall the code LGTM! Nice work!

Comment on lines +153 to +155
const base64Contents = await readFile(extension.outputPath, {encoding: 'base64'})
await touchFile(bundlePath)
await writeFile(bundlePath, base64Contents)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use copyFile here instead of reading and writing?

Copy link
Contributor Author

@saga-dasgupta saga-dasgupta Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did have copyFile here before but I need it to be in base64 format inside the bundlePath because code in core expects this to be base64 formatted, so copyFIle which copies file as is doesn't work here.

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch from 4c6bf01 to 43b671e Compare October 7, 2024 14:10
Copy link
Contributor

@isaacroldan isaacroldan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work @saga-dasgupta, thank you so much for all the extra clean up 🙇

@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch from 47477ba to bb7b4f0 Compare October 8, 2024 16:05
@saga-dasgupta saga-dasgupta force-pushed the functions_7452.gcs_upload_solution branch from bb7b4f0 to 6834807 Compare October 8, 2024 17:21
@saga-dasgupta saga-dasgupta added this pull request to the merge queue Oct 8, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 8, 2024
@saga-dasgupta saga-dasgupta added this pull request to the merge queue Oct 8, 2024
@saga-dasgupta saga-dasgupta removed this pull request from the merge queue due to a manual request Oct 8, 2024
@saga-dasgupta saga-dasgupta added this pull request to the merge queue Oct 8, 2024
Merged via the queue into main with commit 58dfe9c Oct 8, 2024
36 checks passed
@saga-dasgupta saga-dasgupta deleted the functions_7452.gcs_upload_solution branch October 8, 2024 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants