2020-09-23 11:19:20 -04:00
import { issue , issueCommand } from './command'
import { issueCommand as issueFileCommand } from './file-command'
2021-07-28 17:34:31 -04:00
import { toCommandProperties , toCommandValue } from './utils'
2019-05-16 23:36:45 -04:00
2019-09-09 11:46:48 -04:00
import * as os from 'os'
2019-06-04 22:00:25 -04:00
import * as path from 'path'
2022-08-08 14:39:23 -04:00
import { v4 as uuidv4 } from 'uuid'
2019-06-04 22:00:25 -04:00
2021-09-28 12:55:21 -04:00
import { OidcClient } from './oidc-utils'
2019-05-21 12:00:23 -04:00
/**
* Interface for getInput options
*/
export interface InputOptions {
/** Optional. Whether the input is required. If required and not present, will throw. Defaults to false */
required? : boolean
2021-05-11 13:51:36 -04:00
/** Optional. Whether leading/trailing whitespace will be trimmed for the input. Defaults to true */
trimWhitespace? : boolean
2019-05-21 12:00:23 -04:00
}
2019-06-25 13:54:41 -04:00
/**
* The code to exit an action
*/
export enum ExitCode {
/**
* A code indicating that the action was successful
*/
Success = 0 ,
/**
* A code indicating that the action was a failure
*/
2019-08-06 09:12:30 -04:00
Failure = 1
2019-06-25 13:54:41 -04:00
}
2021-07-28 17:34:31 -04:00
/**
* Optional properties that can be sent with annotatation commands (notice, error, and warning)
* See: https://docs.github.com/en/rest/reference/checks#create-a-check-run for more information about annotations.
*/
export interface AnnotationProperties {
/**
* A title for the annotation.
*/
title? : string
2021-09-28 15:47:06 +02:00
/**
* The path of the file for which the annotation should be created.
*/
file? : string
2021-07-28 17:34:31 -04:00
/**
* The start line for the annotation.
*/
startLine? : number
/**
* The end line for the annotation. Defaults to `startLine` when `startLine` is provided.
*/
endLine? : number
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
*/
startColumn? : number
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
* Defaults to `startColumn` when `startColumn` is provided.
*/
endColumn? : number
}
2019-05-17 10:23:01 -04:00
//-----------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------
2019-05-16 23:36:45 -04:00
/**
2019-10-01 17:13:05 -04:00
* Sets env variable for this action and future actions in the job
2019-05-16 23:36:45 -04:00
* @param name the name of the variable to set
2020-04-09 17:00:53 -04:00
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
2019-05-16 23:36:45 -04:00
*/
2020-04-09 17:00:53 -04:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function exportVariable ( name : string , val : any ) : void {
const convertedVal = toCommandValue ( val )
process . env [ name ] = convertedVal
2020-09-23 11:19:20 -04:00
const filePath = process . env [ 'GITHUB_ENV' ] || ''
if ( filePath ) {
2022-08-08 14:16:39 -04:00
const delimiter = `ghadelimiter_ ${ uuidv4 () } `
2022-08-08 14:39:23 -04:00
// These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter.
2022-08-08 14:16:39 -04:00
if ( name . includes ( delimiter )) {
2022-08-08 14:39:23 -04:00
throw new Error (
`Unexpected input: name should not contain the delimiter " ${ delimiter } "`
)
2022-08-08 14:16:39 -04:00
}
if ( convertedVal . includes ( delimiter )) {
2022-08-08 14:39:23 -04:00
throw new Error (
`Unexpected input: value should not contain the delimiter " ${ delimiter } "`
)
2022-08-08 14:16:39 -04:00
}
2020-09-23 11:19:20 -04:00
const commandValue = ` ${ name } << ${ delimiter }${ os . EOL }${ convertedVal }${ os . EOL }${ delimiter } `
issueFileCommand ( 'ENV' , commandValue )
} else {
issueCommand ( 'set-env' , { name }, convertedVal )
}
2019-05-16 23:36:45 -04:00
}
/**
2019-10-01 17:13:05 -04:00
* Registers a secret which will get masked from logs
* @param secret value of the secret
2019-05-16 23:36:45 -04:00
*/
2019-10-01 17:13:05 -04:00
export function setSecret ( secret : string ) : void {
issueCommand ( 'add-mask' , {}, secret )
2019-05-20 19:17:56 -04:00
}
2019-05-16 23:36:45 -04:00
2019-06-04 22:00:25 -04:00
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
export function addPath ( inputPath : string ) : void {
2020-09-23 11:19:20 -04:00
const filePath = process . env [ 'GITHUB_PATH' ] || ''
if ( filePath ) {
issueFileCommand ( 'PATH' , inputPath )
} else {
issueCommand ( 'add-path' , {}, inputPath )
}
2019-06-04 22:00:25 -04:00
process . env [ 'PATH' ] = ` ${ inputPath }${ path . delimiter }${ process . env [ 'PATH' ] } `
}
2019-05-17 10:23:01 -04:00
/**
2021-05-19 17:08:51 +02:00
* Gets the value of an input.
* Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.
* Returns an empty string if the value is not defined.
2019-05-20 19:17:56 -04:00
*
2019-05-17 10:23:01 -04:00
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string
*/
2019-05-21 12:03:13 -04:00
export function getInput ( name : string , options? : InputOptions ) : string {
2019-05-21 10:51:22 -04:00
const val : string =
2019-09-12 19:41:11 +02:00
process . env [ `INPUT_ ${ name . replace ( / /g , '_' ). toUpperCase () } ` ] || ''
2019-05-20 19:17:56 -04:00
if ( options && options . required && ! val ) {
throw new Error ( `Input required and not supplied: ${ name } ` )
}
2019-05-17 10:23:01 -04:00
2021-05-11 13:51:36 -04:00
if ( options && options . trimWhitespace === false ) {
return val
}
2019-05-20 19:17:56 -04:00
return val . trim ()
2019-05-17 10:23:01 -04:00
}
2021-06-04 09:28:49 -04:00
/**
* Gets the values of an multiline input. Each value is also trimmed.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string[]
*
*/
export function getMultilineInput (
name : string ,
options? : InputOptions
) : string [] {
const inputs : string [] = getInput ( name , options )
. split ( '\n' )
. filter ( x => x !== '' )
return inputs
}
2021-04-28 15:32:25 -05:00
/**
* Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
* Support boolean input list: `true | True | TRUE | false | False | FALSE` .
* The return value is also in boolean type.
* ref: https://yaml.org/spec/1.2/spec.html#id2804923
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns boolean
*/
export function getBooleanInput ( name : string , options? : InputOptions ) : boolean {
const trueValue = [ 'true' , 'True' , 'TRUE' ]
const falseValue = [ 'false' , 'False' , 'FALSE' ]
const val = getInput ( name , options )
if ( trueValue . includes ( val )) return true
if ( falseValue . includes ( val )) return false
throw new TypeError (
`Input does not meet YAML 1.2 "Core Schema" specification: ${ name } \ n` +
`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``
)
}
2019-06-24 16:14:47 -04:00
/**
* Sets the value of an output.
*
* @param name name of the output to set
2020-04-09 17:00:53 -04:00
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
2019-06-24 16:14:47 -04:00
*/
2020-04-09 17:00:53 -04:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function setOutput ( name : string , value : any ) : void {
2021-04-13 12:01:19 -05:00
process . stdout . write ( os . EOL )
2019-06-25 07:19:19 -04:00
issueCommand ( 'set-output' , { name }, value )
2019-06-24 16:14:47 -04:00
}
2020-04-13 13:25:54 -04:00
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
*
*/
export function setCommandEcho ( enabled : boolean ) : void {
issue ( 'echo' , enabled ? 'on' : 'off' )
}
2019-05-16 23:36:45 -04:00
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
/**
2019-05-20 19:17:56 -04:00
* Sets the action status to failed.
2019-05-16 23:36:45 -04:00
* When the action exits it will be with an exit code of 1
* @param message add error issue message
*/
2020-04-09 17:00:53 -04:00
export function setFailed ( message : string | Error ) : void {
2019-05-21 12:00:23 -04:00
process . exitCode = ExitCode . Failure
2020-04-09 17:00:53 -04:00
2019-05-20 19:17:56 -04:00
error ( message )
2019-05-16 23:36:45 -04:00
}
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
2020-03-02 07:45:27 -05:00
/**
* Gets whether Actions Step Debug is on or not
*/
export function isDebug () : boolean {
return process . env [ 'RUNNER_DEBUG' ] === '1'
}
2019-05-16 23:36:45 -04:00
/**
* Writes debug message to user log
* @param message debug message
*/
2019-05-21 17:08:25 -04:00
export function debug ( message : string ) : void {
2019-05-21 15:26:44 -04:00
issueCommand ( 'debug' , {}, message )
2019-05-16 23:36:45 -04:00
}
/**
* Adds an error issue
2020-04-09 17:00:53 -04:00
* @param message error issue message. Errors will be converted to string via toString()
2021-07-28 17:34:31 -04:00
* @param properties optional properties to add to the annotation.
2019-05-16 23:36:45 -04:00
*/
2021-07-28 17:34:31 -04:00
export function error (
message : string | Error ,
properties : AnnotationProperties = {}
) : void {
issueCommand (
'error' ,
toCommandProperties ( properties ),
message instanceof Error ? message . toString () : message
)
2019-05-16 23:36:45 -04:00
}
/**
2021-07-28 17:34:31 -04:00
* Adds a warning issue
2020-04-09 17:00:53 -04:00
* @param message warning issue message. Errors will be converted to string via toString()
2021-07-28 17:34:31 -04:00
* @param properties optional properties to add to the annotation.
2019-05-16 23:36:45 -04:00
*/
2021-07-28 17:34:31 -04:00
export function warning (
message : string | Error ,
properties : AnnotationProperties = {}
) : void {
issueCommand (
'warning' ,
toCommandProperties ( properties ),
message instanceof Error ? message . toString () : message
)
}
/**
* Adds a notice issue
* @param message notice issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
export function notice (
message : string | Error ,
properties : AnnotationProperties = {}
) : void {
issueCommand (
'notice' ,
toCommandProperties ( properties ),
message instanceof Error ? message . toString () : message
)
2019-05-16 23:36:45 -04:00
}
2019-08-28 22:35:27 -04:00
2019-09-09 11:46:48 -04:00
/**
* Writes info to log with console.log.
* @param message info message
*/
export function info ( message : string ) : void {
process . stdout . write ( message + os . EOL )
}
2019-08-28 22:35:27 -04:00
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
export function startGroup ( name : string ) : void {
issue ( 'group' , name )
}
/**
* End an output group.
*/
export function endGroup () : void {
issue ( 'endgroup' )
}
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
export async function group < T >( name : string , fn : () => Promise < T >) : Promise < T > {
startGroup ( name )
2019-08-28 22:47:37 -04:00
let result : T
try {
result = await fn ()
} finally {
endGroup ()
}
2019-08-28 22:35:27 -04:00
return result
}
2019-09-19 22:02:45 -04:00
//-----------------------------------------------------------------------
// Wrapper action state
//-----------------------------------------------------------------------
/**
* Saves state for current action, the state can only be retrieved by this action's post job execution.
*
* @param name name of the state to store
2020-04-09 17:00:53 -04:00
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
2019-09-19 22:02:45 -04:00
*/
2020-04-09 17:00:53 -04:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function saveState ( name : string , value : any ) : void {
2019-09-19 22:18:51 -04:00
issueCommand ( 'save-state' , { name }, value )
2019-09-19 22:02:45 -04:00
}
/**
* Gets the value of an state set by this action's main execution.
*
* @param name name of the state to get
* @returns string
*/
export function getState ( name : string ) : string {
return process . env [ `STATE_ ${ name } ` ] || ''
}
2021-09-28 12:55:21 -04:00
export async function getIDToken ( aud? : string ) : Promise < string > {
return await OidcClient . getIDToken ( aud )
}
2022-03-01 21:32:26 -05:00
/**
2022-05-05 17:29:20 +00:00
* Summary exports
2022-03-01 21:32:26 -05:00
*/
2022-05-05 17:29:20 +00:00
export { summary } from './summary'
2022-05-05 19:44:13 +00:00
/**
* @deprecated use core.summary
*/
export { markdownSummary } from './summary'
2022-06-15 08:18:44 -07:00
/**
* Path exports
*/
export { toPosixPath , toWin32Path , toPlatformPath } from './path-utils'