@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.
- package/.checkov.yml +3 -0
- package/.env.example +379 -0
- package/.github/codeql/codeql-config.yml +7 -0
- package/.github/copilot-instructions.md +79 -0
- package/.github/dependabot.yml +32 -0
- package/.github/workflows/codeql-analysis.yml +53 -0
- package/.github/workflows/continuous-delivery.yml +93 -0
- package/.github/workflows/continuous-integration.yml +382 -0
- package/.github/workflows/linter.yml +47 -0
- package/.github/workflows/release.yaml +100 -0
- package/.github/workflows/version-check.yml +44 -0
- package/.grype.yml +151 -0
- package/.markdown-lint.yml +7 -0
- package/.mega-linter.yml +188 -0
- package/.node-version +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc.yml +14 -0
- package/.vscode/launch.json +15 -0
- package/.vscode/mcp.json +9 -0
- package/.vscode/settings.json +15 -0
- package/.vscode/tasks.json +51 -0
- package/.yaml-lint.yml +10 -0
- package/CHANGELOG.md +75 -0
- package/CODEOWNERS +3 -0
- package/CODE_OF_CONDUCT.md +74 -0
- package/CONTRIBUTING.md +140 -0
- package/LICENSE +21 -0
- package/README.md +277 -2
- package/SECURITY.md +42 -0
- package/SUPPORT.md +19 -0
- package/__fixtures__/@actions/core.ts +14 -0
- package/__fixtures__/@actions/exec.ts +9 -0
- package/__fixtures__/@actions/github.ts +3 -0
- package/__fixtures__/@actions/http-client.ts +9 -0
- package/__fixtures__/@actions/io.ts +9 -0
- package/__fixtures__/@octokit/rest.ts +18 -0
- package/__fixtures__/crypto.ts +7 -0
- package/__fixtures__/fs.ts +27 -0
- package/__fixtures__/javascript/no-export/.env.fixture +2 -0
- package/__fixtures__/javascript/no-export/action.yml +16 -0
- package/__fixtures__/javascript/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-export/package.json +12 -0
- package/__fixtures__/javascript/no-export/src/index.js +0 -0
- package/__fixtures__/javascript/no-export/src/main.js +0 -0
- package/__fixtures__/javascript/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript/no-import/action.yml +16 -0
- package/__fixtures__/javascript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-import/package.json +12 -0
- package/__fixtures__/javascript/no-import/src/index.js +3 -0
- package/__fixtures__/javascript/no-import/src/main.js +7 -0
- package/__fixtures__/javascript/success/.env.fixture +2 -0
- package/__fixtures__/javascript/success/action.yml +16 -0
- package/__fixtures__/javascript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/success/package.json +12 -0
- package/__fixtures__/javascript/success/post/index.js +3 -0
- package/__fixtures__/javascript/success/post/main.js +13 -0
- package/__fixtures__/javascript/success/pre/index.js +3 -0
- package/__fixtures__/javascript/success/pre/main.js +13 -0
- package/__fixtures__/javascript/success/src/index.js +3 -0
- package/__fixtures__/javascript/success/src/main.js +13 -0
- package/__fixtures__/javascript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/no-import/action.yml +16 -0
- package/__fixtures__/javascript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/no-import/package.json +13 -0
- package/__fixtures__/javascript-esm/no-import/src/index.js +3 -0
- package/__fixtures__/javascript-esm/no-import/src/main.js +7 -0
- package/__fixtures__/javascript-esm/success/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/success/action.yml +16 -0
- package/__fixtures__/javascript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/success/package.json +13 -0
- package/__fixtures__/javascript-esm/success/post/index.js +3 -0
- package/__fixtures__/javascript-esm/success/post/main.js +13 -0
- package/__fixtures__/javascript-esm/success/pre/index.js +3 -0
- package/__fixtures__/javascript-esm/success/pre/main.js +13 -0
- package/__fixtures__/javascript-esm/success/src/index.js +3 -0
- package/__fixtures__/javascript-esm/success/src/main.js +13 -0
- package/__fixtures__/path.ts +7 -0
- package/__fixtures__/payloads/issue_opened.json +33 -0
- package/__fixtures__/stream/promises.ts +3 -0
- package/__fixtures__/tsconfig-paths.ts +4 -0
- package/__fixtures__/typescript/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript/no-import/action.yml +16 -0
- package/__fixtures__/typescript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/no-import/package.json +15 -0
- package/__fixtures__/typescript/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript/no-import/tsconfig.json +20 -0
- package/__fixtures__/typescript/success/.env.fixture +2 -0
- package/__fixtures__/typescript/success/action.yml +16 -0
- package/__fixtures__/typescript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success/package.json +15 -0
- package/__fixtures__/typescript/success/post/index.ts +3 -0
- package/__fixtures__/typescript/success/post/main.ts +9 -0
- package/__fixtures__/typescript/success/pre/index.ts +3 -0
- package/__fixtures__/typescript/success/pre/main.ts +9 -0
- package/__fixtures__/typescript/success/src/index.ts +3 -0
- package/__fixtures__/typescript/success/src/main.ts +9 -0
- package/__fixtures__/typescript/success/tsconfig.json +20 -0
- package/__fixtures__/typescript/success-yaml/.env.fixture +2 -0
- package/__fixtures__/typescript/success-yaml/action.yaml +16 -0
- package/__fixtures__/typescript/success-yaml/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success-yaml/package.json +15 -0
- package/__fixtures__/typescript/success-yaml/post/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/post/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/pre/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/pre/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/src/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/src/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/tsconfig.json +20 -0
- package/__fixtures__/typescript-esm/no-export/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-export/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-export/package.json +17 -0
- package/__fixtures__/typescript-esm/no-export/src/index.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/src/main.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-import/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-import/package.json +17 -0
- package/__fixtures__/typescript-esm/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/success/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/success/action.yml +17 -0
- package/__fixtures__/typescript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/success/package.json +17 -0
- package/__fixtures__/typescript-esm/success/post/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/post/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/pre/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/pre/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/action.yml +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/package.json +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/tsconfig.json +21 -0
- package/__tests__/command.test.ts +224 -0
- package/__tests__/stubs/artifact/internal/client.test.ts +340 -0
- package/__tests__/stubs/artifact/internal/delete/delete-artifact.test.ts +152 -0
- package/__tests__/stubs/artifact/internal/download/download-artifact.test.ts +119 -0
- package/__tests__/stubs/artifact/internal/find/get-artifact.test.ts +237 -0
- package/__tests__/stubs/artifact/internal/find/list-artifacts.test.ts +218 -0
- package/__tests__/stubs/artifact/internal/find/retry-options.test.ts +54 -0
- package/__tests__/stubs/artifact/internal/shared/config.test.ts +91 -0
- package/__tests__/stubs/artifact/internal/shared/errors.test.ts +38 -0
- package/__tests__/stubs/artifact/internal/shared/user-agent.test.ts +22 -0
- package/__tests__/stubs/artifact/internal/upload/path-and-artifact-name-validation.test.ts +53 -0
- package/__tests__/stubs/artifact/internal/upload/upload-artifact.test.ts +126 -0
- package/__tests__/stubs/artifact/internal/upload/upload-zip-specification.test.ts +49 -0
- package/__tests__/stubs/cache/cache.test.ts +357 -0
- package/__tests__/stubs/cache/errors.test.ts +55 -0
- package/__tests__/stubs/cache/internal/cacheUtils.test.ts +109 -0
- package/__tests__/stubs/cache/internal/constants.test.ts +81 -0
- package/__tests__/stubs/cache/internal/tar.test.ts +129 -0
- package/__tests__/stubs/core/core.test.ts +760 -0
- package/__tests__/stubs/core/path-utils.test.ts +45 -0
- package/__tests__/stubs/core/platform.test.ts +89 -0
- package/__tests__/stubs/core/summary.test.ts +455 -0
- package/__tests__/stubs/env.test.ts +72 -0
- package/__tests__/stubs/github/context.test.ts +73 -0
- package/__tests__/stubs/github/github.test.ts +15 -0
- package/__tests__/stubs/github/internal/utils.test.ts +98 -0
- package/__tests__/stubs/github/utils.test.ts +16 -0
- package/__tests__/utils/config.test.ts +78 -0
- package/__tests__/utils/output.test.ts +32 -0
- package/__tests__/utils/package.test.ts +33 -0
- package/badges/coverage.svg +1 -0
- package/bin/local-action.js +121 -0
- package/docs/create-a-job-summary.md +32 -0
- package/docs/debugging-in-vscode.md +27 -0
- package/docs/img/job-summary.png +0 -0
- package/docs/supported-functionality.md +126 -0
- package/eslint.config.mjs +74 -0
- package/jest.config.ts +41 -0
- package/package.json +93 -4
- package/src/command.ts +171 -0
- package/src/commands/run.ts +616 -0
- package/src/index.ts +21 -0
- package/src/stubs/artifact/artifact.ts +17 -0
- package/src/stubs/artifact/internal/client.ts +400 -0
- package/src/stubs/artifact/internal/delete/delete-artifact.ts +126 -0
- package/src/stubs/artifact/internal/download/download-artifact.ts +309 -0
- package/src/stubs/artifact/internal/find/get-artifact.ts +135 -0
- package/src/stubs/artifact/internal/find/list-artifacts.ts +188 -0
- package/src/stubs/artifact/internal/find/retry-options.ts +57 -0
- package/src/stubs/artifact/internal/shared/config.ts +64 -0
- package/src/stubs/artifact/internal/shared/errors.ts +53 -0
- package/src/stubs/artifact/internal/shared/interfaces.ts +195 -0
- package/src/stubs/artifact/internal/shared/user-agent.ts +13 -0
- package/src/stubs/artifact/internal/upload/path-and-artifact-name-validation.ts +92 -0
- package/src/stubs/artifact/internal/upload/upload-artifact.ts +127 -0
- package/src/stubs/artifact/internal/upload/upload-zip-specification.ts +108 -0
- package/src/stubs/artifact/internal/upload/zip.ts +122 -0
- package/src/stubs/cache/cache.ts +334 -0
- package/src/stubs/cache/errors.ts +31 -0
- package/src/stubs/cache/interfaces.ts +4 -0
- package/src/stubs/cache/internal/cacheUtils.ts +207 -0
- package/src/stubs/cache/internal/constants.ts +45 -0
- package/src/stubs/cache/internal/tar.ts +374 -0
- package/src/stubs/cache/options.ts +91 -0
- package/src/stubs/core/core.ts +743 -0
- package/src/stubs/core/path-utils.ts +39 -0
- package/src/stubs/core/platform.ts +132 -0
- package/src/stubs/core/summary.ts +399 -0
- package/src/stubs/env.ts +40 -0
- package/src/stubs/github/context.ts +94 -0
- package/src/stubs/github/github.ts +29 -0
- package/src/stubs/github/interfaces.ts +52 -0
- package/src/stubs/github/internal/utils.ts +83 -0
- package/src/stubs/github/utils.ts +52 -0
- package/src/types/quibble.d.ts +5 -0
- package/src/types.ts +116 -0
- package/src/utils/config.ts +47 -0
- package/src/utils/output.ts +20 -0
- package/src/utils/package.ts +38 -0
- package/tsconfig.base.json +29 -0
- package/tsconfig.eslint.json +22 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last Reviewed Commit: 6876e2a664ec02908178087905b9155e9892a437
|
|
3
|
+
* Last Reviewed Date: 2026-01-16
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
*
|
|
7
|
+
* - Across the board, the `issueCommand` and `issueFileCommand` calls were
|
|
8
|
+
* removed for easier implementation and testing.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import path from 'path'
|
|
12
|
+
import type { CoreMetadata } from '../../types.js'
|
|
13
|
+
import { EnvMeta } from '../env.js'
|
|
14
|
+
import { toPlatformPath, toPosixPath, toWin32Path } from './path-utils.js'
|
|
15
|
+
import * as platform from './platform.js'
|
|
16
|
+
import { Summary } from './summary.js'
|
|
17
|
+
|
|
18
|
+
export const CORE_STUBS = {
|
|
19
|
+
addPath,
|
|
20
|
+
debug,
|
|
21
|
+
endGroup,
|
|
22
|
+
error,
|
|
23
|
+
exportVariable,
|
|
24
|
+
getBooleanInput,
|
|
25
|
+
getIDToken,
|
|
26
|
+
getInput,
|
|
27
|
+
getMultilineInput,
|
|
28
|
+
getState,
|
|
29
|
+
group,
|
|
30
|
+
info,
|
|
31
|
+
isDebug,
|
|
32
|
+
notice,
|
|
33
|
+
platform,
|
|
34
|
+
saveState,
|
|
35
|
+
setCommandEcho,
|
|
36
|
+
setFailed,
|
|
37
|
+
setOutput,
|
|
38
|
+
setSecret,
|
|
39
|
+
startGroup,
|
|
40
|
+
summary: new Summary(),
|
|
41
|
+
toPlatformPath,
|
|
42
|
+
toPosixPath,
|
|
43
|
+
toWin32Path,
|
|
44
|
+
warning
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Metadata for `@actions/core`
|
|
49
|
+
*/
|
|
50
|
+
export const CoreMeta: CoreMetadata = {
|
|
51
|
+
echo: false,
|
|
52
|
+
exitCode: 0,
|
|
53
|
+
exitMessage: '',
|
|
54
|
+
outputs: {},
|
|
55
|
+
secrets: [],
|
|
56
|
+
state: {},
|
|
57
|
+
stepDebug: process.env.ACTIONS_STEP_DEBUG === 'true',
|
|
58
|
+
stepSummaryPath:
|
|
59
|
+
/* istanbul ignore next*/ process.env.GITHUB_STEP_SUMMARY ?? '',
|
|
60
|
+
colors: {
|
|
61
|
+
cyan: (msg: string) => console.log(msg),
|
|
62
|
+
blue: (msg: string) => console.log(msg),
|
|
63
|
+
gray: (msg: string) => console.log(msg),
|
|
64
|
+
green: (msg: string) => console.log(msg),
|
|
65
|
+
magenta: (msg: string) => console.log(msg),
|
|
66
|
+
red: (msg: string) => console.log(msg),
|
|
67
|
+
white: (msg: string) => console.log(msg),
|
|
68
|
+
yellow: (msg: string) => console.log(msg)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Resets the core metadata
|
|
74
|
+
*
|
|
75
|
+
* @returns void
|
|
76
|
+
*/
|
|
77
|
+
export function ResetCoreMetadata(): void {
|
|
78
|
+
CoreMeta.echo = false
|
|
79
|
+
CoreMeta.exitCode = 0
|
|
80
|
+
CoreMeta.exitMessage = ''
|
|
81
|
+
CoreMeta.outputs = {}
|
|
82
|
+
CoreMeta.secrets = []
|
|
83
|
+
CoreMeta.state = {}
|
|
84
|
+
CoreMeta.stepDebug = process.env.ACTIONS_STEP_DEBUG === 'true'
|
|
85
|
+
CoreMeta.stepSummaryPath = process.env.GITHUB_STEP_SUMMARY ?? ''
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Optional properties that can be sent with annotation commands (notice, error,
|
|
90
|
+
* and warning).
|
|
91
|
+
*/
|
|
92
|
+
export type AnnotationProperties = {
|
|
93
|
+
/** A title for the annotation. */
|
|
94
|
+
title?: string
|
|
95
|
+
|
|
96
|
+
/** The path of the file for which the annotation should be created. */
|
|
97
|
+
file?: string
|
|
98
|
+
|
|
99
|
+
/** The start line for the annotation. */
|
|
100
|
+
startLine?: number
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The end line for the annotation. Defaults to `startLine` when `startLine`
|
|
104
|
+
* is provided.
|
|
105
|
+
*/
|
|
106
|
+
endLine?: number
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The start column for the annotation. Cannot be sent when `startLine` and
|
|
110
|
+
* `endLine` are different values.
|
|
111
|
+
*/
|
|
112
|
+
startColumn?: number
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The end column for the annotation. Cannot be sent when `startLine` and
|
|
116
|
+
* `endLine` are different values. Defaults to `startColumn` when
|
|
117
|
+
* `startColumn` is provided.
|
|
118
|
+
*/
|
|
119
|
+
endColumn?: number
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Options for getInput.
|
|
124
|
+
*/
|
|
125
|
+
export type InputOptions = {
|
|
126
|
+
/**
|
|
127
|
+
* Optional. Whether the input is required. If required and not present,
|
|
128
|
+
* will throw. Defaults to false.
|
|
129
|
+
*/
|
|
130
|
+
required?: boolean
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Optional. Whether leading/trailing whitespace will be trimmed for the
|
|
134
|
+
* input. Defaults to true.
|
|
135
|
+
*/
|
|
136
|
+
trimWhitespace?: boolean
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Prepends to the PATH
|
|
141
|
+
*
|
|
142
|
+
* @remarks
|
|
143
|
+
*
|
|
144
|
+
* - Use environment metadata to track updated PATH
|
|
145
|
+
*
|
|
146
|
+
* @param inputPath The path to prepend to the PATH
|
|
147
|
+
* @returns void
|
|
148
|
+
*/
|
|
149
|
+
export function addPath(inputPath: string): void {
|
|
150
|
+
EnvMeta.path = `${inputPath}${path.delimiter}${process.env.PATH}`
|
|
151
|
+
process.env.PATH = EnvMeta.path
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
//-----------------------------------------------------------------------
|
|
155
|
+
// Variables
|
|
156
|
+
//-----------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Saves an environment variable
|
|
160
|
+
*
|
|
161
|
+
* @remarks
|
|
162
|
+
*
|
|
163
|
+
* - Saves variables to the environment metadata.
|
|
164
|
+
*
|
|
165
|
+
* @param name The name of the environment variable
|
|
166
|
+
* @param value The value of the environment variable
|
|
167
|
+
* @returns void
|
|
168
|
+
*/
|
|
169
|
+
export function exportVariable(
|
|
170
|
+
name: string,
|
|
171
|
+
value: string | undefined | null | object
|
|
172
|
+
): void {
|
|
173
|
+
// Convert the value to a string
|
|
174
|
+
value =
|
|
175
|
+
value === undefined || value === null
|
|
176
|
+
? ''
|
|
177
|
+
: typeof value === 'string' || value instanceof String
|
|
178
|
+
? value.toString()
|
|
179
|
+
: JSON.stringify(value)
|
|
180
|
+
|
|
181
|
+
EnvMeta.env[name] = value
|
|
182
|
+
process.env[name] = value
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Register a secret to mask it in logs
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
*
|
|
190
|
+
* - Adds secrets to core metadata.
|
|
191
|
+
*
|
|
192
|
+
* @param secret The value to register
|
|
193
|
+
* @returns void
|
|
194
|
+
*/
|
|
195
|
+
export function setSecret(secret: string): void {
|
|
196
|
+
CoreMeta.secrets.push(secret)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Gets the action input from the environment variables
|
|
201
|
+
*
|
|
202
|
+
* @remarks
|
|
203
|
+
*
|
|
204
|
+
* - Adds support for lowercase environment variables.
|
|
205
|
+
* - Checks default values from the action.yml file.
|
|
206
|
+
*
|
|
207
|
+
* @param name The name of the input
|
|
208
|
+
* @param options The options for the input
|
|
209
|
+
* @returns The value of the input
|
|
210
|
+
*/
|
|
211
|
+
export function getInput(name: string, options?: InputOptions): string {
|
|
212
|
+
// Get input by name, or an empty string if not found
|
|
213
|
+
let input: string =
|
|
214
|
+
process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] ||
|
|
215
|
+
process.env[`INPUT_${name.replace(/ /g, '_')}`] ||
|
|
216
|
+
''
|
|
217
|
+
|
|
218
|
+
// If the input is not present in the environment variables, it has not been
|
|
219
|
+
// set. In that case, check the default value.
|
|
220
|
+
if (input === '' && EnvMeta.inputs[name]?.default !== undefined)
|
|
221
|
+
input = EnvMeta.inputs[name].default.toString()
|
|
222
|
+
|
|
223
|
+
// Throw an error if the input is required and not supplied
|
|
224
|
+
if (options && options.required === true && input === '')
|
|
225
|
+
throw new Error(`Input required and not supplied: ${name}`)
|
|
226
|
+
|
|
227
|
+
// Trim whitespace, if specified
|
|
228
|
+
if (options && options.trimWhitespace === true) input = input.trim()
|
|
229
|
+
|
|
230
|
+
return input
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Gets multiline inputs from environment variables
|
|
235
|
+
*
|
|
236
|
+
* @remarks
|
|
237
|
+
*
|
|
238
|
+
* - Adds support for lowercase environment variables.
|
|
239
|
+
* - Checks default values from the action.yml file.
|
|
240
|
+
*
|
|
241
|
+
* @param name The name of the input
|
|
242
|
+
* @param options The options for the input
|
|
243
|
+
* @returns The value of the input
|
|
244
|
+
*/
|
|
245
|
+
export function getMultilineInput(
|
|
246
|
+
name: string,
|
|
247
|
+
options?: InputOptions
|
|
248
|
+
): string[] {
|
|
249
|
+
// Get input by name, split by newline, and filter out empty strings
|
|
250
|
+
let input: string[] = (
|
|
251
|
+
process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] ||
|
|
252
|
+
process.env[`INPUT_${name.replace(/ /g, '_')}`] ||
|
|
253
|
+
''
|
|
254
|
+
)
|
|
255
|
+
.split('\n')
|
|
256
|
+
.filter(x => x !== '')
|
|
257
|
+
|
|
258
|
+
// If the input is not present in the environment variables, it has not been
|
|
259
|
+
// set. In that case, check the default value.
|
|
260
|
+
if (input.length === 0 && EnvMeta.inputs[name]?.default !== undefined)
|
|
261
|
+
input = EnvMeta.inputs[name].default
|
|
262
|
+
.toString()
|
|
263
|
+
.split('\n')
|
|
264
|
+
.filter(x => x !== '')
|
|
265
|
+
|
|
266
|
+
// Throw an error if the input is required and not supplied
|
|
267
|
+
if (options && options.required === true && input.length === 0)
|
|
268
|
+
throw new Error(`Input required and not supplied: ${name}`)
|
|
269
|
+
|
|
270
|
+
// Trim whitespace, if specified
|
|
271
|
+
if (options && options.trimWhitespace === true)
|
|
272
|
+
return input.map(x => x.trim())
|
|
273
|
+
|
|
274
|
+
return input
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Gets boolean inputs from environment variables
|
|
279
|
+
*
|
|
280
|
+
* @remarks
|
|
281
|
+
*
|
|
282
|
+
* - Adds support for lowercase environment variables.
|
|
283
|
+
* - Checks default values from the action.yml file.
|
|
284
|
+
*
|
|
285
|
+
* @param name The name of the input
|
|
286
|
+
* @param options The options for the input
|
|
287
|
+
* @returns The value of the input
|
|
288
|
+
*/
|
|
289
|
+
export function getBooleanInput(name: string, options?: InputOptions): boolean {
|
|
290
|
+
// This is effectively a copy of the actual `getInput` function, instead of
|
|
291
|
+
// using proxyquire's `callThru()` option.
|
|
292
|
+
|
|
293
|
+
// Get input by name, or an empty string if not found
|
|
294
|
+
let input: string = (
|
|
295
|
+
process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] ||
|
|
296
|
+
process.env[`INPUT_${name.replace(/ /g, '_')}`] ||
|
|
297
|
+
''
|
|
298
|
+
).trim()
|
|
299
|
+
|
|
300
|
+
// If the input is not present in the environment variables, it has not been
|
|
301
|
+
// set. In that case, check the default value.
|
|
302
|
+
if (input === '' && EnvMeta.inputs[name]?.default !== undefined) {
|
|
303
|
+
// we call .toString in case its a boolean
|
|
304
|
+
input = EnvMeta.inputs[name].default.toString().trim()
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Throw an error if the input is required and not supplied
|
|
308
|
+
if (input === '')
|
|
309
|
+
if (options && options.required === true) {
|
|
310
|
+
throw new Error(`Input required and not supplied: ${name}`)
|
|
311
|
+
} else {
|
|
312
|
+
// here is where we would ideally return either `false` or `undefined` but we'll need upstream changes
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (['true', 'True', 'TRUE'].includes(input)) return true
|
|
316
|
+
if (['false', 'False', 'FALSE'].includes(input)) return false
|
|
317
|
+
|
|
318
|
+
// Throw an error if the input is not a boolean
|
|
319
|
+
throw new TypeError(
|
|
320
|
+
`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
|
|
321
|
+
`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Saves outputs and logs to the console
|
|
327
|
+
*
|
|
328
|
+
* @remarks
|
|
329
|
+
*
|
|
330
|
+
* - Saves outputs to the core metadata.
|
|
331
|
+
* - Adds extra debugging output.
|
|
332
|
+
*
|
|
333
|
+
* @param name The name of the output
|
|
334
|
+
* @param value The value of the output
|
|
335
|
+
* @returns void
|
|
336
|
+
*/
|
|
337
|
+
export function setOutput(name: string, value: any): void {
|
|
338
|
+
// Ideally the value is a string, but if not, we must convert it.
|
|
339
|
+
const convertedValue =
|
|
340
|
+
typeof value === 'string'
|
|
341
|
+
? value
|
|
342
|
+
: value === undefined || value === null
|
|
343
|
+
? ''
|
|
344
|
+
: typeof value === 'object' || value instanceof Object
|
|
345
|
+
? JSON.stringify(value)
|
|
346
|
+
: value.toString()
|
|
347
|
+
|
|
348
|
+
// If an output contains a secret, log the following and skip adding to the
|
|
349
|
+
// core metadata.
|
|
350
|
+
//
|
|
351
|
+
// "Skip output {output.Key} since it may contain secret."
|
|
352
|
+
//
|
|
353
|
+
// This is done by GitHub Actions itself, not by @actions/core...
|
|
354
|
+
// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs#overview
|
|
355
|
+
if (CoreMeta.secrets.some(secret => convertedValue.includes(secret)))
|
|
356
|
+
return warning(`Skip output ${name} since it may contain secret.`)
|
|
357
|
+
|
|
358
|
+
// Save the output to the core metadata
|
|
359
|
+
CoreMeta.outputs[name] = convertedValue
|
|
360
|
+
|
|
361
|
+
// This command is deprecated...it is being used here so there's meaningful
|
|
362
|
+
// log output for debugging purposes.
|
|
363
|
+
CoreMeta.colors.cyan(`::set-output name=${name}::${convertedValue}`)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Enables or disables the echoing of commands into stdout.
|
|
368
|
+
*
|
|
369
|
+
* @remarks
|
|
370
|
+
*
|
|
371
|
+
* - Currently this does nothing.
|
|
372
|
+
*
|
|
373
|
+
* @param enabled Whether to enable command echoing
|
|
374
|
+
* @returns void
|
|
375
|
+
*/
|
|
376
|
+
export function setCommandEcho(enabled: boolean): void {
|
|
377
|
+
CoreMeta.echo = enabled
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
//-----------------------------------------------------------------------
|
|
381
|
+
// Results
|
|
382
|
+
//-----------------------------------------------------------------------
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Set the action status to failed
|
|
386
|
+
*
|
|
387
|
+
* @remarks
|
|
388
|
+
*
|
|
389
|
+
* - Sets exit code and message in core metadata.
|
|
390
|
+
* - Does not set a failure exit code for the process.
|
|
391
|
+
*
|
|
392
|
+
* @param message The message to log
|
|
393
|
+
* @returns void
|
|
394
|
+
*/
|
|
395
|
+
export function setFailed(message: string | Error): void {
|
|
396
|
+
CoreMeta.exitCode = 1
|
|
397
|
+
CoreMeta.exitMessage = message.toString()
|
|
398
|
+
|
|
399
|
+
error(message.toString())
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//-----------------------------------------------------------------------
|
|
403
|
+
// Logging Commands
|
|
404
|
+
//-----------------------------------------------------------------------
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Logs a message with optional annotations
|
|
408
|
+
*
|
|
409
|
+
* This is used internally by the other logging functions. It doesn't need to be
|
|
410
|
+
* called directly.
|
|
411
|
+
*
|
|
412
|
+
* @remarks
|
|
413
|
+
*
|
|
414
|
+
* - This is specific to the local-action tool and is used to centralize log
|
|
415
|
+
* formatting and styling.
|
|
416
|
+
*
|
|
417
|
+
* @param type The type of log message
|
|
418
|
+
* @param message The message to log
|
|
419
|
+
* @param properties The annotation properties
|
|
420
|
+
* @returns void
|
|
421
|
+
*/
|
|
422
|
+
export function log(
|
|
423
|
+
type: string,
|
|
424
|
+
message?: string,
|
|
425
|
+
properties: AnnotationProperties = {
|
|
426
|
+
title: undefined,
|
|
427
|
+
file: undefined,
|
|
428
|
+
startLine: undefined,
|
|
429
|
+
endLine: undefined,
|
|
430
|
+
startColumn: undefined,
|
|
431
|
+
endColumn: undefined
|
|
432
|
+
}
|
|
433
|
+
): void {
|
|
434
|
+
const params: string[] = []
|
|
435
|
+
|
|
436
|
+
const color =
|
|
437
|
+
{
|
|
438
|
+
debug: CoreMeta.colors.gray,
|
|
439
|
+
error: CoreMeta.colors.red,
|
|
440
|
+
warning: CoreMeta.colors.yellow,
|
|
441
|
+
notice: CoreMeta.colors.magenta,
|
|
442
|
+
info: CoreMeta.colors.white,
|
|
443
|
+
group: CoreMeta.colors.blue,
|
|
444
|
+
endgroup: CoreMeta.colors.blue
|
|
445
|
+
}[type] ?? CoreMeta.colors.gray
|
|
446
|
+
|
|
447
|
+
// Default endLine to startLine if not provided
|
|
448
|
+
if (properties.startLine && !properties.endLine)
|
|
449
|
+
properties.endLine = properties.startLine
|
|
450
|
+
|
|
451
|
+
// Default endColumn to startColumn if not provided
|
|
452
|
+
if (properties.startColumn && !properties.endColumn)
|
|
453
|
+
properties.endColumn = properties.startColumn
|
|
454
|
+
|
|
455
|
+
// Throw an error if startLine and endLine are different and startColumn or
|
|
456
|
+
// endColumn are set
|
|
457
|
+
if (
|
|
458
|
+
properties.startLine &&
|
|
459
|
+
properties.endLine &&
|
|
460
|
+
properties.startLine !== properties.endLine &&
|
|
461
|
+
(properties.startColumn || properties.endColumn)
|
|
462
|
+
)
|
|
463
|
+
throw new Error(
|
|
464
|
+
'Error: Annotations spanning multiple lines must not include startColumn or endColumn'
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
if (properties.title) params.push(`title=${properties.title}`)
|
|
468
|
+
if (properties.file) params.push(`file=${properties.file}`)
|
|
469
|
+
if (properties.startLine) params.push(`line=${properties.startLine}`)
|
|
470
|
+
if (properties.endLine) params.push(`endLine=${properties.endLine}`)
|
|
471
|
+
if (properties.startColumn) params.push(`col=${properties.startColumn}`)
|
|
472
|
+
if (properties.endColumn) params.push(`endColumn=${properties.endColumn}`)
|
|
473
|
+
|
|
474
|
+
if (message === undefined) return color(`::${type}::`)
|
|
475
|
+
|
|
476
|
+
// Check for any secrets and redact them
|
|
477
|
+
for (const secret of CoreMeta.secrets)
|
|
478
|
+
if (message?.includes(secret)) message = message.replaceAll(secret, '****')
|
|
479
|
+
|
|
480
|
+
if (params.length > 0) color(`::${type} ${params.join(',')}::${message}`)
|
|
481
|
+
else color(`::${type}::${message}`)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Returns true if debugging is enabled
|
|
486
|
+
*
|
|
487
|
+
* @remarks
|
|
488
|
+
*
|
|
489
|
+
* - Gets status from the core metadata.
|
|
490
|
+
*
|
|
491
|
+
* @returns Whether debugging is enabled
|
|
492
|
+
*/
|
|
493
|
+
export function isDebug(): boolean {
|
|
494
|
+
return CoreMeta.stepDebug
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Logs a debug message to the console
|
|
499
|
+
*
|
|
500
|
+
* E.g. `::debug::{message}`
|
|
501
|
+
*
|
|
502
|
+
* @remarks
|
|
503
|
+
*
|
|
504
|
+
* - Uses custom logging utility function.
|
|
505
|
+
*
|
|
506
|
+
* @param message The message to log
|
|
507
|
+
* @returns void
|
|
508
|
+
*/
|
|
509
|
+
export function debug(message: string): void {
|
|
510
|
+
// Only log debug messages if the `stepDebug` flag is set
|
|
511
|
+
if (!CoreMeta.stepDebug) return
|
|
512
|
+
|
|
513
|
+
log('debug', message)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Logs an error message to the console
|
|
518
|
+
*
|
|
519
|
+
* E.g. `::error file={name},line={line},endLine={endLine},title={title}::{message}`
|
|
520
|
+
*
|
|
521
|
+
* @remarks
|
|
522
|
+
*
|
|
523
|
+
* - Uses custom logging utility function.
|
|
524
|
+
*
|
|
525
|
+
* @param message The message to log
|
|
526
|
+
* @param properties The annotation properties
|
|
527
|
+
* @returns void
|
|
528
|
+
*/
|
|
529
|
+
export function error(
|
|
530
|
+
message: string | Error,
|
|
531
|
+
properties: AnnotationProperties = {
|
|
532
|
+
title: undefined,
|
|
533
|
+
file: undefined,
|
|
534
|
+
startLine: undefined,
|
|
535
|
+
endLine: undefined,
|
|
536
|
+
startColumn: undefined,
|
|
537
|
+
endColumn: undefined
|
|
538
|
+
}
|
|
539
|
+
): void {
|
|
540
|
+
log(
|
|
541
|
+
'error',
|
|
542
|
+
message instanceof Error ? message.toString() : message,
|
|
543
|
+
properties
|
|
544
|
+
)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Logs a warning message to the console
|
|
549
|
+
*
|
|
550
|
+
* E.g. `::warning file={name},line={line},endLine={endLine},title={title}::{message}`
|
|
551
|
+
*
|
|
552
|
+
* @remarks
|
|
553
|
+
*
|
|
554
|
+
* - Uses custom logging utility function.
|
|
555
|
+
*
|
|
556
|
+
* @param message The message to log
|
|
557
|
+
* @param properties The annotation properties
|
|
558
|
+
* @returns void
|
|
559
|
+
*/
|
|
560
|
+
export function warning(
|
|
561
|
+
message: string | Error,
|
|
562
|
+
properties: AnnotationProperties = {
|
|
563
|
+
title: undefined,
|
|
564
|
+
file: undefined,
|
|
565
|
+
startLine: undefined,
|
|
566
|
+
endLine: undefined,
|
|
567
|
+
startColumn: undefined,
|
|
568
|
+
endColumn: undefined
|
|
569
|
+
}
|
|
570
|
+
): void {
|
|
571
|
+
log(
|
|
572
|
+
'warning',
|
|
573
|
+
message instanceof Error ? message.toString() : message,
|
|
574
|
+
properties
|
|
575
|
+
)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Logs a notice message to the console
|
|
580
|
+
*
|
|
581
|
+
* E.g. `::notice file={name},line={line},endLine={endLine},title={title}::{message}`
|
|
582
|
+
*
|
|
583
|
+
* @remarks
|
|
584
|
+
*
|
|
585
|
+
* - Uses custom logging utility function.
|
|
586
|
+
*
|
|
587
|
+
* @param message The message to log
|
|
588
|
+
* @param properties The annotation properties
|
|
589
|
+
* @returns void
|
|
590
|
+
*/
|
|
591
|
+
export function notice(
|
|
592
|
+
message: string | Error,
|
|
593
|
+
properties: AnnotationProperties = {
|
|
594
|
+
title: undefined,
|
|
595
|
+
file: undefined,
|
|
596
|
+
startLine: undefined,
|
|
597
|
+
endLine: undefined,
|
|
598
|
+
startColumn: undefined,
|
|
599
|
+
endColumn: undefined
|
|
600
|
+
}
|
|
601
|
+
): void {
|
|
602
|
+
log(
|
|
603
|
+
'notice',
|
|
604
|
+
message instanceof Error ? message.toString() : message,
|
|
605
|
+
properties
|
|
606
|
+
)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Logs an info message to the console
|
|
611
|
+
*
|
|
612
|
+
* E.g. `::info::{message}`
|
|
613
|
+
*
|
|
614
|
+
* @remarks
|
|
615
|
+
*
|
|
616
|
+
* - Uses custom logging utility function.
|
|
617
|
+
*
|
|
618
|
+
* @param message The message to log
|
|
619
|
+
* @returns void
|
|
620
|
+
*/
|
|
621
|
+
export function info(message: string): void {
|
|
622
|
+
log('info', message)
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Starts a group of log lines
|
|
627
|
+
*
|
|
628
|
+
* @remarks
|
|
629
|
+
*
|
|
630
|
+
* - Uses custom logging utility function.
|
|
631
|
+
*
|
|
632
|
+
* @param title The title of the group
|
|
633
|
+
* @returns void
|
|
634
|
+
*/
|
|
635
|
+
export function startGroup(title: string): void {
|
|
636
|
+
log('group', title, {
|
|
637
|
+
title: undefined,
|
|
638
|
+
file: undefined,
|
|
639
|
+
startLine: undefined,
|
|
640
|
+
endLine: undefined,
|
|
641
|
+
startColumn: undefined,
|
|
642
|
+
endColumn: undefined
|
|
643
|
+
})
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Ends a group of log lines
|
|
648
|
+
*
|
|
649
|
+
* @remarks
|
|
650
|
+
*
|
|
651
|
+
* - Uses custom logging utility function.
|
|
652
|
+
*
|
|
653
|
+
* @param title The title of the group
|
|
654
|
+
* @returns void
|
|
655
|
+
*/
|
|
656
|
+
export function endGroup(): void {
|
|
657
|
+
log('endgroup', undefined, {
|
|
658
|
+
title: undefined,
|
|
659
|
+
file: undefined,
|
|
660
|
+
startLine: undefined,
|
|
661
|
+
endLine: undefined,
|
|
662
|
+
startColumn: undefined,
|
|
663
|
+
endColumn: undefined
|
|
664
|
+
})
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Wraps an asynchronous function call in a group
|
|
669
|
+
*
|
|
670
|
+
* @remarks
|
|
671
|
+
*
|
|
672
|
+
* - Uses custom logging utility function.
|
|
673
|
+
*
|
|
674
|
+
* @param name The name of the group
|
|
675
|
+
* @param fn The function to call
|
|
676
|
+
* @returns A promise that resolves the result of the function
|
|
677
|
+
*/
|
|
678
|
+
export async function group<T>(name: string, fn: () => Promise<T>): Promise<T> {
|
|
679
|
+
// Start the group
|
|
680
|
+
startGroup(name)
|
|
681
|
+
|
|
682
|
+
let result: T
|
|
683
|
+
|
|
684
|
+
try {
|
|
685
|
+
// Await the function
|
|
686
|
+
result = await fn()
|
|
687
|
+
} finally {
|
|
688
|
+
endGroup()
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return result
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
//-----------------------------------------------------------------------
|
|
695
|
+
// Wrapper action state
|
|
696
|
+
//-----------------------------------------------------------------------
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Save the state of the action.
|
|
700
|
+
*
|
|
701
|
+
* @remarks
|
|
702
|
+
*
|
|
703
|
+
* - Saves the value to core metadata.
|
|
704
|
+
*
|
|
705
|
+
* @param name The name of the state
|
|
706
|
+
* @param value The value of the state
|
|
707
|
+
* @returns void
|
|
708
|
+
*/
|
|
709
|
+
export function saveState(name: string, value: unknown): void {
|
|
710
|
+
if (value === undefined || value === null) CoreMeta.state[name] = ''
|
|
711
|
+
else if (typeof value === 'string' || value instanceof String)
|
|
712
|
+
CoreMeta.state[name] = value as string
|
|
713
|
+
else CoreMeta.state[name] = JSON.stringify(value)
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Get the state for the action.
|
|
718
|
+
*
|
|
719
|
+
* @remarks
|
|
720
|
+
*
|
|
721
|
+
* - Gets the value from core metadata.
|
|
722
|
+
*
|
|
723
|
+
* @param name The name of the state
|
|
724
|
+
* @returns The value of the state
|
|
725
|
+
*/
|
|
726
|
+
export function getState(name: string): string {
|
|
727
|
+
return CoreMeta.state[name] || ''
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Gets an OIDC token
|
|
732
|
+
*
|
|
733
|
+
* @remarks
|
|
734
|
+
*
|
|
735
|
+
* - Not yet implemented.
|
|
736
|
+
*
|
|
737
|
+
* @param aud The audience for the token
|
|
738
|
+
* @returns A promise that resolves the OIDC token
|
|
739
|
+
*/
|
|
740
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
741
|
+
export async function getIDToken(aud?: string): Promise<string> {
|
|
742
|
+
throw new Error('Not implemented')
|
|
743
|
+
}
|