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

feat: enable jbang [email protected] and jbang tree@https:/jbang.dev #1274

Merged
merged 2 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ dependencies {
//implementation 'com.google.guava:guava:28.2-jre'


testCompile "com.github.tomakehurst:wiremock-jre8:2.27.2"
testCompile "com.github.tomakehurst:wiremock-jre8:2.32.0"

testImplementation "org.junit.jupiter:junit-jupiter:5.7.1"
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.7.1')
Expand Down
15 changes: 13 additions & 2 deletions docs/modules/ROOT/pages/alias_catalogs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,29 @@ The aliases you create are stored locally (see <<Local Alias Catalogs>>), but JB
You can access those catalogs explicitly (see <<Catalogs>>) but it is much easier to use what we call "implicit catalogs", which
are aliases that have a special format and JBang is smart enough to know where to find their definition.

There are two kinds, one that resolves to a Git backed service (github,gitlab and bitbucket) and one that resolves to
https sites.

Examples:

`jbang [email protected]` will (because of the dot in the name) will lookup a catalog first at https://jbang.dev/jbang-catalog.json.

`jbang hello@jbangdev` will run the alias `hello` as defined in `jbang-catalog.json` found in https://github.com/jbangdev/jbang-catalog.

This allows anyone to provide a set of jbang scripts defined in their github, gitlab or bitbucket repositories.
This allows anyone to provide a set of jbang scripts defined in their website or in a github, gitlab or bitbucket repositories.

The full format is `<alias>@<user/org>(/repository)(/branch)(~path)` allowing you to do things like:
The full format is `<alias>@<user/org>(/repository)(/branch)(~path)` or `<alias>@<hostname>(/path/to/catalog)` allowing you to do things like:

.Implicit Catalog Examples:
|====
|Command | Description

|`jbang [email protected]`
|`hello` alias found in `https://acme.corp/jbang-catalog.json` if available or the default branch searched on github, gitlab and bitbucket in that order.

|`jbang [email protected]/a/path/to/jbang-catalog.json`
|`hello` alias found in `https://acme.corp/a/path/to/jbang-catalog.json` if available.

|`jbang hello@acme`
|`hello` alias found in `acme/jbang-catalog/jbang-catalog.json` of the default branch searched on github, gitlab and bitbucket in that order.

Expand Down
39 changes: 26 additions & 13 deletions src/main/java/dev/jbang/catalog/ImplicitCatalogRef.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package dev.jbang.catalog;

import static dev.jbang.cli.BaseCommand.EXIT_INVALID_INPUT;

import java.util.Arrays;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;

import dev.jbang.cli.ExitException;
import dev.jbang.util.Util;

public class ImplicitCatalogRef {
Expand All @@ -34,6 +31,12 @@ public String url(String host, String infix) {
return host + org + "/" + repo + infix + ref + "/" + path + Catalog.JBANG_CATALOG_JSON;
}

/**
* Return ImplicitCatalogRef if can be parsed into a git accessible structure.
*
* @param name
* @return null if cannot parse it
*/
public static ImplicitCatalogRef parse(String name) {
String[] parts = name.split("~", 2);
String path;
Expand All @@ -44,7 +47,8 @@ public static ImplicitCatalogRef parse(String name) {
}
String[] names = parts[0].split("/");
if (names.length > 3) {
throw new ExitException(EXIT_INVALID_INPUT, "Invalid catalog name '" + name + "'");

return null;
}
String org = names[0];
String repo;
Expand All @@ -62,16 +66,25 @@ public static ImplicitCatalogRef parse(String name) {
return new ImplicitCatalogRef(org, repo, ref, path);
}

static Optional<String> getImplicitCatalogUrl(String catalogName) {
ImplicitCatalogRef icr = parse(catalogName);
public static Optional<String> getImplicitCatalogUrl(String catalogName) {

Optional<ImplicitCatalogRef> icr = Optional.ofNullable(parse(catalogName));
Optional<String> url = chain(
() -> tryDownload(icr.url(GITHUB_URL, "/blob/")),
() -> icr.isPossibleCommit() ? tryDownload(icr.url(GITHUB_URL, "/blob/")) : Optional.empty(),
() -> tryDownload(icr.url(GITLAB_URL, "/-/blob/")),
() -> icr.isPossibleCommit() ? tryDownload(icr.url(GITLAB_URL, "/-/blob/")) : Optional.empty(),
() -> tryDownload(icr.url(BITBUCKET_URL, "/src/")),
() -> icr.isPossibleCommit() ? tryDownload(icr.url(BITBUCKET_URL, "/src/")) : Optional.empty())
.findFirst();
() -> catalogName.startsWith("https://") || catalogName.startsWith("http://")
|| catalogName.startsWith("file://") ? tryDownload(catalogName) : Optional.empty(),
() -> catalogName.contains(".") ? tryDownload("https://" + catalogName) : Optional.empty(),
() -> icr.isPresent() ? tryDownload(icr.get().url(GITHUB_URL, "/blob/")) : Optional.empty(),
() -> icr.isPresent() && icr.get().isPossibleCommit() ? tryDownload(icr.get().url(GITHUB_URL, "/blob/"))
: Optional.empty(),
() -> icr.isPresent() ? tryDownload(icr.get().url(GITLAB_URL, "/-/blob/")) : Optional.empty(),
() -> icr.isPresent() && icr.get().isPossibleCommit()
? tryDownload(icr.get().url(GITLAB_URL, "/-/blob/"))
: Optional.empty(),
() -> icr.isPresent() ? tryDownload(icr.get().url(BITBUCKET_URL, "/src/")) : Optional.empty(),
() -> icr.isPresent() && icr.get().isPossibleCommit()
? tryDownload(icr.get().url(BITBUCKET_URL, "/src/"))
: Optional.empty())
.findFirst();
return url;
}

Expand Down
63 changes: 63 additions & 0 deletions src/test/java/dev/jbang/TestImplicitAlias.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dev.jbang;

import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;

import dev.jbang.catalog.Alias;
import dev.jbang.catalog.ImplicitCatalogRef;

/**
* TODO: use mock to handle https lookups instead of jbang.dev
*/
public class TestImplicitAlias extends BaseTest {

@Test
public void testGitImplicitCatalog() {
assertThat(ImplicitCatalogRef.getImplicitCatalogUrl("jbangdev").get(),
Matchers.equalTo("https://github.com/jbangdev/jbang-catalog/blob/HEAD/jbang-catalog.json"));
assertThat(ImplicitCatalogRef.getImplicitCatalogUrl("jbangdev/jbang-examples").get(),
Matchers.equalTo("https://github.com/jbangdev/jbang-examples/blob/HEAD/jbang-catalog.json"));
}

@Test
public void testImplictURLAlias() {

Alias url = Alias.get("[email protected]");
assertThat(url.scriptRef, Matchers.equalTo("tree/main.java"));

}

@Test
public void testImplictExplicitURLAlias() {

Alias url = Alias.get("tree@https://xam.dk");
assertThat(url.scriptRef, Matchers.equalTo("tree/main.java"));

}

// @Test needs fixing to not generate absolute paths but instead relative paths.
public void testFileURLAlias() throws IOException {

assertThat(jbangTempDir.resolve("inner").toFile().mkdirs(), Matchers.is(true));

Files.copy(examplesTestFolder.resolve("helloworld.java"), jbangTempDir.resolve("inner/helloworld.java"));
String src = jbangTempDir.resolve("inner/helloworld.java").toString();
Path path = jbangTempDir.resolve("jbang-catalog.json");

checkedRun(null, "alias", "add", "-f", path.toString(), "--name=apptest", src);

String url = "apptest@" + path.toUri();
assertThat(url, Matchers.stringContainsInOrder("file://"));

Alias alias = Alias.get(url);

assertThat(alias.scriptRef, Matchers.equalTo("helloworld.java"));

}
}