@camunda8/cli 2.6.0-alpha.4 → 2.6.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -8,7 +8,7 @@ A default [c8ctl](https://github.com/camunda/c8ctl) plugin that provides an opin
|
|
|
8
8
|
# Start with a specific version
|
|
9
9
|
c8ctl cluster start 8.9.0-alpha5
|
|
10
10
|
|
|
11
|
-
# Start using a version alias
|
|
11
|
+
# Start using a version alias (dynamically resolved)
|
|
12
12
|
c8ctl cluster start stable
|
|
13
13
|
c8ctl cluster start alpha
|
|
14
14
|
|
|
@@ -22,6 +22,21 @@ c8ctl cluster start --debug
|
|
|
22
22
|
c8ctl cluster stop
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Version aliases
|
|
26
|
+
|
|
27
|
+
The `stable` and `alpha` aliases are resolved dynamically by querying the
|
|
28
|
+
[Camunda Download Center](https://downloads.camunda.cloud/release/camunda/c8run/).
|
|
29
|
+
This means you always get the latest available version without waiting for a
|
|
30
|
+
plugin update.
|
|
31
|
+
|
|
32
|
+
| Alias | Resolves to |
|
|
33
|
+
|----------|-------------|
|
|
34
|
+
| `stable` | Highest minor release that is GA (e.g. `8.8`) |
|
|
35
|
+
| `alpha` | Highest minor release overall (e.g. `8.9`) |
|
|
36
|
+
|
|
37
|
+
If the download server is unreachable, the aliases fall back to the values
|
|
38
|
+
shipped in the plugin's `package.json`.
|
|
39
|
+
|
|
25
40
|
## How it works
|
|
26
41
|
|
|
27
42
|
1. **Download**: Automatically downloads the correct c8run binary for your platform from the Camunda Download Center
|
|
@@ -24,25 +24,112 @@ import { join, dirname } from 'node:path';
|
|
|
24
24
|
import { fileURLToPath } from 'node:url';
|
|
25
25
|
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
|
-
// Version aliases
|
|
27
|
+
// Version aliases – dynamic discovery with package.json fallback
|
|
28
28
|
// ---------------------------------------------------------------------------
|
|
29
29
|
|
|
30
|
+
const DOWNLOAD_BASE_URL = 'https://downloads.camunda.cloud/release/camunda/c8run/';
|
|
31
|
+
|
|
30
32
|
const _pluginPackageJson = JSON.parse(
|
|
31
33
|
readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'),
|
|
32
34
|
);
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
+
const _fallbackAliases = _pluginPackageJson.c8ctl.versionAliases;
|
|
36
|
+
const KNOWN_ALIAS_NAMES = new Set(['stable', 'alpha']);
|
|
35
37
|
|
|
36
38
|
function isVersionAlias(versionSpec) {
|
|
37
|
-
return
|
|
39
|
+
return KNOWN_ALIAS_NAMES.has(versionSpec);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Fetch the c8run download directory listing and discover the latest
|
|
44
|
+
* stable and alpha minor versions.
|
|
45
|
+
*
|
|
46
|
+
* Returns { stable: "X.Y", alpha: "X.Y" } or null on failure.
|
|
47
|
+
*/
|
|
48
|
+
export async function discoverLatestVersions() {
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch(DOWNLOAD_BASE_URL);
|
|
51
|
+
if (!response.ok) return null;
|
|
52
|
+
const html = await response.text();
|
|
53
|
+
return parseVersionsFromHtml(html);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse the HTML directory listing from the download server to extract
|
|
61
|
+
* the latest stable and alpha minor versions.
|
|
62
|
+
*
|
|
63
|
+
* - Minor version directories (e.g. "8.8/", "8.9/") are rolling releases
|
|
64
|
+
* updated in-place.
|
|
65
|
+
* - An alpha train exists when there are "X.Y.0-alphaN/" directories
|
|
66
|
+
* for a given minor. The highest minor with alphas is the alpha alias.
|
|
67
|
+
* - The highest minor without alphas is the stable alias.
|
|
68
|
+
*/
|
|
69
|
+
export function parseVersionsFromHtml(html) {
|
|
70
|
+
// Match minor-version directories like "8.8/", "8.9/"
|
|
71
|
+
const minorMatches = [...html.matchAll(/href="(\d+\.\d+)\/"/g)].map(m => m[1]);
|
|
72
|
+
// Match alpha directories like "8.9.0-alpha5/"
|
|
73
|
+
const alphaMatches = [...html.matchAll(/href="(\d+\.\d+)\.0-alpha\d+\/"/g)].map(m => m[1]);
|
|
74
|
+
|
|
75
|
+
if (minorMatches.length === 0) return null;
|
|
76
|
+
|
|
77
|
+
const compareSemver = (a, b) => {
|
|
78
|
+
const [aMaj, aMin] = a.split('.').map(Number);
|
|
79
|
+
const [bMaj, bMin] = b.split('.').map(Number);
|
|
80
|
+
return aMaj - bMaj || aMin - bMin;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const sortedMinors = [...new Set(minorMatches)].sort(compareSemver);
|
|
84
|
+
const alphaSet = new Set(alphaMatches);
|
|
85
|
+
|
|
86
|
+
const highestMinor = sortedMinors[sortedMinors.length - 1];
|
|
87
|
+
|
|
88
|
+
// The alpha train is the highest minor that has alpha directories.
|
|
89
|
+
// The stable release is the minor just below the alpha train,
|
|
90
|
+
// or the highest minor if no alpha train exists.
|
|
91
|
+
const highestAlphaMinor = [...alphaSet].sort(compareSemver).pop();
|
|
92
|
+
|
|
93
|
+
let stable;
|
|
94
|
+
if (highestAlphaMinor) {
|
|
95
|
+
// Stable = the highest minor that is lower than the alpha train
|
|
96
|
+
stable = sortedMinors.filter(v => compareSemver(v, highestAlphaMinor) < 0).pop() || highestMinor;
|
|
97
|
+
} else {
|
|
98
|
+
stable = highestMinor;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
stable,
|
|
103
|
+
alpha: highestMinor,
|
|
104
|
+
};
|
|
38
105
|
}
|
|
39
106
|
|
|
40
|
-
|
|
41
|
-
|
|
107
|
+
// Cache the discovery result for the process lifetime
|
|
108
|
+
let _dynamicAliases = undefined;
|
|
109
|
+
|
|
110
|
+
async function getDynamicAliases() {
|
|
111
|
+
if (_dynamicAliases === undefined) {
|
|
112
|
+
_dynamicAliases = await discoverLatestVersions();
|
|
113
|
+
}
|
|
114
|
+
return _dynamicAliases;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function resolveVersion(versionSpec) {
|
|
118
|
+
if (!isVersionAlias(versionSpec)) return versionSpec;
|
|
119
|
+
const dynamic = await getDynamicAliases();
|
|
120
|
+
if (dynamic?.[versionSpec]) return dynamic[versionSpec];
|
|
121
|
+
return _fallbackAliases[versionSpec] ?? versionSpec;
|
|
42
122
|
}
|
|
43
123
|
|
|
44
|
-
function getVersionAliasEntries() {
|
|
45
|
-
|
|
124
|
+
async function getVersionAliasEntries() {
|
|
125
|
+
const dynamic = await getDynamicAliases();
|
|
126
|
+
const aliases = dynamic || _fallbackAliases;
|
|
127
|
+
return Object.entries(aliases);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Reset the cached dynamic aliases (for testing). */
|
|
131
|
+
export function _resetDynamicAliasCache() {
|
|
132
|
+
_dynamicAliases = undefined;
|
|
46
133
|
}
|
|
47
134
|
|
|
48
135
|
// ---------------------------------------------------------------------------
|
|
@@ -714,8 +801,8 @@ export const commands = {
|
|
|
714
801
|
console.log(' --c8-version <version> Alternative flag form for version');
|
|
715
802
|
console.log(' --debug Stream raw c8run output during start');
|
|
716
803
|
console.log('');
|
|
717
|
-
console.log('Version aliases:');
|
|
718
|
-
for (const [alias, resolved] of getVersionAliasEntries()) {
|
|
804
|
+
console.log('Version aliases (dynamically resolved):');
|
|
805
|
+
for (const [alias, resolved] of await getVersionAliasEntries()) {
|
|
719
806
|
console.log(` ${alias.padEnd(22)} → ${resolved}`);
|
|
720
807
|
}
|
|
721
808
|
console.log('');
|
|
@@ -737,7 +824,10 @@ export const commands = {
|
|
|
737
824
|
logger.error(error.message);
|
|
738
825
|
process.exit(1);
|
|
739
826
|
}
|
|
740
|
-
const version = resolveVersion(versionSpec);
|
|
827
|
+
const version = await resolveVersion(versionSpec);
|
|
828
|
+
if (isVersionAlias(versionSpec)) {
|
|
829
|
+
logger.info(`Resolved alias "${versionSpec}" → ${version}`);
|
|
830
|
+
}
|
|
741
831
|
const config = { cacheDir: getCacheDir(), version, isAlias: isVersionAlias(versionSpec) };
|
|
742
832
|
|
|
743
833
|
if (parsed.subcommand === 'start') {
|