diff --git a/README.md b/README.md index f6611479..8485cbe4 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,11 @@ Add a step like this to your workflow: # Default: ignore pathspec_error_handling: ignore - # Arguments for the git pull command. By default, the action does not pull. + # Whether to pull from the remote. Set to true to run git pull with no extra + # args, false (or omit) to skip, or a string for git pull arguments + # (e.g. '--rebase --autostash'). # Default: '' - pull: '--rebase --autostash ...' + pull: true # Whether to push the commit and, if any, its tags to the repo. It can also be used to set the git push arguments (see the paragraph below for more info) # Default: true @@ -153,7 +155,7 @@ By default the action runs the following command: `git push origin ${new_branch One way to use this is if you want to force push to a trusted/static branch name in your repo: set the `push` input to, for example, `origin yourBranch --force`. Do not build that string from untrusted refs such as `github.head_ref`. -If multiple jobs may push to the same branch (for example a matrix), set `push_attempts` to try the push more than once. When `pull` is set, each failed attempt re-runs that pull (e.g. `--rebase --autostash`) before pushing again, so a commit that lost a race can catch up to the remote tip. Without `pull`, retries only re-run push. The default is `1` (no retries). A typical concurrent setup looks like: +If multiple jobs may push to the same branch (for example a matrix), set `push_attempts` to try the push more than once. When `pull` is set (`true` for a default `git pull`, or a string such as `--rebase --autostash`), each failed attempt re-runs that pull before pushing again, so a commit that lost a race can catch up to the remote tip. Without `pull`, retries only re-run push. The default is `1` (no retries). A typical concurrent setup looks like: ```yaml with: diff --git a/action.yml b/action.yml index e2246a51..f4a8a93a 100644 --- a/action.yml +++ b/action.yml @@ -48,7 +48,7 @@ inputs: required: false default: ignore pull: - description: Arguments for the git pull command. By default, the action does not pull. + description: Whether to pull from the remote. true runs git pull with no extra args; false or omit skips pull; any other string is passed as git pull arguments. By default, the action does not pull. required: false push: description: Whether to push the commit and, if any, its tags to the repo. It can also be used to set the git push arguments (more info in the README) diff --git a/lib/index.js b/lib/index.js index 629a0556..4e6ef21b 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 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","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 Fa={committed:"false",commit_long_sha:undefined,commit_sha:undefined,pushed:"false",tagged:"false",tag_pushed:"false"};Object.entries(Fa).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}`);Fa[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 Fa){info(`${e}: ${Fa[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("allow_unsafe_git_protocols",true))warning("allow_unsafe_git_protocols is enabled: transport allowlist and scheme:: remote-helper URL checks are disabled. Only use this with fully trusted git argument inputs.");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 va=io_getInput("cwd")||"";const Ua=resolveBaseDir(va);let Na;function gitChildEnv(e={}){const t={...process.env,...e};if(!io_getInput("allow_unsafe_git_protocols",true)){t.GIT_ALLOW_PROTOCOL="https:http:ssh:file:git";t.GIT_PROTOCOL_FROM_USER="0"}return t}function parseGitArgs(e){return matchGitArgs(e,{allowUnsafeGitProtocols:io_getInput("allow_unsafe_git_protocols",true)})}const Ma=[];info(`Running in ${Ua}`);(async()=>{assertWorkingDirectory(Ua,va);Na=lo({baseDir:Ua});await checkInputs();Na.env(gitChildEnv());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 Na.diffSummary(["--cached"])).files.length;const n=parseGitArgs(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 Na.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 Na.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 Na.fetch(parseGitArgs(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 Na.checkout([a]).then(()=>{log(undefined,`'${a}' branch already existed.`)}).catch(()=>{log(undefined,`Creating '${a}' branch.`);return Na.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 Na.commit(io_getInput("message"),parseGitArgs(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 Na.tag(parseGitArgs(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 Na.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 Na.pushTags("origin",parseGitArgs(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(Ma.length===1)throw Ma[0];else if(Ma.length>1){Ma.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 Na.fetch(undefined,log).pull(undefined,undefined,parseGitArgs(e),log);info("> Checking for conflicts...");const r=await Na.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 Na.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 Na.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 Na.push(undefined,undefined,parseGitArgs(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",...parseGitArgs(r)]:parseGitArgs(r);n.push(await Na.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")Ma.push(s)}else throw t}))}if(t){await assertGitlinksWithTempIndex(s,e)}else{const e=await Na.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 Na.raw(["rev-parse","--git-path","index"])).trim();const n=u.isAbsolute(s)?s:u.join(Ua,s);if(l.existsSync(n)){l.copyFileSync(n,r)}else{const e=lo({baseDir:Ua}).env(gitChildEnv({GIT_INDEX_FILE:r}));const t=await Na.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:Ua}).env(gitChildEnv({GIT_INDEX_FILE:r}));for(const r of e){await o.add(parseGitArgs(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",...parseGitArgs(r)]:parseGitArgs(r);n.push(await Na.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")Ma.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","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 Fa={committed:"false",commit_long_sha:undefined,commit_sha:undefined,pushed:"false",tagged:"false",tag_pushed:"false"};Object.entries(Fa).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}`);Fa[e]=t;setOutput(e,t)}function parseBoolOrGitArgs(e){try{return io_getInput(e,true)}catch{return io_getInput(e)||""}}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 Fa){info(`${e}: ${Fa[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("allow_unsafe_git_protocols",true))warning("allow_unsafe_git_protocols is enabled: transport allowlist and scheme:: remote-helper URL checks are disabled. Only use this with fully trusted git argument inputs.");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.");const o=parseBoolOrGitArgs("pull");if(io_getInput("pull")){core_debug(`Current pull option: '${o}' (parsed as ${typeof o})`)}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 a=parsePushAttempts(io_getInput("push_attempts")||"1");core_debug(`Current push_attempts option: ${a}`);if(a>1&&!o){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 va=io_getInput("cwd")||"";const Ua=resolveBaseDir(va);let Na;function gitChildEnv(e={}){const t={...process.env,...e};if(!io_getInput("allow_unsafe_git_protocols",true)){t.GIT_ALLOW_PROTOCOL="https:http:ssh:file:git";t.GIT_PROTOCOL_FROM_USER="0"}return t}function parseGitArgs(e){return matchGitArgs(e,{allowUnsafeGitProtocols:io_getInput("allow_unsafe_git_protocols",true)})}const Ma=[];info(`Running in ${Ua}`);(async()=>{assertWorkingDirectory(Ua,va);Na=lo({baseDir:Ua});await checkInputs();Na.env(gitChildEnv());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 Na.diffSummary(["--cached"])).files.length;const n=parseGitArgs(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 Na.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 Na.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 Na.fetch(parseGitArgs(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 Na.checkout([a]).then(()=>{log(undefined,`'${a}' branch already existed.`)}).catch(()=>{log(undefined,`Creating '${a}' branch.`);return Na.checkout(["-b",a],log)})}const l=parseBoolOrGitArgs("pull");if(l){await pullFromRemote(l,{restage:true,ignoreErrors:t})}else info("> Not pulling from repo.");info("> Creating commit...");const u=await Na.commit(io_getInput("message"),parseGitArgs(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 Na.tag(parseGitArgs(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 Na.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 Na.pushTags("origin",parseGitArgs(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(Ma.length===1)throw Ma[0];else if(Ma.length>1){Ma.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=parseBoolOrGitArgs("pull");if(r){info(`> Would pull from remote${r===true?"":` 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...");const r=e===true?"":e;core_debug(`Current git pull arguments: ${r}`);await Na.fetch(undefined,log).pull(undefined,undefined,parseGitArgs(r),log);info("> Checking for conflicts...");const s=await Na.status(undefined,log);if(s.conflicted.length){throw new Error(`There are ${s.conflicted.length} conflicting files: ${s.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 Na.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 Na.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 Na.push(undefined,undefined,parseGitArgs(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",...parseGitArgs(r)]:parseGitArgs(r);n.push(await Na.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")Ma.push(s)}else throw t}))}if(t){await assertGitlinksWithTempIndex(s,e)}else{const e=await Na.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 Na.raw(["rev-parse","--git-path","index"])).trim();const n=u.isAbsolute(s)?s:u.join(Ua,s);if(l.existsSync(n)){l.copyFileSync(n,r)}else{const e=lo({baseDir:Ua}).env(gitChildEnv({GIT_INDEX_FILE:r}));const t=await Na.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:Ua}).env(gitChildEnv({GIT_INDEX_FILE:r}));for(const r of e){await o.add(parseGitArgs(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",...parseGitArgs(r)]:parseGitArgs(r);n.push(await Na.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")Ma.push(s)}else throw t}))}return n} \ No newline at end of file diff --git a/src/io.ts b/src/io.ts index 50ca9926..01b7d336 100644 --- a/src/io.ts +++ b/src/io.ts @@ -67,6 +67,20 @@ export function setOutput(name: T, value: OutputTypes[T]) { core.setOutput(name, value); } +/** + * Parses an input that can be a boolean (`true`/`false`) or a git-args string. + * Empty / unset values are returned as an empty string (falsy). + */ +export function parseBoolOrGitArgs( + name: 'fetch' | 'push' | 'pull', +): string | boolean { + try { + return getInput(name, true); + } catch { + return getInput(name) || ''; + } +} + /** * Parses `push_attempts` as a positive integer (≥ 1). * Accepts only base-10 integer strings (optional leading `+`). @@ -279,6 +293,13 @@ export async function checkInputs() { core.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.", ); + + const pullOption = parseBoolOrGitArgs('pull'); + if (getInput('pull')) { + core.debug( + `Current pull option: '${pullOption}' (parsed as ${typeof pullOption})`, + ); + } // #endregion // #region push @@ -299,7 +320,7 @@ export async function checkInputs() { // #region push_attempts const pushAttempts = parsePushAttempts(getInput('push_attempts') || '1'); core.debug(`Current push_attempts option: ${pushAttempts}`); - if (pushAttempts > 1 && !getInput('pull')) { + if (pushAttempts > 1 && !pullOption) { core.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.', ); diff --git a/src/main.ts b/src/main.ts index fb6864b3..638ab2f3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import { checkInputs, getInput, logOutputs, + parseBoolOrGitArgs, parsePushAttempts, setOutput, } from './io'; @@ -159,7 +160,7 @@ core.info(`Running in ${baseDir}`); }); } - const pullOption = getInput('pull'); + const pullOption = parseBoolOrGitArgs('pull'); if (pullOption) { await pullFromRemote(pullOption, {restage: true, ignoreErrors}); } else core.info('> Not pulling from repo.'); @@ -311,9 +312,14 @@ async function logDryRunRemainingSteps() { ); } - const pullOption = getInput('pull'); - if (pullOption) core.info(`> Would pull from remote with: ${pullOption}.`); - else core.info('> Would not pull from repo.'); + const pullOption = parseBoolOrGitArgs('pull'); + if (pullOption) { + core.info( + `> Would pull from remote${ + pullOption === true ? '' : ` with: ${pullOption}` + }.`, + ); + } else core.info('> Would not pull from repo.'); core.info( `> Would create commit with message: "${getInput('message')}"${ @@ -366,17 +372,18 @@ async function logDryRunRemainingSteps() { } async function pullFromRemote( - pullOption: string, + pullOption: true | string, options: { restage: boolean; ignoreErrors: 'all' | 'pathspec' | 'none'; }, ) { core.info('> Pulling from remote...'); - core.debug(`Current git pull arguments: ${pullOption}`); + const args = pullOption === true ? '' : pullOption; + core.debug(`Current git pull arguments: ${args}`); await git .fetch(undefined, log) - .pull(undefined, undefined, parseGitArgs(pullOption), log); + .pull(undefined, undefined, parseGitArgs(args), log); core.info('> Checking for conflicts...'); const status = await git.status(undefined, log); diff --git a/test/integration/action.test.ts b/test/integration/action.test.ts index 810a2ad0..42145f44 100644 --- a/test/integration/action.test.ts +++ b/test/integration/action.test.ts @@ -1,6 +1,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import { + commitAndPushToRemote, createFixture, type Fixture, gitLog, @@ -272,6 +273,90 @@ describe('action integration', () => { expect(fs.existsSync(path.join(f.local, 'skip-me.txt'))).toBe(true); }); + it('pull: true incorporates remote commits before committing', () => { + const f = fixture!; + commitAndPushToRemote(f, 'from-remote.txt', 'remote\n', 'Remote change'); + writeFile(f.local, 'from-local.txt', 'local\n'); + + const result = runAction(f, { + message: 'Local change', + pull: 'true', + push: 'false', + }); + + expect(result.status).toBe(0); + expect(result.outputs.committed).toBe('true'); + expect(result.stdout).toMatch(/> Pulling from remote/); + expect(result.stdout).not.toMatch(/Not pulling from repo/); + + const files = listFilesAtHead(f.local); + expect(files).toContain('from-remote.txt'); + expect(files).toContain('from-local.txt'); + }); + + it.each([ + {pull: 'false', label: 'false'}, + {pull: undefined, label: 'omitted'}, + ])('skips pull when pull is $label', ({pull}) => { + const f = fixture!; + commitAndPushToRemote(f, 'from-remote.txt', 'remote\n', 'Remote change'); + writeFile(f.local, 'from-local.txt', 'local\n'); + + const result = runAction(f, { + message: 'Local change only', + ...(pull !== undefined ? {pull} : {}), + push: 'false', + }); + + expect(result.status).toBe(0); + expect(result.outputs.committed).toBe('true'); + expect(result.stdout).toMatch(/Not pulling from repo/); + + const files = listFilesAtHead(f.local); + expect(files).toContain('from-local.txt'); + expect(files).not.toContain('from-remote.txt'); + }); + + it('pull with custom git args still pulls', () => { + const f = fixture!; + commitAndPushToRemote(f, 'from-remote.txt', 'remote\n', 'Remote change'); + writeFile(f.local, 'from-local.txt', 'local\n'); + + const result = runAction(f, { + message: 'Local change', + pull: '--rebase --autostash', + push: 'false', + }); + + expect(result.status).toBe(0); + expect(result.outputs.committed).toBe('true'); + expect(result.stdout).toMatch(/> Pulling from remote/); + + const files = listFilesAtHead(f.local); + expect(files).toContain('from-remote.txt'); + expect(files).toContain('from-local.txt'); + }); + + it('dry_run with pull: true reports a default pull without mutating', () => { + const f = fixture!; + writeFile(f.local, 'dry-pull.txt', 'preview\n'); + const before = gitRevParse(f.local, 'HEAD'); + + const result = runAction(f, { + message: 'Would commit', + dry_run: 'true', + pull: 'true', + push: 'false', + }); + + expect(result.status).toBe(0); + expect(result.outputs.committed).toBe('false'); + expect(gitRevParse(f.local, 'HEAD')).toBe(before); + expect(listFilesAtHead(f.local)).not.toContain('dry-pull.txt'); + expect(result.stdout).toMatch(/> Would pull from remote\./); + expect(result.stdout).not.toMatch(/with: true/); + }); + it('commits when cwd is an absolute path and process.cwd differs', () => { const f = fixture!; writeFile(f.local, 'abs-cwd.txt', 'absolute\n'); diff --git a/test/integration/helpers.ts b/test/integration/helpers.ts index d7529ceb..5427bf17 100644 --- a/test/integration/helpers.ts +++ b/test/integration/helpers.ts @@ -58,6 +58,10 @@ function configureFixtureRepo(repo: string, name: string, email: string) { git(['config', 'user.email', email], repo); git(['config', 'commit.gpgsign', 'false'], repo); git(['config', 'tag.gpgsign', 'false'], repo); + // Host pull.* config must not leak into fixtures (rebase without --autostash + // would fail once the action has staged local changes). + git(['config', 'pull.rebase', 'false'], repo); + git(['config', 'pull.ff', 'true'], repo); } /** @@ -297,6 +301,31 @@ export function writeFile(repo: string, relativePath: string, content: string) { fs.writeFileSync(full, content); } +/** + * Clone the bare remote into a sibling worktree, commit a file, and push. + * Returns the new remote HEAD SHA. Does not touch `fixture.local`. + */ +export function commitAndPushToRemote( + fixture: Fixture, + relativePath: string, + content: string, + message: string, +): string { + const parent = path.dirname(fixture.local); + const work = fs.mkdtempSync(path.join(parent, 'remote-work-')); + try { + git(['clone', '-q', fixture.remote, '.'], work); + configureFixtureRepo(work, 'Remote Writer', 'remote@example.com'); + writeFile(work, relativePath, content); + git(['add', '--', relativePath], work); + git(['commit', '-q', '-m', message], work); + git(['push', '-q', 'origin', 'HEAD'], work); + return git(['rev-parse', 'HEAD'], work); + } finally { + fs.rmSync(work, {recursive: true, force: true}); + } +} + export function removeFile(repo: string, relativePath: string) { fs.unlinkSync(path.join(repo, relativePath)); } diff --git a/test/io.test.ts b/test/io.test.ts index f28df34d..b39ef6f4 100644 --- a/test/io.test.ts +++ b/test/io.test.ts @@ -1,4 +1,31 @@ -import {parsePushAttempts} from '../src/io'; +import {parseBoolOrGitArgs, parsePushAttempts} from '../src/io'; + +describe('parseBoolOrGitArgs', () => { + const original = process.env.INPUT_PULL; + + afterEach(() => { + if (original === undefined) delete process.env.INPUT_PULL; + else process.env.INPUT_PULL = original; + }); + + it('parses true/false as booleans', () => { + process.env.INPUT_PULL = 'true'; + expect(parseBoolOrGitArgs('pull')).toBe(true); + + process.env.INPUT_PULL = 'false'; + expect(parseBoolOrGitArgs('pull')).toBe(false); + }); + + it('returns git-args strings unchanged', () => { + process.env.INPUT_PULL = '--rebase --autostash'; + expect(parseBoolOrGitArgs('pull')).toBe('--rebase --autostash'); + }); + + it('returns an empty string when unset', () => { + delete process.env.INPUT_PULL; + expect(parseBoolOrGitArgs('pull')).toBe(''); + }); +}); describe('parsePushAttempts', () => { it('accepts positive integers', () => {