Skip to content

Commit dd95ad9

Browse files
committed
fix(licensing): add unityLicensingToolset input + fix HOME/USER under runAsHostUser
Addresses #739. Two opt-in, backwards-compatible changes for users on Linux Docker builds with a Unity floating-license server: 1. Floating license servers that host multiple toolsets had no way to tell the Licensing Client which toolset to request — Unity could fall through to an entitlement that lacks build-target support (e.g. Android), then silently produce a Linux Standalone artifact. The action now accepts an optional unityLicensingToolset input that is written into services-config.json. When unset, the rendered config is byte-for-byte identical to before. 2. With runAsHostUser: true, su was invoked without explicit HOME/USER, so the host user inherited root's environment (HOME=/root, USER unset). The Unity Licensing Client, which writes to ~/.config/unity3d, could not resolve a writable home directory, leading to intermittent license activation failures. Set HOME/USER/LOGNAME explicitly before sourcing build steps. Change lives entirely inside the existing runAsHostUser branch.
1 parent d829bfc commit dd95ad9

9 files changed

Lines changed: 1385 additions & 14258 deletions

File tree

action.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@ inputs:
168168
default: ''
169169
required: false
170170
description: 'The Unity licensing server address to use for activating Unity.'
171+
unityLicensingToolset:
172+
default: ''
173+
required: false
174+
description:
175+
'Optional toolset identifier for Unity floating-license servers that host multiple toolsets (e.g.
176+
"LicenseServer_1234567890_3"). When set, written to services-config.json so the Licensing Client
177+
requests entitlements from the named toolset instead of relying on the server-side default. Leave
178+
empty to preserve previous behavior.'
171179
dockerWorkspacePath:
172180
default: '/github/workspace'
173181
required: false
@@ -181,8 +189,7 @@ inputs:
181189
linux64RemoveExecutableExtension:
182190
default: 'false'
183191
required: false
184-
description:
185-
'When building for StandaloneLinux64, remove the default file extension of `.x86_64`. Set to true to restore the extensionless behavior from v4.'
192+
description: 'When building for StandaloneLinux64, remove the default file extension of `.x86_64`. Set to true to restore the extensionless behavior from v4.'
186193

187194
outputs:
188195
volume:

dist/index.js

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

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.

dist/licenses.txt

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

dist/platforms/ubuntu/entrypoint.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ if [[ "$RUN_AS_HOST_USER" == "true" ]]; then
7171
# Don't stop on error when running our scripts as error handling is baked in
7272
set +e
7373

74-
# Switch to the host user so we can create files with the correct ownership
75-
su $USERNAME -c "$SHELL -c 'source /steps/runsteps.sh'"
74+
# Switch to the host user so we can create files with the correct ownership.
75+
# Pass HOME/USER explicitly so the Unity Licensing Client (which writes to
76+
# ~/.config/unity3d) resolves a real, writable home directory rather than
77+
# falling back to /home/UNKNOWN when getpwuid() inside the container has no
78+
# entry for the host UID. -p preserves the rest of the env from root.
79+
su -p $USERNAME -c "HOME=/home/$USERNAME USER=$USERNAME LOGNAME=$USERNAME $SHELL -c 'source /steps/runsteps.sh'"
7680
else
7781
echo "Running as root"
7882

src/model/build-parameters.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,18 @@ describe('BuildParameters', () => {
127127
${Platform.types.StandaloneLinux64} | ${''} | ${'n/a'} | ${true}
128128
`(
129129
'appends $expectedExtension for $targetPlatform with linux64RemoveExecutableExtension=$linux64RemoveExecutableExtension',
130-
async ({ targetPlatform, expectedExtension, androidExportType, linux64RemoveExecutableExtension }) => {
130+
async ({
131+
targetPlatform,
132+
expectedExtension,
133+
androidExportType,
134+
linux64RemoveExecutableExtension,
135+
}) => {
131136
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
132137
vi.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
133138
vi.spyOn(Input, 'androidExportType', 'get').mockReturnValue(androidExportType);
134-
vi.spyOn(Input, 'linux64RemoveExecutableExtension', 'get').mockReturnValue(linux64RemoveExecutableExtension);
139+
vi.spyOn(Input, 'linux64RemoveExecutableExtension', 'get').mockReturnValue(
140+
linux64RemoveExecutableExtension,
141+
);
135142
await expect(BuildParameters.create()).resolves.toEqual(
136143
expect.objectContaining({ buildFile: `${targetPlatform}${expectedExtension}` }),
137144
);
@@ -221,6 +228,14 @@ describe('BuildParameters', () => {
221228
);
222229
});
223230

231+
it('returns the unity licensing toolset', async () => {
232+
const mockValue = 'LicenseServer_1234567890_3';
233+
vi.spyOn(Input, 'unityLicensingToolset', 'get').mockReturnValue(mockValue);
234+
await expect(BuildParameters.create()).resolves.toEqual(
235+
expect.objectContaining({ unityLicensingToolset: mockValue }),
236+
);
237+
});
238+
224239
it('throws error when no unity license provider provided', async () => {
225240
delete process.env.UNITY_LICENSE; // Need to delete this as it is set for every test currently
226241
await expect(BuildParameters.create()).rejects.toThrowError();

src/model/build-parameters.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BuildParameters {
1818
public customImage!: string;
1919
public unitySerial!: string;
2020
public unityLicensingServer!: string;
21+
public unityLicensingToolset!: string;
2122
public skipActivation!: string;
2223
public runnerTempPath!: string;
2324
public targetPlatform!: string;
@@ -136,6 +137,7 @@ class BuildParameters {
136137
customImage: Input.customImage,
137138
unitySerial,
138139
unityLicensingServer: Input.unityLicensingServer,
140+
unityLicensingToolset: Input.unityLicensingToolset,
139141
skipActivation: Input.skipActivation,
140142
runnerTempPath: Input.runnerTempPath,
141143
targetPlatform: Input.targetPlatform,

src/model/input.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ class Input {
122122
return Input.getInput('unityLicensingServer') ?? '';
123123
}
124124

125+
static get unityLicensingToolset(): string {
126+
return Input.getInput('unityLicensingToolset') ?? '';
127+
}
128+
125129
static get buildMethod(): string {
126130
return Input.getInput('buildMethod') ?? ''; // Processed in docker file
127131
}

src/model/platform-setup.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class PlatformSetup {
3232

3333
let servicesConfig = fs.readFileSync(servicesConfigPathTemplate).toString();
3434
servicesConfig = servicesConfig.replace('%URL%', buildParameters.unityLicensingServer);
35+
36+
if (buildParameters.unityLicensingToolset) {
37+
const parsed = JSON.parse(servicesConfig);
38+
parsed.toolset = buildParameters.unityLicensingToolset;
39+
servicesConfig = JSON.stringify(parsed, undefined, 2);
40+
}
41+
3542
fs.writeFileSync(servicesConfigPath, servicesConfig);
3643

3744
SetupAndroid.setup(buildParameters);

0 commit comments

Comments
 (0)