2020-09-23 15:19:20 +00:00
import { issue , issueCommand } from './command'
import { issueCommand as issueFileCommand } from './file-command'
2021-07-28 21:34:31 +00:00
import { toCommandProperties , toCommandValue } from './utils'
2019-05-17 03:36:45 +00:00
2019-09-09 15:46:48 +00:00
import * as os from 'os'
2019-06-05 02:00:25 +00:00
import * as path from 'path'
2022-08-08 18:39:23 +00:00
import { v4 as uuidv4 } from 'uuid'
2019-06-05 02:00:25 +00:00
2021-09-28 16:55:21 +00:00
import { OidcClient } from './oidc-utils'
2019-05-21 16:00:23 +00: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 17:51:36 +00:00
/** Optional. Whether leading/trailing whitespace will be trimmed for the input. Defaults to true */
trimWhitespace? : boolean
2019-05-21 16:00:23 +00:00
}
2019-06-25 17:54:41 +00: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 13:12:30 +00:00
Failure = 1
2019-06-25 17:54:41 +00:00
}
2021-07-28 21:34:31 +00: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 13:47:06 +00:00
/ * *
* The path of the file for which the annotation should be created .
* /
file? : string
2021-07-28 21:34:31 +00: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 14:23:01 +00:00
//-----------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------
2019-05-17 03:36:45 +00:00
/ * *
2019-10-01 21:13:05 +00:00
* Sets env variable for this action and future actions in the job
2019-05-17 03:36:45 +00:00
* @param name the name of the variable to set
2020-04-09 21:00:53 +00:00
* @param val the value of the variable . Non - string values will be converted to a string via JSON . stringify
2019-05-17 03:36:45 +00:00
* /
2020-04-09 21:00:53 +00: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 15:19:20 +00:00
const filePath = process . env [ 'GITHUB_ENV' ] || ''
if ( filePath ) {
2022-08-08 18:16:39 +00:00
const delimiter = ` ghadelimiter_ ${ uuidv4 ( ) } `
2022-08-08 18:39:23 +00: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 18:16:39 +00:00
if ( name . includes ( delimiter ) ) {
2022-08-08 18:39:23 +00:00
throw new Error (
` Unexpected input: name should not contain the delimiter " ${ delimiter } " `
)
2022-08-08 18:16:39 +00:00
}
if ( convertedVal . includes ( delimiter ) ) {
2022-08-08 18:39:23 +00:00
throw new Error (
` Unexpected input: value should not contain the delimiter " ${ delimiter } " `
)
2022-08-08 18:16:39 +00:00
}
2020-09-23 15:19:20 +00:00
const commandValue = ` ${ name } << ${ delimiter } ${ os . EOL } ${ convertedVal } ${ os . EOL } ${ delimiter } `
issueFileCommand ( 'ENV' , commandValue )
} else {
issueCommand ( 'set-env' , { name } , convertedVal )
}
2019-05-17 03:36:45 +00:00
}
/ * *
2019-10-01 21:13:05 +00:00
* Registers a secret which will get masked from logs
* @param secret value of the secret
2019-05-17 03:36:45 +00:00
* /
2019-10-01 21:13:05 +00:00
export function setSecret ( secret : string ) : void {
issueCommand ( 'add-mask' , { } , secret )
2019-05-20 23:17:56 +00:00
}
2019-05-17 03:36:45 +00:00
2019-06-05 02:00:25 +00:00
/ * *
* Prepends inputPath to the PATH ( for this action and future actions )
* @param inputPath
* /
export function addPath ( inputPath : string ) : void {
2020-09-23 15:19:20 +00:00
const filePath = process . env [ 'GITHUB_PATH' ] || ''
if ( filePath ) {
issueFileCommand ( 'PATH' , inputPath )
} else {
issueCommand ( 'add-path' , { } , inputPath )
}
2019-06-05 02:00:25 +00:00
process . env [ 'PATH' ] = ` ${ inputPath } ${ path . delimiter } ${ process . env [ 'PATH' ] } `
}
2019-05-17 14:23:01 +00:00
/ * *
2021-05-19 15:08:51 +00: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 23:17:56 +00:00
*
2019-05-17 14:23:01 +00:00
* @param name name of the input to get
* @param options optional . See InputOptions .
* @returns string
* /
2019-05-21 16:03:13 +00:00
export function getInput ( name : string , options? : InputOptions ) : string {
2019-05-21 14:51:22 +00:00
const val : string =
2019-09-12 17:41:11 +00:00
process . env [ ` INPUT_ ${ name . replace ( / /g , '_' ) . toUpperCase ( ) } ` ] || ''
2019-05-20 23:17:56 +00:00
if ( options && options . required && ! val ) {
throw new Error ( ` Input required and not supplied: ${ name } ` )
}
2019-05-17 14:23:01 +00:00
2021-05-11 17:51:36 +00:00
if ( options && options . trimWhitespace === false ) {
return val
}
2019-05-20 23:17:56 +00:00
return val . trim ( )
2019-05-17 14:23:01 +00:00
}
2021-06-04 13:28:49 +00: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 !== '' )
2021-12-26 11:53:30 +00:00
if ( options && options . trimWhitespace === false ) {
return inputs
}
return inputs . map ( input = > input . trim ( ) )
2021-06-04 13:28:49 +00:00
}
2021-04-28 20:32:25 +00: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 20:14:47 +00:00
/ * *
* Sets the value of an output .
*
* @param name name of the output to set
2020-04-09 21:00:53 +00:00
* @param value value to store . Non - string values will be converted to a string via JSON . stringify
2019-06-24 20:14:47 +00:00
* /
2020-04-09 21:00:53 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function setOutput ( name : string , value : any ) : void {
2021-04-13 17:01:19 +00:00
process . stdout . write ( os . EOL )
2019-06-25 11:19:19 +00:00
issueCommand ( 'set-output' , { name } , value )
2019-06-24 20:14:47 +00:00
}
2020-04-13 17:25:54 +00: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-17 03:36:45 +00:00
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
/ * *
2019-05-20 23:17:56 +00:00
* Sets the action status to failed .
2019-05-17 03:36:45 +00:00
* When the action exits it will be with an exit code of 1
* @param message add error issue message
* /
2020-04-09 21:00:53 +00:00
export function setFailed ( message : string | Error ) : void {
2019-05-21 16:00:23 +00:00
process . exitCode = ExitCode . Failure
2020-04-09 21:00:53 +00:00
2019-05-20 23:17:56 +00:00
error ( message )
2019-05-17 03:36:45 +00:00
}
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
2020-03-02 12:45:27 +00:00
/ * *
* Gets whether Actions Step Debug is on or not
* /
export function isDebug ( ) : boolean {
return process . env [ 'RUNNER_DEBUG' ] === '1'
}
2019-05-17 03:36:45 +00:00
/ * *
* Writes debug message to user log
* @param message debug message
* /
2019-05-21 21:08:25 +00:00
export function debug ( message : string ) : void {
2019-05-21 19:26:44 +00:00
issueCommand ( 'debug' , { } , message )
2019-05-17 03:36:45 +00:00
}
/ * *
* Adds an error issue
2020-04-09 21:00:53 +00:00
* @param message error issue message . Errors will be converted to string via toString ( )
2021-07-28 21:34:31 +00:00
* @param properties optional properties to add to the annotation .
2019-05-17 03:36:45 +00:00
* /
2021-07-28 21:34:31 +00:00
export function error (
message : string | Error ,
properties : AnnotationProperties = { }
) : void {
issueCommand (
'error' ,
toCommandProperties ( properties ) ,
message instanceof Error ? message . toString ( ) : message
)
2019-05-17 03:36:45 +00:00
}
/ * *
2021-07-28 21:34:31 +00:00
* Adds a warning issue
2020-04-09 21:00:53 +00:00
* @param message warning issue message . Errors will be converted to string via toString ( )
2021-07-28 21:34:31 +00:00
* @param properties optional properties to add to the annotation .
2019-05-17 03:36:45 +00:00
* /
2021-07-28 21:34:31 +00: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-17 03:36:45 +00:00
}
2019-08-29 02:35:27 +00:00
2019-09-09 15:46:48 +00: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-29 02:35:27 +00: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-29 02:47:37 +00:00
let result : T
try {
result = await fn ( )
} finally {
endGroup ( )
}
2019-08-29 02:35:27 +00:00
return result
}
2019-09-20 02:02:45 +00: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 21:00:53 +00:00
* @param value value to store . Non - string values will be converted to a string via JSON . stringify
2019-09-20 02:02:45 +00:00
* /
2020-04-09 21:00:53 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function saveState ( name : string , value : any ) : void {
2019-09-20 02:18:51 +00:00
issueCommand ( 'save-state' , { name } , value )
2019-09-20 02:02:45 +00: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 16:55:21 +00:00
export async function getIDToken ( aud? : string ) : Promise < string > {
return await OidcClient . getIDToken ( aud )
}
2022-03-02 02:32:26 +00:00
/ * *
2022-05-05 17:29:20 +00:00
* Summary exports
2022-03-02 02:32:26 +00: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 15:18:44 +00:00
/ * *
* Path exports
* /
export { toPosixPath , toWin32Path , toPlatformPath } from './path-utils'