Skip to content

Conversation

@mstoykov
Copy link
Contributor

@mstoykov mstoykov commented Oct 17, 2025

What?

Reimplement auto extension resolution without using esbuild or k6deps, but the internal methods that k6 uses to load modules.

Why?

This removes the need for a separate project to have the same way to parse and understand imports and also double parsing everything.

Also fixing a number of bugs coming from this and removes the maintaince burden to keep both projects align.

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

Based on #5240 and requires #5319 to have the same functionality as the same.

Fixes #5127
FIxes #5176
Fixes #5104
Closes #5102
Requirement for #5166 ( likely a future PR that refactors more of test_load.go)

Likely some updates to every other issue around automatic extension resolution as well.

@mstoykov mstoykov added this to the v1.4.0 milestone Oct 17, 2025
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 17, 2025 15:59 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 17, 2025 16:09 — with GitHub Actions Inactive
@mstoykov mstoykov force-pushed the basicNativeNativeBinaryProvisioning branch from 5c93d1d to d738041 Compare October 21, 2025 10:34
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 21, 2025 10:41 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 21, 2025 10:45 — with GitHub Actions Inactive
@mstoykov mstoykov marked this pull request as ready for review October 21, 2025 10:47
@mstoykov mstoykov requested a review from a team as a code owner October 21, 2025 10:47
@mstoykov mstoykov requested review from ankur22, codebien, oleiade and pablochacin and removed request for a team October 21, 2025 10:47
@mstoykov
Copy link
Contributor Author

This likely should get more tests, and either drop the launcher.go and the old way or to further make it possible to use the old resolution method ... for now at least.

But I would like some initial feedback and thoughts.

constraints := string(match[idxUseConstraints])

if _, ok := deps[extension]; ok {
return deps, fmt.Errorf("already had a use directivce for %q", extension)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return deps, fmt.Errorf("already had a use directivce for %q", extension)
return deps, fmt.Errorf("already had a use directive for %q", extension)

Is this printed to the user? Can we make it a bit more user friendly? I guess if this appears out of nowhere the user is not getting it fast.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please see it now.

Comment on lines 305 to 326
// TODO(@mstoykov) potentially figure out some less "exceptionl workflow" solution
type runDifferentBinaryError struct {
customBinary commandExecutor
}
Copy link
Contributor

Choose a reason for hiding this comment

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

To be honest, that approach seems it introduces not very linear logic which is difficult to follow and remember. I'd appreciate if we try to find a better way before merge it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do agree with you which is why I left the comment.

Unfortunately having gone though doing the changes ... this seems like the most concise and not convuleted way to do it.

Effectively we want to stop executing the current workflow and run a new program.

Currently we use the fact that returning an error will do that, and we return errors from the different places where the source is loaded in the same way. They all propagate it backwards and then in the root command where nothing else will happen otherwise we check if it is the specific error and run the command, instead of errroring.

In all other cases all this backtracking will need to be codified, which likely will mean a lot more changes to signatures of functions and changes to run, cloud( and cloud run), archive, inspect and ... propagate it backwards? Have it run here and return backwards to stop?

The only other not very involved way I can see is to execute here , and return a "do nothing error", which seems worse as it is now an error you should propagate backwards but the root still needs to figure out it should not do anything with it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mstoykov Can you open an issue and assign to the next milestone so we don't lose track of it, please?

Base automatically changed from allUnknownModulesDetection to master October 21, 2025 14:17
@mstoykov mstoykov force-pushed the basicNativeNativeBinaryProvisioning branch from 65afd95 to c8e52fa Compare October 22, 2025 08:56
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 22, 2025 09:04 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 22, 2025 09:06 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 22, 2025 09:17 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 22, 2025 09:19 — with GitHub Actions Inactive
Copy link
Contributor

@pablochacin pablochacin left a comment

Choose a reason for hiding this comment

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

I just gave a first pass and centered my comments on the structure of the code.

I find it unintuitive that we use an error for actually handling the missing dependencies. I would prefer if we could split the logic and use the error for reporting and let someone else (the root command?) to handle it by attempting binary provisioning.

var differentBinaryError runDifferentBinaryError

if errors.As(err, &differentBinaryError) {
err = differentBinaryError.customBinary.run(c.globalState)
Copy link
Contributor

Choose a reason for hiding this comment

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

I find getting the custom binary from the error unintuitive.
I would expect that the error was about missing dependencies and handle it here by attempting the binary provisioning. That would have a better separation of concerns between the error and how it is handled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do agree on that part, but as I explain in https://raintank-corp.slack.com/archives/C07CJ4T7KN1/p1761206377837119?thread_ts=1761122691.317629&cid=C07CJ4T7KN1 , the alternative is probably twice as many changes if not more. and likely still very strange behaviours.

This way we unroll back to a state where I know nothing is happening and then running the new binary, if possible.

Please move the discussion there. And if this is the problem, I will do the changes, but given the time restrictions on v1.4.0 approaching, the complexity and the importantce of the changes, I would prefer to not keep adding stuff. I already had quite a lot of problems with stuff that ... I would define as implementation quirks

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't follow you. Unless I'm mistaken, the Slack thread you are pointing me to is about another unrelated topic (how we should resolve pragmas).

My comment is about the structure of the code. Regardless of how we find out the missing extensions, I think we should separate that from obtaining the binary.

And I think that discussion should happen here as it is related to the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aaah ,... sorry.

Do you mean like e48314e ?

@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 24, 2025 08:59 — with GitHub Actions Inactive
@mstoykov
Copy link
Contributor Author

I think I have gone through all the points and I also did some refactoring to make it easier to follow.
I also feel like now we probably do not need more tests. Does anyone has any other ideas?

cc @codebien @pablochacin

@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 24, 2025 10:41 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 24, 2025 10:44 — with GitHub Actions Inactive
codebien
codebien previously approved these changes Oct 24, 2025
Copy link
Contributor

@codebien codebien left a comment

Choose a reason for hiding this comment

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

@mstoykov much better now, thanks for the effort 🙇

LGTM, as soon as we have a green CI.

Copy link
Contributor

@pablochacin pablochacin left a comment

Choose a reason for hiding this comment

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

Thanks for the changes. I like this structure more. I left some comments, none of them blocking.

return nil
}

func findDirectives(text []byte) []string {
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reason for not using regexp from k6deps for this analysis? wouldn't it be more compact?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. I needed to fix them which turned out to not work particularly well
  2. I ... did find they are slightly buggy in strange cases such as "use k6 with k6/x/sql with something" is ... .okay and it parsed it as "use k6 something" if I remember correctly
  3. I do not think it is more readable and I am pretty sure it is 1-2 lines shorter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

3cca41f you can see that all the definitions are basically more than half the current implementation.

And I do not think I am the only person who thinks the regex are ... not exactly the easiest thing to debug.

Copy link
Contributor

@pablochacin pablochacin left a comment

Choose a reason for hiding this comment

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

@mstoykov I didn't mean to ask for changes (I'm pretty sure I only submitted comments), so please ignore that. Github and its mysterious ways....

@mstoykov mstoykov requested a review from pablochacin October 24, 2025 13:29
@mstoykov mstoykov force-pushed the basicNativeNativeBinaryProvisioning branch from 38432f1 to ca4a183 Compare October 24, 2025 15:54
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 24, 2025 16:01 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 24, 2025 16:02 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants