@ronaldphilipsen/local-action 0.0.0-stage → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/.checkov.yml +3 -0
  2. package/.env.example +379 -0
  3. package/.github/codeql/codeql-config.yml +7 -0
  4. package/.github/copilot-instructions.md +79 -0
  5. package/.github/dependabot.yml +32 -0
  6. package/.github/workflows/codeql-analysis.yml +53 -0
  7. package/.github/workflows/continuous-delivery.yml +93 -0
  8. package/.github/workflows/continuous-integration.yml +382 -0
  9. package/.github/workflows/linter.yml +47 -0
  10. package/.github/workflows/release.yaml +100 -0
  11. package/.github/workflows/version-check.yml +44 -0
  12. package/.grype.yml +151 -0
  13. package/.markdown-lint.yml +7 -0
  14. package/.mega-linter.yml +188 -0
  15. package/.node-version +1 -0
  16. package/.prettierignore +4 -0
  17. package/.prettierrc.yml +14 -0
  18. package/.vscode/launch.json +15 -0
  19. package/.vscode/mcp.json +9 -0
  20. package/.vscode/settings.json +15 -0
  21. package/.vscode/tasks.json +51 -0
  22. package/.yaml-lint.yml +10 -0
  23. package/CHANGELOG.md +75 -0
  24. package/CODEOWNERS +3 -0
  25. package/CODE_OF_CONDUCT.md +74 -0
  26. package/CONTRIBUTING.md +140 -0
  27. package/LICENSE +21 -0
  28. package/README.md +277 -2
  29. package/SECURITY.md +42 -0
  30. package/SUPPORT.md +19 -0
  31. package/__fixtures__/@actions/core.ts +14 -0
  32. package/__fixtures__/@actions/exec.ts +9 -0
  33. package/__fixtures__/@actions/github.ts +3 -0
  34. package/__fixtures__/@actions/http-client.ts +9 -0
  35. package/__fixtures__/@actions/io.ts +9 -0
  36. package/__fixtures__/@octokit/rest.ts +18 -0
  37. package/__fixtures__/crypto.ts +7 -0
  38. package/__fixtures__/fs.ts +27 -0
  39. package/__fixtures__/javascript/no-export/.env.fixture +2 -0
  40. package/__fixtures__/javascript/no-export/action.yml +16 -0
  41. package/__fixtures__/javascript/no-export/node_modules/.gitkeep +0 -0
  42. package/__fixtures__/javascript/no-export/package.json +12 -0
  43. package/__fixtures__/javascript/no-export/src/index.js +0 -0
  44. package/__fixtures__/javascript/no-export/src/main.js +0 -0
  45. package/__fixtures__/javascript/no-import/.env.fixture +2 -0
  46. package/__fixtures__/javascript/no-import/action.yml +16 -0
  47. package/__fixtures__/javascript/no-import/node_modules/.gitkeep +0 -0
  48. package/__fixtures__/javascript/no-import/package.json +12 -0
  49. package/__fixtures__/javascript/no-import/src/index.js +3 -0
  50. package/__fixtures__/javascript/no-import/src/main.js +7 -0
  51. package/__fixtures__/javascript/success/.env.fixture +2 -0
  52. package/__fixtures__/javascript/success/action.yml +16 -0
  53. package/__fixtures__/javascript/success/node_modules/.gitkeep +0 -0
  54. package/__fixtures__/javascript/success/package.json +12 -0
  55. package/__fixtures__/javascript/success/post/index.js +3 -0
  56. package/__fixtures__/javascript/success/post/main.js +13 -0
  57. package/__fixtures__/javascript/success/pre/index.js +3 -0
  58. package/__fixtures__/javascript/success/pre/main.js +13 -0
  59. package/__fixtures__/javascript/success/src/index.js +3 -0
  60. package/__fixtures__/javascript/success/src/main.js +13 -0
  61. package/__fixtures__/javascript-esm/no-import/.env.fixture +2 -0
  62. package/__fixtures__/javascript-esm/no-import/action.yml +16 -0
  63. package/__fixtures__/javascript-esm/no-import/node_modules/.gitkeep +0 -0
  64. package/__fixtures__/javascript-esm/no-import/package.json +13 -0
  65. package/__fixtures__/javascript-esm/no-import/src/index.js +3 -0
  66. package/__fixtures__/javascript-esm/no-import/src/main.js +7 -0
  67. package/__fixtures__/javascript-esm/success/.env.fixture +2 -0
  68. package/__fixtures__/javascript-esm/success/action.yml +16 -0
  69. package/__fixtures__/javascript-esm/success/node_modules/.gitkeep +0 -0
  70. package/__fixtures__/javascript-esm/success/package.json +13 -0
  71. package/__fixtures__/javascript-esm/success/post/index.js +3 -0
  72. package/__fixtures__/javascript-esm/success/post/main.js +13 -0
  73. package/__fixtures__/javascript-esm/success/pre/index.js +3 -0
  74. package/__fixtures__/javascript-esm/success/pre/main.js +13 -0
  75. package/__fixtures__/javascript-esm/success/src/index.js +3 -0
  76. package/__fixtures__/javascript-esm/success/src/main.js +13 -0
  77. package/__fixtures__/path.ts +7 -0
  78. package/__fixtures__/payloads/issue_opened.json +33 -0
  79. package/__fixtures__/stream/promises.ts +3 -0
  80. package/__fixtures__/tsconfig-paths.ts +4 -0
  81. package/__fixtures__/typescript/no-import/.env.fixture +2 -0
  82. package/__fixtures__/typescript/no-import/action.yml +16 -0
  83. package/__fixtures__/typescript/no-import/node_modules/.gitkeep +0 -0
  84. package/__fixtures__/typescript/no-import/package.json +15 -0
  85. package/__fixtures__/typescript/no-import/src/index.ts +3 -0
  86. package/__fixtures__/typescript/no-import/src/main.ts +3 -0
  87. package/__fixtures__/typescript/no-import/tsconfig.json +20 -0
  88. package/__fixtures__/typescript/success/.env.fixture +2 -0
  89. package/__fixtures__/typescript/success/action.yml +16 -0
  90. package/__fixtures__/typescript/success/node_modules/.gitkeep +0 -0
  91. package/__fixtures__/typescript/success/package.json +15 -0
  92. package/__fixtures__/typescript/success/post/index.ts +3 -0
  93. package/__fixtures__/typescript/success/post/main.ts +9 -0
  94. package/__fixtures__/typescript/success/pre/index.ts +3 -0
  95. package/__fixtures__/typescript/success/pre/main.ts +9 -0
  96. package/__fixtures__/typescript/success/src/index.ts +3 -0
  97. package/__fixtures__/typescript/success/src/main.ts +9 -0
  98. package/__fixtures__/typescript/success/tsconfig.json +20 -0
  99. package/__fixtures__/typescript/success-yaml/.env.fixture +2 -0
  100. package/__fixtures__/typescript/success-yaml/action.yaml +16 -0
  101. package/__fixtures__/typescript/success-yaml/node_modules/.gitkeep +0 -0
  102. package/__fixtures__/typescript/success-yaml/package.json +15 -0
  103. package/__fixtures__/typescript/success-yaml/post/index.ts +3 -0
  104. package/__fixtures__/typescript/success-yaml/post/main.ts +9 -0
  105. package/__fixtures__/typescript/success-yaml/pre/index.ts +3 -0
  106. package/__fixtures__/typescript/success-yaml/pre/main.ts +9 -0
  107. package/__fixtures__/typescript/success-yaml/src/index.ts +3 -0
  108. package/__fixtures__/typescript/success-yaml/src/main.ts +9 -0
  109. package/__fixtures__/typescript/success-yaml/tsconfig.json +20 -0
  110. package/__fixtures__/typescript-esm/no-export/.env.fixture +2 -0
  111. package/__fixtures__/typescript-esm/no-export/action.yml +17 -0
  112. package/__fixtures__/typescript-esm/no-export/node_modules/.gitkeep +0 -0
  113. package/__fixtures__/typescript-esm/no-export/package.json +17 -0
  114. package/__fixtures__/typescript-esm/no-export/src/index.ts +0 -0
  115. package/__fixtures__/typescript-esm/no-export/src/main.ts +0 -0
  116. package/__fixtures__/typescript-esm/no-export/tsconfig.json +25 -0
  117. package/__fixtures__/typescript-esm/no-import/.env.fixture +2 -0
  118. package/__fixtures__/typescript-esm/no-import/action.yml +17 -0
  119. package/__fixtures__/typescript-esm/no-import/node_modules/.gitkeep +0 -0
  120. package/__fixtures__/typescript-esm/no-import/package.json +17 -0
  121. package/__fixtures__/typescript-esm/no-import/src/index.ts +3 -0
  122. package/__fixtures__/typescript-esm/no-import/src/main.ts +3 -0
  123. package/__fixtures__/typescript-esm/no-import/tsconfig.json +25 -0
  124. package/__fixtures__/typescript-esm/success/.env.fixture +2 -0
  125. package/__fixtures__/typescript-esm/success/action.yml +17 -0
  126. package/__fixtures__/typescript-esm/success/node_modules/.gitkeep +0 -0
  127. package/__fixtures__/typescript-esm/success/package.json +17 -0
  128. package/__fixtures__/typescript-esm/success/post/index.ts +3 -0
  129. package/__fixtures__/typescript-esm/success/post/main.ts +9 -0
  130. package/__fixtures__/typescript-esm/success/pre/index.ts +3 -0
  131. package/__fixtures__/typescript-esm/success/pre/main.ts +9 -0
  132. package/__fixtures__/typescript-esm/success/src/index.ts +3 -0
  133. package/__fixtures__/typescript-esm/success/src/main.ts +9 -0
  134. package/__fixtures__/typescript-esm/success/tsconfig.json +25 -0
  135. package/__fixtures__/typescript-esm/tsconfig-comments/.env.fixture +2 -0
  136. package/__fixtures__/typescript-esm/tsconfig-comments/action.yml +17 -0
  137. package/__fixtures__/typescript-esm/tsconfig-comments/node_modules/.gitkeep +0 -0
  138. package/__fixtures__/typescript-esm/tsconfig-comments/package.json +17 -0
  139. package/__fixtures__/typescript-esm/tsconfig-comments/src/index.ts +3 -0
  140. package/__fixtures__/typescript-esm/tsconfig-comments/src/main.ts +9 -0
  141. package/__fixtures__/typescript-esm/tsconfig-comments/tsconfig.json +21 -0
  142. package/__tests__/command.test.ts +224 -0
  143. package/__tests__/stubs/artifact/internal/client.test.ts +340 -0
  144. package/__tests__/stubs/artifact/internal/delete/delete-artifact.test.ts +152 -0
  145. package/__tests__/stubs/artifact/internal/download/download-artifact.test.ts +119 -0
  146. package/__tests__/stubs/artifact/internal/find/get-artifact.test.ts +237 -0
  147. package/__tests__/stubs/artifact/internal/find/list-artifacts.test.ts +218 -0
  148. package/__tests__/stubs/artifact/internal/find/retry-options.test.ts +54 -0
  149. package/__tests__/stubs/artifact/internal/shared/config.test.ts +91 -0
  150. package/__tests__/stubs/artifact/internal/shared/errors.test.ts +38 -0
  151. package/__tests__/stubs/artifact/internal/shared/user-agent.test.ts +22 -0
  152. package/__tests__/stubs/artifact/internal/upload/path-and-artifact-name-validation.test.ts +53 -0
  153. package/__tests__/stubs/artifact/internal/upload/upload-artifact.test.ts +126 -0
  154. package/__tests__/stubs/artifact/internal/upload/upload-zip-specification.test.ts +49 -0
  155. package/__tests__/stubs/cache/cache.test.ts +357 -0
  156. package/__tests__/stubs/cache/errors.test.ts +55 -0
  157. package/__tests__/stubs/cache/internal/cacheUtils.test.ts +109 -0
  158. package/__tests__/stubs/cache/internal/constants.test.ts +81 -0
  159. package/__tests__/stubs/cache/internal/tar.test.ts +129 -0
  160. package/__tests__/stubs/core/core.test.ts +760 -0
  161. package/__tests__/stubs/core/path-utils.test.ts +45 -0
  162. package/__tests__/stubs/core/platform.test.ts +89 -0
  163. package/__tests__/stubs/core/summary.test.ts +455 -0
  164. package/__tests__/stubs/env.test.ts +72 -0
  165. package/__tests__/stubs/github/context.test.ts +73 -0
  166. package/__tests__/stubs/github/github.test.ts +15 -0
  167. package/__tests__/stubs/github/internal/utils.test.ts +98 -0
  168. package/__tests__/stubs/github/utils.test.ts +16 -0
  169. package/__tests__/utils/config.test.ts +78 -0
  170. package/__tests__/utils/output.test.ts +32 -0
  171. package/__tests__/utils/package.test.ts +33 -0
  172. package/badges/coverage.svg +1 -0
  173. package/bin/local-action.js +121 -0
  174. package/docs/create-a-job-summary.md +32 -0
  175. package/docs/debugging-in-vscode.md +27 -0
  176. package/docs/img/job-summary.png +0 -0
  177. package/docs/supported-functionality.md +126 -0
  178. package/eslint.config.mjs +74 -0
  179. package/jest.config.ts +41 -0
  180. package/package.json +93 -4
  181. package/src/command.ts +171 -0
  182. package/src/commands/run.ts +616 -0
  183. package/src/index.ts +21 -0
  184. package/src/stubs/artifact/artifact.ts +17 -0
  185. package/src/stubs/artifact/internal/client.ts +400 -0
  186. package/src/stubs/artifact/internal/delete/delete-artifact.ts +126 -0
  187. package/src/stubs/artifact/internal/download/download-artifact.ts +309 -0
  188. package/src/stubs/artifact/internal/find/get-artifact.ts +135 -0
  189. package/src/stubs/artifact/internal/find/list-artifacts.ts +188 -0
  190. package/src/stubs/artifact/internal/find/retry-options.ts +57 -0
  191. package/src/stubs/artifact/internal/shared/config.ts +64 -0
  192. package/src/stubs/artifact/internal/shared/errors.ts +53 -0
  193. package/src/stubs/artifact/internal/shared/interfaces.ts +195 -0
  194. package/src/stubs/artifact/internal/shared/user-agent.ts +13 -0
  195. package/src/stubs/artifact/internal/upload/path-and-artifact-name-validation.ts +92 -0
  196. package/src/stubs/artifact/internal/upload/upload-artifact.ts +127 -0
  197. package/src/stubs/artifact/internal/upload/upload-zip-specification.ts +108 -0
  198. package/src/stubs/artifact/internal/upload/zip.ts +122 -0
  199. package/src/stubs/cache/cache.ts +334 -0
  200. package/src/stubs/cache/errors.ts +31 -0
  201. package/src/stubs/cache/interfaces.ts +4 -0
  202. package/src/stubs/cache/internal/cacheUtils.ts +207 -0
  203. package/src/stubs/cache/internal/constants.ts +45 -0
  204. package/src/stubs/cache/internal/tar.ts +374 -0
  205. package/src/stubs/cache/options.ts +91 -0
  206. package/src/stubs/core/core.ts +743 -0
  207. package/src/stubs/core/path-utils.ts +39 -0
  208. package/src/stubs/core/platform.ts +132 -0
  209. package/src/stubs/core/summary.ts +399 -0
  210. package/src/stubs/env.ts +40 -0
  211. package/src/stubs/github/context.ts +94 -0
  212. package/src/stubs/github/github.ts +29 -0
  213. package/src/stubs/github/interfaces.ts +52 -0
  214. package/src/stubs/github/internal/utils.ts +83 -0
  215. package/src/stubs/github/utils.ts +52 -0
  216. package/src/types/quibble.d.ts +5 -0
  217. package/src/types.ts +116 -0
  218. package/src/utils/config.ts +47 -0
  219. package/src/utils/output.ts +20 -0
  220. package/src/utils/package.ts +38 -0
  221. package/tsconfig.base.json +29 -0
  222. package/tsconfig.eslint.json +22 -0
  223. package/tsconfig.json +18 -0
@@ -0,0 +1,45 @@
1
+ import { jest } from '@jest/globals'
2
+ import path from 'path'
3
+ import { ResetCoreMetadata } from '../../../src/stubs/core/core.js'
4
+ import {
5
+ toPlatformPath,
6
+ toPosixPath,
7
+ toWin32Path
8
+ } from '../../../src/stubs/core/path-utils.js'
9
+ import { ResetEnvMetadata } from '../../../src/stubs/env.js'
10
+
11
+ // Prevent output during tests
12
+ jest.spyOn(console, 'log').mockImplementation(() => {})
13
+ jest.spyOn(console, 'table').mockImplementation(() => {})
14
+
15
+ describe('path-utils', () => {
16
+ beforeEach(() => {
17
+ // Reset metadata
18
+ ResetEnvMetadata()
19
+ ResetCoreMetadata()
20
+ })
21
+
22
+ afterEach(() => {
23
+ jest.resetAllMocks()
24
+ })
25
+
26
+ describe('toWin32Path()', () => {
27
+ it('Returns a WIN32 path', () => {
28
+ expect(toWin32Path('C:/Users/mona/Desktop')).toEqual(
29
+ 'C:\\Users\\mona\\Desktop'
30
+ )
31
+ })
32
+ })
33
+
34
+ describe('toPlatformPath()', () => {
35
+ it('Returns a platform-specific path', () => {
36
+ expect(toPlatformPath('C:/Users/mona/Desktop')).toEqual(
37
+ `C:${path.sep}Users${path.sep}mona${path.sep}Desktop`
38
+ )
39
+
40
+ expect(toPosixPath('C:\\Users\\mona\\Desktop')).toEqual(
41
+ `C:${path.sep}Users${path.sep}mona${path.sep}Desktop`
42
+ )
43
+ })
44
+ })
45
+ })
@@ -0,0 +1,89 @@
1
+ import { jest } from '@jest/globals'
2
+ import * as exec from '../../../__fixtures__/@actions/exec.js'
3
+
4
+ jest.unstable_mockModule('@actions/exec', () => exec)
5
+
6
+ const platform = await import('../../../src/stubs/core/platform.js')
7
+
8
+ describe('platform', () => {
9
+ afterEach(() => {
10
+ jest.resetAllMocks()
11
+ })
12
+
13
+ describe('getWindowsInfo', () => {
14
+ it('Gets Windows OS info', async () => {
15
+ exec.getExecOutput
16
+ .mockResolvedValueOnce({
17
+ stdout: '10',
18
+ stderr: '',
19
+ exitCode: 0
20
+ } as never)
21
+ .mockResolvedValueOnce({
22
+ stdout: 'Microsoft Windows 10 Pro',
23
+ stderr: '',
24
+ exitCode: 0
25
+ } as never)
26
+
27
+ const result = await platform.getWindowsInfo()
28
+
29
+ expect(exec.getExecOutput).toHaveBeenCalledTimes(2)
30
+ expect(result).toMatchObject({
31
+ name: 'Microsoft Windows 10 Pro',
32
+ version: '10'
33
+ })
34
+ })
35
+ })
36
+
37
+ describe('getMacOsInfo', () => {
38
+ it('Gets macOS info', async () => {
39
+ exec.getExecOutput.mockResolvedValueOnce({
40
+ stdout:
41
+ 'ProductName: macOS\nProductVersion: 13.0.1\nBuildVersion: 22A400',
42
+ stderr: '',
43
+ exitCode: 0
44
+ } as never)
45
+
46
+ const result = await platform.getMacOsInfo()
47
+
48
+ expect(exec.getExecOutput).toHaveBeenCalledTimes(1)
49
+ expect(result).toMatchObject({
50
+ name: 'macOS',
51
+ version: '13.0.1'
52
+ })
53
+ })
54
+
55
+ it('Gets macOS info (defaults to empty strings)', async () => {
56
+ exec.getExecOutput.mockResolvedValueOnce({
57
+ stdout: '',
58
+ stderr: '',
59
+ exitCode: 0
60
+ } as never)
61
+
62
+ const result = await platform.getMacOsInfo()
63
+
64
+ expect(exec.getExecOutput).toHaveBeenCalledTimes(1)
65
+ expect(result).toMatchObject({
66
+ name: '',
67
+ version: ''
68
+ })
69
+ })
70
+ })
71
+
72
+ describe('getLinuxInfo', () => {
73
+ it('Gets Linux OS info', async () => {
74
+ exec.getExecOutput.mockResolvedValueOnce({
75
+ stdout: 'Linux\nMint',
76
+ stderr: '',
77
+ exitCode: 0
78
+ } as never)
79
+
80
+ const result = await platform.getLinuxInfo()
81
+
82
+ expect(exec.getExecOutput).toHaveBeenCalledTimes(1)
83
+ expect(result).toMatchObject({
84
+ name: 'Linux',
85
+ version: 'Mint'
86
+ })
87
+ })
88
+ })
89
+ })
@@ -0,0 +1,455 @@
1
+ import { jest } from '@jest/globals'
2
+ import fs from 'fs'
3
+ import { EOL } from 'os'
4
+ import path from 'path'
5
+ import { CoreMeta, ResetCoreMetadata } from '../../../src/stubs/core/core.js'
6
+ import { Summary } from '../../../src/stubs/core/summary.js'
7
+
8
+ let summary: Summary = new Summary()
9
+
10
+ // Prevent output during tests
11
+ jest.spyOn(console, 'log').mockImplementation(() => {})
12
+
13
+ describe('Summary', () => {
14
+ beforeEach(() => {
15
+ // Reset the summary instance
16
+ summary = new Summary()
17
+
18
+ CoreMeta.stepSummaryPath = 'summary.md'
19
+ })
20
+
21
+ afterEach(() => {
22
+ jest.resetAllMocks()
23
+
24
+ // Restore environment metadata
25
+ ResetCoreMetadata()
26
+ })
27
+
28
+ describe('constructor', () => {
29
+ it('Creates an instance of the Summary class', () => {
30
+ expect(summary).toBeInstanceOf(Summary)
31
+ })
32
+ })
33
+
34
+ describe('filePath()', () => {
35
+ let fs_accessSyncSpy: jest.SpiedFunction<typeof fs.accessSync>
36
+ let fs_existsSyncSpy: jest.SpiedFunction<typeof fs.existsSync>
37
+ let path_resolveSpy: jest.SpiedFunction<typeof path.resolve>
38
+
39
+ beforeEach(() => {
40
+ fs_accessSyncSpy = jest
41
+ .spyOn(fs, 'accessSync')
42
+ .mockImplementation(() => {})
43
+ fs_existsSyncSpy = jest.spyOn(fs, 'existsSync').mockReturnValue(true)
44
+ path_resolveSpy = jest
45
+ .spyOn(path, 'resolve')
46
+ .mockReturnValueOnce('/path/to/summary.md')
47
+ })
48
+
49
+ afterEach(() => {
50
+ fs_accessSyncSpy.mockRestore()
51
+ fs_existsSyncSpy.mockRestore()
52
+ path_resolveSpy.mockRestore()
53
+ })
54
+
55
+ it('Resolves the summary file path from the environment', async () => {
56
+ await expect(summary.filePath()).resolves.toBe('/path/to/summary.md')
57
+
58
+ expect(fs_accessSyncSpy).toHaveBeenCalledWith(
59
+ '/path/to/summary.md',
60
+ fs.constants.R_OK | fs.constants.W_OK
61
+ )
62
+ })
63
+
64
+ it('Returns the already-resolved file path', async () => {
65
+ await summary.filePath()
66
+ await summary.filePath()
67
+ await summary.filePath()
68
+
69
+ expect(fs_accessSyncSpy).toHaveBeenCalledTimes(1)
70
+ expect(fs_accessSyncSpy).toHaveBeenNthCalledWith(
71
+ 1,
72
+ '/path/to/summary.md',
73
+ fs.constants.R_OK | fs.constants.W_OK
74
+ )
75
+
76
+ await expect(summary.filePath()).resolves.toBe('/path/to/summary.md')
77
+ })
78
+
79
+ it('Throws an error if the environment variable is not set', async () => {
80
+ CoreMeta.stepSummaryPath = ''
81
+
82
+ await expect(summary.filePath()).rejects.toThrow(
83
+ 'Unable to find environment variable for $GITHUB_STEP_SUMMARY. Check if your runtime environment supports job summaries.'
84
+ )
85
+ })
86
+
87
+ it('Throws an error if the file does not exist', async () => {
88
+ fs_accessSyncSpy.mockReset().mockImplementation(() => {
89
+ throw new Error('File does not exist')
90
+ })
91
+
92
+ await expect(summary.filePath()).rejects.toThrow(
93
+ `Unable to access summary file: '/path/to/summary.md'. Check if the file has correct read/write permissions.`
94
+ )
95
+ })
96
+ })
97
+
98
+ describe('wrap()', () => {
99
+ it('Wraps the input string with the provided tag', () => {
100
+ expect(summary.wrap('div', 'text')).toBe('<div>text</div>')
101
+ })
102
+
103
+ it('Creates a self-closing tag when no input string is provided', () => {
104
+ expect(summary.wrap('img', null)).toBe('<img>')
105
+ })
106
+
107
+ it('Adds HTML attributes', () => {
108
+ expect(
109
+ summary.wrap('a', 'GitHub.com', {
110
+ href: 'https://github.com',
111
+ target: '_blank'
112
+ })
113
+ ).toBe('<a href="https://github.com" target="_blank">GitHub.com</a>')
114
+ })
115
+ })
116
+
117
+ describe('write()', () => {
118
+ let fs_accessSyncSpy: jest.SpiedFunction<typeof fs.accessSync>
119
+ let fs_appendFileSyncSpy: jest.SpiedFunction<typeof fs.appendFileSync>
120
+ let fs_existsSyncSpy: jest.SpiedFunction<typeof fs.existsSync>
121
+ let fs_writeFileSyncSpy: jest.SpiedFunction<typeof fs.writeFileSync>
122
+ let path_resolveSpy: jest.SpiedFunction<typeof path.resolve>
123
+
124
+ beforeEach(() => {
125
+ fs_accessSyncSpy = jest
126
+ .spyOn(fs, 'accessSync')
127
+ .mockImplementation(() => {})
128
+ fs_appendFileSyncSpy = jest
129
+ .spyOn(fs, 'appendFileSync')
130
+ .mockImplementation(() => {})
131
+ fs_existsSyncSpy = jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true)
132
+ fs_writeFileSyncSpy = jest
133
+ .spyOn(fs, 'writeFileSync')
134
+ .mockImplementation(() => {})
135
+ path_resolveSpy = jest
136
+ .spyOn(path, 'resolve')
137
+ .mockReturnValueOnce('/path/to/summary.md')
138
+
139
+ // Add some text to test with
140
+ summary.addRaw('text')
141
+ })
142
+
143
+ afterEach(() => {
144
+ fs_accessSyncSpy.mockRestore()
145
+ fs_appendFileSyncSpy.mockRestore()
146
+ fs_existsSyncSpy.mockRestore()
147
+ fs_writeFileSyncSpy.mockRestore()
148
+ path_resolveSpy.mockRestore()
149
+
150
+ // Clear the buffer for the next test
151
+ summary.emptyBuffer()
152
+ })
153
+
154
+ it('Appends content to the summary file', async () => {
155
+ await summary.write()
156
+
157
+ expect(fs_existsSyncSpy).toHaveBeenCalledWith('/path/to/summary.md')
158
+ expect(fs_writeFileSyncSpy).not.toHaveBeenCalled()
159
+ expect(fs_appendFileSyncSpy).toHaveBeenCalledWith(
160
+ '/path/to/summary.md',
161
+ 'text',
162
+ { encoding: 'utf8' }
163
+ )
164
+ })
165
+
166
+ it('Creates the summary file if it does not exist', async () => {
167
+ fs_existsSyncSpy.mockReset().mockReturnValueOnce(false)
168
+
169
+ await summary.write()
170
+
171
+ expect(fs_existsSyncSpy).toHaveBeenCalledWith('/path/to/summary.md')
172
+ expect(fs_writeFileSyncSpy).toHaveBeenCalledWith(
173
+ '/path/to/summary.md',
174
+ '',
175
+ { encoding: 'utf8' }
176
+ )
177
+ expect(fs_appendFileSyncSpy).toHaveBeenCalledWith(
178
+ '/path/to/summary.md',
179
+ 'text',
180
+ { encoding: 'utf8' }
181
+ )
182
+ })
183
+
184
+ it('Overwrites the summary file', async () => {
185
+ await summary.write({ overwrite: true })
186
+
187
+ expect(fs_existsSyncSpy).toHaveBeenCalledWith('/path/to/summary.md')
188
+ expect(fs_writeFileSyncSpy).toHaveBeenCalledWith(
189
+ '/path/to/summary.md',
190
+ 'text',
191
+ { encoding: 'utf8' }
192
+ )
193
+ expect(fs_appendFileSyncSpy).not.toHaveBeenCalled()
194
+ })
195
+ })
196
+
197
+ describe('clear()', () => {
198
+ it('Clears the buffer', async () => {
199
+ const summary_emptyBufferSpy = jest
200
+ .spyOn(summary, 'emptyBuffer')
201
+ .mockReturnValue(summary)
202
+ const summary_writeSpy = jest
203
+ .spyOn(summary, 'write')
204
+ .mockResolvedValue(summary)
205
+
206
+ await summary.clear()
207
+
208
+ expect(summary_emptyBufferSpy).toHaveBeenCalled()
209
+ expect(summary_writeSpy).toHaveBeenCalled()
210
+ })
211
+ })
212
+
213
+ describe('stringify()', () => {
214
+ it('Returns the buffer', () => {
215
+ summary.addRaw('text')
216
+
217
+ expect(summary.stringify()).toEqual('text')
218
+ })
219
+ })
220
+
221
+ describe('isEmptyBuffer()', () => {
222
+ it('Returns true if the buffer is empty', () => {
223
+ expect(summary.isEmptyBuffer()).toBe(true)
224
+ })
225
+
226
+ it('Returns false if the buffer is not empty', () => {
227
+ summary.addRaw('text')
228
+
229
+ expect(summary.isEmptyBuffer()).toBe(false)
230
+ })
231
+ })
232
+
233
+ describe('emptyBuffer()', () => {
234
+ it('Empties the buffer', () => {
235
+ summary.addRaw('text')
236
+ summary.emptyBuffer()
237
+
238
+ expect(summary.isEmptyBuffer()).toBe(true)
239
+ expect(summary.stringify()).toEqual('')
240
+ })
241
+ })
242
+
243
+ describe('addRaw()', () => {
244
+ it('Adds text', () => {
245
+ summary.addRaw('text')
246
+
247
+ expect(summary.stringify()).toEqual('text')
248
+ })
249
+
250
+ it('Adds an EOL', () => {
251
+ const summary_addEOLSpy = jest
252
+ .spyOn(summary, 'addEOL')
253
+ .mockReturnValue(summary)
254
+
255
+ summary.addRaw('text', true)
256
+
257
+ expect(summary.stringify()).toEqual('text')
258
+ expect(summary_addEOLSpy).toHaveBeenCalled()
259
+ })
260
+ })
261
+
262
+ describe('addEOL()', () => {
263
+ it('Adds an EOL', () => {
264
+ const summary_addRawSpy = jest
265
+ .spyOn(summary, 'addRaw')
266
+ .mockReturnValue(summary)
267
+
268
+ summary.addEOL()
269
+
270
+ expect(summary_addRawSpy).toHaveBeenCalledWith(EOL)
271
+ })
272
+ })
273
+
274
+ describe('addCodeBlock()', () => {
275
+ it('Adds a code block', () => {
276
+ summary.addCodeBlock('text')
277
+
278
+ expect(summary.stringify() === `<pre><code>text</code></pre>${EOL}`).toBe(
279
+ true
280
+ )
281
+ })
282
+
283
+ it('Adds a code block with syntax highlighting', () => {
284
+ summary.addCodeBlock('text', 'javascript')
285
+
286
+ expect(
287
+ summary.stringify() ===
288
+ `<pre lang="javascript"><code>text</code></pre>${EOL}`
289
+ ).toBe(true)
290
+ })
291
+ })
292
+
293
+ describe('addList()', () => {
294
+ it('Adds an unordered list', () => {
295
+ summary.addList(['text', 'text'])
296
+
297
+ expect(
298
+ summary.stringify() === `<ul><li>text</li><li>text</li></ul>${EOL}`
299
+ ).toBe(true)
300
+ })
301
+
302
+ it('Adds an ordered list', () => {
303
+ summary.addList(['text', 'text'], true)
304
+
305
+ expect(
306
+ summary.stringify() === `<ol><li>text</li><li>text</li></ol>${EOL}`
307
+ ).toBe(true)
308
+ })
309
+ })
310
+
311
+ describe('addTable()', () => {
312
+ it('Adds a table', () => {
313
+ summary.addTable([
314
+ [
315
+ {
316
+ data: 'text',
317
+ header: true,
318
+ colspan: '1',
319
+ rowspan: '1'
320
+ },
321
+ {
322
+ data: 'text',
323
+ header: true,
324
+ colspan: '1',
325
+ rowspan: '1'
326
+ },
327
+ {
328
+ data: 'text',
329
+ header: true
330
+ }
331
+ ],
332
+ [
333
+ {
334
+ data: 'text'
335
+ },
336
+ 'text',
337
+ 'text'
338
+ ]
339
+ ])
340
+
341
+ expect(
342
+ summary.stringify() ===
343
+ `<table><tr><th colspan="1" rowspan="1">text</th><th colspan="1" rowspan="1">text</th><th>text</th></tr><tr><td>text</td><td>text</td><td>text</td></tr></table>${EOL}`
344
+ ).toBe(true)
345
+ })
346
+ })
347
+
348
+ describe('addDetails()', () => {
349
+ it('Adds a details element', () => {
350
+ summary.addDetails('label', 'text')
351
+
352
+ expect(
353
+ summary.stringify() ===
354
+ `<details><summary>label</summary>text</details>${EOL}`
355
+ ).toBe(true)
356
+ })
357
+ })
358
+
359
+ describe('addImage()', () => {
360
+ it('Adds an image', () => {
361
+ summary.addImage('src', 'alt')
362
+
363
+ expect(summary.stringify() === `<img src="src" alt="alt">${EOL}`).toBe(
364
+ true
365
+ )
366
+ })
367
+
368
+ it('Adds an image with options', () => {
369
+ summary.addImage('src', 'alt', {
370
+ width: '100',
371
+ height: '100'
372
+ })
373
+
374
+ expect(
375
+ summary.stringify() ===
376
+ `<img src="src" alt="alt" width="100" height="100">${EOL}`
377
+ ).toBe(true)
378
+ })
379
+ })
380
+
381
+ describe('addHeading()', () => {
382
+ it('Adds a heading (no level)', () => {
383
+ summary.addHeading('text')
384
+
385
+ expect(summary.stringify() === `<h1>text</h1>${EOL}`).toBe(true)
386
+ })
387
+
388
+ it('Adds a heading (number level)', () => {
389
+ summary.addHeading('text', 2)
390
+
391
+ expect(summary.stringify() === `<h2>text</h2>${EOL}`).toBe(true)
392
+ })
393
+
394
+ it('Adds a heading (string level)', () => {
395
+ summary.addHeading('text', '3')
396
+
397
+ expect(summary.stringify() === `<h3>text</h3>${EOL}`).toBe(true)
398
+ })
399
+
400
+ it('Adds a heading (out of bounds level)', () => {
401
+ summary.addHeading('text', -10)
402
+
403
+ expect(summary.stringify() === `<h1>text</h1>${EOL}`).toBe(true)
404
+ })
405
+
406
+ it('Adds a heading (NaN level)', () => {
407
+ summary.addHeading('text', 'text')
408
+
409
+ expect(summary.stringify() === `<h1>text</h1>${EOL}`).toBe(true)
410
+ })
411
+ })
412
+
413
+ describe('addSeparator()', () => {
414
+ it('Adds a horizontal rule', () => {
415
+ summary.addSeparator()
416
+
417
+ expect(summary.stringify() === `<hr>${EOL}`).toBe(true)
418
+ })
419
+ })
420
+
421
+ describe('addBreak()', () => {
422
+ it('Adds a line break', () => {
423
+ summary.addBreak()
424
+
425
+ expect(summary.stringify() === `<br>${EOL}`).toBe(true)
426
+ })
427
+ })
428
+
429
+ describe('addQuote()', () => {
430
+ it('Adds a quote', () => {
431
+ summary.addQuote('text')
432
+
433
+ expect(
434
+ summary.stringify() === `<blockquote>text</blockquote>${EOL}`
435
+ ).toBe(true)
436
+ })
437
+
438
+ it('Adds a quote with citation', () => {
439
+ summary.addQuote('text', 'citation')
440
+
441
+ expect(
442
+ summary.stringify() ===
443
+ `<blockquote cite="citation">text</blockquote>${EOL}`
444
+ ).toBe(true)
445
+ })
446
+ })
447
+
448
+ describe('addLink()', () => {
449
+ it('Adds a link', () => {
450
+ summary.addLink('text', 'url')
451
+
452
+ expect(summary.stringify() === `<a href="url">text</a>${EOL}`).toBe(true)
453
+ })
454
+ })
455
+ })
@@ -0,0 +1,72 @@
1
+ import { jest } from '@jest/globals'
2
+ import { ResetCoreMetadata } from '../../src/stubs/core/core.js'
3
+ import { EnvMeta, ResetEnvMetadata } from '../../src/stubs/env.js'
4
+ import type { EnvMetadata } from '../../src/types.js'
5
+
6
+ /** Empty EnvMetadata Object */
7
+ const empty: EnvMetadata = {
8
+ actionFile: '',
9
+ actionPath: '',
10
+ artifacts: [],
11
+ caches: {},
12
+ dotenvFile: '',
13
+ entrypoint: '',
14
+ env: {},
15
+ inputs: {},
16
+ outputs: {},
17
+ path: '',
18
+ preEntrypoint: undefined,
19
+ postEntrypoint: undefined
20
+ }
21
+
22
+ // Prevent output during tests
23
+ jest.spyOn(console, 'log').mockImplementation(() => {})
24
+
25
+ describe('Env', () => {
26
+ beforeEach(() => {
27
+ // Reset metadata
28
+ ResetEnvMetadata()
29
+ ResetCoreMetadata()
30
+ })
31
+
32
+ afterEach(() => {
33
+ jest.resetAllMocks()
34
+ })
35
+
36
+ describe('EnvMeta', () => {
37
+ it('Tracks updates to the environment metadata', () => {
38
+ // Initial state should be empty
39
+ expect(EnvMeta).toMatchObject(empty)
40
+
41
+ // Update the metadata
42
+ EnvMeta.actionFile = 'action.yml'
43
+ EnvMeta.actionPath = '/some/path'
44
+ EnvMeta.artifacts = [{ id: 1, name: 'test', size: 0 }]
45
+ EnvMeta.dotenvFile = '.env'
46
+ EnvMeta.entrypoint = 'main.ts'
47
+ EnvMeta.env = { TEST: 'test' }
48
+ EnvMeta.inputs = { input: { description: 'test input' } }
49
+ EnvMeta.outputs = { output: { description: 'test output' } }
50
+ EnvMeta.path = '/usr/bin'
51
+
52
+ // Verify the updated metadata
53
+ expect(EnvMeta).toMatchObject({
54
+ actionFile: 'action.yml',
55
+ actionPath: '/some/path',
56
+ artifacts: [{ id: 1, name: 'test', size: 0 }],
57
+ dotenvFile: '.env',
58
+ entrypoint: 'main.ts',
59
+ env: { TEST: 'test' },
60
+ inputs: { input: { description: 'test input' } },
61
+ outputs: { output: { description: 'test output' } },
62
+ path: '/usr/bin'
63
+ })
64
+
65
+ // Reset the metadata
66
+ ResetEnvMetadata()
67
+
68
+ // Verify the reset metadata
69
+ expect(EnvMeta).toMatchObject(empty)
70
+ })
71
+ })
72
+ })