Skip to content

Commit 58c2adc

Browse files
- fix unity hub cli editor output capture - updated version parsing - added unit tests
1 parent 09afb64 commit 58c2adc

File tree

9 files changed

+667
-111
lines changed

9 files changed

+667
-111
lines changed

.github/workflows/build.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,69 @@ jobs:
3535
echo "UNITY_EDITORS: '${{ env.UNITY_EDITORS }}'"
3636
echo "UNITY_EDITOR_PATH: '${{ env.UNITY_EDITOR_PATH }}'"
3737
echo "UNITY_PROJECT_PATH: '${{ env.UNITY_PROJECT_PATH }}'"
38+
# If unity-version is None, UNITY_EDITOR_PATH must be empty
39+
if [[ "${{ matrix.unity-version }}" == "None" ]]; then
40+
if [[ -n "${{ env.UNITY_EDITOR_PATH }}" ]]; then
41+
echo "Error: UNITY_EDITOR_PATH should be empty when unity-version is None, but got '${{ env.UNITY_EDITOR_PATH }}'"
42+
exit 1
43+
else
44+
echo "UNITY_EDITOR_PATH is correctly empty for unity-version=None."
45+
exit 0
46+
fi
47+
fi
48+
# Extract Unity version from UNITY_EDITOR_PATH using regex
49+
if [[ "${{ env.UNITY_EDITOR_PATH }}" =~ ([0-9]+\.[0-9]+\.[0-9]+[abcfpx]?[0-9]*) ]]; then
50+
UNITY_EDITOR_VERSION="${BASH_REMATCH[1]}"
51+
echo "Detected Unity Editor version: $UNITY_EDITOR_VERSION"
52+
else
53+
echo "Could not extract Unity version from UNITY_EDITOR_PATH: '${{ env.UNITY_EDITOR_PATH }}'"
54+
exit 1
55+
fi
56+
# Strip revision/hash from matrix.unity-version (e.g., '5.6.7f1 (e80cc3114ac1)' -> '5.6.7f1')
57+
MATRIX_UNITY_VERSION_PREFIX="${{ matrix.unity-version }}"
58+
if [[ "$MATRIX_UNITY_VERSION_PREFIX" =~ ^([0-9]+\.[0-9]+\.[0-9]+[abcfpx]?[0-9]*) ]]; then
59+
MATRIX_UNITY_VERSION_PREFIX="${BASH_REMATCH[1]}"
60+
fi
61+
# Support matrix.unity-version patterns ending with .x after major.minor (e.g., 2021.3.x)
62+
if [[ "${{ matrix.unity-version }}" =~ ^([0-9]+\.[0-9]+)\.x$ ]]; then
63+
UNITY_MAJOR_MINOR="${BASH_REMATCH[1]}"
64+
if [[ "$UNITY_EDITOR_VERSION" == "$UNITY_MAJOR_MINOR"* ]]; then
65+
echo "Unity version matches matrix.unity-version: $UNITY_EDITOR_VERSION satisfies ${{ matrix.unity-version }}"
66+
else
67+
echo "Unity version mismatch: $UNITY_EDITOR_VERSION does not satisfy ${{ matrix.unity-version }}"
68+
exit 1
69+
fi
70+
# Support matrix.unity-version patterns ending with .x after major (e.g., 2022.x)
71+
elif [[ "${{ matrix.unity-version }}" =~ ^([0-9]+)\.x$ ]]; then
72+
UNITY_MAJOR="${BASH_REMATCH[1]}"
73+
if [[ "$UNITY_EDITOR_VERSION" == "$UNITY_MAJOR"* ]]; then
74+
echo "Unity version matches matrix.unity-version: $UNITY_EDITOR_VERSION satisfies ${{ matrix.unity-version }}"
75+
else
76+
echo "Unity version mismatch: $UNITY_EDITOR_VERSION does not satisfy ${{ matrix.unity-version }}"
77+
exit 1
78+
fi
79+
# Support matrix.unity-version patterns with only major.minor (e.g., 2020.3)
80+
elif [[ "${{ matrix.unity-version }}" =~ ^([0-9]+\.[0-9]+)$ ]]; then
81+
UNITY_MAJOR_MINOR="${BASH_REMATCH[1]}"
82+
if [[ "$UNITY_EDITOR_VERSION" == "$UNITY_MAJOR_MINOR"* ]]; then
83+
echo "Unity version matches matrix.unity-version: $UNITY_EDITOR_VERSION satisfies ${{ matrix.unity-version }}"
84+
else
85+
echo "Unity version mismatch: $UNITY_EDITOR_VERSION does not satisfy ${{ matrix.unity-version }}"
86+
exit 1
87+
fi
88+
# Support matrix.unity-version patterns with only major (e.g., 6000)
89+
elif [[ "${{ matrix.unity-version }}" =~ ^([0-9]+)$ ]]; then
90+
UNITY_MAJOR="${BASH_REMATCH[1]}"
91+
if [[ "$UNITY_EDITOR_VERSION" == "$UNITY_MAJOR"* ]]; then
92+
echo "Unity version matches matrix.unity-version: $UNITY_EDITOR_VERSION satisfies ${{ matrix.unity-version }}"
93+
else
94+
echo "Unity version mismatch: $UNITY_EDITOR_VERSION does not satisfy ${{ matrix.unity-version }}"
95+
exit 1
96+
fi
97+
elif [[ "$UNITY_EDITOR_VERSION" == "$MATRIX_UNITY_VERSION_PREFIX" ]]; then
98+
echo "Unity version matches matrix.unity-version: $UNITY_EDITOR_VERSION satisfies ${{ matrix.unity-version }}"
99+
else
100+
echo "Unity version mismatch: $UNITY_EDITOR_VERSION does not satisfy ${{ matrix.unity-version }}"
101+
exit 1
102+
fi
103+
shell: bash

