Add Feature to test Unity Packages (#164)

* (should fail) add jq install to docker image

* (might fail) remove rm rf call

* move things around to try to fix test

* Revert "(might fail) remove rm rf call"

This reverts commit 22f74ebca7.

* remove silent setting from docker test

* Fix failing test's Docker image

* Add new input and basic test

* Add test package; start using jq cli

* Use test package in test workflow

* Create temporary Unity Project and run tests

* Test removing jq install from Dockerfile

* Revert "Test removing jq install from Dockerfile"

This reverts commit 6aa7a6f443.

* Remove mkdir call

* remove duplicate command

* add packageMode option back in

* build changes

* check for apt-get before installing jq

* change apt-get version check message

* spelling and documentation fixes

* add working example unity package with tests

* add temp pwd call to help figure out absolute pathing

* fix workflow package location

* add jq to add package to temp project packages

* try fixing jq calls

* clean up jq calls, fix variable expansion

* try renaming jq args

* try using different arg syntax for jq

* try wrapping args in parentheses

* try using double quotes only

* try changing up quoting

* try properly using string interpolation

* try removing colon

* add string interpolation to key

* omit double quotes from jq call to retrieve package name

* clean up logging

* add rest of workflow tests

* Revert "add rest of workflow tests"

This reverts commit c0bb008b2c.

* add play mode test without cache

* add package mode all mode workflow step

* add consecutive ppackage mode workflow step

* add package mode "like in the readme" test

* fix workflow syntax error

* try to fix syntax error again

* use correct folder

* *hopefully actually* use correct package path

* try adding caching to "readme" test

* remove caching/mentions of caching from package mode tests

* fix artifacts paths

* fix artifacts pathing and names

* fix combined artifacts for package mode

* clean up documentation and exit code

* clarify allowed docker images for packageMode

* update README to mention Unity packages

* move package name validation to TS part of action

* improve logging for temp project creation failure

* make husky hook executable

* add error for missing tests folder

* update docs to reflect unsupported packages

* remove jq install

* Revert "remove jq install"

This reverts commit bd35ac8f6f.

* TEMP log image in use

* Revert "TEMP log image in use"

This reverts commit 95722dcab4.

* Revert "Revert "remove jq install""

This reverts commit e3bac048b1.

* TEMP list installed packages

* Revert "TEMP list installed packages"

This reverts commit db9c07da38.

* TEMP log project's manifest

* add code coverage package to generated project

* remove temp project manifest log

* add coverage to package mode tests

* update name of package coverage steps

* add codecoverage dependency to test package

* Revert "add codecoverage dependency to test package"

This reverts commit 4b2c03069d.

* add assembly filters for coverage

* TEMP console log project folder

* Revert "TEMP console log project folder"

This reverts commit 411ec51817.

* add logic to copy package to folder without activation file

* fix false positive activation file detection

* fix improper bash "if" formatting

* TEMP remove conditional for package copying

* Revert "TEMP remove conditional for package copying"

This reverts commit 4f12d83889.

* Revert "fix improper bash "if" formatting"

This reverts commit acb975bcea.

* Revert "fix false positive activation file detection"

This reverts commit 580c9c14a0.

* Revert "add logic to copy package to folder without activation file"

This reverts commit b20d994b5d.

* run yarn build

* move package mode check lower in the file

* throw error if unity version is auto in package mode

* fix unity version error wording

* try deleting activate license file

* try logging hidden package files

* try deleting all non-package files

* fix license activation files deletion

* scrap file removals and print dir permissions

* log permissions for package folder

* Add packageMode inputs to main

* fix fs mocks and run yarn build

* fix documentation and add error message for missing jq

* add clarification on package mode caveats

* fix line endings problem (?)

* Revert "fix line endings problem (?)"

This reverts commit 1cba302bc4.

* Revert "add clarification on package mode caveats"

This reverts commit fb62d36ba1.

* Revert "fix documentation and add error message for missing jq"

This reverts commit 0df3ab6b88.

* Redo the input docs fixes

* Redo the jq presence test

* update readme to indicate package mode caveats

* fix wording on coverageOptions

* one more wording fix on coverageOptions

* move sample package to example.com domain

---------

Co-authored-by: Aaron Trudeau <120415438+trudeaua-vividream-software@users.noreply.github.com>
This commit is contained in:
Aaron Trudeau
2023-07-03 11:09:20 -04:00
committed by GitHub
parent 31086d9859
commit 7787abf249
45 changed files with 1058 additions and 11 deletions

View File

@@ -19,6 +19,8 @@ export async function run() {
gitPrivateToken,
githubToken,
checkName,
packageMode,
packageName,
chownFilesTo,
unityLicensingServer,
} = Input.getFromUser();
@@ -37,6 +39,8 @@ export async function run() {
artifactsPath,
useHostNetwork,
sshAgent,
packageMode,
packageName,
gitPrivateToken,
githubToken,
chownFilesTo,

View File

@@ -62,6 +62,8 @@ const Docker = {
artifactsPath,
useHostNetwork,
sshAgent,
packageMode,
packageName,
gitPrivateToken,
githubToken,
runnerTemporaryPath,
@@ -95,6 +97,8 @@ const Docker = {
--env COVERAGE_OPTIONS="${coverageOptions}" \
--env COVERAGE_RESULTS_PATH="CodeCoverage" \
--env ARTIFACTS_PATH="${artifactsPath}" \
--env PACKAGE_MODE="${packageMode}" \
--env PACKAGE_NAME="${packageName}" \
--env GITHUB_REF \
--env GITHUB_SHA \
--env GITHUB_REPOSITORY \
@@ -142,6 +146,8 @@ const Docker = {
artifactsPath,
useHostNetwork,
sshAgent,
packageMode,
packageName,
gitPrivateToken,
githubToken,
runnerTemporaryPath,
@@ -175,6 +181,8 @@ const Docker = {
--env COVERAGE_OPTIONS="${coverageOptions}" \
--env COVERAGE_RESULTS_PATH="CodeCoverage" \
--env ARTIFACTS_PATH="${artifactsPath}" \
--env PACKAGE_MODE="${packageMode}" \
--env PACKAGE_NAME="${packageName}" \
--env GITHUB_REF \
--env GITHUB_SHA \
--env GITHUB_REPOSITORY \

View File

@@ -1,7 +1,11 @@
import Input from './input';
import fs from 'fs';
jest.mock('./unity-version-parser');
const mockedFsExistsSync = jest.spyOn(fs, 'existsSync');
const mockedFsReadFileSync = jest.spyOn(fs, 'readFileSync');
describe('Input', () => {
describe('getFromUser', () => {
it('does not throw', () => {
@@ -33,4 +37,79 @@ describe('Input', () => {
expect(Input.isValidFolderName(folderName)).toStrictEqual(false);
});
});
describe('getPackageNameFromPackageJson', () => {
it('throws error if package.json cannot be found at the given project path', () => {
mockedFsExistsSync.mockReturnValue(false);
expect(() => Input.getPackageNameFromPackageJson('some/path')).toThrow(
'Invalid projectPath - Cannot find package.json at some/path/package.json',
);
});
it('throws error if package.json contents cannot be parsed', () => {
mockedFsExistsSync.mockReturnValue(true);
mockedFsReadFileSync.mockReturnValue(Buffer.from('DefinitelyNotJSON'));
expect(() => Input.getPackageNameFromPackageJson('some/path')).toThrow(
/Unable to parse package.json contents as JSON/,
);
});
it('throws error if name field in package.json is not present', () => {
mockedFsExistsSync.mockReturnValue(true);
mockedFsReadFileSync.mockReturnValue(
Buffer.from(JSON.stringify({ notName: 'some-package', alsoNotName: 'some-package' })),
);
expect(() => Input.getPackageNameFromPackageJson('some/path')).toThrow(
'Unable to parse package name from package.json - package name should be string, but was undefined',
);
});
it('throws error if name field in package.json is present but not a string', () => {
mockedFsExistsSync.mockReturnValue(true);
mockedFsReadFileSync.mockReturnValue(
Buffer.from(JSON.stringify({ name: 3, notName: 'some-package' })),
);
expect(() => Input.getPackageNameFromPackageJson('some/path')).toThrow(
'Unable to parse package name from package.json - package name should be string, but was number',
);
});
it('throws error if name field in package.json is present but empty', () => {
mockedFsExistsSync.mockReturnValue(true);
mockedFsReadFileSync.mockReturnValue(Buffer.from(JSON.stringify({ name: '', notName: 3 })));
expect(() => Input.getPackageNameFromPackageJson('some/path')).toThrow(
'Package name from package.json is a string, but is empty',
);
});
it('returns the name field in package.json if it is present as a non-empty string', () => {
mockedFsExistsSync.mockReturnValue(true);
mockedFsReadFileSync.mockReturnValue(
Buffer.from(JSON.stringify({ name: 'some-package', notName: 'not-what-we-want' })),
);
expect(Input.getPackageNameFromPackageJson('some/path')).toStrictEqual('some-package');
});
});
describe('verifyTestsFolderIsPresent', () => {
it('throws error if tests folder is not present', () => {
mockedFsExistsSync.mockReturnValue(false);
expect(() => Input.verifyTestsFolderIsPresent('some/path')).toThrow(
'Invalid projectPath - Cannot find package tests folder at some/path/Tests',
);
});
it('does not throw if tests folder is present', () => {
mockedFsExistsSync.mockReturnValue(true);
expect(() => Input.verifyTestsFolderIsPresent('some/path')).not.toThrow();
});
});
});

View File

@@ -1,4 +1,5 @@
import UnityVersionParser from './unity-version-parser';
import fs from 'fs';
import { getInput } from '@actions/core';
const Input = {
@@ -12,6 +13,53 @@ const Input = {
return validFolderName.test(folderName);
},
/**
* When in package mode, we need to scrape the package's name from its package.json file
*/
getPackageNameFromPackageJson(packagePath) {
const packageJsonPath = `${packagePath}/package.json`;
if (!fs.existsSync(packageJsonPath)) {
throw new Error(`Invalid projectPath - Cannot find package.json at ${packageJsonPath}`);
}
let packageJson;
try {
packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
} catch (error) {
if (error instanceof SyntaxError) {
throw new SyntaxError(`Unable to parse package.json contents as JSON - ${error.message}`);
}
throw new Error(`Unable to parse package.json contents as JSON - unknown error ocurred`);
}
const rawPackageName = packageJson.name;
if (typeof rawPackageName !== 'string') {
throw new TypeError(
`Unable to parse package name from package.json - package name should be string, but was ${typeof rawPackageName}`,
);
}
if (rawPackageName.length === 0) {
throw new Error(`Package name from package.json is a string, but is empty`);
}
return rawPackageName;
},
/**
* When in package mode, we need to ensure that the Tests folder is present
*/
verifyTestsFolderIsPresent(packagePath) {
if (!fs.existsSync(`${packagePath}/Tests`)) {
throw new Error(
`Invalid projectPath - Cannot find package tests folder at ${packagePath}/Tests`,
);
}
},
getFromUser() {
// Input variables specified in workflow using "with" prop.
const unityVersion = getInput('unityVersion') || 'auto';
@@ -27,6 +75,8 @@ const Input = {
const gitPrivateToken = getInput('gitPrivateToken') || '';
const githubToken = getInput('githubToken') || '';
const checkName = getInput('checkName') || 'Test Results';
const rawPackageMode = getInput('packageMode') || 'false';
let packageName = '';
const chownFilesTo = getInput('chownFilesTo') || '';
// Validate input
@@ -46,8 +96,28 @@ const Input = {
throw new Error(`Invalid useHostNetwork "${rawUseHostNetwork}"`);
}
// Sanitise input
if (rawPackageMode !== 'true' && rawPackageMode !== 'false') {
throw new Error(`Invalid packageMode "${rawPackageMode}"`);
}
// sanitize packageMode input and projectPath input since they are needed
// for input validation
const packageMode = rawPackageMode === 'true';
const projectPath = rawProjectPath.replace(/\/$/, '');
// if in package mode, attempt to get the package's name, and ensure tests are present
if (packageMode) {
if (unityVersion === 'auto') {
throw new Error(
'Package Mode is enabled, but unityVersion is set to "auto". unityVersion must manually be set in Package Mode.',
);
}
packageName = this.getPackageNameFromPackageJson(projectPath);
this.verifyTestsFolderIsPresent(projectPath);
}
// Sanitise other input
const artifactsPath = rawArtifactsPath.replace(/\/$/, '');
const useHostNetwork = rawUseHostNetwork === 'true';
const editorVersion =
@@ -67,6 +137,8 @@ const Input = {
gitPrivateToken,
githubToken,
checkName,
packageMode,
packageName,
chownFilesTo,
unityLicensingServer,
};