Skip to content

Commit dce593f

Browse files
maxandersenclaude
andcommitted
feat: implement version pinning for JBang aliases
Implements version pinning syntax for aliases using alias:version@catalog format, allowing users to specify versions at invocation time without modifying catalog files. Features: - Version parsing: Parse alias:version@catalog syntax in Alias.merge() - Distinguish GAVs from alias:version using colon counting and dot detection - Store version in transient requestedVersion field - Validate empty version/alias names and invalid formats - Property replacement: Support ${jbang.app.version:default} in scriptRefs - Uses ProjectBuilder.getContextProperties() for full property context - Property replacement takes precedence over automatic replacement - Allows: jbang -Dmyprop=xyz myalias:1.2 to use myprop in properties - Maven GAV version replacement - Handle full GAV: group:artifact:version:classifier@type - Handle lenient GAV: group:artifact (appends version) - Preserve classifier and type when replacing version - Git URL version replacement for GitHub, GitLab, Bitbucket - GitHub: /blob/REF/ and raw.githubusercontent.com/org/repo/REF/ - GitLab: /-/blob/REF/ and /-/raw/REF/ - Bitbucket: /src/REF/ and /raw/REF/ - Safe version substitution with Matcher.quoteReplacement() - Catalog reference version replacement - Pattern: alias@org/repo/REF → alias@org/repo/version - Version propagates through alias chains - Error handling: Hard errors when version specified but no pattern matches Examples: jbang mytool:1.5.0 # Pin version 1.5.0 jbang mytool:1.5.0@myorg # Pin version from catalog jbang tool:v2.0@org/repo/main # Pin git-based catalog Fixes #1979 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent ffae7d4 commit dce593f

4 files changed

Lines changed: 880 additions & 14 deletions

File tree

docs/modules/ROOT/pages/alias_catalogs.adoc

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,120 @@ The full format is `<alias>@<user/org>(/repository)(/branch)(~path)` or `<alias>
9898

9999
|====
100100

101+
== Version Pinning
102+
103+
Version pinning allows you to specify a version when running an alias, enabling you to use different versions of the same tool without modifying the catalog definition. This is particularly useful for testing, compatibility checks, or using specific versions of tools.
104+
105+
=== Syntax
106+
107+
The version pinning syntax is: `alias:version@catalog`
108+
109+
Examples:
110+
111+
[source,bash]
112+
----
113+
jbang mytool:1.5.0@mycatalog # Pin to version 1.5.0
114+
jbang tool:v2.0.0@jbangdev # Pin to v2.0.0 from jbangdev catalog
115+
jbang app:1.2.3 # Pin to 1.2.3 from local catalog
116+
----
117+
118+
=== How It Works
119+
120+
When you specify a version, JBang applies different replacement strategies depending on the alias's script reference:
121+
122+
==== Maven GAV Coordinates
123+
124+
For aliases that reference Maven artifacts, the version replaces the version component in the GAV coordinates:
125+
126+
[source,json]
127+
----
128+
{
129+
"aliases": {
130+
"picocli": {
131+
"script-ref": "info.picocli:picocli-codegen:4.6.0"
132+
}
133+
}
134+
}
135+
----
136+
137+
Running `jbang picocli:4.7.0` resolves to `info.picocli:picocli-codegen:4.7.0`
138+
139+
This works with:
140+
141+
- Basic GAV: `group:artifact:version` → `group:artifact:newversion`
142+
- GAV with classifier: `group:artifact:version:classifier` → `group:artifact:newversion:classifier`
143+
- GAV with classifier and type: `group:artifact:version:classifier@type` → `group:artifact:newversion:classifier@type`
144+
- Partial GAV: `group:artifact` → `group:artifact:newversion`
145+
146+
==== Git URLs
147+
148+
For aliases that reference GitHub, GitLab, or Bitbucket URLs, the version replaces the branch/tag/ref in the URL:
149+
150+
*GitHub:*
151+
152+
- `https://github.com/org/repo/blob/main/script.java` + `:v1.0.0` → `https://github.com/org/repo/blob/v1.0.0/script.java`
153+
- `https://raw.githubusercontent.com/org/repo/main/script.java` + `:v1.0.0` → `https://raw.githubusercontent.com/org/repo/v1.0.0/script.java`
154+
155+
*GitLab:*
156+
157+
- `https://gitlab.com/org/repo/-/blob/develop/script.java` + `:v1.0` → `https://gitlab.com/org/repo/-/blob/v1.0/script.java`
158+
- `https://gitlab.com/org/repo/-/raw/main/script.java` + `:v1.0` → `https://gitlab.com/org/repo/-/raw/v1.0/script.java`
159+
160+
*Bitbucket:*
161+
162+
- `https://bitbucket.org/org/repo/src/master/script.java` + `:1.0` → `https://bitbucket.org/org/repo/src/1.0/script.java`
163+
- `https://bitbucket.org/org/repo/raw/master/script.java` + `:1.0` → `https://bitbucket.org/org/repo/raw/1.0/script.java`
164+
165+
==== Property-Based Versioning
166+
167+
For maximum flexibility, aliases can use property placeholders that get replaced when a version is specified:
168+
169+
[source,json]
170+
----
171+
{
172+
"aliases": {
173+
"quarkus": {
174+
"script-ref": "io.quarkus:quarkus-cli:${jbang.app.version:3.0.0}"
175+
},
176+
"example": {
177+
"script-ref": "https://github.com/org/repo/blob/${jbang.app.version:main}/script.java"
178+
}
179+
}
180+
}
181+
----
182+
183+
Running `jbang quarkus:3.5.0` resolves to `io.quarkus:quarkus-cli:3.5.0`
184+
185+
Running `jbang example:v2.0` resolves to `https://github.com/org/repo/blob/v2.0/script.java`
186+
187+
If no version is specified, the default value (after the colon) is used.
188+
189+
NOTE: Property replacement takes precedence over automatic version replacement. If your alias uses `${jbang.app.version}`, automatic replacement is skipped.
190+
191+
==== Alias Chains
192+
193+
Version pinning works through alias chains. If an alias references another alias, the version propagates through the chain:
194+
195+
[source,json]
196+
----
197+
{
198+
"aliases": {
199+
"base-tool": {
200+
"script-ref": "com.example:tool:1.0.0"
201+
},
202+
"tool": {
203+
"script-ref": "base-tool"
204+
}
205+
}
206+
}
207+
----
208+
209+
Running `jbang tool:2.0.0` resolves all the way through to `com.example:tool:2.0.0`
210+
211+
=== Backward Compatibility
212+
213+
Aliases without version pinning work exactly as before. The version syntax is entirely optional and doesn't affect existing usage.
214+
101215
== Local Alias Catalogs
102216

103217
JBang will also look in the current directory for a `jbang-catalog.json` file and if it exists it will look up any aliases

0 commit comments

Comments
 (0)