diff --git a/.github/workflows/timeout-test.yml b/.github/workflows/timeout-test.yml new file mode 100644 index 0000000..64a8f07 --- /dev/null +++ b/.github/workflows/timeout-test.yml @@ -0,0 +1,39 @@ +on: + issue_comment: + types: + - created +jobs: + container-tests: + runs-on: ubuntu-22.04 + name: "Timeout test for testing farm as a github action" + + if: | + github.event.issue.pull_request + && contains(github.event.comment.body, '[test]') + && contains(fromJson('["OWNER", "MEMBER"]'), github.event.comment.author_association) + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + ref: "refs/pull/${{ github.event.issue.number }}/head" + + - name: Run the tests + uses: ./ + id: tf_results + with: + api_key: ${{ secrets.TF_PUBLIC_API_KEY }} + git_ref: "main" + tmt_plan_regex: "timeout_plan" + pull_request_status_name: "Timeout test" + update_pull_request_status: "true" + timeout: 10 + + - name: Check if log contains exceed limit + run: | + curl ${{ steps.tf_results.outputs.test_log_url }} > results.log + ret_val = $(grep 'duration \"10s\" exceeded' results.log) + if [[ $ret_val != 0 ]]; then + exit 1 + fi + exit 0 diff --git a/dist/action.js b/dist/action.js new file mode 100644 index 0000000..f767230 --- /dev/null +++ b/dist/action.js @@ -0,0 +1,190 @@ +import { debug, getBooleanInput, getInput, notice, setOutput, summary, } from '@actions/core'; +import TestingFarmAPI from 'testing-farm'; +import { setTimeout } from 'timers/promises'; +import { TFError } from './error'; +import { setTfArtifactUrl, setTfRequestId } from './state'; +import { composeStatusDescription, getSummary } from './util'; +import { pipelineSettingsSchema, envSettingsSchema, tfScopeSchema, timeoutSchema, tmtArtifactsInputSchema, tmtArtifactsSchema, tmtContextInputSchema, tmtContextSchema, tmtEnvSecretsSchema, tmtEnvVarsSchema, tmtPlanRegexSchema, tmtPathSchema, } from './schema/input'; +import { requestDetailsSchema, requestSchema, } from './schema/testing-farm-api'; +async function action(pr) { + const tfInstance = getInput('api_url'); + const api = new TestingFarmAPI(tfInstance); + // Get commit SHA value + const sha = pr.sha; + debug(`SHA: '${sha}'`); + // Set artifacts url + const tfScopeParsed = tfScopeSchema.safeParse(getInput('tf_scope')); + const tfScope = tfScopeParsed.success ? tfScopeParsed.data : 'public'; + const tfUrl = tfScope === 'public' + ? 'https://artifacts.dev.testing-farm.io' + : 'http://artifacts.osci.redhat.com/testing-farm'; + // Generate tmt variables + const tmtEnvVarsParsed = tmtEnvVarsSchema.safeParse(getInput('variables')); + const tmtEnvVars = tmtEnvVarsParsed.success ? tmtEnvVarsParsed.data : {}; + // Generate tmt secrets + const tmtEnvSecretsParsed = tmtEnvSecretsSchema.safeParse(getInput('secrets')); + const tmtEnvSecrets = tmtEnvSecretsParsed.success + ? tmtEnvSecretsParsed.data + : {}; + // Generate tmt artifacts + const tmtArtifactsParsed = tmtArtifactsInputSchema.safeParse(getInput('copr_artifacts')); + const tmtArtifacts = tmtArtifactsParsed.success + ? tmtArtifactsSchema.parse(tmtArtifactsParsed.data) + : []; + // Generate tmt hardware specification + // See https://tmt.readthedocs.io/en/stable/spec/plans.html#hardware + // https://gitlab.com/testing-farm/docs/root/-/merge_requests/120/diffs?view=inline + const rawTmtHardware = getInput('tmt_hardware'); + let tmtHardware; + if (rawTmtHardware) { + tmtHardware = JSON.parse(rawTmtHardware); + } + // Conditionally include the name attribute only if tmt_plan_regex is not null + const tmtPathParsed = tmtPathSchema.safeParse(getInput('tmt_path')); + const tmtPath = tmtPathParsed.success ? tmtPathParsed.data : '.'; + // Generate tmt context + const tmtContextParsed = tmtContextInputSchema.safeParse(getInput('tmt_context')); + const tmtContext = tmtContextParsed.success + ? tmtContextSchema.parse(tmtContextParsed.data) + : undefined; + // Conditionally include the name attribute only if tmt_plan_regex is not null + const tmtPlanRegexParsed = tmtPlanRegexSchema.safeParse(getInput('tmt_plan_regex')); + const tmtPlanRegex = tmtPlanRegexParsed.success + ? { name: tmtPlanRegexParsed.data } + : {}; + // Generate environment settings + const envSettingsParsed = envSettingsSchema.safeParse(JSON.parse(getInput('environment_settings'))); + const envSettings = envSettingsParsed.success ? envSettingsParsed.data : {}; + const pipelineSettings = pipelineSettingsSchema.parse(JSON.parse(getInput('pipeline_settings'))); + // Schedule a test on Testing Farm + const request = { + api_key: getInput('api_key', { required: true }), + test: { + fmf: Object.assign({ url: getInput('git_url', { required: true }), ref: getInput('git_ref'), path: tmtPath }, tmtPlanRegex), + }, + environments: [ + { + arch: getInput('arch'), + os: { + compose: getInput('compose'), + }, + variables: tmtEnvVars, + settings: envSettings, + secrets: tmtEnvSecrets, + artifacts: tmtArtifacts, + tmt: Object.assign({}, (tmtContext ? { context: tmtContext } : {})), + }, + ], + settings: { + pipeline: pipelineSettings, + }, + }; + let tfResponseRaw; + if (!rawTmtHardware) { + // Use newRequest method in case tmt_hardware is not defined or parameter is not properly formatted + tfResponseRaw = await api.newRequest(request, false); + } + else { + // The strict mode should be enabled once https://github.com/redhat-plumbers-in-action/testing-farm/issues/71 is fixed + tfResponseRaw = await api.unsafeNewRequest(Object.assign(Object.assign({}, request), { environments: [Object.assign(Object.assign({}, request.environments[0]), { hardware: tmtHardware })] })); + } + // Remove all secrets from request before printing it + delete request.api_key; + request.environments.map((env) => delete env.secrets); + debug(`Testing Farm request (except api_key and environment[].secrets): ${JSON.stringify(request, null, 2)}`); + debug(`Testing Farm response: ${JSON.stringify(tfResponseRaw, null, 2)}`); + const tfResponse = requestSchema.parse(tfResponseRaw); + const tfArtifactUrl = `${tfUrl}/${tfResponse.id}`; + notice(`Testing Farm logs: ${tfArtifactUrl}`); + // Set outputs and states + debug('Setting outputs and states'); + setOutput('request_id', tfResponse.id); + setOutput('request_url', `${tfInstance}/requests/${tfResponse.id}`); + setOutput('test_log_url', tfArtifactUrl); + setTfRequestId(tfResponse.id); + setTfArtifactUrl(tfArtifactUrl); + // Create Pull Request status in state pending + await pr.setStatus('pending', 'Build started', `${tfArtifactUrl}`); + // Interval of 30 seconds in milliseconds + const interval = 30 * 1000; + const parsedTimeout = timeoutSchema.safeParse(getInput('timeout')); + // set timeout to 960 * 30 seconds ~ 8 hours ; timeout from input is in minutes (hence * 2) + let timeout = parsedTimeout.success ? parsedTimeout.data * 2 : 960; + let tfResult; + // Check if scheduled test is still running + // Ask Testing Farm every 30 seconds + debug(`Testing Farm - waiting for results (timeout: ${timeout} minutes)`); + do { + tfResult = requestDetailsSchema.parse(await api.requestDetails(tfResponse.id, false)); + if (tfResult.state !== 'running' && + tfResult.state !== 'new' && + tfResult.state !== 'pending' && + tfResult.state !== 'queued') { + break; + } + debug(`Testing Farm - state: '${tfResult.state}'`); + timeout--; + await setTimeout(interval); + } while (timeout > 0); + if (timeout === 0) { + throw new TFError(`Testing Farm - timeout reached. The test is still in state: '${tfResult.state}'`, `${tfArtifactUrl}`); + } + debug(`response:'${JSON.stringify(tfResult, null, 2)}'`); + // Get final state of Testing Farm scheduled request + const state = tfResult.state; + const result = tfResult.result ? tfResult.result.overall : 'unknown'; + let finalState = 'success'; + let infraError = false; + let log = ''; + notice(`State is ${state} and result is: ${result}`); + if (state === 'complete') { + if (result !== 'passed') { + finalState = 'failure'; + } + } + else { + // Mark job in case of infrastructure issues. Report to Testing Farm team + infraError = true; + finalState = 'failure'; + log = 'pipeline.log'; + } + notice(`Final state is: ${finalState}`); + notice(`Infra state is: ${infraError ? 'Failed' : 'OK'}`); + // Switch Pull Request Status to final state + await pr.setStatus(finalState, composeStatusDescription(infraError, getSummary(tfResult.result)), `${tfArtifactUrl}`); + // Add comment with Testing Farm request/result to Pull Request + if (getBooleanInput('create_issue_comment')) { + await pr.addComment(`Testing Farm [request](${tfInstance}/requests/${tfResponse.id}) for ${getInput('compose')}/${getInput('copr_artifacts')} regression testing has been created.` + + `Once finished, results should be available [here](${tfArtifactUrl}/).\n` + + `[Full pipeline log](${tfArtifactUrl}/pipeline.log).`); + } + // Create Github Summary + if (getBooleanInput('create_github_summary')) { + await summary + .addHeading('Testing Farm as a GitHub Action summary') + .addTable([ + [ + { data: 'Compose', header: true }, + { data: 'Arch', header: true }, + { data: 'Infrastructure State', header: true }, + { data: 'Test result', header: true }, + { data: 'Link to logs', header: true }, + ], + [ + getInput('compose'), + getInput('arch'), + infraError ? 'Failed' : 'OK', + finalState, + `test ` + + `pipeline`, + ], + ]) + .write(); + } + // Exit with error in case of failure in test + if (finalState === 'failure') { + throw new TFError(composeStatusDescription(infraError, getSummary(tfResult.result)), `${tfArtifactUrl}`); + } +} +export default action; +//# sourceMappingURL=action.js.map \ No newline at end of file diff --git a/dist/action.js.map b/dist/action.js.map new file mode 100644 index 0000000..72389c0 --- /dev/null +++ b/dist/action.js.map @@ -0,0 +1 @@ +{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/error.js b/dist/error.js new file mode 100644 index 0000000..037b0b2 --- /dev/null +++ b/dist/error.js @@ -0,0 +1,12 @@ +/** + * Custom error class for TF errors. + * @param message - The error message + * @param url - The optional URL to link to Testing Farm logs + */ +export class TFError extends Error { + constructor(message, url) { + super(message); + this.url = url; + } +} +//# sourceMappingURL=error.js.map \ No newline at end of file diff --git a/dist/error.js.map b/dist/error.js.map new file mode 100644 index 0000000..876b3ee --- /dev/null +++ b/dist/error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAChC,YACE,OAAe,EACN,GAAY;QAErB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,QAAG,GAAH,GAAG,CAAS;IAGvB,CAAC;CACF"} \ No newline at end of file diff --git a/dist/main.js b/dist/main.js new file mode 100644 index 0000000..f9fa30f --- /dev/null +++ b/dist/main.js @@ -0,0 +1,40 @@ +import { getInput, setFailed } from '@actions/core'; +import { context } from '@actions/github'; +import '@total-typescript/ts-reset'; +import action from './action'; +import { TFError } from './error'; +import { getOctokit } from './octokit'; +import post from './post'; +import { PullRequest } from './pull-request'; +import { isPost } from './state'; +let pr = undefined; +// All the code should be inside this try block +try { + const octokit = getOctokit(getInput('github_token', { required: true })); + pr = await PullRequest.initialize(context.issue.number, octokit); + // Check if the script was invoked in the post step + if (!isPost) { + // Call the action function from action.ts + await action(pr); + } + else { + await post(pr); + } +} +catch (error) { + let message; + if (error instanceof Error) { + message = error.message; + } + else { + message = JSON.stringify(error); + } + // Set the Pull Request status to error when error occurs + if (pr) { + const url = error instanceof TFError ? error.url : undefined; + await pr.setStatus('error', `${message}`, url); + } + // Log the error and set the action status to failed + setFailed(message); +} +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/dist/main.js.map b/dist/main.js.map new file mode 100644 index 0000000..675eec9 --- /dev/null +++ b/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,4BAA4B,CAAC;AAEpC,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,IAAI,MAAM,QAAQ,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,IAAI,EAAE,GAA4B,SAAS,CAAC;AAE5C,+CAA+C;AAC/C,IAAI,CAAC;IACH,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzE,EAAE,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEjE,mDAAmD;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,0CAA0C;QAC1C,MAAM,MAAM,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;AACH,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,IAAI,OAAe,CAAC;IAEpB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,yDAAyD;IACzD,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,GAAG,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7D,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,oDAAoD;IACpD,SAAS,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC"} \ No newline at end of file diff --git a/dist/octokit.js b/dist/octokit.js new file mode 100644 index 0000000..3427efe --- /dev/null +++ b/dist/octokit.js @@ -0,0 +1,24 @@ +import { info, warning } from '@actions/core'; +import { Octokit } from '@octokit/core'; +import { throttling } from '@octokit/plugin-throttling'; +const CustomOctokit = Octokit.plugin(throttling); +export function getOctokit(token) { + return new CustomOctokit({ + auth: token, + throttle: { + onRateLimit: (retryAfter, options, _octokit, retryCount) => { + warning(`Request quota exhausted for request ${options.method} ${options.url}`); + // Retry once after hitting a rate limit error, then give up + if (retryCount < 1) { + info(`Retrying after ${retryAfter} seconds!`); + return true; + } + }, + onSecondaryRateLimit: (_retryAfter, options) => { + // When a secondary rate limit is hit, don't retry + warning(`SecondaryRateLimit detected for request ${options.method} ${options.url}`); + }, + }, + }); +} +//# sourceMappingURL=octokit.js.map \ No newline at end of file diff --git a/dist/octokit.js.map b/dist/octokit.js.map new file mode 100644 index 0000000..693fe0f --- /dev/null +++ b/dist/octokit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"octokit.js","sourceRoot":"","sources":["../src/octokit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAIjD,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,aAAa,CAAC;QACvB,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE;YACR,WAAW,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;gBACzD,OAAO,CACL,uCAAuC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CACvE,CAAC;gBAEF,4DAA4D;gBAC5D,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;oBACnB,IAAI,CAAC,kBAAkB,UAAU,WAAW,CAAC,CAAC;oBAC9C,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,oBAAoB,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE;gBAC7C,kDAAkD;gBAClD,OAAO,CACL,2CAA2C,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAC3E,CAAC;YACJ,CAAC;SACF;KACF,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/dist/post.js b/dist/post.js new file mode 100644 index 0000000..9235e8e --- /dev/null +++ b/dist/post.js @@ -0,0 +1,24 @@ +import { debug, getInput, notice } from '@actions/core'; +import TestingFarmAPI from 'testing-farm'; +import { getTfArtifactUrl, getTfRequestId } from './state'; +async function post(pr) { + const tfInstance = getInput('api_url'); + const tfRequestId = getTfRequestId(); + const tfArtifactUrl = getTfArtifactUrl(); + const api = new TestingFarmAPI(tfInstance); + // This should happen really rarely, but it's better to check + if (!tfRequestId) { + throw new Error('POST: Missing Testing Farm request id'); + } + const request = { + api_key: getInput('api_key', { required: true }), + }; + notice(`Cancelling Testing Farm request: ${tfRequestId}`); + await api.cancelRequest(tfRequestId, request, false); + debug(`Request ${tfRequestId} was cancelled`); + // Set status to success when the request was cancelled + // It's not a test failure, the request was cancelled by the user + await pr.setStatus('success', 'Testing Farm request was cancelled', tfArtifactUrl !== null && tfArtifactUrl !== void 0 ? tfArtifactUrl : undefined); +} +export default post; +//# sourceMappingURL=post.js.map \ No newline at end of file diff --git a/dist/post.js.map b/dist/post.js.map new file mode 100644 index 0000000..4e9a08a --- /dev/null +++ b/dist/post.js.map @@ -0,0 +1 @@ +{"version":3,"file":"post.js","sourceRoot":"","sources":["../src/post.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,cAAc,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE3D,KAAK,UAAU,IAAI,CAAC,EAAe;IACjC,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IAEzC,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IAE3C,6DAA6D;IAC7D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;KACjD,CAAC;IAEF,MAAM,CAAC,oCAAoC,WAAW,EAAE,CAAC,CAAC;IAC1D,MAAM,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACrD,KAAK,CAAC,WAAW,WAAW,gBAAgB,CAAC,CAAC;IAE9C,uDAAuD;IACvD,iEAAiE;IACjE,MAAM,EAAE,CAAC,SAAS,CAChB,SAAS,EACT,oCAAoC,EACpC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,SAAS,CAC3B,CAAC;AACJ,CAAC;AAED,eAAe,IAAI,CAAC"} \ No newline at end of file diff --git a/dist/pull-request.js b/dist/pull-request.js new file mode 100644 index 0000000..973dbf9 --- /dev/null +++ b/dist/pull-request.js @@ -0,0 +1,53 @@ +import { debug, getBooleanInput, getInput } from '@actions/core'; +import { context } from '@actions/github'; +/** + * Class for holding information about a Pull Request and interacting with it via the GitHub API. + */ +export class PullRequest { + /** + * PullRequest constructor, it's not meant to be called directly, use the static initialize method instead. + * @param number - The Pull Request number + * @param sha - The head sha of the Pull Request + * @param octokit - The Octokit instance to use for interacting with the GitHub API + */ + constructor(number, sha, octokit) { + this.number = number; + this.sha = sha; + this.octokit = octokit; + } + /** + * Set the Pull Request status using the GitHub API. + * @param state - The state of the status, can be one of error, failure, pending or success + * @param description - The description of the status + * @param url - The URL to link to from the status + */ + async setStatus(state, description, url) { + const usePullRequestStatuses = getBooleanInput('update_pull_request_status'); + // Don't set the statuses when they are disabled + if (!usePullRequestStatuses) { + debug('Skipping setting Pull Request Status'); + return; + } + const { data } = await this.octokit.request('POST /repos/{owner}/{repo}/statuses/{sha}', Object.assign(Object.assign({}, context.repo), { sha: this.sha, state, context: `Testing Farm - ${getInput('pull_request_status_name')}`, description: description ? description.slice(0, 140) : description, target_url: url })); + debug(`Setting Pull Request Status response: ${JSON.stringify(data, null, 2)}`); + } + /** + * Comment on the Pull Request using the GitHub API. + * @param body - The body of the comment + */ + async addComment(body) { + const { data } = await this.octokit.request('POST /repos/{owner}/{repo}/issues/{issue_number}/comments', Object.assign(Object.assign({}, context.repo), { issue_number: this.number, body })); + debug(`Adding Issue comment response: ${JSON.stringify(data, null, 2)}`); + } + /** + * Initialize a PullRequest instance using data fetched from GitHub API. + * @param number - The Pull Request number + * @param octokit - The Octokit instance to use for interacting with the GitHub API + * @returns A Promise that resolves to a PullRequest instance + */ + static async initialize(number, octokit) { + const { data } = await octokit.request('GET /repos/{owner}/{repo}/pulls/{pull_number}', Object.assign(Object.assign({}, context.repo), { pull_number: number })); + return new this(data.number, data.head.sha, octokit); + } +} +//# sourceMappingURL=pull-request.js.map \ No newline at end of file diff --git a/dist/pull-request.js.map b/dist/pull-request.js.map new file mode 100644 index 0000000..57a7bad --- /dev/null +++ b/dist/pull-request.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pull-request.js","sourceRoot":"","sources":["../src/pull-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK1C;;GAEG;AACH,MAAM,OAAO,WAAW;IACtB;;;;;OAKG;IACH,YACW,MAAc,EACd,GAAW,EACX,OAAsB;QAFtB,WAAM,GAAN,MAAM,CAAQ;QACd,QAAG,GAAH,GAAG,CAAQ;QACX,YAAO,GAAP,OAAO,CAAe;IAC9B,CAAC;IAEJ;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CACb,KAAoF,EACpF,WAAmB,EACnB,GAAY;QAEZ,MAAM,sBAAsB,GAAG,eAAe,CAC5C,4BAA4B,CAC7B,CAAC;QAEF,gDAAgD;QAChD,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC5B,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CACzC,2CAA2C,kCAEtC,OAAO,CAAC,IAAI,KACf,GAAG,EAAE,IAAI,CAAC,GAAG,EACb,KAAK,EACL,OAAO,EAAE,kBAAkB,QAAQ,CAAC,0BAA0B,CAAC,EAAE,EACjE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAClE,UAAU,EAAE,GAAG,IAElB,CAAC;QAEF,KAAK,CACH,yCAAyC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CACzE,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CACzC,2DAA2D,kCAEtD,OAAO,CAAC,IAAI,KACf,YAAY,EAAE,IAAI,CAAC,MAAM,EACzB,IAAI,IAEP,CAAC;QAEF,KAAK,CAAC,kCAAkC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,UAAU,CACrB,MAAc,EACd,OAAsB;QAEtB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CACpC,+CAA+C,kCAE1C,OAAO,CAAC,IAAI,KACf,WAAW,EAAE,MAAM,IAEtB,CAAC;QAEF,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;CACF"} \ No newline at end of file diff --git a/dist/schema/input.js b/dist/schema/input.js new file mode 100644 index 0000000..c47d01b --- /dev/null +++ b/dist/schema/input.js @@ -0,0 +1,78 @@ +import { z } from 'zod'; +export const tfScopeSchema = z.enum(['public', 'private']); +// Parse string input into object of key-value pairs +// input: 'REPO_URL=GITHUB_SERVER_URL/GITHUB_REPOSITORY;REPO_NAME=GITHUB_REPOSITORY' +// output: { REPO_URL: 'GITHUB_SERVER_URL/GITHUB_REPOSITORY', REPO_NAME: 'GITHUB_REPOSITORY' } +const stringToArraySchema = z.string().transform(str => str.split(';')); +const keyValueArrayToObjectSchema = stringToArraySchema.transform(arr => { + let obj = {}; + arr.forEach(item => { + const [key, ...values] = item.split('='); + // ''.split('=') returns [''] ; we have to check for this case + if (key === '' && Array.isArray(values) && values.length === 0) + return; + obj[key] = values.join('='); + }); + return z.record(z.string(), z.string()).parse(obj); +}); +export const tmtEnvVarsSchema = keyValueArrayToObjectSchema; +export const tmtEnvSecretsSchema = keyValueArrayToObjectSchema; +export const tmtArtifactsInputSchema = stringToArraySchema.transform(arr => { + let artifacts = []; + arr.forEach(item => { + if (item === '') + return; + artifacts.push({ type: 'fedora-copr-build', id: item }); + }); + return artifacts; +}); +export const tmtContextInputSchema = keyValueArrayToObjectSchema; +// https://api.testing-farm.io/redoc#operation/request_a_new_test_v0_1_requests_post +export const tmtArtifactsSchema = z + .array(z.object({ + id: z.string().min(1), + type: z.string().min(1), + packages: z.array(z.string().min(1)).optional(), + install: z.boolean().optional(), + order: z.number().optional(), +})) + .default([]); +// https://api.testing-farm.io/redoc#operation/request_a_new_test_v0_1_requests_post +// https://tmt.readthedocs.io/en/stable/spec/context.html#dimension +export const tmtContextSchema = z.object({ + distro: z.string().min(1).optional(), + variant: z.string().min(1).optional(), + arch: z.string().min(1).optional(), + component: z.string().min(1).optional(), + collection: z.string().min(1).optional(), + module: z.string().min(1).optional(), + initiator: z.string().min(1).optional(), + trigger: z.string().min(1).optional(), +}); +export const envSettingsSchema = z + .object({ + pipeline: z + .object({ + skip_guest_setup: z.boolean().optional(), + }) + .optional(), + provisioning: z + .object({ + post_install_script: z.string().min(1).optional(), + tags: z.record(z.string()).optional(), + }) + .optional(), +}) + .optional(); +export const pipelineSettingsSchema = z + .object({ + timeout: z.number().min(1).optional(), + type: z.enum(['tmt-multihost']).optional(), + 'provision-error-failed-result': z.boolean().optional(), + 'parallel-limit': z.number().nonnegative().optional(), +}) + .optional(); +export const timeoutSchema = z.coerce.number(); +export const tmtPlanRegexSchema = z.string().min(1); +export const tmtPathSchema = z.string().min(1); +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/dist/schema/input.js.map b/dist/schema/input.js.map new file mode 100644 index 0000000..d3c34b0 --- /dev/null +++ b/dist/schema/input.js.map @@ -0,0 +1 @@ +{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/schema/input.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/schema/testing-farm-api.js b/dist/schema/testing-farm-api.js new file mode 100644 index 0000000..4442b0c --- /dev/null +++ b/dist/schema/testing-farm-api.js @@ -0,0 +1,14 @@ +import { z } from 'zod'; +export const requestSchema = z.object({ + id: z.string(), +}); +export const requestDetailsSchema = z.object({ + state: z.string(), + result: z + .object({ + summary: z.union([z.string(), z.null()]), + overall: z.string(), + }) + .nullable(), +}); +//# sourceMappingURL=testing-farm-api.js.map \ No newline at end of file diff --git a/dist/schema/testing-farm-api.js.map b/dist/schema/testing-farm-api.js.map new file mode 100644 index 0000000..bfd7dd4 --- /dev/null +++ b/dist/schema/testing-farm-api.js.map @@ -0,0 +1 @@ +{"version":3,"file":"testing-farm-api.js","sourceRoot":"","sources":["../../src/schema/testing-farm-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;CACf,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;KACpB,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/state.js b/dist/state.js new file mode 100644 index 0000000..6ebf64f --- /dev/null +++ b/dist/state.js @@ -0,0 +1,23 @@ +// Inspired by action/checkout state handling +import { getState, saveState } from '@actions/core'; +// Indicates whether the POST action is running +export const isPost = !!getState('isPost'); +export function setTfRequestId(requestId) { + saveState('requestId', requestId); +} +export function getTfRequestId() { + return getState('requestId'); +} +export function setTfArtifactUrl(requestUrl) { + saveState('artifactUrl', requestUrl); +} +export function getTfArtifactUrl() { + return getState('artifactUrl'); +} +// Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic. +// This is necessary since we don't have a separate entry point. +// ?NOTE: Post is invoked only when cancelled() is true +if (!isPost) { + saveState('isPost', 'true'); +} +//# sourceMappingURL=state.js.map \ No newline at end of file diff --git a/dist/state.js.map b/dist/state.js.map new file mode 100644 index 0000000..5d09488 --- /dev/null +++ b/dist/state.js.map @@ -0,0 +1 @@ +{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAE3C,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,SAAS,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC;AAED,0GAA0G;AAC1G,gEAAgE;AAChE,uDAAuD;AACvD,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC9B,CAAC"} \ No newline at end of file diff --git a/dist/util.js b/dist/util.js new file mode 100644 index 0000000..b0084e5 --- /dev/null +++ b/dist/util.js @@ -0,0 +1,16 @@ +import { z } from 'zod'; +export function composeStatusDescription(infraError, tfSummary) { + let description = infraError + ? 'Build failed - Infra problems' + : 'Build finished'; + return description + tfSummary; +} +export function getSummary(result) { + const parsedResult = z + .object({ + summary: z.string().min(1), + }) + .safeParse(result); + return parsedResult.success ? ` - ${parsedResult.data.summary}` : ''; +} +//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/dist/util.js.map b/dist/util.js.map new file mode 100644 index 0000000..2e9c687 --- /dev/null +++ b/dist/util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,wBAAwB,CACtC,UAAmB,EACnB,SAAiB;IAEjB,IAAI,WAAW,GAAG,UAAU;QAC1B,CAAC,CAAC,+BAA+B;QACjC,CAAC,CAAC,gBAAgB,CAAC;IAErB,OAAO,WAAW,GAAG,SAAS,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAe;IACxC,MAAM,YAAY,GAAG,CAAC;SACnB,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC3B,CAAC;SACD,SAAS,CAAC,MAAM,CAAC,CAAC;IAErB,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC"} \ No newline at end of file diff --git a/plans/timeout_plan.fmf b/plans/timeout_plan.fmf new file mode 100644 index 0000000..094e1b3 --- /dev/null +++ b/plans/timeout_plan.fmf @@ -0,0 +1,10 @@ +summary: Basic timeout test +execute: + how: tmt + duration: 10s + script: | + set +x + echo "Set sleep time to an hour for sure." + sleep 30 + echo "this should never happened because of timeout" + exit 0