Skip to content

Conversation

jandubois
Copy link
Member

This is a reimplementation of the bash code in #3937 (comment)

@jandubois jandubois added this to the v2.0.0 milestone Oct 4, 2025
@jandubois jandubois changed the title Implement custom github URL scheme in Go Implement custom github: URL scheme in Go Oct 4, 2025
@jandubois jandubois marked this pull request as draft October 4, 2025 03:38
@jandubois
Copy link
Member Author

I've turned this back into a Draft for now because I still want to make 2 changes compared to the old bash script:

  1. An empty REPO should be treated as a repeat of the ORG:

    github:ORG means github:ORG/ORG and github:ORG//PATH means github:ORG/ORG/PATH

  2. A missing PATH should not mean lima.yaml but .lima.yaml, and we should follow symlinks.

    The lima.yaml name is not so useful because it will mean you must specify --name if you don't want your instance be called lima. And people may not want to have a non-hidden lima.yaml in the root of their repo. This adds a network roundtrip, but I think is reasonable.

Combined this will allow you to use github:newlinux to point to github:newlinux/newlinux/templates/newlinux.yaml with a much shorter URL, and the default instance name would also be newlinux.

@AkihiroSuda
Copy link
Member

github:ORG means github:ORG/ORG

github:ORG/.github may make more sense?
Still makes sense to fall-back to github:ORG/ORG

github:ORG//PATH means github:ORG/ORG/PATH

This looks confusing to me. // should just be same as / ?

@AkihiroSuda
Copy link
Member

github:newlinux to point to github:newlinux/newlinux/templates/newlinux.yaml

Users probably don't want this file name either, as the file name doesn't explain what this YAML is for.
Can be easily confused as a Kubernetes manifest.

Maybe it should be resolved as github:newlinux/newlinux/newlinux.lima.yaml?
The instance name should be resolved as newlinux omitting the .lima.yaml suffix.

@jandubois
Copy link
Member Author

github:ORG means github:ORG/ORG

github:ORG/.github may make more sense?

That doesn't make sense to me, the .github repo is for storing GitHub related metadata, not project specific files.

Many projects use the same name for their org and main repo. We would be using lima/lima too, had the lima org still been available.

Still makes sense to fall-back to github:ORG/ORG

Yet another network roundtrip, and I doubt that .github is a common use case.

github:ORG//PATH means github:ORG/ORG/PATH

This looks confusing to me. // should just be same as / ?

It is a direct extension of "an empty REPO means it is the same as the ORG".

I don't see what useful purpose treating extra slashes as redundant would serve.

It is not really different from file://foo/bar meaning something completely different from file:///foo/bar.

github:newlinux to point to github:newlinux/newlinux/templates/newlinux.yaml
Users probably don't want this file name either, as the file name doesn't explain what this YAML is for.

It creates an instance with the newlinux distro or software. The same way we have rockylinux and almalinux templates.

Can be easily confused as a Kubernetes manifest.

How so? Why can github:gardenlinux be confused with a Kubernetes manifest, but template:rockylinux can not?

Maybe it should be resolved as github:newlinux/newlinux/newlinux.lima.yaml?
The instance name should be resolved as newlinux omitting the .lima.yaml suffix.

I would prefer not adding another heuristic. Let's keep things simple!

I still think my suggestions are sensible!

@AkihiroSuda
Copy link
Member

Can be easily confused as a Kubernetes manifest.

How so? Why can github:gardenlinux be confused with a Kubernetes manifest, but template:rockylinux can not?

What I meant was that newlinux.yaml in the repo could be confused as a YAML for Kubernetes or something else that accepts YAML.

@AkihiroSuda
Copy link
Member

An alternative to REPO.lima.yaml would be lima/REPO.yaml or .lima/REPO.yaml.

@jandubois
Copy link
Member Author

jandubois commented Oct 4, 2025

An alternative to REPO.lima.yaml would be lima/REPO.yaml or .lima/REPO.yaml.

