Attempt to streamline dev lifecycle (git hooks) (#357)
* fix: misalignments in dev lifecycle * fix: dist no longer added to staged * fix: misalignments in dev lifecycle * chore: multi-platform hooks and tests * chore: multi-platform hooks and tests * chore: add intention for colors * chore: update lint-staged to fix color * chore: update dist files * feat: move to lefthook (remove husky and lint-staged) * feat: move to lefthook (remove husky and lint-staged) * fix: test aftereach * fix: test aftereach * fix: early restore call * feat: jest fails if something gets logged to console * chore: add todos of misplaced code * chore: update dist files * chore: move jest file
This commit is contained in:
@@ -5,16 +5,15 @@ import BuildParameters from './build-parameters';
|
||||
import Input from './input';
|
||||
import Platform from './platform';
|
||||
|
||||
// Todo - Don't use process.env directly, that's what the input model class is for.
|
||||
const testLicense =
|
||||
'<?xml version="1.0" encoding="UTF-8"?><root>\n <License id="Terms">\n <MachineBindings>\n <Binding Key="1" Value="576562626572264761624c65526f7578"/>\n <Binding Key="2" Value="576562626572264761624c65526f7578"/>\n </MachineBindings>\n <MachineID Value="D7nTUnjNAmtsUMcnoyrqkgIbYdM="/>\n <SerialHash Value="2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80"/>\n <Features>\n <Feature Value="33"/>\n <Feature Value="1"/>\n <Feature Value="12"/>\n <Feature Value="2"/>\n <Feature Value="24"/>\n <Feature Value="3"/>\n <Feature Value="36"/>\n <Feature Value="17"/>\n <Feature Value="19"/>\n <Feature Value="62"/>\n </Features>\n <DeveloperData Value="AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg=="/>\n <SerialMasked Value="F4-BGRX-XD4E-ZCWV-C5JW-XXXX"/>\n <StartDate Value="2021-02-08T00:00:00"/>\n <UpdateDate Value="2021-02-09T00:34:57"/>\n <InitialActivationDate Value="2021-02-08T00:34:56"/>\n <LicenseVersion Value="6.x"/>\n <ClientProvidedVersion Value="2018.4.30f1"/>\n <AlwaysOnline Value="false"/>\n <Entitlements>\n <Entitlement Ns="unity_editor" Tag="UnityPersonal" Type="EDITOR" ValidTo="9999-12-31T00:00:00"/>\n <Entitlement Ns="unity_editor" Tag="DarkSkin" Type="EDITOR_FEATURE" ValidTo="9999-12-31T00:00:00"/>\n </Entitlements>\n </License>\n<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#Terms"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>';
|
||||
process.env.UNITY_LICENSE = testLicense;
|
||||
|
||||
const determineVersion = jest.spyOn(Versioning, 'determineVersion').mockImplementation(async () => '1.3.37');
|
||||
|
||||
const determineUnityVersion = jest
|
||||
.spyOn(UnityVersioning, 'determineUnityVersion')
|
||||
.mockImplementation(() => '2019.2.11f1');
|
||||
|
||||
const determineSdkManagerParameters = jest
|
||||
.spyOn(AndroidVersioning, 'determineSdkManagerParameters')
|
||||
.mockImplementation(() => 'platforms;android-30');
|
||||
|
||||
@@ -55,15 +55,13 @@ class BuildParameters {
|
||||
|
||||
static async create(): Promise<BuildParameters> {
|
||||
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidAppBundle);
|
||||
|
||||
const unityVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
|
||||
|
||||
const buildVersion = await Versioning.determineVersion(Input.versioningStrategy, Input.specifiedVersion);
|
||||
|
||||
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode);
|
||||
|
||||
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(Input.androidTargetSdkVersion);
|
||||
|
||||
// Todo - Don't use process.env directly, that's what the input model class is for.
|
||||
// ---
|
||||
let unitySerial = '';
|
||||
if (!process.env.UNITY_SERIAL) {
|
||||
//No serial was present so it is a personal license that we need to convert
|
||||
@@ -78,6 +76,7 @@ class BuildParameters {
|
||||
unitySerial = process.env.UNITY_SERIAL!;
|
||||
}
|
||||
core.setSecret(unitySerial);
|
||||
// ---
|
||||
|
||||
return {
|
||||
version: unityVersion,
|
||||
|
||||
@@ -7,12 +7,14 @@ export class GitRepoReader {
|
||||
static GetSha() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public static async GetRemote() {
|
||||
return (await CloudRunnerSystem.Run(`git remote -v`))
|
||||
.split(' ')[1]
|
||||
.split('https://github.com/')[1]
|
||||
.split('.git')[0];
|
||||
}
|
||||
|
||||
public static async GetBranch() {
|
||||
assert(fs.existsSync(`.git`));
|
||||
return (await System.run(`git branch`, [], {}, false)).split('*')[1].split(`\n`)[0].replace(/ /g, ``);
|
||||
|
||||
@@ -2,8 +2,11 @@ import { GithubCliReader } from './github-cli';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
describe(`github cli`, () => {
|
||||
it(`returns`, async () => {
|
||||
// Todo - We can not assume that everyone has the GitHub cli installed locally.
|
||||
it.skip(`returns`, async () => {
|
||||
const token = await GithubCliReader.GetGitHubAuthToken();
|
||||
|
||||
// Todo - use expect(result).toStrictEqual(something)
|
||||
core.info(token);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -147,7 +147,7 @@ class Input {
|
||||
}
|
||||
|
||||
static get androidTargetSdkVersion() {
|
||||
return core.getInput('androidTargetSdkVersion') || '';
|
||||
return Input.getInput('androidTargetSdkVersion') || '';
|
||||
}
|
||||
|
||||
static get sshAgent() {
|
||||
@@ -155,7 +155,7 @@ class Input {
|
||||
}
|
||||
|
||||
static async gitPrivateToken() {
|
||||
return core.getInput('gitPrivateToken') || (await Input.githubToken());
|
||||
return Input.getInput('gitPrivateToken') || (await Input.githubToken());
|
||||
}
|
||||
|
||||
static get chownFilesTo() {
|
||||
|
||||
46
src/model/system.integration.test.ts
Normal file
46
src/model/system.integration.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as core from '@actions/core';
|
||||
import System from './system';
|
||||
|
||||
jest.spyOn(core, 'debug').mockImplementation(() => {});
|
||||
jest.spyOn(core, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(core, 'warning').mockImplementation(() => {});
|
||||
jest.spyOn(core, 'error').mockImplementation(() => {});
|
||||
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
|
||||
describe('System', () => {
|
||||
describe('run', () => {
|
||||
/**
|
||||
* Not all shells (e.g. Powershell, sh) have a reference to `echo` binary (absent or alias).
|
||||
* To ensure our integration with '@actions/exec' works as expected we run some specific tests in CI only
|
||||
*/
|
||||
describe('integration', () => {
|
||||
if (!process.env.CI) {
|
||||
it("doesn't run locally", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
} else {
|
||||
it('runs a command successfully', async () => {
|
||||
await expect(System.run('true')).resolves.not.toBeNull();
|
||||
});
|
||||
|
||||
it('outputs results', async () => {
|
||||
await expect(System.run('echo test')).resolves.toStrictEqual('test\n');
|
||||
});
|
||||
|
||||
it('throws on when error code is not 0', async () => {
|
||||
await expect(System.run('false')).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('allows pipes using buffer', async () => {
|
||||
await expect(
|
||||
System.run('sh', undefined, {
|
||||
input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'),
|
||||
// eslint-disable-next-line github/no-then
|
||||
}).then((result) => Number(result)),
|
||||
).resolves.not.toBeNaN();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,57 +1,46 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import System from './system';
|
||||
|
||||
jest.spyOn(core, 'debug').mockImplementation(() => {});
|
||||
const info = jest.spyOn(core, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(core, 'warning').mockImplementation(() => {});
|
||||
jest.spyOn(core, 'error').mockImplementation(() => {});
|
||||
const execSpy = jest.spyOn(exec, 'exec').mockImplementation(async () => 0);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
|
||||
describe('System', () => {
|
||||
describe('run', () => {
|
||||
it('runs a command successfully', async () => {
|
||||
await expect(System.run('true')).resolves.not.toBeNull();
|
||||
});
|
||||
describe('units', () => {
|
||||
it('passes the command to command line', async () => {
|
||||
await expect(System.run('echo test')).resolves.not.toBeNull();
|
||||
await expect(execSpy).toHaveBeenLastCalledWith('echo test', expect.anything(), expect.anything());
|
||||
});
|
||||
|
||||
it('outputs results', async () => {
|
||||
await expect(System.run('echo test')).resolves.toStrictEqual('test\n');
|
||||
});
|
||||
it('throws on when error code is not 0', async () => {
|
||||
execSpy.mockImplementationOnce(async () => 1);
|
||||
await expect(System.run('false')).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('throws on when error code is not 0', async () => {
|
||||
await expect(System.run('false')).rejects.toThrowError();
|
||||
});
|
||||
it('throws when no command is given', async () => {
|
||||
await expect(System.run('')).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('throws when no arguments are given', async () => {
|
||||
await expect(System.run('')).rejects.toThrowError();
|
||||
});
|
||||
it('throws when command consists only of spaces', async () => {
|
||||
await expect(System.run(' \t\n')).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('outputs info', async () => {
|
||||
await expect(System.run('echo test')).resolves.not.toBeNull();
|
||||
expect(info).toHaveBeenLastCalledWith('test\n');
|
||||
});
|
||||
it('outputs info', async () => {
|
||||
execSpy.mockImplementationOnce(async (input, _, options) => {
|
||||
options?.listeners?.stdout?.(Buffer.from(input, 'utf8'));
|
||||
return 0;
|
||||
});
|
||||
|
||||
it('outputs info only once', async () => {
|
||||
await expect(System.run('echo 1')).resolves.not.toBeNull();
|
||||
expect(info).toHaveBeenCalledTimes(1);
|
||||
expect(info).toHaveBeenLastCalledWith('1\n');
|
||||
|
||||
info.mockClear();
|
||||
await expect(System.run('echo 2')).resolves.not.toBeNull();
|
||||
await expect(System.run('echo 3')).resolves.not.toBeNull();
|
||||
expect(info).toHaveBeenCalledTimes(2);
|
||||
expect(info).toHaveBeenLastCalledWith('3\n');
|
||||
});
|
||||
|
||||
it('allows pipes using buffer', async () => {
|
||||
await expect(
|
||||
System.run('sh', undefined, {
|
||||
input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'),
|
||||
// eslint-disable-next-line github/no-then
|
||||
}).then((result) => Number(result)),
|
||||
).resolves.not.toBeNaN();
|
||||
await expect(System.run('foo-bar')).resolves.not.toBeNull();
|
||||
expect(info).toHaveBeenCalledTimes(1);
|
||||
expect(info).toHaveBeenLastCalledWith('foo-bar');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,6 +45,10 @@ class System {
|
||||
};
|
||||
|
||||
try {
|
||||
if (command.trim() === '') {
|
||||
throw new Error(`Failed to execute empty command`);
|
||||
}
|
||||
|
||||
const exitCode = await exec(command, arguments_, { silent: true, listeners, ...options });
|
||||
showOutput();
|
||||
if (exitCode !== 0) {
|
||||
|
||||
Reference in New Issue
Block a user