Description
Description
When I write a key value pair by echo inside a workflow it can be used by other steps as variables and is visible inside the context. But when I use core.setOutput('key1', 'value1')
it doesn't.
Also the content inside the $GITHUB_OUTPUT files is completely different.
Steps to reproduce
Set output with echo - works
Here an example which uses the described new way of setting outputs by environment variables. This works and the output file is in an expected way:
- name: Print output by worfklow
id: output_test_by_worfklow
if: always()
run: |
echo "scan-trafficlight=RED" >> "$GITHUB_OUTPUT" # Test Output 1
echo "scan-findings-count=1" >> "$GITHUB_OUTPUT" # Test Output 2
- name: Show all github output files
id: output_file
if: always()
run: |
echo "GITHUB_OUTPUT=$GITHUB_OUTPUT"
DIRECTORY=$(dirname -- "$GITHUB_OUTPUT")
# Check if the directory exists
if [ ! -d "$DIRECTORY" ]; then
echo "Directory does not exist."
exit 1
fi
# Iterate through each file in the directory
for FILE in "$DIRECTORY"/*; do
# Check if the file name starts with "set_output"
if [[ $(basename "$FILE") == set_output* ]]; then
echo "----------------------------------------------------------------------------------------------------"
echo "Contents of $FILE:"
echo "----------------------------------------------------------------------------------------------------"
cat "$FILE"
echo # Add a newline for better readability
fi
done
- name: Print Context Information
if: always()
env:
CONTEXT: ${{ toJson(steps) }}
run: echo "$CONTEXT"
After execution I got following:
----------------------------------------------------------------------------------------------------
Contents of /runner/_work/_temp/_runner_file_commands/set_output_8c665a1b-cb6b-4962-96ca-3075398fe305:
----------------------------------------------------------------------------------------------------
scan-trafficlight=RED
scan-findings-count=1
and the (reduced) context output looks like this
"output_test_by_worfklow": {
"outputs": {
"scan-trafficlight": "RED",
"scan-findings-count": "1"
},
"outcome": "success",
"conclusion": "success"
}
Means everything is working. Fine.
Set output via API - DOES NOT WORK
But when I write a custom action and use internally there :
core.setOutput('scan-trafficlight','RED')
core.setOutput('scan-findings-count','1')
to define output, it writes the files in a different way and the context does
not contain the two keys:
- name: Print output by custom action
id: output_test_by_custom_action
uses: {orgname}/{customActionWhichSetsOutput}
- name: Show all github output files
id: output_file
if: always()
run: |
echo "GITHUB_OUTPUT=$GITHUB_OUTPUT"
DIRECTORY=$(dirname -- "$GITHUB_OUTPUT")
# Check if the directory exists
if [ ! -d "$DIRECTORY" ]; then
echo "Directory does not exist."
exit 1
fi
# Iterate through each file in the directory
for FILE in "$DIRECTORY"/*; do
# Check if the file name starts with "set_output"
if [[ $(basename "$FILE") == set_output* ]]; then
echo "----------------------------------------------------------------------------------------------------"
echo "Contents of $FILE:"
echo "----------------------------------------------------------------------------------------------------"
cat "$FILE"
echo # Add a newline for better readability
fi
done
- name: Print Context Information
if: always()
env:
CONTEXT: ${{ toJson(steps) }}
run: echo "$CONTEXT"
After execution I got following:
----------------------------------------------------------------------------------------------------
Contents of /runner/_work/_temp/_runner_file_commands/set_output_9550026e-04b7-4a5e-963b-4d7838e73e4d:
----------------------------------------------------------------------------------------------------
scan-trafficlight<<ghadelimiter_12b579a9-fb20-4e41-8b6d-53dd97e57865
RED
ghadelimiter_12b579a9-fb20-4e41-8b6d-53dd97e57865
scan-findings-count<<ghadelimiter_b1042cbc-4b13-4648-851b-83535f96876c
1
ghadelimiter_b1042cbc-4b13-4648-851b-83535f96876c
and the (reduced) context output looks like this
"output_test_by_custom_action": {
"outputs": {
},
"outcome": "success",
"conclusion": "success"
}
Means:
- The output is written different to the output by echo!
- The context does not contain output information/there is no access to it.
Additional info
Workaround (did not help)
I tried to write the file directly {key}={value}{os.EOL}
but the 2 keys were still not
visible in context output.
Analyze
// https://github.com/actions/toolkit/blob/main/packages/core/src/core.ts#L192
export function setOutput(name: string, value: any): void {
const filePath = process.env['GITHUB_OUTPUT'] || ''
if (filePath) {
return issueFileCommand('OUTPUT', prepareKeyValueMessage(name, value))
}
process.stdout.write(os.EOL)
issueCommand('set-output', {name}, toCommandValue(value))
}
this calls
// https://github.com/actions/toolkit/blob/main/packages/core/src/file-command.ts
export function prepareKeyValueMessage(key: string, value: any): string {
const delimiter = `ghadelimiter_${crypto.randomUUID()}`
const convertedValue = toCommandValue(value)
// 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.
if (key.includes(delimiter)) {
throw new Error(
`Unexpected input: name should not contain the delimiter "${delimiter}"`
)
}
if (convertedValue.includes(delimiter)) {
throw new Error(
`Unexpected input: value should not contain the delimiter "${delimiter}"`
)
}
return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`
}
Hm... the usage of ${crypto.randomUUID()}
looks odd: What shall here be the purpose of the crypto uuid? Was the intention to ensure keys are unqiue? It is always different. What was the real purpose for this. Sorry I did not get it.
Why does it not appear inside the context? Could it be that the read mechanism which sets the context is not able to read the new format?
Expected behavior
- I would expect that the output file structure would be same for echos and for API usages.
- using core.setOutput(...) should result in the output listed inside the context
Target
This appeared with core 1.10.1 and newer