Maybe I've not been clear enough: I expect ORG/REPO/.lima.yaml to be a symlink to any other file in the repo. It is up to the user where to put it and what to call it.

It can be a YAML file as well, but I think it would almost always be a symlink.

So in my example I assumed it would be a symlink to templates/newlinux.yaml.

@jandubois jandubois force-pushed the url-github branch 2 times, most recently from 5ae31b5 to 4e3ca40 Compare October 4, 2025 06:40
@jandubois
Copy link
Member Author

I've implemented the changes I suggested above. I also created a jandubois/jandubois repo for testing:

ls -la ~/git/jandubois
total 0
drwxr-xr-x@  5 jan  staff  160 Oct  3 22:10 .
drwxr-xr-x@ 11 jan  staff  352 Oct  3 22:09 ..
drwxr-xr-x@ 12 jan  staff  384 Oct  3 22:11 .git
lrwxr-xr-x@  1 jan  staff   19 Oct  3 22:10 .lima.yaml -> templates/demo.yaml
drwxr-xr-x@  3 jan  staff   96 Oct  3 22:09 templatesl tmpl url github:jandubois
https://raw.githubusercontent.com/jandubois/jandubois/main/templates/demo.yaml

The symlink check is actually done for any file called .lima.yaml or lima.yaml. When we implement #4135 we can do it for all URLs and read the whole file, and just return the content if the file isn't a symlink.

@AkihiroSuda I don't think the tests should reference my personal repos; can I create lima-vm/lima-vm with the same content?

The tests should probably move to BATS later, but there is a lot of plugin functionality that still needs tests.

@AkihiroSuda
Copy link
Member

.lima.yaml or lima.yaml

Why both? The dot file seems better for the specially reserved file name.
Is there any case the dot file has to be avoided?

I don't think the tests should reference my personal repos; can I create lima-vm/lima-vm with the same content?

The unit test for resolving the URL doesn't need to rely on an actual repo?
You can also use https://pkg.go.dev/net/http/httptest#NewServer to emulate GitHub.

If you want to write an "integration" test that actually fetches a YAML content from a repo, it is fine to rely on jandubois/jandubois.
If you don't like that, you can create a test org/repo like lima-vm-test/lima-vm-test, but I don't think we should create lima-vm/lima-vm as it is quite confusing to have both lima and lima-vm.
Alternatively we could rename lima to lima-vm, but it doesn't seem worth doing.

@jandubois
Copy link
Member Author

.lima.yaml or lima.yaml

Why both? The dot file seems better for the specially reserved file name. Is there any case the dot file has to be avoided?

So you can have lima.yaml files in other places in your repo that are symlinks. The non-dot version is because the default filename is lima.yaml if the URL ends with a slash. We could make it also .lima.yaml, but I think if the file is in a subdirectory, I would not want to have it hidden. This gives the user a choice.

Example:

l tmpl url github:jandubois//docs/
https://raw.githubusercontent.com/jandubois/jandubois/main/templates/demo.yaml

It doesn't really matter because if the file is not a symlink, then it will not be treated specially:

l tmpl url github:jandubois//test/lima.yaml
https://raw.githubusercontent.com/jandubois/jandubois/main/test/lima.yaml

I don't think the tests should reference my personal repos; can I create lima-vm/lima-vm with the same content?

The unit test for resolving the URL doesn't need to rely on an actual repo? You can also use https://pkg.go.dev/net/http/httptest#NewServer to emulate GitHub.

I want to turn them into BATS anyways; I wrote them in Go because at first I forgot that they need network access. There is no reason they shouldn't be integration tests and test the real thing.

If you want to write an "integration" test that actually fetches a YAML content from a repo, it is fine to rely on jandubois/jandubois. If you don't like that, you can create a test org/repo like lima-vm-test/lima-vm-test, but I don't think we should create lima-vm/lima-vm as it is quite confusing to have both lima and lima-vm. Alternatively we could rename lima to lima-vm, but it doesn't seem worth doing.

