fix!: change behavior related to branches and pulling
I would have opened a pull request, but for some reason GitHub was preventing me to do so... Anyway, here's the description: This PR makes the action run on whatever has been checked out by previous steps. This is better because it makes the action faster and solves some issues that are caused by it pulling from the wrong ref (especially in PRs that involve a fork). The previous branch-related inputs have been removed, in favor of a new input called `new-branch`: this will allow you to create a new branch from the starting ref. If the branch already exists the action will try to push anyway, but that can result in the remote rejecting the push because it's not straightforward. For info on how to handle this situation, please check out the README. In conclusion, this PR makes the user responsible for handling branches, while still keeping an easy-to-use option to create new branches for those who need it: just make sure that you also consider when the branch already exists. Fixes #327
This commit is contained in:
28
README.md
28
README.md
@@ -27,14 +27,6 @@ Add a step like this to your workflow:
|
||||
# Default: depends on the default_author input
|
||||
author_email: mail@example.com
|
||||
|
||||
# The name of the branch to use, if different from the one that triggered the workflow.
|
||||
# Default: the branch that triggered the run
|
||||
branch: some-branch
|
||||
|
||||
# How the action should behave when the targeted branch is missing: "create" will create a new one on the remote, "throw" will exit
|
||||
# Default: throw
|
||||
branch_mode: create
|
||||
|
||||
# The name of the custom committer you want to use, if different from the author of the commit.
|
||||
# Default: the name of the author (set with either author_name or default_author)
|
||||
committer_name: Committer Name
|
||||
@@ -58,6 +50,10 @@ Add a step like this to your workflow:
|
||||
# Default: 'Commit from GitHub Actions (name of the workflow)'
|
||||
message: 'Your commit message'
|
||||
|
||||
# If this input is set, the action will push the commit to a new branch with this name.
|
||||
# Default: ''
|
||||
new_branch: custom-new-branch
|
||||
|
||||
# The way the action should handle pathspec errors from the add and remove commands. Three options are available:
|
||||
# - ignore -> errors will be logged but the step won't fail
|
||||
# - exitImmediately -> the action will stop right away, and the step will fail
|
||||
@@ -101,7 +97,7 @@ You can also use JSON or YAML arrays (e.g. `'["first", "second"]'`, `"['first',
|
||||
|
||||
### Pushing
|
||||
|
||||
By default the action runs the following command: `git push origin ${branch input} --set-upstream`. You can use the `push` input to modify this behavior, here's what you can set it to:
|
||||
By default the action runs the following command: `git push origin ${new_branch input} --set-upstream`. You can use the `push` input to modify this behavior, here's what you can set it to:
|
||||
|
||||
- `true`: this is the default value, it will behave as usual.
|
||||
- `false`: this prevents the action from pushing at all, no `git push` command is run.
|
||||
@@ -110,6 +106,20 @@ By default the action runs the following command: `git push origin ${branch inpu
|
||||
|
||||
One way to use this is if you want to force push to a branch of your repo: you'll need to set the `push` input to, for example, `origin yourBranch --force`.
|
||||
|
||||
### Creating a new branch
|
||||
|
||||
If you want the action to commit in a new branch, you can use the `new_branch` input.
|
||||
|
||||
Please note that if the branch exists, the action will still try push to it, but it's possible that the push will be rejected by the remote as non-straightforward.
|
||||
|
||||
If that's the case, you need to make sure that the branch you want to commit to is already checked out before you run the action.
|
||||
If you're **really** sure that you want to commit to that branch, you can also force-push by setting the `push` input to something like `origin yourBranchName --set-upstream --force`.
|
||||
|
||||
If you want to commit files "across different branches", here are two ways to do it:
|
||||
|
||||
1. You can check them out in two different directories, generate your files, move them to your destination and then run `add-and-commit` in the destination directory using the `cwd` input.
|
||||
2. You can manually commit those files with `git` commands as you would on your machine. There are several ways to do this depending on the scenario. One of them if to stash your changes, checkout the destination branch, and popping the stash. You can then use the `add-and-commit` action as usual. Please note that this is just an example and may not work for you, since your use case may be different.
|
||||
|
||||
### Tagging
|
||||
|
||||
You can use the `tag` option to enter the arguments for a `git add` command. In order for the action to isolate the tag name from the rest of the arguments, it should be the first word not preceded by an hyphen (e.g. `-a tag-name -m "some other stuff"` is ok).
|
||||
|
||||
12
action.yml
12
action.yml
@@ -12,13 +12,6 @@ inputs:
|
||||
author_email:
|
||||
description: The email of the user that will be displayed as the author of the commit
|
||||
required: false
|
||||
branch:
|
||||
description: Name of the branch to use, if different from the one that triggered the workflow
|
||||
required: false
|
||||
branch_mode:
|
||||
description: How the action should behave when the targeted branch is missing
|
||||
required: false
|
||||
default: throw
|
||||
commit:
|
||||
description: Additional arguments for the git commit command
|
||||
required: false
|
||||
@@ -39,12 +32,15 @@ inputs:
|
||||
message:
|
||||
description: The message for the commit
|
||||
required: false
|
||||
new_branch:
|
||||
description: The name of the branch to create.
|
||||
required: false
|
||||
pathspec_error_handling:
|
||||
description: The way the action should handle pathspec errors from the add and remove commands.
|
||||
required: false
|
||||
default: ignore
|
||||
pull:
|
||||
description: Arguments for the git pull command. Use NO-PULL to avoid the action pulling at all.
|
||||
description: Arguments for the git pull command. 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)
|
||||
|
||||
4
lib/index.js
generated
4
lib/index.js
generated
File diff suppressed because one or more lines are too long
232
src/io.ts
Normal file
232
src/io.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import * as core from '@actions/core'
|
||||
import { getUserInfo, parseInputArray } from './util'
|
||||
|
||||
interface InputTypes {
|
||||
add: string
|
||||
author_name: string
|
||||
author_email: string
|
||||
commit: string | undefined
|
||||
committer_name: string
|
||||
committer_email: string
|
||||
cwd: string
|
||||
default_author: 'github_actor' | 'user_info' | 'github_actions'
|
||||
message: string
|
||||
new_branch: string | undefined
|
||||
pathspec_error_handling: 'ignore' | 'exitImmediately' | 'exitAtEnd'
|
||||
pull: string | undefined
|
||||
push: string
|
||||
remove: string | undefined
|
||||
tag: string | undefined
|
||||
|
||||
github_token: string | undefined
|
||||
}
|
||||
export type input = keyof InputTypes
|
||||
|
||||
interface OutputTypes {
|
||||
committed: 'true' | 'false'
|
||||
commit_sha: string | undefined
|
||||
pushed: 'true' | 'false'
|
||||
tagged: 'true' | 'false'
|
||||
}
|
||||
export type output = keyof OutputTypes
|
||||
|
||||
export const outputs: OutputTypes = {
|
||||
committed: 'false',
|
||||
commit_sha: undefined,
|
||||
pushed: 'false',
|
||||
tagged: 'false'
|
||||
}
|
||||
// Setup default output values
|
||||
Object.entries(outputs).forEach(([name, value]) => core.setOutput(name, value))
|
||||
|
||||
export function getInput<T extends input>(name: T, parseAsBool: true): boolean
|
||||
export function getInput<T extends input>(
|
||||
name: T,
|
||||
parseAsBool?: false
|
||||
): InputTypes[T]
|
||||
export function getInput<T extends input>(
|
||||
name: T,
|
||||
parseAsBool = false
|
||||
): InputTypes[T] | boolean {
|
||||
if (parseAsBool) return core.getBooleanInput(name)
|
||||
// @ts-expect-error
|
||||
return core.getInput(name)
|
||||
}
|
||||
|
||||
export function setOutput<T extends output>(name: T, value: OutputTypes[T]) {
|
||||
core.debug(`Setting output: ${name}=${value}`)
|
||||
outputs[name] = value
|
||||
core.setOutput(name, value)
|
||||
}
|
||||
|
||||
export function logOutputs() {
|
||||
core.startGroup('Outputs')
|
||||
for (const key in outputs) {
|
||||
core.info(`${key}: ${outputs[key]}`)
|
||||
}
|
||||
core.endGroup()
|
||||
}
|
||||
|
||||
export async function checkInputs() {
|
||||
function setInput(input: input, value: string | undefined) {
|
||||
if (value) return (process.env[`INPUT_${input.toUpperCase()}`] = value)
|
||||
else return delete process.env[`INPUT_${input.toUpperCase()}`]
|
||||
}
|
||||
function setDefault(input: input, value: string) {
|
||||
if (!getInput(input)) setInput(input, value)
|
||||
return getInput(input)
|
||||
}
|
||||
|
||||
// #region add, remove
|
||||
if (!getInput('add') && !getInput('remove'))
|
||||
throw new Error(
|
||||
"Both 'add' and 'remove' are empty, the action has nothing to do."
|
||||
)
|
||||
|
||||
if (getInput('add')) {
|
||||
const parsed = parseInputArray(getInput('add'))
|
||||
if (parsed.length == 1)
|
||||
core.info('Add input parsed as single string, running 1 git add command.')
|
||||
else if (parsed.length > 1)
|
||||
core.info(
|
||||
`Add input parsed as string array, running ${parsed.length} git add commands.`
|
||||
)
|
||||
else core.setFailed('Add input: array length < 1')
|
||||
}
|
||||
if (getInput('remove')) {
|
||||
const parsed = parseInputArray(getInput('remove') || '')
|
||||
if (parsed.length == 1)
|
||||
core.info(
|
||||
'Remove input parsed as single string, running 1 git rm command.'
|
||||
)
|
||||
else if (parsed.length > 1)
|
||||
core.info(
|
||||
`Remove input parsed as string array, running ${parsed.length} git rm commands.`
|
||||
)
|
||||
else core.setFailed('Remove input: array length < 1')
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region default_author
|
||||
const default_author_valid = ['github_actor', 'user_info', 'github_actions']
|
||||
if (!default_author_valid.includes(getInput('default_author')))
|
||||
throw new Error(
|
||||
`'${getInput(
|
||||
'default_author'
|
||||
)}' is not a valid value for default_author. Valid values: ${default_author_valid.join(
|
||||
', '
|
||||
)}`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region author_name, author_email
|
||||
let name, email
|
||||
switch (getInput('default_author')) {
|
||||
case 'github_actor': {
|
||||
name = process.env.GITHUB_ACTOR
|
||||
email = `${process.env.GITHUB_ACTOR}@users.noreply.github.com`
|
||||
break
|
||||
}
|
||||
|
||||
case 'user_info': {
|
||||
if (!getInput('author_name') || !getInput('author_email')) {
|
||||
const res = await getUserInfo(process.env.GITHUB_ACTOR)
|
||||
if (!res?.name)
|
||||
core.warning("Couldn't fetch author name, filling with github_actor.")
|
||||
if (!res?.email)
|
||||
core.warning(
|
||||
"Couldn't fetch author email, filling with github_actor."
|
||||
)
|
||||
|
||||
res?.name && (name = res?.name)
|
||||
res?.email && (email = res.email)
|
||||
if (name && email) break
|
||||
}
|
||||
|
||||
!name && (name = process.env.GITHUB_ACTOR)
|
||||
!email && (email = `${process.env.GITHUB_ACTOR}@users.noreply.github.com`)
|
||||
break
|
||||
}
|
||||
|
||||
case 'github_actions': {
|
||||
name = 'github-actions'
|
||||
email = '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', name)
|
||||
setDefault('author_email', email)
|
||||
core.info(
|
||||
`> Using '${getInput('author_name')} <${getInput(
|
||||
'author_email'
|
||||
)}>' as author.`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region committer_name, committer_email
|
||||
if (getInput('committer_name') || getInput('committer_email'))
|
||||
core.info(
|
||||
`> Using custom committer info: ${
|
||||
getInput('committer_name') ||
|
||||
getInput('author_name') + ' [from author info]'
|
||||
} <${
|
||||
getInput('committer_email') ||
|
||||
getInput('author_email') + ' [from author info]'
|
||||
}>`
|
||||
)
|
||||
|
||||
setDefault('committer_name', getInput('author_name'))
|
||||
setDefault('committer_email', getInput('author_email'))
|
||||
core.debug(
|
||||
`Committer: ${getInput('committer_name')} <${getInput('committer_email')}>`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region message
|
||||
setDefault(
|
||||
'message',
|
||||
`Commit from GitHub Actions (${process.env.GITHUB_WORKFLOW})`
|
||||
)
|
||||
core.info(`> Using "${getInput('message')}" as commit message.`)
|
||||
// #endregion
|
||||
|
||||
// #region pathspec_error_handling
|
||||
const peh_valid = ['ignore', 'exitImmediately', 'exitAtEnd']
|
||||
if (!peh_valid.includes(getInput('pathspec_error_handling')))
|
||||
throw new Error(
|
||||
`"${getInput(
|
||||
'pathspec_error_handling'
|
||||
)}" is not a valid value for the 'pathspec_error_handling' input. Valid values are: ${peh_valid.join(
|
||||
', '
|
||||
)}`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region push
|
||||
if (getInput('push')) {
|
||||
// It has to be either 'true', 'false', or any other string (use as arguments)
|
||||
let value: string | boolean
|
||||
|
||||
try {
|
||||
value = getInput('push', true)
|
||||
} catch {
|
||||
value = getInput('push')
|
||||
}
|
||||
|
||||
core.debug(`Current push option: '${value}' (parsed as ${typeof value})`)
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region github_token
|
||||
if (!getInput('github_token'))
|
||||
core.warning(
|
||||
'No github_token has been detected, the action may fail if it needs to use the API'
|
||||
)
|
||||
// #endregion
|
||||
}
|
||||
305
src/main.ts
305
src/main.ts
@@ -1,17 +1,8 @@
|
||||
import * as core from '@actions/core'
|
||||
import path from 'path'
|
||||
import simpleGit, { CommitSummary, Response } from 'simple-git'
|
||||
import YAML from 'js-yaml'
|
||||
import {
|
||||
getInput,
|
||||
getUserInfo,
|
||||
input,
|
||||
log,
|
||||
matchGitArgs,
|
||||
outputs,
|
||||
readJSON,
|
||||
setOutput
|
||||
} from './util'
|
||||
import { checkInputs, getInput, logOutputs, setOutput } from './io'
|
||||
import { log, matchGitArgs, parseInputArray } from './util'
|
||||
|
||||
const baseDir = path.join(process.cwd(), getInput('cwd') || '')
|
||||
const git = simpleGit({ baseDir })
|
||||
@@ -56,41 +47,27 @@ core.info(`Running in ${baseDir}`)
|
||||
|
||||
await git.fetch(['--tags', '--force'], log)
|
||||
|
||||
core.info('> Switching/creating branch...')
|
||||
/** This should store whether the branch already existed, of if a new one was created */
|
||||
let branchType!: 'existing' | 'new'
|
||||
await git
|
||||
.checkout(getInput('branch'))
|
||||
.then(() => (branchType = 'existing'))
|
||||
.catch(() => {
|
||||
if (getInput('branch_mode') == 'create') {
|
||||
log(
|
||||
undefined,
|
||||
`'${getInput('branch')}' branch not found, trying to create one.`
|
||||
)
|
||||
branchType = 'new'
|
||||
return git.checkoutLocalBranch(getInput('branch'), log)
|
||||
} else throw `'${getInput('branch')}' branch not found.`
|
||||
})
|
||||
|
||||
/*
|
||||
The current default value is set here: it will not pull when it has
|
||||
created a new branch, it will use --rebase when the branch already existed
|
||||
*/
|
||||
const pull =
|
||||
getInput('pull') || (branchType == 'new' ? 'NO-PULL' : '--no-rebase')
|
||||
if (pull == 'NO-PULL') core.info('> Not pulling from repo.')
|
||||
else {
|
||||
core.info('> Pulling from remote...')
|
||||
core.debug(`Current git pull arguments: ${pull}`)
|
||||
const targetBranch = getInput('new_branch')
|
||||
if (targetBranch) {
|
||||
await git
|
||||
.fetch(undefined, log)
|
||||
.pull(undefined, undefined, matchGitArgs(pull), log)
|
||||
.checkout(targetBranch)
|
||||
.then(() => {
|
||||
log(undefined, `'${targetBranch}' branch already existed.`)
|
||||
})
|
||||
.catch(() => {
|
||||
log(undefined, `Creating '${targetBranch}' branch.`)
|
||||
return git.checkoutLocalBranch(targetBranch, log)
|
||||
})
|
||||
}
|
||||
|
||||
core.info('> Re-staging files...')
|
||||
if (getInput('add')) await add('all')
|
||||
if (getInput('remove')) await remove('all')
|
||||
const pullOption = getInput('pull')
|
||||
if (pullOption) {
|
||||
core.info('> Pulling from remote...')
|
||||
core.debug(`Current git pull arguments: ${pullOption}`)
|
||||
await git
|
||||
.fetch(undefined, log)
|
||||
.pull(undefined, undefined, matchGitArgs(pullOption), log)
|
||||
} else core.info('> Not pulling from repo.')
|
||||
|
||||
core.info('> Creating commit...')
|
||||
await git.commit(
|
||||
@@ -131,11 +108,13 @@ core.info(`Running in ${baseDir}`)
|
||||
|
||||
if (pushOption === true) {
|
||||
core.debug(
|
||||
`Running: git push origin ${getInput('branch')} --set-upstream`
|
||||
`Running: git push origin ${
|
||||
getInput('new_branch') || ''
|
||||
} --set-upstream`
|
||||
)
|
||||
await git.push(
|
||||
'origin',
|
||||
getInput('branch'),
|
||||
getInput('new_branch'),
|
||||
{ '--set-upstream': null },
|
||||
(err, data?) => {
|
||||
if (data) setOutput('pushed', 'true')
|
||||
@@ -203,201 +182,6 @@ core.info(`Running in ${baseDir}`)
|
||||
core.setFailed(e)
|
||||
})
|
||||
|
||||
async function checkInputs() {
|
||||
function setInput(input: input, value: string | undefined) {
|
||||
if (value) return (process.env[`INPUT_${input.toUpperCase()}`] = value)
|
||||
else return delete process.env[`INPUT_${input.toUpperCase()}`]
|
||||
}
|
||||
function setDefault(input: input, value: string) {
|
||||
if (!getInput(input)) setInput(input, value)
|
||||
return getInput(input)
|
||||
}
|
||||
|
||||
const eventPath = process.env.GITHUB_EVENT_PATH,
|
||||
event = eventPath && readJSON(eventPath)
|
||||
|
||||
const isPR = process.env.GITHUB_EVENT_NAME?.includes('pull_request'),
|
||||
defaultBranch = isPR
|
||||
? (event?.pull_request?.head?.ref as string)
|
||||
: process.env.GITHUB_REF?.substring(11)
|
||||
|
||||
// #region add, remove
|
||||
if (!getInput('add') && !getInput('remove'))
|
||||
throw new Error(
|
||||
"Both 'add' and 'remove' are empty, the action has nothing to do."
|
||||
)
|
||||
|
||||
if (getInput('add')) {
|
||||
const parsed = parseInputArray(getInput('add'))
|
||||
if (parsed.length == 1)
|
||||
core.info('Add input parsed as single string, running 1 git add command.')
|
||||
else if (parsed.length > 1)
|
||||
core.info(
|
||||
`Add input parsed as string array, running ${parsed.length} git add commands.`
|
||||
)
|
||||
else core.setFailed('Add input: array length < 1')
|
||||
}
|
||||
if (getInput('remove')) {
|
||||
const parsed = parseInputArray(getInput('remove') || '')
|
||||
if (parsed.length == 1)
|
||||
core.info(
|
||||
'Remove input parsed as single string, running 1 git rm command.'
|
||||
)
|
||||
else if (parsed.length > 1)
|
||||
core.info(
|
||||
`Remove input parsed as string array, running ${parsed.length} git rm commands.`
|
||||
)
|
||||
else core.setFailed('Remove input: array length < 1')
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region default_author
|
||||
const default_author_valid = ['github_actor', 'user_info', 'github_actions']
|
||||
if (!default_author_valid.includes(getInput('default_author')))
|
||||
throw new Error(
|
||||
`'${getInput(
|
||||
'default_author'
|
||||
)}' is not a valid value for default_author. Valid values: ${default_author_valid.join(
|
||||
', '
|
||||
)}`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region author_name, author_email
|
||||
let name, email
|
||||
switch (getInput('default_author')) {
|
||||
case 'github_actor': {
|
||||
name = process.env.GITHUB_ACTOR
|
||||
email = `${process.env.GITHUB_ACTOR}@users.noreply.github.com`
|
||||
break
|
||||
}
|
||||
|
||||
case 'user_info': {
|
||||
if (!getInput('author_name') || !getInput('author_email')) {
|
||||
const res = await getUserInfo(process.env.GITHUB_ACTOR)
|
||||
if (!res?.name)
|
||||
core.warning("Couldn't fetch author name, filling with github_actor.")
|
||||
if (!res?.email)
|
||||
core.warning(
|
||||
"Couldn't fetch author email, filling with github_actor."
|
||||
)
|
||||
|
||||
res?.name && (name = res?.name)
|
||||
res?.email && (email = res.email)
|
||||
if (name && email) break
|
||||
}
|
||||
|
||||
!name && (name = process.env.GITHUB_ACTOR)
|
||||
!email && (email = `${process.env.GITHUB_ACTOR}@users.noreply.github.com`)
|
||||
break
|
||||
}
|
||||
|
||||
case 'github_actions': {
|
||||
name = 'github-actions'
|
||||
email = '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', name)
|
||||
setDefault('author_email', email)
|
||||
core.info(
|
||||
`> Using '${getInput('author_name')} <${getInput(
|
||||
'author_email'
|
||||
)}>' as author.`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region committer_name, committer_email
|
||||
if (getInput('committer_name') || getInput('committer_email'))
|
||||
core.info(
|
||||
`> Using custom committer info: ${
|
||||
getInput('committer_name') ||
|
||||
getInput('author_name') + ' [from author info]'
|
||||
} <${
|
||||
getInput('committer_email') ||
|
||||
getInput('author_email') + ' [from author info]'
|
||||
}>`
|
||||
)
|
||||
|
||||
setDefault('committer_name', getInput('author_name'))
|
||||
setDefault('committer_email', getInput('author_email'))
|
||||
core.debug(
|
||||
`Committer: ${getInput('committer_name')} <${getInput('committer_email')}>`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region message
|
||||
setDefault(
|
||||
'message',
|
||||
`Commit from GitHub Actions (${process.env.GITHUB_WORKFLOW})`
|
||||
)
|
||||
core.info(`> Using "${getInput('message')}" as commit message.`)
|
||||
// #endregion
|
||||
|
||||
// #region branch
|
||||
const branch = setDefault('branch', defaultBranch || '')
|
||||
if (isPR)
|
||||
core.info(`> Running for a PR, the action will use '${branch}' as ref.`)
|
||||
// #endregion
|
||||
|
||||
// #region branch_mode
|
||||
const branch_mode_valid = ['throw', 'create']
|
||||
if (!branch_mode_valid.includes(getInput('branch_mode')))
|
||||
throw new Error(
|
||||
`"${getInput(
|
||||
'branch_mode'
|
||||
)}" is not a valid value for the 'branch_mode' input. Valid values are: ${branch_mode_valid.join(
|
||||
', '
|
||||
)}`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region pathspec_error_handling
|
||||
const peh_valid = ['ignore', 'exitImmediately', 'exitAtEnd']
|
||||
if (!peh_valid.includes(getInput('pathspec_error_handling')))
|
||||
throw new Error(
|
||||
`"${getInput(
|
||||
'pathspec_error_handling'
|
||||
)}" is not a valid value for the 'pathspec_error_handling' input. Valid values are: ${peh_valid.join(
|
||||
', '
|
||||
)}`
|
||||
)
|
||||
// #endregion
|
||||
|
||||
// #region pull
|
||||
if (getInput('pull') == 'NO-PULL')
|
||||
core.debug("NO-PULL found: won't pull from remote.")
|
||||
// #endregion
|
||||
|
||||
// #region push
|
||||
if (getInput('push')) {
|
||||
// It has to be either 'true', 'false', or any other string (use as arguments)
|
||||
let value: string | boolean
|
||||
|
||||
try {
|
||||
value = getInput('push', true)
|
||||
} catch {
|
||||
value = getInput('push')
|
||||
}
|
||||
|
||||
core.debug(`Current push option: '${value}' (parsed as ${typeof value})`)
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region github_token
|
||||
if (!getInput('github_token'))
|
||||
core.warning(
|
||||
'No github_token has been detected, the action may fail if it needs to use the API'
|
||||
)
|
||||
// #endregion
|
||||
}
|
||||
|
||||
async function add(
|
||||
ignoreErrors: 'all' | 'pathspec' | 'none' = 'none'
|
||||
): Promise<(void | Response<void>)[]> {
|
||||
@@ -481,44 +265,3 @@ async function remove(
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse a JSON array, then a YAML array.
|
||||
* If both fail, it returns an array containing the input value as its only element
|
||||
*/
|
||||
function parseInputArray(input: string): string[] {
|
||||
try {
|
||||
const json = JSON.parse(input)
|
||||
if (
|
||||
json &&
|
||||
Array.isArray(json) &&
|
||||
json.every((e) => typeof e == 'string')
|
||||
) {
|
||||
core.debug(`Input parsed as JSON array of length ${json.length}`)
|
||||
return json
|
||||
}
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
const yaml = YAML.load(input)
|
||||
if (
|
||||
yaml &&
|
||||
Array.isArray(yaml) &&
|
||||
yaml.every((e) => typeof e == 'string')
|
||||
) {
|
||||
core.debug(`Input parsed as YAML array of length ${yaml.length}`)
|
||||
return yaml
|
||||
}
|
||||
} catch {}
|
||||
|
||||
core.debug('Input parsed as single string')
|
||||
return [input]
|
||||
}
|
||||
|
||||
function logOutputs() {
|
||||
core.startGroup('Outputs')
|
||||
for (const key in outputs) {
|
||||
core.info(`${key}: ${outputs[key]}`)
|
||||
}
|
||||
core.endGroup()
|
||||
}
|
||||
|
||||
95
src/util.ts
95
src/util.ts
@@ -1,44 +1,9 @@
|
||||
import { parseArgsStringToArgv } from 'string-argv'
|
||||
import * as core from '@actions/core'
|
||||
import YAML from 'js-yaml'
|
||||
import { Toolkit } from 'actions-toolkit'
|
||||
import fs from 'fs'
|
||||
|
||||
interface InputTypes {
|
||||
add: string
|
||||
author_name: string
|
||||
author_email: string
|
||||
branch: string
|
||||
branch_mode: 'throw' | 'create'
|
||||
commit: string | undefined
|
||||
committer_name: string
|
||||
committer_email: string
|
||||
cwd: string
|
||||
default_author: 'github_actor' | 'user_info' | 'github_actions'
|
||||
message: string
|
||||
pathspec_error_handling: 'ignore' | 'exitImmediately' | 'exitAtEnd'
|
||||
pull: string | undefined
|
||||
push: string
|
||||
remove: string | undefined
|
||||
tag: string | undefined
|
||||
|
||||
github_token: string | undefined
|
||||
}
|
||||
export type input = keyof InputTypes
|
||||
|
||||
interface OutputTypes {
|
||||
committed: 'true' | 'false'
|
||||
commit_sha: string | undefined
|
||||
pushed: 'true' | 'false'
|
||||
tagged: 'true' | 'false'
|
||||
}
|
||||
export type output = keyof OutputTypes
|
||||
|
||||
export const outputs: OutputTypes = {
|
||||
committed: 'false',
|
||||
commit_sha: undefined,
|
||||
pushed: 'false',
|
||||
tagged: 'false'
|
||||
}
|
||||
import { input, output } from './io'
|
||||
|
||||
type RecordOf<T extends string> = Record<T, string | undefined>
|
||||
export const tools = new Toolkit<RecordOf<input>, RecordOf<output>>({
|
||||
@@ -50,20 +15,6 @@ export const tools = new Toolkit<RecordOf<input>, RecordOf<output>>({
|
||||
]
|
||||
})
|
||||
|
||||
export function getInput<T extends input>(name: T, parseAsBool: true): boolean
|
||||
export function getInput<T extends input>(
|
||||
name: T,
|
||||
parseAsBool?: false
|
||||
): InputTypes[T]
|
||||
export function getInput<T extends input>(
|
||||
name: T,
|
||||
parseAsBool = false
|
||||
): InputTypes[T] | boolean {
|
||||
if (parseAsBool) return core.getBooleanInput(name)
|
||||
// @ts-expect-error
|
||||
return core.getInput(name)
|
||||
}
|
||||
|
||||
export async function getUserInfo(username?: string) {
|
||||
if (!username) return undefined
|
||||
|
||||
@@ -117,6 +68,39 @@ export function matchGitArgs(string: string) {
|
||||
return parsed
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse a JSON array, then a YAML array.
|
||||
* If both fail, it returns an array containing the input value as its only element
|
||||
*/
|
||||
export function parseInputArray(input: string): string[] {
|
||||
try {
|
||||
const json = JSON.parse(input)
|
||||
if (
|
||||
json &&
|
||||
Array.isArray(json) &&
|
||||
json.every((e) => typeof e == 'string')
|
||||
) {
|
||||
core.debug(`Input parsed as JSON array of length ${json.length}`)
|
||||
return json
|
||||
}
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
const yaml = YAML.load(input)
|
||||
if (
|
||||
yaml &&
|
||||
Array.isArray(yaml) &&
|
||||
yaml.every((e) => typeof e == 'string')
|
||||
) {
|
||||
core.debug(`Input parsed as YAML array of length ${yaml.length}`)
|
||||
return yaml
|
||||
}
|
||||
} catch {}
|
||||
|
||||
core.debug('Input parsed as single string')
|
||||
return [input]
|
||||
}
|
||||
|
||||
export function readJSON(filePath: string) {
|
||||
let fileContent: string
|
||||
try {
|
||||
@@ -131,12 +115,3 @@ export function readJSON(filePath: string) {
|
||||
throw `Couldn't parse file to JSON. File path: ${filePath}`
|
||||
}
|
||||
}
|
||||
|
||||
export function setOutput<T extends output>(name: T, value: OutputTypes[T]) {
|
||||
core.debug(`Setting output: ${name}=${value}`)
|
||||
outputs[name] = value
|
||||
core.setOutput(name, value)
|
||||
}
|
||||
|
||||
// Setup default output values
|
||||
Object.entries(outputs).forEach(([name, value]) => core.setOutput(name, value))
|
||||
|
||||
Reference in New Issue
Block a user