Skip to content

Commit 2abd39e

Browse files
authored
Merge pull request #56 from unity-sds/520
Stabilization of Verisioning and Predictable Defaults #520
2 parents d72f99f + 104fa49 commit 2abd39e

File tree

3 files changed

+178
-1
lines changed

3 files changed

+178
-1
lines changed

backend/internal/processes/marketplace.go

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ func gitClone(url string, basedir string) (string, error) {
7979
sha = parts[1]
8080
}
8181

82+
log.Infof("Basedir: %s, url: %s, sha: %s", basedir, url, sha)
83+
8284
repo, err := git.PlainClone(basedir, false, &git.CloneOptions{
8385
URL: url,
8486
Progress: os.Stdout,
@@ -99,13 +101,15 @@ func gitClone(url string, basedir string) (string, error) {
99101
if sha != "" {
100102
w, err := repo.Worktree()
101103
if err != nil {
104+
log.Infof("Couldn't open repo: %v", err)
102105
return "", err
103106
}
104107

105108
err = w.Checkout(&git.CheckoutOptions{
106109
Hash: plumbing.NewHash(sha),
107110
})
108111
if err != nil {
112+
log.Infof("Couldn't open sha: %v", err)
109113
return "", err
110114
}
111115
}

src/lib/ExtendedSemver.ts

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import semver from 'semver';
2+
3+
type SpecialVersion = 'latest' | 'current' | 'stable';
4+
type Version = string | SpecialVersion;
5+
6+
interface SemverResult {
7+
major: number;
8+
minor: number;
9+
patch: number;
10+
prerelease: string[];
11+
build: string[];
12+
version: string;
13+
}
14+
15+
export default class ExtendedSemver {
16+
private readonly specialVersions: Record<SpecialVersion, string> = {
17+
latest: '999999.999999.999999',
18+
current: '999999.999999.999998',
19+
stable: '999999.999999.999997'
20+
};
21+
22+
/**
23+
* Converts non-standard version to semver-compatible string
24+
* @param version The version string to normalize
25+
* @returns A semver-compatible version string
26+
* @throws Error if version is invalid
27+
*/
28+
private normalize(version: Version): string {
29+
const versionLower = version.toLowerCase();
30+
31+
// Handle special keywords
32+
if (versionLower in this.specialVersions) {
33+
return this.specialVersions[versionLower as SpecialVersion];
34+
}
35+
36+
// Handle suffixed versions (e.g., "24.4-stable")
37+
if (version.includes('-')) {
38+
const [base, suffix] = version.split('-');
39+
const parts = base.split('.');
40+
41+
// Pad with zeros for consistent comparison
42+
while (parts.length < 3) {
43+
parts.push('0');
44+
}
45+
46+
// Handle stable suffix specially since it should be higher than base
47+
if (suffix.toLowerCase() === 'stable') {
48+
return parts.join('.');
49+
}
50+
51+
return `${parts.join('.')}-${suffix}`;
52+
}
53+
54+
// Handle versions without enough parts
55+
if (!version.includes('.')) {
56+
return `${version}.0.0`;
57+
}
58+
59+
const parts = version.split('.');
60+
while (parts.length < 3) {
61+
parts.push('0');
62+
}
63+
64+
return parts.join('.');
65+
}
66+
67+
/**
68+
* Compares two versions
69+
* @returns -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2
70+
*/
71+
compare(version1: Version, version2: Version): number {
72+
const v1 = this.normalize(version1);
73+
const v2 = this.normalize(version2);
74+
75+
return semver.compare(v1, v2);
76+
}
77+
78+
/**
79+
* Sorts an array of versions in ascending order
80+
*/
81+
sort(versions: Version[]): Version[] {
82+
const normalized = versions.map((v) => ({
83+
original: v,
84+
normalized: this.normalize(v)
85+
}));
86+
87+
return normalized
88+
.sort((a, b) => semver.compare(a.normalized, b.normalized))
89+
.map((v) => v.original);
90+
}
91+
92+
/**
93+
* Checks if a version satisfies a semver range
94+
*/
95+
satisfies(version: Version, range: string): boolean {
96+
const normalized = this.normalize(version);
97+
return semver.satisfies(normalized, range);
98+
}
99+
100+
/**
101+
* Checks if version1 is greater than version2
102+
*/
103+
gt(version1: Version, version2: Version): boolean {
104+
return semver.gt(this.normalize(version1), this.normalize(version2));
105+
}
106+
107+
/**
108+
* Checks if version1 is less than version2
109+
*/
110+
lt(version1: Version, version2: Version): boolean {
111+
return semver.lt(this.normalize(version1), this.normalize(version2));
112+
}
113+
114+
/**
115+
* Checks if two versions are equal
116+
*/
117+
eq(version1: Version, version2: Version): boolean {
118+
return semver.eq(this.normalize(version1), this.normalize(version2));
119+
}
120+
121+
/**
122+
* Parses a version string into its components
123+
* @returns Parsed version object or null if invalid
124+
*/
125+
parse(version: Version): SemverResult | null {
126+
const parsed = semver.parse(this.normalize(version));
127+
if (!parsed) return null;
128+
129+
return {
130+
major: parsed.major,
131+
minor: parsed.minor,
132+
patch: parsed.patch,
133+
prerelease: [...parsed.prerelease] as string[],
134+
build: [...parsed.build],
135+
version: parsed.version
136+
};
137+
}
138+
139+
/**
140+
* Coerces a string into a semver version, handling both standard and non-standard formats
141+
* Returns null if the version string is invalid or cannot be coerced
142+
* @example
143+
* coerce('v2') => '2.0.0'
144+
* coerce('42.6.7.9.3-alpha') => '42.6.7'
145+
* coerce('latest') => '999999.999999.999999'
146+
* coerce('v24.4-stable') => '24.4.0'
147+
*/
148+
coerce(version: string): string | null {
149+
// Handle special versions first
150+
const versionLower = version.toLowerCase();
151+
if (versionLower in this.specialVersions) {
152+
return this.specialVersions[versionLower as SpecialVersion];
153+
}
154+
155+
// Remove 'v' prefix if it exists
156+
version = version.replace(/^v/, '');
157+
158+
// Handle suffixed versions before coercing
159+
if (version.includes('-')) {
160+
const [base] = version.split('-');
161+
// Use semver's coerce on the base version
162+
const coerced = semver.coerce(base);
163+
if (!coerced) return null;
164+
return coerced.version;
165+
}
166+
167+
// Use semver's built-in coerce for standard version strings
168+
const coerced = semver.coerce(version);
169+
return coerced ? coerced.version : null;
170+
}
171+
}

src/routes/marketplace/+page.svelte

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
import semver from 'semver';
2+
import ExtendedSemver from '../../lib/ExtendedSemver';
33
import ProductItem from '../../components/ProductItem.svelte';
44
import CategoryList from '../../components/CategoryList.svelte';
55
import Header from '../../components/Header.svelte';
@@ -9,6 +9,8 @@
99
import { fade, slide } from 'svelte/transition';
1010
import { goto } from '$app/navigation';
1111
12+
const semver = new ExtendedSemver();
13+
1214
$: categories = ['All', ...new Set($marketplaceStore.map((p) => p.Category))];
1315
$: filteredProducts = $marketplaceStore.filter(
1416
(p) => $selectedCategory === 'All' || $selectedCategory === p.Category

0 commit comments

Comments
 (0)