It would have to be lima-vm/lima-vm to match the ORG name, otherwise it doesn't work. We could just put a pointer to lima.git at the top of the README, so I don't think it matters. The lima.git is also a pinned repo, whereas the lima-vm one would drop down in the list of less-frequently being used repos.

Note that the README.md of the lima-vm/lima-vm will show up on the profile page of the lima-vm org, so it may be useful to have it anyways; idk.

I will for now continue to use jandubois/jandubois until we have consensus. I just feel it is cleaner not to rely on external resources, but maybe it doesn't matter, it is just a test.

@jandubois
Copy link
Member Author

There is one other change I want to make: the branch/tag/sha should follow the repo, not the path/filename: github:ORG/REPO@TAG/PATH instead of github:ORG/REPO/PATH@TAG.

I think I originally put it last because it comes last in go.mod etc, but that is irrelevant for Lima templates. The branch/tag/sha is a property of the repo and not the file, so it should be closer to the repo name.

Additional benefits:

  • The template filename remains at the end of the URL instead of being sandwiched.
  • It mirrors the order in the githubusercontent replacement URL.

Not super important, but feels better to me.

@AkihiroSuda
Copy link
Member

github:ORG/REPO@TAG/PATH

This may not work well when the tag contains a slash.

@jandubois
Copy link
Member Author

Thanks, didn't think of that. So I won't change it.

@jandubois
Copy link
Member Author

Why both? The dot file seems better for the specially reserved file name. Is there any case the dot file has to be avoided?

So you can have lima.yaml files in other places in your repo that are symlinks. The non-dot version is because the default filename is lima.yaml if the URL ends with a slash. We could make it also .lima.yaml, but I think if the file is in a subdirectory, I would not want to have it hidden.

I changed my mind on this. It is simpler to say "when only a directory is specified, then the filename will be .lima.yaml". And we don't really want to see the lima.yaml file in repositories.

By using .lima.yaml everywhere, every directory can have a hidden symlink that is used when you specify just the directory (with a trailing slash), which seems more useful.

Thanks for questioning this; it was not a good idea to support lima.yaml as the default.

This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
@jandubois
Copy link
Member Author

jandubois commented Oct 5, 2025

I've rewritten the tests using BATS:

./lib/bats-core/bin/bats -T tests/url-github.bats
url-github.bats
 ✓ github:jandubois/jandubois/templates/demo.yaml@main [79]
 ✓ github:jandubois/jandubois/templates/demo.yaml [465]
 ✓ github:jandubois/jandubois/templates/demo [414]
 ✓ github:jandubois/jandubois/.lima.yaml [566]
 ✓ github:jandubois/jandubois/@v0.0.0 [206]
 ✓ github:jandubois/jandubois [414]
 ✓ github:jandubois//templates/demo.yaml@main [40]
 ✓ github:jandubois//templates/demo.yaml [358]
 ✓ github:jandubois//templates/demo [391]
 ✓ github:jandubois//.lima.yaml [419]
 ✓ github:jandubois//@v0.0.0 [112]
 ✓ github:jandubois// [457]
 ✓ github:jandubois/ [409]
 ✓ github:[email protected] [103]
 ✓ github:jandubois [408]
 ✓ github:jandubois/jandubois/docs/.lima.yaml@main [222]
 ✓ github:jandubois/jandubois/docs/.lima.yaml [434]
 ✓ github:jandubois/jandubois/docs/.lima [652]
 ✓ github:jandubois/jandubois/docs/ [466]
 ✓ github:jandubois//docs/[email protected] [209]
 ✓ github:jandubois//docs/.lima.yaml [441]
 ✓ github:jandubois//docs/.lima [545]
 ✓ github:jandubois//docs/@v0.0.0 [109]
 ✓ github:jandubois//docs/ [428]
 ✓ .lima.yaml is retained when it is not a symlink [530]
 ✓ hidden files without an extension get a .yaml extension [398]
 ✓ files that have an extension do not get a .yaml extension [357]
 ✓ github: URLs are EXPERIMENTAL [445]
 ✓ Empty github: url returns an error [49]
 ✓ Missing org returns an error [47]