dist/index.js

Lines changed: 138 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -35680,7 +35680,6 @@ function getUnityVersionsFromInput(architecture) {
3568035680
const versionParts = version.split('.');
3568135681
switch (versionParts.length) {
3568235682
case 1:
35683-
version = version + '.0.0';
3568435683
break;
3568535684
case 2:
3568635685
version = version + '.0';
@@ -35857,7 +35856,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
3585735856
exports.Get = Get;
3585835857
exports.SetInstallPath = SetInstallPath;
3585935858
exports.UnityEditor = UnityEditor;
35859+
exports.getLatestHubReleases = getLatestHubReleases;
3586035860
exports.ListInstalledEditors = ListInstalledEditors;
35861+
exports.getEditorReleaseInfo = getEditorReleaseInfo;
3586135862
const asar = __nccwpck_require__(6561);
3586235863
const core = __nccwpck_require__(2186);
3586335864
const exec = __nccwpck_require__(1514);
@@ -36197,7 +36198,16 @@ async function patchBeeBackend(editorPath) {
3619736198
}
3619836199
}
3619936200
async function getLatestHubReleases() {
36200-
return (await execUnityHub([`editors`, `--releases`])).split('\n').map(line => line.trim()).filter(line => line.length > 0);
36201+
const versionRegex = /(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/;
36202+
return (await execUnityHub([`editors`, `--releases`]))
36203+
.split('\n')
36204+
.map(line => line.trim())
36205+
.filter(line => line.length > 0)
36206+
.map(line => {
36207+
const match = line.match(versionRegex);
36208+
return match ? match[0] : '';
36209+
})
36210+
.filter(v => v.length > 0);
3620136211
}
3620236212
async function installUnity(unityVersion, modules) {
3620336213
if (unityVersion.isLegacy()) {
@@ -36275,7 +36285,7 @@ async function checkInstalledEditors(unityVersion, failOnEmpty, installPath = un
3627536285
const paths = await ListInstalledEditors();
3627636286
core.debug(`Paths: ${JSON.stringify(paths, null, 2)}`);
3627736287
if (paths && paths.length > 0) {
36278-
const pattern = /(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\s*(?:\((?<arch>Apple silicon|Intel)\))?\s*, installed at (?<editorPath>.*)/;
36288+
const pattern = /(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\s*(?:\((?<arch>Apple silicon|Intel)\))?\s*,? installed at (?<editorPath>.*)/;
3627936289
const matches = paths.map(path => path.match(pattern)).filter(match => match && match.groups);
3628036290
core.debug(`Matches: ${JSON.stringify(matches, null, 2)}`);
3628136291
if (paths.length !== matches.length) {
@@ -36373,12 +36383,19 @@ async function getModulesContent(modulesPath) {
3637336383
return JSON.parse(modulesContent);
3637436384
}
3637536385
async function getEditorReleaseInfo(unityVersion) {
36376-
let version = unityVersion.version;
36377-
if (version.endsWith('.0')) {
36378-
version = version.slice(0, -2);
36386+
const fullUnityVersionPattern = /^\d{1,4}\.\d+\.\d+[abcfpx]\d+$/;
36387+
let version;
36388+
if (fullUnityVersionPattern.test(unityVersion.version)) {
36389+
version = unityVersion.version;
3637936390
}
36380-
if (version.endsWith('.0')) {
36381-
version = version.slice(0, -2);
36391+
else {
36392+
const mm = unityVersion.version.match(/^(\d{1,4})(?:\.(\d+))?/);
36393+
if (mm) {
36394+
version = mm[2] ? `${mm[1]}.${mm[2]}` : mm[1];
36395+
}
36396+
else {
36397+
version = unityVersion.version.split('.')[0];
36398+
}
3638236399
}
3638336400
const releasesClient = new unity_releases_api_1.UnityReleasesClient();
3638436401
const request = {
@@ -36398,19 +36415,52 @@ async function getEditorReleaseInfo(unityVersion) {
3639836415
throw new Error(`No Unity releases found for version: ${version}`);
3639936416
}
3640036417
core.debug(`Found Unity Release: ${JSON.stringify(data, null, 2)}`);
36401-
return data.results[0];
36418+
const isExplicitPrerelease = /[abcpx]$/.test(unityVersion.version) || /[abcpx]/.test(unityVersion.version);
36419+
const results = (data.results || [])
36420+
.filter(r => isExplicitPrerelease ? true : /f\d+$/.test(r.version))
36421+
.sort((a, b) => {
36422+
const parse = (v) => {
36423+
const m = v.match(/(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/);
36424+
return m ? [parseInt(m[2]), parseInt(m[3]), m[4], parseInt(m[5])] : [0, 0, 'f', 0];
36425+
};
36426+
const [aMinor, aPatch, aTag, aNum] = parse(a.version);
36427+
const [bMinor, bPatch, bTag, bNum] = parse(b.version);
36428+
if (aMinor !== bMinor)
36429+
return bMinor - aMinor;
36430+
if (aPatch !== bPatch)
36431+
return bPatch - aPatch;
36432+
const order = { f: 5, p: 4, c: 3, b: 2, a: 1, x: 0 };
36433+
if (order[aTag] !== order[bTag])
36434+
return (order[bTag] || 0) - (order[aTag] || 0);
36435+
return bNum - aNum;
36436+
});
36437+
if (results.length === 0) {
36438+
throw new Error(`No suitable Unity releases (stable) found for version: ${version}`);
36439+
}
36440+
core.debug(`Found Unity Release: ${JSON.stringify({ query: version, picked: results[0] }, null, 2)}`);
36441+
return results[0];
3640236442
}
3640336443
async function fallbackVersionLookup(unityVersion) {
36404-
const splitVersion = unityVersion.version.split(/[fab]/)[0];
36405-
const url = `https://unity.com/releases/editor/whats-new/${splitVersion}`;
36444+
let version = unityVersion.version.split('.')[0];
36445+
if (/^\d{1,4}\.0(\.0)?$/.test(unityVersion.version)) {
36446+
version = unityVersion.version.split('.')[0];
36447+
}
36448+
const url = `https://unity.com/releases/editor/whats-new/${version}`;
3640636449
core.debug(`Fetching release page: "${url}"`);
36407-
const response = await fetch(url);
36450+
let response;
36451+
try {
36452+
response = await fetch(url);
36453+
}
36454+
catch (error) {
36455+
core.warning(`Failed to fetch changeset for Unity ${unityVersion.toString()} [network error]: ${error}`);
36456+
return unityVersion;
36457+
}
3640836458
if (!response.ok) {
3640936459
throw new Error(`Failed to fetch changeset [${response.status}] "${url}"`);
3641036460
}
3641136461
const data = await response.text();
3641236462
core.debug(`Release page content:\n${data}`);
36413-
const match = data.match(/unityhub:\/\/(?<version>\d+\.\d+\.\d+[fab]?\d*)\/(?<changeset>[a-zA-Z0-9]+)/);
36463+
const match = data.match(/unityhub:\/\/(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\/(?<changeset>[a-zA-Z0-9]+)/);
3641436464
if (match && match.groups && match.groups.changeset) {
3641536465
return new unity_version_1.UnityVersion(match.groups.version, match.groups.changeset, unityVersion.architecture);
3641636466
}
@@ -36445,15 +36495,13 @@ class UnityVersion {
3644536495
}
3644636496
}
3644736497
static compare(a, b) {
36448-
const vA = a.version;
36449-
const vB = b.version;
36450-
return semver.compare(vA, vB, true);
36498+
return semver.compare(a.semVer, b.semVer, true);
3645136499
}
3645236500
toString() {
3645336501
return this.changeset ? `${this.version} (${this.changeset})` : this.version;
3645436502
}
3645536503
isLegacy() {
36456-
return semver.major(this.version, { loose: true }) <= 4;
36504+
return this.semVer.major <= 4;
3645736505
}
3645836506
isArmCompatible() {
3645936507
if (this.semVer.major < 2021) {
@@ -36462,48 +36510,89 @@ class UnityVersion {
3646236510
return semver.compare(this.semVer, '2021.0.0', true) >= 0;
3646336511
}
3646436512
findMatch(versions) {
36465-
const exactMatch = versions.find(r => {
36466-
const match = r.match(/(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)/);
36513+
const fullPattern = /^\d{1,4}\.\d+\.\d+[abcfpx]\d+$/;
36514+
const exactMatch = versions.find(release => {
36515+
const match = release.match(/(?<version>\d{1,4}\.\d+\.\d+[abcfpx]\d+)/);
3646736516
return match && match.groups && match.groups.version === this.version;
3646836517
});
3646936518
if (exactMatch) {
3647036519
core.debug(`Exact match found for ${this.version}`);
3647136520
return new UnityVersion(this.version, null, this.architecture);
3647236521
}
36473-
const versionParts = this.version.match(/^(\d+)\.(\d+)\.(\d+)/);
36474-
let minorIsZero = false, patchIsZero = false;
36475-
if (versionParts) {
36476-
const [, , minor, patch] = versionParts;
36477-
minorIsZero = minor === '0';
36478-
patchIsZero = patch === '0';
36479-
}
36480-
if (minorIsZero && patchIsZero) {
36481-
const validReleases = versions
36482-
.map(release => semver.coerce(release))
36483-
.filter(release => release && semver.satisfies(release, `^${this.semVer}`))
36484-
.sort((a, b) => semver.compare(a, b));
36485-
core.debug(`Searching for fallback match for ${this.version}:`);
36486-
validReleases.forEach(release => {
36487-
core.debug(` > ${release}`);
36488-
});
36489-
for (const release of validReleases) {
36490-
if (!release) {
36491-
continue;
36522+
const hasWildcard = /\.x($|[^\w])/.test(this.version) || /\.\*($|[^\w])/.test(this.version);
36523+
const triggerFallback = hasWildcard || !fullPattern.test(this.version);
36524+
if (triggerFallback) {
36525+
let major, minor;
36526+
const xMatch = this.version.match(/^(\d{1,4})(?:\.(\d+|x|\*))?(?:\.(\d+|x|\*))?/);
36527+
if (xMatch) {
36528+
major = xMatch[1];
36529+
minor = xMatch[2];
36530+
}
36531+
let releases = versions
36532+
.map(release => {
36533+
const match = release.match(/(?<version>\d{1,4}\.\d+\.\d+[abcfpx]\d+)/);
36534+
return match && match.groups ? match.groups.version : null;
36535+
})
36536+
.filter(Boolean)
36537+
.filter(version => {
36538+
if (!version) {
36539+
return false;
3649236540
}
36493-
const originalRelease = versions.find(r => r.includes(release.version));
36494-
if (!originalRelease) {
36495-
continue;
36541+
const parts = version.match(/(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/);
36542+
if (!parts || parts[4] !== 'f') {
36543+
return false;
3649636544
}
36497-
const match = originalRelease.match(/(?<version>\d+\.\d+\.\d+[abcfpx]?\d*)\s*(?:\((?<arch>Apple silicon|Intel)\))?/);
36498-
if (!(match && match.groups && match.groups.version)) {
36499-
continue;
36545+
if (major && parts[1] !== major) {
36546+
return false;
36547+
}
36548+
if (minor && minor !== 'x' && minor !== '*' && parts[2] !== minor) {
36549+
return false;
36550+
}
36551+
return true;
36552+
});
36553+
if (releases.length === 0 && minor === '0') {
36554+
releases = versions
36555+
.map(release => {
36556+
const match = release.match(/(?<version>\d{1,4}\.\d+\.\d+[abcfpx]\d+)/);
36557+
return match && match.groups ? match.groups.version : null;
36558+
})
36559+
.filter(Boolean)
36560+
.filter(version => {
36561+
if (!version) {
36562+
return false;
36563+
}
36564+
const parts = version.match(/(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/);
36565+
if (!parts || parts[4] !== 'f') {
36566+
return false;
36567+
}
36568+
if (major && parts[1] !== major) {
36569+
return false;
36570+
}
36571+
return true;
36572+
});
36573+
}
36574+
releases.sort((a, b) => {
36575+
const parse = (v) => {
36576+
const match = v.match(/(\d{1,4})\.(\d+)\.(\d+)([abcfpx])(\d+)/);
36577+
return match ? [parseInt(match[2]), parseInt(match[3]), parseInt(match[5])] : [0, 0, 0];
36578+
};
36579+
const [aMinor, aPatch, af] = parse(a);
36580+
const [bMinor, bPatch, bf] = parse(b);
36581+
if (aMinor !== bMinor) {
36582+
return bMinor - aMinor;
3650036583
}
36501-
if ((this.version.includes('a') && match.groups.version.includes('a')) ||
36502-
(this.version.includes('b') && match.groups.version.includes('b')) ||
36503-
match.groups.version.includes('f')) {
36504-
core.debug(`Found fallback Unity ${match.groups.version}`);
36505-
return new UnityVersion(match.groups.version, null, this.architecture);
36584+
if (aPatch !== bPatch) {
36585+
return bPatch - aPatch;
3650636586
}
36587+
return bf - af;
36588+
});
36589+
core.debug(`Searching for fallback match for ${this.version}:`);
36590+
releases.forEach(version => {
36591+
core.debug(` > ${version}`);
36592+
});
36593+
if (releases.length > 0) {
36594+
core.debug(`Found fallback Unity ${releases[0]}`);
36595+
return new UnityVersion(releases[0], null, this.architecture);
3650736596
}
3650836597
}
3650936598
core.debug(`No matching Unity version found for ${this.version}`);

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "unity-setup",
3-
"version": "1.2.3",
3+
"version": "1.2.5",
44
"description": "A GitHub action for setting up the Unity Game Engine for CI/CD workflows.",
55
"author": "RageAgainstThePixel",
66
"license": "MIT",
@@ -33,7 +33,7 @@
3333
"yaml": "^2.8.1"
3434
},
3535
"devDependencies": {
36-
"@types/node": "^22.17.0",
36+
"@types/node": "^22.18.0",
3737
"@types/semver": "^7.7.0",
3838
"@vercel/ncc": "^0.34.0",
3939
"shx": "^0.3.4",

0 commit comments

Comments
 (0)