utils.mjs 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import * as fs from 'node:fs'
  2. import * as os from 'node:os'
  3. import * as crypto from 'node:crypto'
  4. /** Based on https://github.com/actions/toolkit/blob/4e3b068ce116d28cb840033c02f912100b4592b0/packages/core/src/file-command.ts */
  5. export function setOutput(key, value) {
  6. const filePath = process.env['GITHUB_OUTPUT'] || ''
  7. if (filePath) {
  8. return issueFileCommand('OUTPUT', prepareKeyValueMessage(key, value))
  9. }
  10. process.stdout.write(os.EOL)
  11. }
  12. function issueFileCommand(command, message) {
  13. const filePath = process.env[`GITHUB_${command}`]
  14. if (!filePath) {
  15. throw new Error(
  16. `Unable to find environment variable for file command ${command}`
  17. )
  18. }
  19. if (!fs.existsSync(filePath)) {
  20. throw new Error(`Missing file at path: ${filePath}`)
  21. }
  22. fs.appendFileSync(filePath, `${toCommandValue(message)}${os.EOL}`, {
  23. encoding: 'utf8'
  24. })
  25. }
  26. function prepareKeyValueMessage(key, value) {
  27. const delimiter = `gh-delimiter-${crypto.randomUUID()}`
  28. const convertedValue = toCommandValue(value)
  29. // These should realistically never happen, but just in case someone finds a
  30. // way to exploit uuid generation let's not allow keys or values that contain
  31. // the delimiter.
  32. if (key.includes(delimiter)) {
  33. throw new Error(
  34. `Unexpected input: name should not contain the delimiter "${delimiter}"`
  35. )
  36. }
  37. if (convertedValue.includes(delimiter)) {
  38. throw new Error(
  39. `Unexpected input: value should not contain the delimiter "${delimiter}"`
  40. )
  41. }
  42. return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`
  43. }
  44. function toCommandValue(input) {
  45. if (input === null || input === undefined) {
  46. return ''
  47. } else if (typeof input === 'string' || input instanceof String) {
  48. return input
  49. }
  50. return JSON.stringify(input)
  51. }