30 tests, 0 failures in 12 seconds

I've also simplified the rules if a file looks like a symlink:

Must be non-empty and have no newline, space, or colon. That's it.


I'm somewhat surprised to see that the API call to determine the default branch adds 300-400ms to the processing time. The symlink resolution only takes an additional 50-100ms.

@jandubois jandubois marked this pull request as ready for review October 5, 2025 06:54
@jandubois jandubois requested a review from a team October 5, 2025 06:54
@jandubois
Copy link
Member Author

I'm somewhat surprised to see that the API call to determine the default branch adds 300-400ms to the processing time. The symlink resolution only takes an additional 50-100ms.

Out of curiosity I've sorted the individual tests into the 4 different buckets:

No network requests

 ✓ github:jandubois/jandubois/templates/demo.yaml@main [79]
 ✓ github:jandubois//templates/demo.yaml@main [40]
 ✓ Empty github: url returns an error [49]
 ✓ Missing org returns an error [47]

Symlink resolution via githubusercontent

 ✓ github:jandubois/jandubois/@v0.0.0 [206]
 ✓ github:jandubois//@v0.0.0 [112]
 ✓ github:[email protected] [103]
 ✓ github:jandubois/jandubois/docs/.lima.yaml@main [222]
 ✓ github:jandubois//docs/[email protected] [209]
 ✓ github:jandubois//docs/@v0.0.0 [109]

Default branch lookup via GitHub API

 ✓ github:jandubois/jandubois/templates/demo.yaml [465]
 ✓ github:jandubois/jandubois/templates/demo [414]
 ✓ github:jandubois//templates/demo.yaml [358]
 ✓ github:jandubois//templates/demo [391]
 ✓ hidden files without an extension get a .yaml extension [398]
 ✓ files that have an extension do not get a .yaml extension [357]

Both symlink and branch requests

 ✓ github:jandubois/jandubois/.lima.yaml [566]
 ✓ github:jandubois/jandubois [414]
 ✓ github:jandubois//.lima.yaml [419]
 ✓ github:jandubois// [457]
 ✓ github:jandubois/ [409]
 ✓ github:jandubois [408]
 ✓ github:jandubois/jandubois/docs/.lima.yaml [434]
 ✓ github:jandubois/jandubois/docs/.lima [652]
 ✓ github:jandubois/jandubois/docs/ [466]
 ✓ github:jandubois//docs/.lima.yaml [441]
 ✓ github:jandubois//docs/.lima [545]
 ✓ github:jandubois//docs/ [428]
 ✓ .lima.yaml is retained when it is not a symlink [530]
 ✓ github: URLs are EXPERIMENTAL [445]

@jandubois
Copy link
Member Author

jandubois commented Oct 5, 2025

I got one more idea today:

We could check if the .lima.yaml "symlink" is actually an http://, https://, or a github: URL, and then treat it as a redirect instead of a symlink.

This would allow you to have github:ORG as a short canonical URL, which points to ORG/ORG/.lima.yaml, which could then redirect to a template in a different repo.

That way you don't need to keep the template in the ORG/ORG repo, which may be unwanted.

The problem with this idea is that you cannot specify a tag in the template repo this way, it would always resolve to a branch/tag in the ORG/ORG repo.

So it would be up to the ORG maintainers to decide how they want to structure their repos, and which github: URLs they want to promote. Just because this feature exists doesn't mean you have to use it.

This can always be added later, so I think this PR should be merged as-is for now.

(see next comment)

@jandubois
Copy link
Member Author

jandubois commented Oct 5, 2025

The problem with this idea is that you cannot specify a tag in the template repo this way, it would always resolve to a branch/tag in the ORG/ORG repo.

Here is an example using our own lima-vm org that shows how we could make it work:

Assume we have lima-vm/lima-vm/.lima.yaml containing github:lima-vm/lima/templates/default in the master (default) branch. There are no release tags in this repo.

