From 70f2a15b019f54e157b2cc9599d7d936a809ca15 Mon Sep 17 00:00:00 2001 From: Federico Grandi Date: Fri, 14 Aug 2026 22:57:58 +0200 Subject: [PATCH] fix: resolve absolute cwd without dumping the minified bundle (#495) Co-authored-by: Cursor --- README.md | 2 ++ action.yml | 2 +- lib/index.js | 2 +- src/main.ts | 12 +++++-- src/util.ts | 26 ++++++++++++++ test/integration/action.test.ts | 53 +++++++++++++++++++++++++++++ test/integration/helpers.ts | 15 ++++----- test/util.test.ts | 60 +++++++++++++++++++++++++++++++++ 8 files changed, 158 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a1f09fb9..459ab81a 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ Add a step like this to your workflow: committer_email: mail@example.com # The local path to the directory where your repository is located. You should use actions/checkout first to set it up. + # Relative to the runner workspace, or an absolute path (e.g. ${{ github.workspace }}/path). + # Note: $GITHUB_WORKSPACE is not expanded in with: — use ${{ github.workspace }} instead. # Default: '.' cwd: './path/to/the/repo' diff --git a/action.yml b/action.yml index b6d29711..b468ac02 100644 --- a/action.yml +++ b/action.yml @@ -22,7 +22,7 @@ inputs: description: The email of the custom committer you want to use required: false cwd: - description: The directory where your repository is located. You should use actions/checkout first to set it up + description: The directory where your repository is located (relative to the runner workspace, or an absolute path). You should use actions/checkout first to set it up. In with:, use ${{ github.workspace }} — $GITHUB_WORKSPACE is not expanded. required: false default: '.' default_author: diff --git a/lib/index.js b/lib/index.js index 0fe78108..94ee5613 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,4 +7,4 @@ var uo=Symbol("NOT_RESOLVED");var go=Symbol("MERGE_KEY");function defineScalarTa /* v8 ignore next -- @preserve */ ()=>new ArrayBuffer(0))}}function isJSONResponse(e){return e.type==="application/json"||e.type==="application/scim+json"}function toErrorMessage(e){if(typeof e==="string"){return e}if(e instanceof ArrayBuffer){return"Unknown error"}if("message"in e){const t="documentation_url"in e?` - ${e.documentation_url}`:"";return Array.isArray(e.errors)?`${e.message}: ${e.errors.map(e=>JSON.stringify(e)).join(", ")}${t}`:`${e.message}${t}`}return`Unknown error: ${JSON.stringify(e)}`}function dist_bundle_withDefaults(e,t){const r=e.defaults(t);const newApi=function(e,t){const s=r.merge(e,t);if(!s.request||!s.request.hook){return fetchWrapper(r.parse(s))}const request2=(e,t)=>fetchWrapper(r.parse(r.merge(e,t)));Object.assign(request2,{endpoint:r,defaults:dist_bundle_withDefaults.bind(null,r)});return s.request.hook(request2,s)};return Object.assign(newApi,{endpoint:r,defaults:dist_bundle_withDefaults.bind(null,r)})}var jA=dist_bundle_withDefaults(JA,qA); /* v8 ignore next -- @preserve */ -/* v8 ignore else -- @preserve */var zA="0.0.0-development";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map(e=>` - ${e.message}`).join("\n")}var KA=class extends Error{constructor(e,t,r){super(_buildMessageForResponseErrors(r));this.request=e;this.headers=t;this.response=r;this.errors=r.errors;this.data=r.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}name="GraphqlResponseError";errors;data};var ZA=["method","baseUrl","url","headers","request","query","mediaType","operationName"];var $A=["query","method","url"];var XA=/\/api\/v3\/?$/;function graphql(e,t,r){if(r){if(typeof t==="string"&&"query"in r){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in r){if(!$A.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const s=typeof t==="string"?Object.assign({query:t},r):t;const n=Object.keys(s).reduce((e,t)=>{if(ZA.includes(t)){e[t]=s[t];return e}if(!e.variables){e.variables={}}e.variables[t]=s[t];return e},{});const o=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(XA.test(o)){n.url=o.replace(XA,"/api/graphql")}return e(n).then(e=>{if(e.data.errors){const t={};for(const r of Object.keys(e.headers)){t[r]=e.headers[r]}throw new KA(n,t,e.data)}return e.data.data})}function graphql_dist_bundle_withDefaults(e,t){const r=e.defaults(t);const newApi=(e,t)=>graphql(r,e,t);return Object.assign(newApi,{defaults:graphql_dist_bundle_withDefaults.bind(null,r),endpoint:r.endpoint})}var ea=graphql_dist_bundle_withDefaults(jA,{headers:{"user-agent":`octokit-graphql.js/${zA} ${getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return graphql_dist_bundle_withDefaults(e,{method:"POST",url:"/graphql"})}var ta="(?:[a-zA-Z0-9_-]+)";var ra="\\.";var sa=new RegExp(`^${ta}${ra}${ta}${ra}${ta}$`);var na=sa.test.bind(sa);async function auth(e){const t=na(e);const r=e.startsWith("v1.")||e.startsWith("ghs_");const s=e.startsWith("ghu_");const n=t?"app":r?"installation":s?"user-to-server":"oauth";return{type:"token",token:e,tokenType:n}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,t,r,s){const n=t.endpoint.merge(r,s);n.headers.authorization=withAuthorizationPrefix(e);return t(n)}var oa=function createTokenAuth2(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};const ia="7.0.6";const dist_src_noop=()=>{};const Aa=console.warn.bind(console);const aa=console.error.bind(console);function dist_src_createLogger(e={}){if(typeof e.debug!=="function"){e.debug=dist_src_noop}if(typeof e.info!=="function"){e.info=dist_src_noop}if(typeof e.warn!=="function"){e.warn=Aa}if(typeof e.error!=="function"){e.error=aa}return e}const ca=`octokit-core.js/${ia} ${getUserAgent()}`;class Octokit{static VERSION=ia;static defaults(e){const t=class extends(this){constructor(...t){const r=t[0]||{};if(typeof e==="function"){super(e(r));return}super(Object.assign({},e,r,r.userAgent&&e.userAgent?{userAgent:`${r.userAgent} ${e.userAgent}`}:null))}};return t}static plugins=[];static plugin(...e){const t=this.plugins;const r=class extends(this){static plugins=t.concat(e.filter(e=>!t.includes(e)))};return r}constructor(e={}){const t=new OA.Collection;const r={baseUrl:jA.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:t.bind(null,"request")}),mediaType:{previews:[],format:""}};r.headers["user-agent"]=e.userAgent?`${e.userAgent} ${ca}`:ca;if(e.baseUrl){r.baseUrl=e.baseUrl}if(e.previews){r.mediaType.previews=e.previews}if(e.timeZone){r.headers["time-zone"]=e.timeZone}this.request=jA.defaults(r);this.graphql=withCustomRequest(this.request).defaults(r);this.log=dist_src_createLogger(e.log);this.hook=t;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const r=oa(e.auth);t.wrap("request",r.hook);this.auth=r}}else{const{authStrategy:r,...s}=e;const n=r(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:s},e.auth));t.wrap("request",n.hook);this.auth=n}const s=this.constructor;for(let t=0;t({async next(){if(!l)return{done:true};try{const e=await n({method:o,url:l,headers:a});const t=normalizePaginatedListResponse(e);l=((t.headers.link||"").match(/<([^<>]+)>;\s*rel="next"/)||[])[1];if(!l&&"total_commits"in t.data){const e=new URL(t.url);const r=e.searchParams;const s=parseInt(r.get("page")||"1",10);const n=parseInt(r.get("per_page")||"250",10);if(s*n{if(n.done){return t}let o=false;function done(){o=true}t=t.concat(s?s(n.value,done):n.value.data);if(o){return t}return gather(e,t,r,s)})}var Ea=Object.assign(paginate,{iterator:iterator});var fa=null&&["GET /advisories","GET /app/hook/deliveries","GET /app/installation-requests","GET /app/installations","GET /assignments/{assignment_id}/accepted_assignments","GET /classrooms","GET /classrooms/{classroom_id}/assignments","GET /enterprises/{enterprise}/code-security/configurations","GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}/repositories","GET /enterprises/{enterprise}/dependabot/alerts","GET /enterprises/{enterprise}/teams","GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships","GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /licenses","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /organizations/{org}/dependabot/repository-access","GET /orgs/{org}/actions/cache/usage-by-repository","GET /orgs/{org}/actions/hosted-runners","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/permissions/self-hosted-runners/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/actions/variables","GET /orgs/{org}/actions/variables/{name}/repositories","GET /orgs/{org}/attestations/repositories","GET /orgs/{org}/attestations/{subject_digest}","GET /orgs/{org}/blocks","GET /orgs/{org}/campaigns","GET /orgs/{org}/code-scanning/alerts","GET /orgs/{org}/code-security/configurations","GET /orgs/{org}/code-security/configurations/{configuration_id}/repositories","GET /orgs/{org}/codespaces","GET /orgs/{org}/codespaces/secrets","GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories","GET /orgs/{org}/copilot/billing/seats","GET /orgs/{org}/copilot/metrics","GET /orgs/{org}/dependabot/alerts","GET /orgs/{org}/dependabot/secrets","GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories","GET /orgs/{org}/events","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/insights/api/route-stats/{actor_type}/{actor_id}","GET /orgs/{org}/insights/api/subject-stats","GET /orgs/{org}/insights/api/user-stats/{user_id}","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/members/{username}/codespaces","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/organization-roles/{role_id}/teams","GET /orgs/{org}/organization-roles/{role_id}/users","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/packages/{package_type}/{package_name}/versions","GET /orgs/{org}/personal-access-token-requests","GET /orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories","GET /orgs/{org}/personal-access-tokens","GET /orgs/{org}/personal-access-tokens/{pat_id}/repositories","GET /orgs/{org}/private-registries","GET /orgs/{org}/projects","GET /orgs/{org}/projectsV2","GET /orgs/{org}/projectsV2/{project_number}/fields","GET /orgs/{org}/projectsV2/{project_number}/items","GET /orgs/{org}/properties/values","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/rulesets","GET /orgs/{org}/rulesets/rule-suites","GET /orgs/{org}/rulesets/{ruleset_id}/history","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/security-advisories","GET /orgs/{org}/settings/immutable-releases/repositories","GET /orgs/{org}/settings/network-configurations","GET /orgs/{org}/team/{team_slug}/copilot/metrics","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/{project_id}/collaborators","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/caches","GET /repos/{owner}/{repo}/actions/organization-secrets","GET /repos/{owner}/{repo}/actions/organization-variables","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/variables","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/activity","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/attestations/{subject_digest}","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/codespaces","GET /repos/{owner}/{repo}/codespaces/devcontainers","GET /repos/{owner}/{repo}/codespaces/secrets","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/status","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/compare/{basehead}","GET /repos/{owner}/{repo}/compare/{base}...{head}","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/dependabot/alerts","GET /repos/{owner}/{repo}/dependabot/secrets","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/environments","GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies","GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps","GET /repos/{owner}/{repo}/environments/{environment_name}/secrets","GET /repos/{owner}/{repo}/environments/{environment_name}/variables","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by","GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocking","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/releases/{release_id}/reactions","GET /repos/{owner}/{repo}/rules/branches/{branch}","GET /repos/{owner}/{repo}/rulesets","GET /repos/{owner}/{repo}/rulesets/rule-suites","GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations","GET /repos/{owner}/{repo}/security-advisories","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repos/{owner}/{repo}/topics","GET /repositories","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/codespaces","GET /user/codespaces/secrets","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/packages/{package_type}/{package_name}/versions","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/social_accounts","GET /user/ssh_signing_keys","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /users","GET /users/{username}/attestations/{subject_digest}","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/packages","GET /users/{username}/projects","GET /users/{username}/projectsV2","GET /users/{username}/projectsV2/{project_number}/fields","GET /users/{username}/projectsV2/{project_number}/items","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/social_accounts","GET /users/{username}/ssh_signing_keys","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return fa.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=pa;const Ca=new Context;const Qa=getApiBaseUrl();const Ia={baseUrl:Qa,request:{agent:getProxyAgent(Qa),fetch:getProxyFetch(Qa)}};const Ba=Octokit.plugin(restEndpointMethods,paginateRest).defaults(Ia);function getOctokitOptions(e,t){const r=Object.assign({},t||{});const s=getAuthString(e,r);if(s){r.auth=s}const n=getUserAgentWithOrchestrationId(r.userAgent);if(n){r.userAgent=n}return r}const ma=new Context;function getOctokit(e,t,...r){const s=Ba.plugin(...r);return new s(getOctokitOptions(e,t))}function getOctokitClient(){const e=io_getInput("github_token");if(!e){throw new Error("github_token is required")}return getOctokit(e)}async function getUserInfo(e){if(!e)return undefined;const t=getOctokitClient();const r=await t.rest.users.getByUsername({username:e});core_debug(`Fetched github actor from the API: ${JSON.stringify(r?.data,null,2)}`);return{name:r?.data?.name,email:r?.data?.email}}const wa=/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/gu;function neutralizeLogString(e){return e.replace(wa,e=>{const t=e.codePointAt(0).toString(16).padStart(4,"0");return`\\u${t}`})}const ya="[Circular]";function neutralizeForLog(e,t=new WeakSet){if(typeof e==="string")return neutralizeLogString(e);if(typeof e==="number"||typeof e==="boolean"||e===null||e===undefined){return e}if(e instanceof Error){const t=new Error(neutralizeLogString(e.message));t.name=neutralizeLogString(e.name);if(e.stack){t.stack=neutralizeLogString(e.stack)}return t}if(Array.isArray(e)){if(t.has(e))return ya;t.add(e);return e.map(e=>neutralizeForLog(e,t))}if(typeof e==="object"){if(t.has(e))return ya;t.add(e);const r={};for(const[s,n]of Object.entries(e)){r[neutralizeLogString(s)]=neutralizeForLog(n,t)}return r}return e}function log(e,t){if(t)console.log(neutralizeForLog(t));if(e){const t=neutralizeForLog(e);if(typeof t==="string"||t instanceof Error){error(t)}else{error(String(t))}}}const ba=["user.name","user.email","author.name","author.email","committer.name","committer.email"];function pickGitIdentityConfig(e){const t={};for(const r of ba){if(Object.prototype.hasOwnProperty.call(e,r)){t[r]=e[r]}}return t}function assertValidBranchName(e){if(!e||!e.trim()){throw new Error("The new_branch value is empty.")}if(e.startsWith("-")){throw new Error(`The new_branch value '${e}' cannot start with '-' (it would be interpreted as a git option).`)}for(const t of e){const r=t.codePointAt(0);if(r<=31||r===127||r>=128&&r<=159||/\s/u.test(t)){throw new Error(`The new_branch value '${e}' contains whitespace or control characters.`)}}try{(0,ue.execFileSync)("git",["check-ref-format","--branch",e],{stdio:"ignore"})}catch{throw new Error(`The new_branch value '${e}' is not a valid git branch name.`)}}const ka=[{canonical:"upload-pack",minPrefix:"upl"},{canonical:"receive-pack",minPrefix:"rece"},{canonical:"exec",minPrefix:"e"}];const Ta=[{canonical:"file",minPrefix:"fi"}];const Ra=[{canonical:"message",minPrefix:"mes"},{canonical:"local-user",minPrefix:"local-"},{canonical:"cleanup",minPrefix:"cleanup"},{canonical:"file",minPrefix:"fi"},{canonical:"upload-pack",minPrefix:"upl"},{canonical:"receive-pack",minPrefix:"rece"},{canonical:"exec",minPrefix:"e"}];const Da=new Set(["m","u","F"]);function getLongOptionName(e){if(!e.startsWith("--")||e==="--")return undefined;const t=e.slice(2);const r=t.indexOf("=");return(r===-1?t:t.slice(0,r)).toLowerCase()}function longOptionHasInlineValue(e){if(!e.startsWith("--")||e==="--")return false;return e.slice(2).includes("=")}function matchesLongOptionPrefix(e,t){const r=getLongOptionName(e);if(!r)return false;return t.some(({canonical:e,minPrefix:t})=>r.length>=t.length&&e.startsWith(r))}function isDangerousRemoteHelperOption(e){return matchesLongOptionPrefix(e,ka)}function isDangerousMessageFileShortOption(e){if(!e.startsWith("-")||e.startsWith("--"))return false;const t=e.slice(1);for(let e=0;e` - ${e}`).join("\n");const r=e.map(e=>` git rm --cached -- ${e}`).join("\n");throw new Error(`Refusing to commit unexpected gitlink(s) (embedded git repository staged as mode 160000):\n${t}\n`+"Git records a nested .git directory as a gitlink, not as its files. "+`Remove the nested .git directory, or unstage the path(s) with:\n${r}`)}function parseInputArray(e){core_debug(`Parsing input array: ${e}`);try{const t=load(e);if(t&&Array.isArray(t)&&t.every(e=>typeof e==="string")){core_debug(`Input parsed as YAML array of length ${t.length}`);return t}}catch{}core_debug("Input parsed as single string");return[e]}function readJSON(e){let t;try{t=fs.readFileSync(e,{encoding:"utf8"})}catch{throw`Couldn't read file. File path: ${e}`}try{return JSON.parse(t)}catch{throw`Couldn't parse file to JSON. File path: ${e}`}}const Sa={committed:"false",commit_long_sha:undefined,commit_sha:undefined,pushed:"false",tagged:"false",tag_pushed:"false"};Object.entries(Sa).forEach(([e,t])=>setOutput(e,t));function io_getInput(e,t=false){if(t)return getBooleanInput(e);return getInput(e)}function io_setOutput(e,t){core_debug(`Setting output: ${e}=${t}`);Sa[e]=t;setOutput(e,t)}function parsePushAttempts(e){const t=e.trim();if(!/^\+?\d+$/.test(t)){throw new Error(`'${e}' is not a valid value for push_attempts. It must be a positive integer (≥ 1).`)}const r=Number.parseInt(t,10);if(!Number.isSafeInteger(r)||r<1){throw new Error(`'${e}' is not a valid value for push_attempts. It must be a positive integer (≥ 1).`)}return r}function logOutputs(){startGroup("Outputs");for(const e in Sa){info(`${e}: ${Sa[e]}`)}endGroup()}async function checkInputs(){function setInput(e,t){if(t)return process.env[`INPUT_${e.toUpperCase()}`]=t;else return delete process.env[`INPUT_${e.toUpperCase()}`]}function setDefault(e,t){if(!io_getInput(e))setInput(e,t);return io_getInput(e)}if(!io_getInput("add")&&!io_getInput("remove"))throw new Error("Both 'add' and 'remove' are empty, the action has nothing to do.");if(io_getInput("add")){const e=parseInputArray(io_getInput("add"));if(e.length===1)info("Add input parsed as single string, running 1 git add command.");else if(e.length>1)info(`Add input parsed as string array, running ${e.length} git add commands.`);else setFailed("Add input: array length < 1")}if(io_getInput("remove")){const e=parseInputArray(io_getInput("remove")||"");if(e.length===1)info("Remove input parsed as single string, running 1 git rm command.");else if(e.length>1)info(`Remove input parsed as string array, running ${e.length} git rm commands.`);else setFailed("Remove input: array length < 1")}const e=["github_actor","user_info","github_actions"];if(!e.includes(io_getInput("default_author")))throw new Error(`'${io_getInput("default_author")}' is not a valid value for default_author. Valid values: ${e.join(", ")}`);if(io_getInput("dry_run",true))info("> Dry run enabled: no mutating git operations will be performed.");if(io_getInput("fetch")){let e;try{e=io_getInput("fetch",true)}catch{e=io_getInput("fetch")}core_debug(`Current fetch option: '${e}' (parsed as ${typeof e})`)}let t,r;switch(io_getInput("default_author")){case"github_actor":{t=process.env.GITHUB_ACTOR??"";r=`${process.env.GITHUB_ACTOR}@users.noreply.github.com`;break}case"user_info":{if(!io_getInput("author_name")||!io_getInput("author_email")){const e=await getUserInfo(process.env.GITHUB_ACTOR);if(!e?.name)warning("Couldn't fetch author name, filling with github_actor.");if(!e?.email)warning("Couldn't fetch author email, filling with github_actor.");e?.name&&(t=e?.name);e?.email&&(r=e.email);if(t&&r)break}!t&&(t=process.env.GITHUB_ACTOR??"");!r&&(r=`${process.env.GITHUB_ACTOR}@users.noreply.github.com`);break}case"github_actions":{t="github-actions";r="41898282+github-actions[bot]@users.noreply.github.com";break}default:throw new Error("This should not happen, please contact the author of this action. (checkInputs.author)")}setDefault("author_name",t);setDefault("author_email",r);info(`> Using '${io_getInput("author_name")} <${io_getInput("author_email")}>' as author.`);if(io_getInput("committer_name")||io_getInput("committer_email"))info(`> Using custom committer info: ${io_getInput("committer_name")||io_getInput("author_name")+" [from author info]"} <${io_getInput("committer_email")||io_getInput("author_email")+" [from author info]"}>`);setDefault("committer_name",io_getInput("author_name"));setDefault("committer_email",io_getInput("author_email"));core_debug(`Committer: ${io_getInput("committer_name")} <${io_getInput("committer_email")}>`);setDefault("message",`Commit from GitHub Actions (${process.env.GITHUB_WORKFLOW})`);info(`> Using "${io_getInput("message")}" as commit message.`);const s=io_getInput("new_branch");if(s)assertValidBranchName(s);const n=["ignore","exitImmediately","exitAtEnd"];if(!n.includes(io_getInput("pathspec_error_handling")))throw new Error(`"${io_getInput("pathspec_error_handling")}" is not a valid value for the 'pathspec_error_handling' input. Valid values are: ${n.join(", ")}`);if(io_getInput("pull")==="NO-PULL")warning("`NO-PULL` is a legacy option for the `pull` input. If you don't want the action to pull the repo, simply remove this input.");if(io_getInput("push")){let e;try{e=io_getInput("push",true)}catch{e=io_getInput("push")}core_debug(`Current push option: '${e}' (parsed as ${typeof e})`)}const o=parsePushAttempts(io_getInput("push_attempts")||"1");core_debug(`Current push_attempts option: ${o}`);if(o>1&&!io_getInput("pull")){warning("push_attempts is greater than 1 but pull is not set. Retries will re-run push only; without pull (e.g. --rebase), concurrent remote updates are unlikely to recover.")}if(!io_getInput("github_token"))warning("No github_token has been detected, the action may fail if it needs to use the API")}const Fa=u.join(process.cwd(),io_getInput("cwd")||"");const va=lo({baseDir:Fa});const Ua=[];info(`Running in ${Fa}`);(async()=>{await checkInputs();const e=io_getInput("dry_run",true);startGroup("Internal logs");info(e?"> Staging files (dry run)...":"> Staging files...");const t=io_getInput("pathspec_error_handling")==="ignore"?"pathspec":"none";let r=false;if(io_getInput("add")){info(e?"> Adding files (dry run)...":"> Adding files...");const s=await add(t,e);if(e)r=r||s.some(e=>typeof e==="string"&&e.trim().length>0)}else info("> No files to add.");if(io_getInput("remove")){info(e?"> Removing files (dry run)...":"> Removing files...");const s=await main_remove(t,e);if(e)r=r||s.some(e=>{if(e===null||e===undefined)return false;const t=typeof e==="string"?e:String(e);return t.trim().length>0})}else info("> No files to remove.");info("> Checking for uncommitted changes in the git working tree...");const s=(await va.diffSummary(["--cached"])).files.length;const n=matchGitArgs(io_getInput("commit")||"").includes("--allow-empty");if(s>0||r||n){info(e?`> Dry run: would proceed (${s} already staged`+`${r?", staging probes reported changes":""}`+`${n?", --allow-empty":""}).`:`> Found ${s} changed files.`);core_debug(`--allow-empty argument detected: ${n}`);if(e){await logDryRunRemainingSteps();endGroup();info("> Dry run completed. No changes were made.");return}await va.addConfig("user.email",io_getInput("author_email"),undefined,log).addConfig("user.name",io_getInput("author_name"),undefined,log).addConfig("author.email",io_getInput("author_email"),undefined,log).addConfig("author.name",io_getInput("author_name"),undefined,log).addConfig("committer.email",io_getInput("committer_email"),undefined,log).addConfig("committer.name",io_getInput("committer_name"),undefined,log);if(isDebug()){const e=pickGitIdentityConfig((await va.listConfig()).all);core_debug(Object.keys(e).length?"> Current git identity config\n"+JSON.stringify(e,null,2):"> Git identity config set (no identity keys present in listConfig)")}let o;try{o=io_getInput("fetch",true)}catch{o=io_getInput("fetch")}if(o){info("> Fetching repo...");await va.fetch(matchGitArgs(o===true?"":o),log)}else info("> Not fetching repo.");const a=io_getInput("new_branch");if(a){info("> Checking-out branch...");if(!o)warning("Creating a new branch without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.");await va.checkout([a]).then(()=>{log(undefined,`'${a}' branch already existed.`)}).catch(()=>{log(undefined,`Creating '${a}' branch.`);return va.checkout(["-b",a],log)})}const l=io_getInput("pull");if(l){await pullFromRemote(l,{restage:true,ignoreErrors:t})}else info("> Not pulling from repo.");info("> Creating commit...");const u=await va.commit(io_getInput("message"),matchGitArgs(io_getInput("commit")||""));log(undefined,u);if(!u.commit){throw new Error("Commit did not produce a SHA; refusing to report committed=true.")}io_setOutput("committed","true");io_setOutput("commit_long_sha",u.commit);io_setOutput("commit_sha",u.commit.substring(0,7));if(io_getInput("tag")){info("> Tagging commit...");if(!o)warning("Creating a tag without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.");await va.tag(matchGitArgs(io_getInput("tag")||""),(e,t)=>{if(t)io_setOutput("tagged","true");return log(e,t)}).then(e=>{io_setOutput("tagged","true");return log(null,e)}).catch(e=>setFailed(e))}else info("> No tag info provided.");let g;try{g=io_getInput("push",true)}catch{g=io_getInput("push")}if(g){const e=parsePushAttempts(io_getInput("push_attempts")||"1");for(let r=1;r<=e;r++){try{info(e>1?`> Pushing commit to repo (attempt ${r}/${e})...`:"> Pushing commit to repo...");await pushCommit(g);break}catch(s){if(r===e)throw s;const n=s instanceof Error?s.message:String(s);warning(`Push failed (attempt ${r}/${e}): ${neutralizeLogString(n)}`);if(l){await pullFromRemote(l,{restage:false,ignoreErrors:t});const e=(await va.revparse(["HEAD"])).trim();io_setOutput("commit_long_sha",e);io_setOutput("commit_sha",e.substring(0,7))}}}if(io_getInput("tag")){info("> Pushing tags to repo...");await va.pushTags("origin",matchGitArgs(io_getInput("tag_push")||"")).then(e=>{io_setOutput("tag_pushed","true");return log(null,e)}).catch(e=>setFailed(e))}else info("> No tags to push.")}else info("> Not pushing anything.");endGroup();info("> Task completed.")}else{endGroup();info(e?"> Dry run: working tree clean. Nothing would be committed.":"> Working tree clean. Nothing to commit.")}})().then(()=>{if(Ua.length===1)throw Ua[0];else if(Ua.length>1){Ua.forEach(e=>error(e));throw"There have been multiple runtime errors."}}).then(logOutputs).catch(e=>{endGroup();logOutputs();setFailed(e)});async function logDryRunRemainingSteps(){info(`> Would set git identity: ${io_getInput("author_name")} <${io_getInput("author_email")}> (committer: ${io_getInput("committer_name")} <${io_getInput("committer_email")}>)`);let e;try{e=io_getInput("fetch",true)}catch{e=io_getInput("fetch")}if(e){info(`> Would fetch repo${e===true?"":` with: ${e}`}.`)}else info("> Would not fetch repo.");const t=io_getInput("new_branch");if(t){info(`> Would check out branch '${t}'.`);if(!e)warning("Creating a new branch without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.")}const r=io_getInput("pull");if(r)info(`> Would pull from remote with: ${r}.`);else info("> Would not pull from repo.");info(`> Would create commit with message: "${io_getInput("message")}"${io_getInput("commit")?` (extra args: ${io_getInput("commit")})`:""}.`);if(io_getInput("tag")){info(`> Would tag commit with: ${io_getInput("tag")}.`);if(!e)warning("Creating a tag without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.")}else info("> No tag info provided.");let s;try{s=io_getInput("push",true)}catch{s=io_getInput("push")}if(s){const e=parsePushAttempts(io_getInput("push_attempts")||"1");if(s===true){const t=io_getInput("new_branch");info(t?`> Would push commit to repo (set upstream for '${t}')${e>1?` with up to ${e} attempts`:""}.`:`> Would push commit to repo${e>1?` with up to ${e} attempts`:""}.`)}else info(`> Would push commit to repo with: ${s}${e>1?` (up to ${e} attempts)`:""}.`);if(io_getInput("tag")){info(`> Would push tags to repo${io_getInput("tag_push")?` with: ${io_getInput("tag_push")}`:""}.`)}else info("> No tags to push.")}else info("> Would not push anything.")}async function pullFromRemote(e,t){info("> Pulling from remote...");core_debug(`Current git pull arguments: ${e}`);await va.fetch(undefined,log).pull(undefined,undefined,matchGitArgs(e),log);info("> Checking for conflicts...");const r=await va.status(undefined,log);if(r.conflicted.length){throw new Error(`There are ${r.conflicted.length} conflicting files: ${r.conflicted.map(neutralizeLogString).join(", ")}`)}info("> No conflicts found.");if(t.restage){info("> Re-staging files...");if(io_getInput("add"))await add(t.ignoreErrors);if(io_getInput("remove"))await main_remove(t.ignoreErrors)}}async function pushCommit(e){if(e===true){const e=io_getInput("new_branch");if(e){core_debug(`Running: git push --set-upstream origin -- ${e}`);await va.raw(["push","--set-upstream","origin","--",e],(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}else{core_debug("Running: git push origin --set-upstream");await va.push("origin",undefined,{"--set-upstream":null},(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}}else{core_debug(`Running: git push ${e}`);await va.push(undefined,undefined,matchGitArgs(e),(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}}async function add(e="none",t=false){const r=io_getInput("add");if(!r)return[];const s=parseInputArray(r);const n=[];for(const r of s){const s=t?["--dry-run",...matchGitArgs(r)]:matchGitArgs(r);n.push(await va.add(s,(t,r)=>log(e==="all"?null:t,r)).catch(t=>{if(e==="all")return;if(t.message.includes("fatal: pathspec")&&t.message.includes("did not match any files")){if(e==="pathspec")return;const t=io_getInput("pathspec_error_handling"),s=new Error(`Add command did not match any file: git add ${r}`);if(t==="exitImmediately")throw s;if(t==="exitAtEnd")Ua.push(s)}else throw t}))}if(t){await assertGitlinksWithTempIndex(s,e)}else{const e=await va.raw(["diff","--cached","--raw"]);assertNoUnexpectedGitlinks(findUnexpectedGitlinks(e))}return n}async function assertGitlinksWithTempIndex(e,t){const r=u.join(n.tmpdir(),`add-and-commit-${process.pid}-${Date.now()}.index`);try{const s=(await va.raw(["rev-parse","--git-path","index"])).trim();const n=u.isAbsolute(s)?s:u.join(Fa,s);if(l.existsSync(n)){l.copyFileSync(n,r)}else{const e=lo({baseDir:Fa}).env({...process.env,GIT_INDEX_FILE:r});const t=await va.raw(["rev-parse","--verify","HEAD"]).then(()=>true).catch(()=>false);if(t){await e.raw(["read-tree","HEAD"])}else{await e.raw(["read-tree","--empty"])}}const o=lo({baseDir:Fa}).env({...process.env,GIT_INDEX_FILE:r});for(const r of e){await o.add(matchGitArgs(r),(e,r)=>log(t==="all"?null:e,r)).catch(e=>{if(t==="all")return;if(e.message.includes("fatal: pathspec")&&e.message.includes("did not match any files")){if(t==="pathspec")return;const e=io_getInput("pathspec_error_handling");if(e==="exitImmediately"){throw new Error(`Add command did not match any file: git add ${r}`)}return}throw e})}const a=await o.raw(["diff","--cached","--raw"]);assertNoUnexpectedGitlinks(findUnexpectedGitlinks(a))}finally{l.rmSync(r,{force:true});l.rmSync(`${r}.lock`,{force:true})}}async function main_remove(e="none",t=false){const r=io_getInput("remove");if(!r)return[];const s=parseInputArray(r);const n=[];for(const r of s){const s=t?["--dry-run",...matchGitArgs(r)]:matchGitArgs(r);n.push(await va.rm(s,(t,r)=>log(e==="all"?null:t,r)).catch(t=>{if(e==="all")return;if(t.message.includes("fatal: pathspec")&&t.message.includes("did not match any files")){if(e==="pathspec")return;const t=io_getInput("pathspec_error_handling"),s=new Error(`Remove command did not match any file:\n git rm ${r}`);if(t==="exitImmediately")throw s;if(t==="exitAtEnd")Ua.push(s)}else throw t}))}return n} \ No newline at end of file +/* v8 ignore else -- @preserve */var zA="0.0.0-development";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map(e=>` - ${e.message}`).join("\n")}var KA=class extends Error{constructor(e,t,r){super(_buildMessageForResponseErrors(r));this.request=e;this.headers=t;this.response=r;this.errors=r.errors;this.data=r.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}name="GraphqlResponseError";errors;data};var ZA=["method","baseUrl","url","headers","request","query","mediaType","operationName"];var $A=["query","method","url"];var XA=/\/api\/v3\/?$/;function graphql(e,t,r){if(r){if(typeof t==="string"&&"query"in r){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in r){if(!$A.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const s=typeof t==="string"?Object.assign({query:t},r):t;const n=Object.keys(s).reduce((e,t)=>{if(ZA.includes(t)){e[t]=s[t];return e}if(!e.variables){e.variables={}}e.variables[t]=s[t];return e},{});const o=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(XA.test(o)){n.url=o.replace(XA,"/api/graphql")}return e(n).then(e=>{if(e.data.errors){const t={};for(const r of Object.keys(e.headers)){t[r]=e.headers[r]}throw new KA(n,t,e.data)}return e.data.data})}function graphql_dist_bundle_withDefaults(e,t){const r=e.defaults(t);const newApi=(e,t)=>graphql(r,e,t);return Object.assign(newApi,{defaults:graphql_dist_bundle_withDefaults.bind(null,r),endpoint:r.endpoint})}var ea=graphql_dist_bundle_withDefaults(jA,{headers:{"user-agent":`octokit-graphql.js/${zA} ${getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return graphql_dist_bundle_withDefaults(e,{method:"POST",url:"/graphql"})}var ta="(?:[a-zA-Z0-9_-]+)";var ra="\\.";var sa=new RegExp(`^${ta}${ra}${ta}${ra}${ta}$`);var na=sa.test.bind(sa);async function auth(e){const t=na(e);const r=e.startsWith("v1.")||e.startsWith("ghs_");const s=e.startsWith("ghu_");const n=t?"app":r?"installation":s?"user-to-server":"oauth";return{type:"token",token:e,tokenType:n}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,t,r,s){const n=t.endpoint.merge(r,s);n.headers.authorization=withAuthorizationPrefix(e);return t(n)}var oa=function createTokenAuth2(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};const ia="7.0.6";const dist_src_noop=()=>{};const Aa=console.warn.bind(console);const aa=console.error.bind(console);function dist_src_createLogger(e={}){if(typeof e.debug!=="function"){e.debug=dist_src_noop}if(typeof e.info!=="function"){e.info=dist_src_noop}if(typeof e.warn!=="function"){e.warn=Aa}if(typeof e.error!=="function"){e.error=aa}return e}const ca=`octokit-core.js/${ia} ${getUserAgent()}`;class Octokit{static VERSION=ia;static defaults(e){const t=class extends(this){constructor(...t){const r=t[0]||{};if(typeof e==="function"){super(e(r));return}super(Object.assign({},e,r,r.userAgent&&e.userAgent?{userAgent:`${r.userAgent} ${e.userAgent}`}:null))}};return t}static plugins=[];static plugin(...e){const t=this.plugins;const r=class extends(this){static plugins=t.concat(e.filter(e=>!t.includes(e)))};return r}constructor(e={}){const t=new OA.Collection;const r={baseUrl:jA.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:t.bind(null,"request")}),mediaType:{previews:[],format:""}};r.headers["user-agent"]=e.userAgent?`${e.userAgent} ${ca}`:ca;if(e.baseUrl){r.baseUrl=e.baseUrl}if(e.previews){r.mediaType.previews=e.previews}if(e.timeZone){r.headers["time-zone"]=e.timeZone}this.request=jA.defaults(r);this.graphql=withCustomRequest(this.request).defaults(r);this.log=dist_src_createLogger(e.log);this.hook=t;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const r=oa(e.auth);t.wrap("request",r.hook);this.auth=r}}else{const{authStrategy:r,...s}=e;const n=r(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:s},e.auth));t.wrap("request",n.hook);this.auth=n}const s=this.constructor;for(let t=0;t({async next(){if(!l)return{done:true};try{const e=await n({method:o,url:l,headers:a});const t=normalizePaginatedListResponse(e);l=((t.headers.link||"").match(/<([^<>]+)>;\s*rel="next"/)||[])[1];if(!l&&"total_commits"in t.data){const e=new URL(t.url);const r=e.searchParams;const s=parseInt(r.get("page")||"1",10);const n=parseInt(r.get("per_page")||"250",10);if(s*n{if(n.done){return t}let o=false;function done(){o=true}t=t.concat(s?s(n.value,done):n.value.data);if(o){return t}return gather(e,t,r,s)})}var Ea=Object.assign(paginate,{iterator:iterator});var fa=null&&["GET /advisories","GET /app/hook/deliveries","GET /app/installation-requests","GET /app/installations","GET /assignments/{assignment_id}/accepted_assignments","GET /classrooms","GET /classrooms/{classroom_id}/assignments","GET /enterprises/{enterprise}/code-security/configurations","GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}/repositories","GET /enterprises/{enterprise}/dependabot/alerts","GET /enterprises/{enterprise}/teams","GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships","GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /licenses","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /organizations/{org}/dependabot/repository-access","GET /orgs/{org}/actions/cache/usage-by-repository","GET /orgs/{org}/actions/hosted-runners","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/permissions/self-hosted-runners/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/actions/variables","GET /orgs/{org}/actions/variables/{name}/repositories","GET /orgs/{org}/attestations/repositories","GET /orgs/{org}/attestations/{subject_digest}","GET /orgs/{org}/blocks","GET /orgs/{org}/campaigns","GET /orgs/{org}/code-scanning/alerts","GET /orgs/{org}/code-security/configurations","GET /orgs/{org}/code-security/configurations/{configuration_id}/repositories","GET /orgs/{org}/codespaces","GET /orgs/{org}/codespaces/secrets","GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories","GET /orgs/{org}/copilot/billing/seats","GET /orgs/{org}/copilot/metrics","GET /orgs/{org}/dependabot/alerts","GET /orgs/{org}/dependabot/secrets","GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories","GET /orgs/{org}/events","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/insights/api/route-stats/{actor_type}/{actor_id}","GET /orgs/{org}/insights/api/subject-stats","GET /orgs/{org}/insights/api/user-stats/{user_id}","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/members/{username}/codespaces","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/organization-roles/{role_id}/teams","GET /orgs/{org}/organization-roles/{role_id}/users","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/packages/{package_type}/{package_name}/versions","GET /orgs/{org}/personal-access-token-requests","GET /orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories","GET /orgs/{org}/personal-access-tokens","GET /orgs/{org}/personal-access-tokens/{pat_id}/repositories","GET /orgs/{org}/private-registries","GET /orgs/{org}/projects","GET /orgs/{org}/projectsV2","GET /orgs/{org}/projectsV2/{project_number}/fields","GET /orgs/{org}/projectsV2/{project_number}/items","GET /orgs/{org}/properties/values","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/rulesets","GET /orgs/{org}/rulesets/rule-suites","GET /orgs/{org}/rulesets/{ruleset_id}/history","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/security-advisories","GET /orgs/{org}/settings/immutable-releases/repositories","GET /orgs/{org}/settings/network-configurations","GET /orgs/{org}/team/{team_slug}/copilot/metrics","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/{project_id}/collaborators","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/caches","GET /repos/{owner}/{repo}/actions/organization-secrets","GET /repos/{owner}/{repo}/actions/organization-variables","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/variables","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/activity","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/attestations/{subject_digest}","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/codespaces","GET /repos/{owner}/{repo}/codespaces/devcontainers","GET /repos/{owner}/{repo}/codespaces/secrets","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/status","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/compare/{basehead}","GET /repos/{owner}/{repo}/compare/{base}...{head}","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/dependabot/alerts","GET /repos/{owner}/{repo}/dependabot/secrets","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/environments","GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies","GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps","GET /repos/{owner}/{repo}/environments/{environment_name}/secrets","GET /repos/{owner}/{repo}/environments/{environment_name}/variables","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by","GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocking","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/releases/{release_id}/reactions","GET /repos/{owner}/{repo}/rules/branches/{branch}","GET /repos/{owner}/{repo}/rulesets","GET /repos/{owner}/{repo}/rulesets/rule-suites","GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations","GET /repos/{owner}/{repo}/security-advisories","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repos/{owner}/{repo}/topics","GET /repositories","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/codespaces","GET /user/codespaces/secrets","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/packages/{package_type}/{package_name}/versions","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/social_accounts","GET /user/ssh_signing_keys","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /users","GET /users/{username}/attestations/{subject_digest}","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/packages","GET /users/{username}/projects","GET /users/{username}/projectsV2","GET /users/{username}/projectsV2/{project_number}/fields","GET /users/{username}/projectsV2/{project_number}/items","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/social_accounts","GET /users/{username}/ssh_signing_keys","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return fa.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=pa;const Ca=new Context;const Qa=getApiBaseUrl();const Ia={baseUrl:Qa,request:{agent:getProxyAgent(Qa),fetch:getProxyFetch(Qa)}};const Ba=Octokit.plugin(restEndpointMethods,paginateRest).defaults(Ia);function getOctokitOptions(e,t){const r=Object.assign({},t||{});const s=getAuthString(e,r);if(s){r.auth=s}const n=getUserAgentWithOrchestrationId(r.userAgent);if(n){r.userAgent=n}return r}const ma=new Context;function getOctokit(e,t,...r){const s=Ba.plugin(...r);return new s(getOctokitOptions(e,t))}function resolveBaseDir(e,t=process.cwd()){return u.resolve(t,e||".")}function assertWorkingDirectory(e,t){if(!l.existsSync(e)||!l.statSync(e).isDirectory()){throw new Error(`The cwd input '${t||"."}' resolved to '${e}', which is not an existing directory. `+"Use a path relative to the runner workspace, or an absolute path that exists "+"(e.g. ${{ github.workspace }}/path — note that $GITHUB_WORKSPACE is not expanded in with:).")}}function getOctokitClient(){const e=io_getInput("github_token");if(!e){throw new Error("github_token is required")}return getOctokit(e)}async function getUserInfo(e){if(!e)return undefined;const t=getOctokitClient();const r=await t.rest.users.getByUsername({username:e});core_debug(`Fetched github actor from the API: ${JSON.stringify(r?.data,null,2)}`);return{name:r?.data?.name,email:r?.data?.email}}const wa=/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/gu;function neutralizeLogString(e){return e.replace(wa,e=>{const t=e.codePointAt(0).toString(16).padStart(4,"0");return`\\u${t}`})}const ya="[Circular]";function neutralizeForLog(e,t=new WeakSet){if(typeof e==="string")return neutralizeLogString(e);if(typeof e==="number"||typeof e==="boolean"||e===null||e===undefined){return e}if(e instanceof Error){const t=new Error(neutralizeLogString(e.message));t.name=neutralizeLogString(e.name);if(e.stack){t.stack=neutralizeLogString(e.stack)}return t}if(Array.isArray(e)){if(t.has(e))return ya;t.add(e);return e.map(e=>neutralizeForLog(e,t))}if(typeof e==="object"){if(t.has(e))return ya;t.add(e);const r={};for(const[s,n]of Object.entries(e)){r[neutralizeLogString(s)]=neutralizeForLog(n,t)}return r}return e}function log(e,t){if(t)console.log(neutralizeForLog(t));if(e){const t=neutralizeForLog(e);if(typeof t==="string"||t instanceof Error){error(t)}else{error(String(t))}}}const ba=["user.name","user.email","author.name","author.email","committer.name","committer.email"];function pickGitIdentityConfig(e){const t={};for(const r of ba){if(Object.prototype.hasOwnProperty.call(e,r)){t[r]=e[r]}}return t}function assertValidBranchName(e){if(!e||!e.trim()){throw new Error("The new_branch value is empty.")}if(e.startsWith("-")){throw new Error(`The new_branch value '${e}' cannot start with '-' (it would be interpreted as a git option).`)}for(const t of e){const r=t.codePointAt(0);if(r<=31||r===127||r>=128&&r<=159||/\s/u.test(t)){throw new Error(`The new_branch value '${e}' contains whitespace or control characters.`)}}try{(0,ue.execFileSync)("git",["check-ref-format","--branch",e],{stdio:"ignore"})}catch{throw new Error(`The new_branch value '${e}' is not a valid git branch name.`)}}const ka=[{canonical:"upload-pack",minPrefix:"upl"},{canonical:"receive-pack",minPrefix:"rece"},{canonical:"exec",minPrefix:"e"}];const Ta=[{canonical:"file",minPrefix:"fi"}];const Ra=[{canonical:"message",minPrefix:"mes"},{canonical:"local-user",minPrefix:"local-"},{canonical:"cleanup",minPrefix:"cleanup"},{canonical:"file",minPrefix:"fi"},{canonical:"upload-pack",minPrefix:"upl"},{canonical:"receive-pack",minPrefix:"rece"},{canonical:"exec",minPrefix:"e"}];const Da=new Set(["m","u","F"]);function getLongOptionName(e){if(!e.startsWith("--")||e==="--")return undefined;const t=e.slice(2);const r=t.indexOf("=");return(r===-1?t:t.slice(0,r)).toLowerCase()}function longOptionHasInlineValue(e){if(!e.startsWith("--")||e==="--")return false;return e.slice(2).includes("=")}function matchesLongOptionPrefix(e,t){const r=getLongOptionName(e);if(!r)return false;return t.some(({canonical:e,minPrefix:t})=>r.length>=t.length&&e.startsWith(r))}function isDangerousRemoteHelperOption(e){return matchesLongOptionPrefix(e,ka)}function isDangerousMessageFileShortOption(e){if(!e.startsWith("-")||e.startsWith("--"))return false;const t=e.slice(1);for(let e=0;e` - ${e}`).join("\n");const r=e.map(e=>` git rm --cached -- ${e}`).join("\n");throw new Error(`Refusing to commit unexpected gitlink(s) (embedded git repository staged as mode 160000):\n${t}\n`+"Git records a nested .git directory as a gitlink, not as its files. "+`Remove the nested .git directory, or unstage the path(s) with:\n${r}`)}function parseInputArray(e){core_debug(`Parsing input array: ${e}`);try{const t=load(e);if(t&&Array.isArray(t)&&t.every(e=>typeof e==="string")){core_debug(`Input parsed as YAML array of length ${t.length}`);return t}}catch{}core_debug("Input parsed as single string");return[e]}function readJSON(e){let t;try{t=fs.readFileSync(e,{encoding:"utf8"})}catch{throw`Couldn't read file. File path: ${e}`}try{return JSON.parse(t)}catch{throw`Couldn't parse file to JSON. File path: ${e}`}}const Sa={committed:"false",commit_long_sha:undefined,commit_sha:undefined,pushed:"false",tagged:"false",tag_pushed:"false"};Object.entries(Sa).forEach(([e,t])=>setOutput(e,t));function io_getInput(e,t=false){if(t)return getBooleanInput(e);return getInput(e)}function io_setOutput(e,t){core_debug(`Setting output: ${e}=${t}`);Sa[e]=t;setOutput(e,t)}function parsePushAttempts(e){const t=e.trim();if(!/^\+?\d+$/.test(t)){throw new Error(`'${e}' is not a valid value for push_attempts. It must be a positive integer (≥ 1).`)}const r=Number.parseInt(t,10);if(!Number.isSafeInteger(r)||r<1){throw new Error(`'${e}' is not a valid value for push_attempts. It must be a positive integer (≥ 1).`)}return r}function logOutputs(){startGroup("Outputs");for(const e in Sa){info(`${e}: ${Sa[e]}`)}endGroup()}async function checkInputs(){function setInput(e,t){if(t)return process.env[`INPUT_${e.toUpperCase()}`]=t;else return delete process.env[`INPUT_${e.toUpperCase()}`]}function setDefault(e,t){if(!io_getInput(e))setInput(e,t);return io_getInput(e)}if(!io_getInput("add")&&!io_getInput("remove"))throw new Error("Both 'add' and 'remove' are empty, the action has nothing to do.");if(io_getInput("add")){const e=parseInputArray(io_getInput("add"));if(e.length===1)info("Add input parsed as single string, running 1 git add command.");else if(e.length>1)info(`Add input parsed as string array, running ${e.length} git add commands.`);else setFailed("Add input: array length < 1")}if(io_getInput("remove")){const e=parseInputArray(io_getInput("remove")||"");if(e.length===1)info("Remove input parsed as single string, running 1 git rm command.");else if(e.length>1)info(`Remove input parsed as string array, running ${e.length} git rm commands.`);else setFailed("Remove input: array length < 1")}const e=["github_actor","user_info","github_actions"];if(!e.includes(io_getInput("default_author")))throw new Error(`'${io_getInput("default_author")}' is not a valid value for default_author. Valid values: ${e.join(", ")}`);if(io_getInput("dry_run",true))info("> Dry run enabled: no mutating git operations will be performed.");if(io_getInput("fetch")){let e;try{e=io_getInput("fetch",true)}catch{e=io_getInput("fetch")}core_debug(`Current fetch option: '${e}' (parsed as ${typeof e})`)}let t,r;switch(io_getInput("default_author")){case"github_actor":{t=process.env.GITHUB_ACTOR??"";r=`${process.env.GITHUB_ACTOR}@users.noreply.github.com`;break}case"user_info":{if(!io_getInput("author_name")||!io_getInput("author_email")){const e=await getUserInfo(process.env.GITHUB_ACTOR);if(!e?.name)warning("Couldn't fetch author name, filling with github_actor.");if(!e?.email)warning("Couldn't fetch author email, filling with github_actor.");e?.name&&(t=e?.name);e?.email&&(r=e.email);if(t&&r)break}!t&&(t=process.env.GITHUB_ACTOR??"");!r&&(r=`${process.env.GITHUB_ACTOR}@users.noreply.github.com`);break}case"github_actions":{t="github-actions";r="41898282+github-actions[bot]@users.noreply.github.com";break}default:throw new Error("This should not happen, please contact the author of this action. (checkInputs.author)")}setDefault("author_name",t);setDefault("author_email",r);info(`> Using '${io_getInput("author_name")} <${io_getInput("author_email")}>' as author.`);if(io_getInput("committer_name")||io_getInput("committer_email"))info(`> Using custom committer info: ${io_getInput("committer_name")||io_getInput("author_name")+" [from author info]"} <${io_getInput("committer_email")||io_getInput("author_email")+" [from author info]"}>`);setDefault("committer_name",io_getInput("author_name"));setDefault("committer_email",io_getInput("author_email"));core_debug(`Committer: ${io_getInput("committer_name")} <${io_getInput("committer_email")}>`);setDefault("message",`Commit from GitHub Actions (${process.env.GITHUB_WORKFLOW})`);info(`> Using "${io_getInput("message")}" as commit message.`);const s=io_getInput("new_branch");if(s)assertValidBranchName(s);const n=["ignore","exitImmediately","exitAtEnd"];if(!n.includes(io_getInput("pathspec_error_handling")))throw new Error(`"${io_getInput("pathspec_error_handling")}" is not a valid value for the 'pathspec_error_handling' input. Valid values are: ${n.join(", ")}`);if(io_getInput("pull")==="NO-PULL")warning("`NO-PULL` is a legacy option for the `pull` input. If you don't want the action to pull the repo, simply remove this input.");if(io_getInput("push")){let e;try{e=io_getInput("push",true)}catch{e=io_getInput("push")}core_debug(`Current push option: '${e}' (parsed as ${typeof e})`)}const o=parsePushAttempts(io_getInput("push_attempts")||"1");core_debug(`Current push_attempts option: ${o}`);if(o>1&&!io_getInput("pull")){warning("push_attempts is greater than 1 but pull is not set. Retries will re-run push only; without pull (e.g. --rebase), concurrent remote updates are unlikely to recover.")}if(!io_getInput("github_token"))warning("No github_token has been detected, the action may fail if it needs to use the API")}const Fa=io_getInput("cwd")||"";const va=resolveBaseDir(Fa);let Ua;const Na=[];info(`Running in ${va}`);(async()=>{assertWorkingDirectory(va,Fa);Ua=lo({baseDir:va});await checkInputs();const e=io_getInput("dry_run",true);startGroup("Internal logs");info(e?"> Staging files (dry run)...":"> Staging files...");const t=io_getInput("pathspec_error_handling")==="ignore"?"pathspec":"none";let r=false;if(io_getInput("add")){info(e?"> Adding files (dry run)...":"> Adding files...");const s=await add(t,e);if(e)r=r||s.some(e=>typeof e==="string"&&e.trim().length>0)}else info("> No files to add.");if(io_getInput("remove")){info(e?"> Removing files (dry run)...":"> Removing files...");const s=await main_remove(t,e);if(e)r=r||s.some(e=>{if(e===null||e===undefined)return false;const t=typeof e==="string"?e:String(e);return t.trim().length>0})}else info("> No files to remove.");info("> Checking for uncommitted changes in the git working tree...");const s=(await Ua.diffSummary(["--cached"])).files.length;const n=matchGitArgs(io_getInput("commit")||"").includes("--allow-empty");if(s>0||r||n){info(e?`> Dry run: would proceed (${s} already staged`+`${r?", staging probes reported changes":""}`+`${n?", --allow-empty":""}).`:`> Found ${s} changed files.`);core_debug(`--allow-empty argument detected: ${n}`);if(e){await logDryRunRemainingSteps();endGroup();info("> Dry run completed. No changes were made.");return}await Ua.addConfig("user.email",io_getInput("author_email"),undefined,log).addConfig("user.name",io_getInput("author_name"),undefined,log).addConfig("author.email",io_getInput("author_email"),undefined,log).addConfig("author.name",io_getInput("author_name"),undefined,log).addConfig("committer.email",io_getInput("committer_email"),undefined,log).addConfig("committer.name",io_getInput("committer_name"),undefined,log);if(isDebug()){const e=pickGitIdentityConfig((await Ua.listConfig()).all);core_debug(Object.keys(e).length?"> Current git identity config\n"+JSON.stringify(e,null,2):"> Git identity config set (no identity keys present in listConfig)")}let o;try{o=io_getInput("fetch",true)}catch{o=io_getInput("fetch")}if(o){info("> Fetching repo...");await Ua.fetch(matchGitArgs(o===true?"":o),log)}else info("> Not fetching repo.");const a=io_getInput("new_branch");if(a){info("> Checking-out branch...");if(!o)warning("Creating a new branch without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.");await Ua.checkout([a]).then(()=>{log(undefined,`'${a}' branch already existed.`)}).catch(()=>{log(undefined,`Creating '${a}' branch.`);return Ua.checkout(["-b",a],log)})}const l=io_getInput("pull");if(l){await pullFromRemote(l,{restage:true,ignoreErrors:t})}else info("> Not pulling from repo.");info("> Creating commit...");const u=await Ua.commit(io_getInput("message"),matchGitArgs(io_getInput("commit")||""));log(undefined,u);if(!u.commit){throw new Error("Commit did not produce a SHA; refusing to report committed=true.")}io_setOutput("committed","true");io_setOutput("commit_long_sha",u.commit);io_setOutput("commit_sha",u.commit.substring(0,7));if(io_getInput("tag")){info("> Tagging commit...");if(!o)warning("Creating a tag without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.");await Ua.tag(matchGitArgs(io_getInput("tag")||""),(e,t)=>{if(t)io_setOutput("tagged","true");return log(e,t)}).then(e=>{io_setOutput("tagged","true");return log(null,e)}).catch(e=>setFailed(e))}else info("> No tag info provided.");let g;try{g=io_getInput("push",true)}catch{g=io_getInput("push")}if(g){const e=parsePushAttempts(io_getInput("push_attempts")||"1");for(let r=1;r<=e;r++){try{info(e>1?`> Pushing commit to repo (attempt ${r}/${e})...`:"> Pushing commit to repo...");await pushCommit(g);break}catch(s){if(r===e)throw s;const n=s instanceof Error?s.message:String(s);warning(`Push failed (attempt ${r}/${e}): ${neutralizeLogString(n)}`);if(l){await pullFromRemote(l,{restage:false,ignoreErrors:t});const e=(await Ua.revparse(["HEAD"])).trim();io_setOutput("commit_long_sha",e);io_setOutput("commit_sha",e.substring(0,7))}}}if(io_getInput("tag")){info("> Pushing tags to repo...");await Ua.pushTags("origin",matchGitArgs(io_getInput("tag_push")||"")).then(e=>{io_setOutput("tag_pushed","true");return log(null,e)}).catch(e=>setFailed(e))}else info("> No tags to push.")}else info("> Not pushing anything.");endGroup();info("> Task completed.")}else{endGroup();info(e?"> Dry run: working tree clean. Nothing would be committed.":"> Working tree clean. Nothing to commit.")}})().then(()=>{if(Na.length===1)throw Na[0];else if(Na.length>1){Na.forEach(e=>error(e));throw"There have been multiple runtime errors."}}).then(logOutputs).catch(e=>{endGroup();logOutputs();setFailed(e)});async function logDryRunRemainingSteps(){info(`> Would set git identity: ${io_getInput("author_name")} <${io_getInput("author_email")}> (committer: ${io_getInput("committer_name")} <${io_getInput("committer_email")}>)`);let e;try{e=io_getInput("fetch",true)}catch{e=io_getInput("fetch")}if(e){info(`> Would fetch repo${e===true?"":` with: ${e}`}.`)}else info("> Would not fetch repo.");const t=io_getInput("new_branch");if(t){info(`> Would check out branch '${t}'.`);if(!e)warning("Creating a new branch without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.")}const r=io_getInput("pull");if(r)info(`> Would pull from remote with: ${r}.`);else info("> Would not pull from repo.");info(`> Would create commit with message: "${io_getInput("message")}"${io_getInput("commit")?` (extra args: ${io_getInput("commit")})`:""}.`);if(io_getInput("tag")){info(`> Would tag commit with: ${io_getInput("tag")}.`);if(!e)warning("Creating a tag without fetching the repo first could result in an error when pushing to GitHub. Refer to the action README for more info about this topic.")}else info("> No tag info provided.");let s;try{s=io_getInput("push",true)}catch{s=io_getInput("push")}if(s){const e=parsePushAttempts(io_getInput("push_attempts")||"1");if(s===true){const t=io_getInput("new_branch");info(t?`> Would push commit to repo (set upstream for '${t}')${e>1?` with up to ${e} attempts`:""}.`:`> Would push commit to repo${e>1?` with up to ${e} attempts`:""}.`)}else info(`> Would push commit to repo with: ${s}${e>1?` (up to ${e} attempts)`:""}.`);if(io_getInput("tag")){info(`> Would push tags to repo${io_getInput("tag_push")?` with: ${io_getInput("tag_push")}`:""}.`)}else info("> No tags to push.")}else info("> Would not push anything.")}async function pullFromRemote(e,t){info("> Pulling from remote...");core_debug(`Current git pull arguments: ${e}`);await Ua.fetch(undefined,log).pull(undefined,undefined,matchGitArgs(e),log);info("> Checking for conflicts...");const r=await Ua.status(undefined,log);if(r.conflicted.length){throw new Error(`There are ${r.conflicted.length} conflicting files: ${r.conflicted.map(neutralizeLogString).join(", ")}`)}info("> No conflicts found.");if(t.restage){info("> Re-staging files...");if(io_getInput("add"))await add(t.ignoreErrors);if(io_getInput("remove"))await main_remove(t.ignoreErrors)}}async function pushCommit(e){if(e===true){const e=io_getInput("new_branch");if(e){core_debug(`Running: git push --set-upstream origin -- ${e}`);await Ua.raw(["push","--set-upstream","origin","--",e],(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}else{core_debug("Running: git push origin --set-upstream");await Ua.push("origin",undefined,{"--set-upstream":null},(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}}else{core_debug(`Running: git push ${e}`);await Ua.push(undefined,undefined,matchGitArgs(e),(e,t)=>{if(t)io_setOutput("pushed","true");return log(e,t)})}}async function add(e="none",t=false){const r=io_getInput("add");if(!r)return[];const s=parseInputArray(r);const n=[];for(const r of s){const s=t?["--dry-run",...matchGitArgs(r)]:matchGitArgs(r);n.push(await Ua.add(s,(t,r)=>log(e==="all"?null:t,r)).catch(t=>{if(e==="all")return;if(t.message.includes("fatal: pathspec")&&t.message.includes("did not match any files")){if(e==="pathspec")return;const t=io_getInput("pathspec_error_handling"),s=new Error(`Add command did not match any file: git add ${r}`);if(t==="exitImmediately")throw s;if(t==="exitAtEnd")Na.push(s)}else throw t}))}if(t){await assertGitlinksWithTempIndex(s,e)}else{const e=await Ua.raw(["diff","--cached","--raw"]);assertNoUnexpectedGitlinks(findUnexpectedGitlinks(e))}return n}async function assertGitlinksWithTempIndex(e,t){const r=u.join(n.tmpdir(),`add-and-commit-${process.pid}-${Date.now()}.index`);try{const s=(await Ua.raw(["rev-parse","--git-path","index"])).trim();const n=u.isAbsolute(s)?s:u.join(va,s);if(l.existsSync(n)){l.copyFileSync(n,r)}else{const e=lo({baseDir:va}).env({...process.env,GIT_INDEX_FILE:r});const t=await Ua.raw(["rev-parse","--verify","HEAD"]).then(()=>true).catch(()=>false);if(t){await e.raw(["read-tree","HEAD"])}else{await e.raw(["read-tree","--empty"])}}const o=lo({baseDir:va}).env({...process.env,GIT_INDEX_FILE:r});for(const r of e){await o.add(matchGitArgs(r),(e,r)=>log(t==="all"?null:e,r)).catch(e=>{if(t==="all")return;if(e.message.includes("fatal: pathspec")&&e.message.includes("did not match any files")){if(t==="pathspec")return;const e=io_getInput("pathspec_error_handling");if(e==="exitImmediately"){throw new Error(`Add command did not match any file: git add ${r}`)}return}throw e})}const a=await o.raw(["diff","--cached","--raw"]);assertNoUnexpectedGitlinks(findUnexpectedGitlinks(a))}finally{l.rmSync(r,{force:true});l.rmSync(`${r}.lock`,{force:true})}}async function main_remove(e="none",t=false){const r=io_getInput("remove");if(!r)return[];const s=parseInputArray(r);const n=[];for(const r of s){const s=t?["--dry-run",...matchGitArgs(r)]:matchGitArgs(r);n.push(await Ua.rm(s,(t,r)=>log(e==="all"?null:t,r)).catch(t=>{if(e==="all")return;if(t.message.includes("fatal: pathspec")&&t.message.includes("did not match any files")){if(e==="pathspec")return;const t=io_getInput("pathspec_error_handling"),s=new Error(`Remove command did not match any file:\n git rm ${r}`);if(t==="exitImmediately")throw s;if(t==="exitAtEnd")Na.push(s)}else throw t}))}return n} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index c3c93bd4..dcc58646 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ import * as core from '@actions/core'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import simpleGit, {Response} from 'simple-git'; +import simpleGit, {Response, SimpleGit} from 'simple-git'; import { checkInputs, getInput, @@ -12,21 +12,27 @@ import { } from './io'; import { assertNoUnexpectedGitlinks, + assertWorkingDirectory, findUnexpectedGitlinks, log, matchGitArgs, neutralizeLogString, parseInputArray, pickGitIdentityConfig, + resolveBaseDir, } from './util'; -const baseDir = path.join(process.cwd(), getInput('cwd') || ''); -const git = simpleGit({baseDir}); +const cwdInput = getInput('cwd') || ''; +const baseDir = resolveBaseDir(cwdInput); +let git!: SimpleGit; const exitErrors: Error[] = []; core.info(`Running in ${baseDir}`); (async () => { + assertWorkingDirectory(baseDir, cwdInput); + git = simpleGit({baseDir}); + await checkInputs(); const dryRun = getInput('dry_run', true); diff --git a/src/util.ts b/src/util.ts index 0bdc6057..dd4e104a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -4,8 +4,34 @@ import * as YAML from 'js-yaml'; import {getOctokit} from '@actions/github'; import {execFileSync} from 'child_process'; import * as fs from 'fs'; +import * as path from 'path'; import {getInput} from './io'; +/** + * Resolves the action working directory from the `cwd` input. + * Absolute paths are kept as-is; relative paths are resolved against `from` + * (default: `process.cwd()`). Empty input is treated as `'.'`. + */ +export function resolveBaseDir( + cwdInput: string, + from: string = process.cwd(), +): string { + return path.resolve(from, cwdInput || '.'); +} + +/** + * Ensures `dir` exists and is a directory before constructing simple-git. + */ +export function assertWorkingDirectory(dir: string, cwdInput: string): void { + if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { + throw new Error( + `The cwd input '${cwdInput || '.'}' resolved to '${dir}', which is not an existing directory. ` + + 'Use a path relative to the runner workspace, or an absolute path that exists ' + + '(e.g. ${{ github.workspace }}/path — note that $GITHUB_WORKSPACE is not expanded in with:).', + ); + } +} + function getOctokitClient() { const token = getInput('github_token'); if (!token) { diff --git a/test/integration/action.test.ts b/test/integration/action.test.ts index 4f9aeb4c..6751ae9c 100644 --- a/test/integration/action.test.ts +++ b/test/integration/action.test.ts @@ -254,4 +254,57 @@ describe('action integration', () => { // Untracked file should still be on disk. expect(fs.existsSync(path.join(f.local, 'skip-me.txt'))).toBe(true); }); + + it('commits when cwd is an absolute path and process.cwd differs', () => { + const f = fixture!; + writeFile(f.local, 'abs-cwd.txt', 'absolute\n'); + const before = gitRevParse(f.local, 'HEAD'); + // Spawn from the fixture parent so process.cwd() !== the git work tree. + const spawnCwd = path.dirname(f.local); + + const result = runAction( + f, + { + message: 'Absolute cwd commit', + cwd: f.local, + push: 'false', + }, + {spawnCwd}, + ); + + expect(result.status).toBe(0); + expect(result.outputs.committed).toBe('true'); + expect(result.stdout).toMatch( + new RegExp(`Running in ${f.local.replace(/\\/g, '\\\\')}`), + ); + const after = gitRevParse(f.local, 'HEAD'); + expect(after).not.toBe(before); + expect(after).toBe(result.outputs.commit_long_sha); + expect(listFilesAtHead(f.local)).toContain('abs-cwd.txt'); + }); + + it('fails clearly when cwd does not exist without dumping the bundle', () => { + const f = fixture!; + const missing = path.join( + path.dirname(f.local), + `missing-cwd-${process.pid}-${Date.now()}`, + ); + + const result = runAction( + f, + { + cwd: missing, + push: 'false', + }, + {spawnCwd: path.dirname(f.local)}, + ); + + expect(result.status).not.toBe(0); + const combined = `${result.stdout}\n${result.stderr}`; + expect(combined).toMatch(/not an existing directory/); + expect(combined).toContain(missing); + // Uncaught throws from the minified bundle dump the whole line of source. + expect(combined).not.toMatch(/function isObject/); + expect(combined.length).toBeLessThan(50_000); + }); }); diff --git a/test/integration/helpers.ts b/test/integration/helpers.ts index 21f81d15..456a1a17 100644 --- a/test/integration/helpers.ts +++ b/test/integration/helpers.ts @@ -182,14 +182,14 @@ export interface ActionInputs { /** * Spawn the shipped action (lib/index.js) with an allowlisted environment. * - * The action resolves the working tree as `path.join(process.cwd(), cwdInput)`. - * On modern Node, `path.join` does not treat an absolute second segment as a - * new root, so we spawn with `process.cwd()` set to the fixture and pass - * `cwd: '.'` rather than an absolute path. + * By default the child process runs with `process.cwd()` = the fixture clone + * and `cwd: '.'`. Pass an absolute `inputs.cwd` with `options.spawnCwd` set to + * another directory to exercise absolute-path resolution. */ export function runAction( fixture: Fixture, inputs: ActionInputs = {}, + options: {spawnCwd?: string} = {}, ): RunActionResult { assertLocalOrigin( git(['remote', 'get-url', 'origin'], fixture.local), @@ -208,8 +208,6 @@ export function runAction( ); fs.writeFileSync(outputFile, ''); - const restInputs = {...inputs}; - delete restInputs.cwd; const merged: Record = { // Mirror action.yml defaults that matter when spawning lib/ directly. cwd: '.', @@ -223,7 +221,7 @@ export function runAction( author_name: 'Integration Tester', author_email: 'integration@example.com', message: 'Integration test commit', - ...restInputs, + ...inputs, }; const env: NodeJS.ProcessEnv = { @@ -247,8 +245,7 @@ export function runAction( } const result = spawnSync(process.execPath, [ACTION_ENTRY], { - // Workspace = fixture clone; action cwd input stays relative ('.'). - cwd: fixture.local, + cwd: options.spawnCwd ?? fixture.local, env, encoding: 'utf8', // Action can take a bit when doing push/tag; keep a generous limit. diff --git a/test/util.test.ts b/test/util.test.ts index 19a61da7..0ebbee2d 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -1,13 +1,73 @@ import { assertNoUnexpectedGitlinks, assertValidBranchName, + assertWorkingDirectory, findUnexpectedGitlinks, matchGitArgs, neutralizeForLog, neutralizeLogString, parseInputArray, pickGitIdentityConfig, + resolveBaseDir, } from '../src/util'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +describe('resolveBaseDir', () => { + const from = path.join(path.sep, 'home', 'runner', 'work', 'repo', 'repo'); + + it('resolves relative paths against from', () => { + expect(resolveBaseDir('./my-checkout', from)).toBe( + path.join(from, 'my-checkout'), + ); + expect(resolveBaseDir('subdir', from)).toBe(path.join(from, 'subdir')); + }); + + it('keeps absolute paths', () => { + const abs = path.join(from, 'my-checkout-path'); + expect(resolveBaseDir(abs, from)).toBe(abs); + expect(resolveBaseDir(abs, path.join(from, 'other'))).toBe(abs); + }); + + it('treats empty and "." as from', () => { + expect(resolveBaseDir('', from)).toBe(from); + expect(resolveBaseDir('.', from)).toBe(from); + }); +}); + +describe('assertWorkingDirectory', () => { + it('accepts an existing directory', () => { + expect(() => + assertWorkingDirectory(os.tmpdir(), os.tmpdir()), + ).not.toThrow(); + }); + + it('rejects a missing path', () => { + const missing = path.join( + os.tmpdir(), + `aac-missing-${process.pid}-${Date.now()}`, + ); + expect(() => assertWorkingDirectory(missing, missing)).toThrow( + /not an existing directory/, + ); + }); + + it('rejects a file path', () => { + const file = path.join( + os.tmpdir(), + `aac-file-${process.pid}-${Date.now()}.txt`, + ); + fs.writeFileSync(file, 'x'); + try { + expect(() => assertWorkingDirectory(file, file)).toThrow( + /not an existing directory/, + ); + } finally { + fs.unlinkSync(file); + } + }); +}); describe('parseInputArray', () => { beforeAll(() => {