cloud-runner-develop
Frostebite 2025-12-04 22:32:47 +00:00
parent 1eca7bb6b9
commit 945dec774c
8 changed files with 388 additions and 65 deletions

View File

@ -23,15 +23,16 @@ jobs:
with:
node-version: '18'
- run: yarn
- run: yarn run cli --help
env:
AWS_REGION: eu-west-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
- run: yarn run cli -m list-resources
env:
AWS_REGION: eu-west-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
# Commented out: Using LocalStack tests instead of real AWS
# - run: yarn run cli --help
# env:
# AWS_REGION: eu-west-2
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS_DEFAULT_REGION: eu-west-2
# - run: yarn run cli -m list-resources
# env:
# AWS_REGION: eu-west-2
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS_DEFAULT_REGION: eu-west-2

View File

@ -19,11 +19,12 @@ env:
GCP_LOGGING: true
GCP_PROJECT: unitykubernetesbuilder
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
AWS_REGION: eu-west-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
AWS_STACK_NAME: game-ci-github-pipelines
# Commented out: Using LocalStack tests instead of real AWS
# AWS_REGION: eu-west-2
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# AWS_DEFAULT_REGION: eu-west-2
# AWS_STACK_NAME: game-ci-github-pipelines
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
CLOUD_RUNNER_DEBUG: true
CLOUD_RUNNER_DEBUG_TREE: true
@ -49,7 +50,8 @@ jobs:
cloudRunnerTests: true
versioning: None
CLOUD_RUNNER_CLUSTER: local-docker
AWS_STACK_NAME: game-ci-github-pipelines
# Commented out: Using LocalStack tests instead of real AWS
# AWS_STACK_NAME: game-ci-github-pipelines
CHECKS_UPDATE: ${{ github.event.inputs.checksObject }}
run: |
git clone -b cloud-runner-develop https://github.com/game-ci/unity-builder

View File

@ -15,9 +15,10 @@ permissions:
statuses: write
env:
AWS_REGION: eu-west-2
AWS_DEFAULT_REGION: eu-west-2
AWS_STACK_NAME: game-ci-team-pipelines
# Commented out: Using LocalStack tests instead of real AWS
# AWS_REGION: eu-west-2
# AWS_DEFAULT_REGION: eu-west-2
AWS_STACK_NAME: game-ci-team-pipelines # Still needed for LocalStack S3 bucket creation
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
DEBUG: true
PROJECT_PATH: test-project
@ -149,44 +150,45 @@ jobs:
AWS_ENDPOINT_URL: http://localhost:4566
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
aws:
name: Cloud Runner Tests (AWS)
runs-on: ubuntu-latest
needs: [k8s, localstack]
strategy:
fail-fast: false
matrix:
test:
- 'cloud-runner-end2end-caching'
- 'cloud-runner-end2end-retaining'
- 'cloud-runner-hooks'
steps:
- uses: actions/checkout@v4
with:
lfs: false
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
- run: yarn install --frozen-lockfile
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
timeout-minutes: 60
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
PROJECT_PATH: test-project
TARGET_PLATFORM: StandaloneWindows64
cloudRunnerTests: true
versioning: None
PROVIDER_STRATEGY: aws
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
# Commented out: Using LocalStack tests instead of real AWS
# aws:
# name: Cloud Runner Tests (AWS)
# runs-on: ubuntu-latest
# needs: [k8s, localstack]
# strategy:
# fail-fast: false
# matrix:
# test:
# - 'cloud-runner-end2end-caching'
# - 'cloud-runner-end2end-retaining'
# - 'cloud-runner-hooks'
# steps:
# - uses: actions/checkout@v4
# with:
# lfs: false
# - name: Configure AWS Credentials
# uses: aws-actions/configure-aws-credentials@v1
# with:
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws-region: ${{ env.AWS_REGION }}
# - uses: actions/setup-node@v4
# with:
# node-version: 20
# cache: 'yarn'
# - run: yarn install --frozen-lockfile
# - run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
# timeout-minutes: 60
# env:
# UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
# UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
# UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
# PROJECT_PATH: test-project
# TARGET_PLATFORM: StandaloneWindows64
# cloudRunnerTests: true
# versioning: None
# PROVIDER_STRATEGY: aws
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
# GITHUB_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}

278
dist/index.js vendored
View File

@ -4368,6 +4368,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", ({ value: true }));
const cloud_runner_system_1 = __nccwpck_require__(4197);
const cloud_runner_logger_1 = __importDefault(__nccwpck_require__(42864));
const shell_quote_1 = __nccwpck_require__(87029);
class LocalCloudRunner {
listResources() {
throw new Error('Method not implemented.');
@ -4422,12 +4423,12 @@ class LocalCloudRunner {
// On Windows, many built-in hooks use POSIX shell syntax. Execute via bash if available.
if (process.platform === 'win32') {
const inline = commands
.replace(/"/g, '\\"')
.replace(/\r/g, '')
.split('\n')
.filter((x) => x.trim().length > 0)
.join(' ; ');
const bashWrapped = `bash -lc "${inline}"`;
// Use shell-quote to properly escape the command string, preventing command injection
const bashWrapped = `bash -lc ${(0, shell_quote_1.quote)([inline])}`;
return await cloud_runner_system_1.CloudRunnerSystem.Run(bashWrapped);
}
return await cloud_runner_system_1.CloudRunnerSystem.Run(commands);
@ -298783,6 +298784,279 @@ module.exports = (string = '') => {
module.exports = /^#!(.*)/;
/***/ }),
/***/ 87029:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
"use strict";
exports.quote = __nccwpck_require__(43730);
exports.parse = __nccwpck_require__(40277);
/***/ }),
/***/ 40277:
/***/ ((module) => {
"use strict";
// '<(' is process substitution operator and
// can be parsed the same as control operator
var CONTROL = '(?:' + [
'\\|\\|',
'\\&\\&',
';;',
'\\|\\&',
'\\<\\(',
'\\<\\<\\<',
'>>',
'>\\&',
'<\\&',
'[&;()|<>]'
].join('|') + ')';
var controlRE = new RegExp('^' + CONTROL + '$');
var META = '|&;()<> \\t';
var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
var DOUBLE_QUOTE = '\'((\\\\\'|[^\'])*?)\'';
var hash = /^#$/;
var SQ = "'";
var DQ = '"';
var DS = '$';
var TOKEN = '';
var mult = 0x100000000; // Math.pow(16, 8);
for (var i = 0; i < 4; i++) {
TOKEN += (mult * Math.random()).toString(16);
}
var startsWithToken = new RegExp('^' + TOKEN);
function matchAll(s, r) {
var origIndex = r.lastIndex;
var matches = [];
var matchObj;
while ((matchObj = r.exec(s))) {
matches.push(matchObj);
if (r.lastIndex === matchObj.index) {
r.lastIndex += 1;
}
}
r.lastIndex = origIndex;
return matches;
}
function getVar(env, pre, key) {
var r = typeof env === 'function' ? env(key) : env[key];
if (typeof r === 'undefined' && key != '') {
r = '';
} else if (typeof r === 'undefined') {
r = '$';
}
if (typeof r === 'object') {
return pre + TOKEN + JSON.stringify(r) + TOKEN;
}
return pre + r;
}
function parseInternal(string, env, opts) {
if (!opts) {
opts = {};
}
var BS = opts.escape || '\\';
var BAREWORD = '(\\' + BS + '[\'"' + META + ']|[^\\s\'"' + META + '])+';
var chunker = new RegExp([
'(' + CONTROL + ')', // control chars
'(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')+'
].join('|'), 'g');
var matches = matchAll(string, chunker);
if (matches.length === 0) {
return [];
}
if (!env) {
env = {};
}
var commented = false;
return matches.map(function (match) {
var s = match[0];
if (!s || commented) {
return void undefined;
}
if (controlRE.test(s)) {
return { op: s };
}
// Hand-written scanner/parser for Bash quoting rules:
//
// 1. inside single quotes, all characters are printed literally.
// 2. inside double quotes, all characters are printed literally
// except variables prefixed by '$' and backslashes followed by
// either a double quote or another backslash.
// 3. outside of any quotes, backslashes are treated as escape
// characters and not printed (unless they are themselves escaped)
// 4. quote context can switch mid-token if there is no whitespace
// between the two quote contexts (e.g. all'one'"token" parses as
// "allonetoken")
var quote = false;
var esc = false;
var out = '';
var isGlob = false;
var i;
function parseEnvVar() {
i += 1;
var varend;
var varname;
var char = s.charAt(i);
if (char === '{') {
i += 1;
if (s.charAt(i) === '}') {
throw new Error('Bad substitution: ' + s.slice(i - 2, i + 1));
}
varend = s.indexOf('}', i);
if (varend < 0) {
throw new Error('Bad substitution: ' + s.slice(i));
}
varname = s.slice(i, varend);
i = varend;
} else if ((/[*@#?$!_-]/).test(char)) {
varname = char;
i += 1;
} else {
var slicedFromI = s.slice(i);
varend = slicedFromI.match(/[^\w\d_]/);
if (!varend) {
varname = slicedFromI;
i = s.length;
} else {
varname = slicedFromI.slice(0, varend.index);
i += varend.index - 1;
}
}
return getVar(env, '', varname);
}
for (i = 0; i < s.length; i++) {
var c = s.charAt(i);
isGlob = isGlob || (!quote && (c === '*' || c === '?'));
if (esc) {
out += c;
esc = false;
} else if (quote) {
if (c === quote) {
quote = false;
} else if (quote == SQ) {
out += c;
} else { // Double quote
if (c === BS) {
i += 1;
c = s.charAt(i);
if (c === DQ || c === BS || c === DS) {
out += c;
} else {
out += BS + c;
}
} else if (c === DS) {
out += parseEnvVar();
} else {
out += c;
}
}
} else if (c === DQ || c === SQ) {
quote = c;
} else if (controlRE.test(c)) {
return { op: s };
} else if (hash.test(c)) {
commented = true;
var commentObj = { comment: string.slice(match.index + i + 1) };
if (out.length) {
return [out, commentObj];
}
return [commentObj];
} else if (c === BS) {
esc = true;
} else if (c === DS) {
out += parseEnvVar();
} else {
out += c;
}
}
if (isGlob) {
return { op: 'glob', pattern: out };
}
return out;
}).reduce(function (prev, arg) { // finalize parsed arguments
// TODO: replace this whole reduce with a concat
return typeof arg === 'undefined' ? prev : prev.concat(arg);
}, []);
}
module.exports = function parse(s, env, opts) {
var mapped = parseInternal(s, env, opts);
if (typeof env !== 'function') {
return mapped;
}
return mapped.reduce(function (acc, s) {
if (typeof s === 'object') {
return acc.concat(s);
}
var xs = s.split(RegExp('(' + TOKEN + '.*?' + TOKEN + ')', 'g'));
if (xs.length === 1) {
return acc.concat(xs[0]);
}
return acc.concat(xs.filter(Boolean).map(function (x) {
if (startsWithToken.test(x)) {
return JSON.parse(x.split(TOKEN)[1]);
}
return x;
}));
}, []);
};
/***/ }),
/***/ 43730:
/***/ ((module) => {
"use strict";
module.exports = function quote(xs) {
return xs.map(function (s) {
if (s === '') {
return '\'\'';
}
if (s && typeof s === 'object') {
return s.op.replace(/(.)/g, '\\$1');
}
if ((/["\s\\]/).test(s) && !(/'/).test(s)) {
return "'" + s.replace(/(['])/g, '\\$1') + "'";
}
if ((/["'\s]/).test(s)) {
return '"' + s.replace(/(["\\$`!])/g, '\\$1') + '"';
}
return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, '$1\\$2');
}).join(' ');
};
/***/ }),
/***/ 45123:

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

27
dist/licenses.txt vendored
View File

@ -19407,6 +19407,33 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
shell-quote
MIT
The MIT License
Copyright (c) 2013 James Halliday (mail@substack.net)
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
shelljs
BSD-3-Clause
Copyright (c) 2012, Artur Adib <arturadib@gmail.com>

View File

@ -9,5 +9,6 @@
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
},
"include": ["src/**/*", "types/**/*"],
"exclude": ["node_modules", "dist"]
}

16
types/shell-quote.d.ts vendored 100644
View File

@ -0,0 +1,16 @@
declare module 'shell-quote' {
/**
* Quote an array of strings to be safe to use as shell arguments.
* @param args - Array of strings to quote
* @returns A properly escaped string for shell usage
*/
export function quote(args: string[]): string;
/**
* Parse a shell command string into an array of arguments.
* @param cmd - The command string to parse
* @returns Array of parsed arguments
*/
export function parse(cmd: string): string[];
}