Then github:[email protected] attempts to fetch lima-vm/lima-vm/[email protected], which fails, because the v1.2.1 tag/branch does not exist.

Because: (1) this is an ORG repo (same name as org), (2) the filename is .lima.yaml and (3) the URL explicitly specified the TAG, the github url code now determines the default branch and fetches the file from lima-vm/lima-vm/.lima.yaml@master.

If this fails, or if the content of this file is anything but a github: redirect, it would stop here with an error.

But since it is a github: redirect it will append the requested v1.2.1 tag to the redirect, resulting in github:lima-vm/lima/templates/[email protected].

Which means github:[email protected] fetches default.yaml from lima.git at the v1.2.1 tag level.


I don't like the complexity of the rules, and that it relies on the requested tag not existing in the ORG repo.

But this assumption is probably true in almost every case (where you want to redirect to another repo), and it improves the usability of the github:ORG urls quite a bit.

Because of the potential for confusion (refetching from default branch when the requested tag doesn't exist) I would limit the tag propagation to ORG repos.


I'm just discussing the idea here; it should still be a separate PR if we decide that we want to implement it.

@AkihiroSuda
Copy link
Member

AkihiroSuda commented Oct 6, 2025

We could check if the .lima.yaml "symlink" is actually an http://, https://, or a github: URL, and then treat it as a redirect instead of a symlink.

This would allow you to have github:ORG as a short canonical URL, which points to ORG/ORG/.lima.yaml, which could then redirect to a template in a different repo.

This is probably fine, but we have to confirm whether we need some sort of "CORS" restriction; do we need to disallow a redirect to a different org?

@jandubois
Copy link
Member Author

This is probably fine, but we have to confirm whether we need some sort of "CORS" restriction; do we need to disallow a redirect to a different org?

IDK. It feels inconsistent because we don't restrict redirects on http/https template URLs to the same domain:

limactl create https://example.com/templates/example.yaml

This can redirect wherever it likes, and we would still load the template.

However, this feature is only meant to be used to redirect from the ORG repo to a different repo within the same ORG, so it feels fine to me to restrict this, at least initially. But this means also that we only allow github: URLs as the redirect targets, and not http/https ones. Which again feels fine, because all allowed locations are accessible by the github: scheme. And http/https doesn't allow the tag propagation.

It is always better to only allow a subset at first, and expand later based on feedback, instead of providing it all, and having to take some of it away again later.

Anyways, I hope this PR can be approved as-is, and this feature can be a separate PR.

Copy link
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

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

Thanks

We need a documentation, probably as a subpage of https://lima-vm.io/docs/templates/
(https://lima-vm.io/docs/templates/github)

github:jandubois//
github:jandubois/
github:[email protected]
github:jandubois
Copy link
Member

Choose a reason for hiding this comment

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

No need to cover in this PR, but maybe we can even further shorten this form to gh:jandubois

Copy link
Member Author

Choose a reason for hiding this comment

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

We could shorten it, but template: is kind of long too, so github: fits right in, and maybe gh: is a bit obscure for some people.

Or did you want gh: as an alias, and not as a replacement? Not sure if that is good, as people might wonder what the difference would be.

Copy link
Member

Choose a reason for hiding this comment

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

As an alias. No need to cover in this PR anyway.

@AkihiroSuda AkihiroSuda requested a review from a team October 6, 2025 05:36
@jandubois
Copy link
Member Author

We need a documentation

Yes, not just for github:, but also for the url-* plugin mechanism, and even plugins in general. Should be a separate PR (or 2).

Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to add unit tests for functions in the file?

Copy link
Member Author

Choose a reason for hiding this comment

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

I originally had unit tests, but replaced them with the BATS (integration) tests because some of them require network access.

I don't see any benefit to splitting the tests up, and find the BATS tests more concise anyways.

@jandubois jandubois merged commit 8944d8b into lima-vm:master Oct 6, 2025
84 of 90 checks passed
@jandubois jandubois deleted the url-github branch October 6, 2025 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants