-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaction.yml
357 lines (324 loc) · 13.7 KB
/
action.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# The MIT License (MIT)
#
# Copyright © 2024 The pyTooling Authors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
name: 📤 Upload Artifact (Preserve File Permissions)
branding:
icon: upload
color: yellow
description: Tarball files before uploading the artifact to preserve file privileges.
author: Patrick Lehmann (@Paebbels)
inputs:
name:
description: |
Name of the artifact to upload.
type: string
required: false
default: 'artifact'
working-directory:
# description:
type: string
required: false
default: ''
path:
description: |
A file, directory or wildcard pattern that describes what to upload
type: string
required: true
if-no-files-found:
description: |
The desired behavior if no files are found using the provided path.
Available Options:
warn: Output a warning but do not fail the action
error: Fail the action with an error message
ignore: Do not output any warnings or errors, the action does not fail
type: string
required: false
default: 'warn'
retention-days:
description: |
Duration after which artifact will expire in days. 0 means using default retention.
Minimum 1 day.
Maximum 90 days unless changed from the repository settings page.
Defaults to repository settings.
type: number
required: false
compression-level:
description: |
The level of compression for Zlib to be applied to the artifact archive.
The value can range from 0 to 9.
For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
type: number
required: false
default: 6
overwrite:
description: |
If true, an artifact with a matching name will be deleted before a new one is uploaded.
If false, the action will fail if an artifact for the given name already exists.
Does not fail if the artifact does not exist.
type: boolean
required: false
default: false
include-hidden-files:
description: |
Whether to include hidden files in the provided path in the artifact
The file contents of any hidden files in the path should be validated before
enabled this to avoid uploading sensitive information.
type: boolean
required: false
default: false
mode:
description: |
Mode of operation. Allowed modes: tar (default), legacy
type: string
required: false
default: 'tar'
investigate:
description: |
If enabled, list content of the created tarball.
type: boolean
required: false
default: false
tarball-name:
description: |
Filename of the embedded tarball.
type: string
required: false
default: '__pyTooling_upload_artifact__.tar'
outputs:
artifact-id:
description: |
GitHub ID of an Artifact, can be used by the REST API.
value: ${{ steps.upload.outputs.artifact-id || steps.upload-legacy.outputs.artifact-id }}
artifact-url:
description: |
URL to download an Artifact. Can be used in many scenarios such as linking to
artifacts in issues or pull requests. Users must be logged-in in order for this
URL to work. This URL is valid as long as the artifact has not expired or the
artifact, run or repository have not been deleted.
value: ${{ steps.upload.outputs.artifact-url || steps.upload-legacy.outputs.artifact-url}}
runs:
using: composite
steps:
- name: Create tarball from given file patterns
id: prepare
if: inputs.mode == 'tar'
shell: bash
run: |
# Create tarball from given file patterns
set +e
shopt -s globstar
ANSI_CYAN=$'\x1b[36m'
ANSI_LIGHT_RED=$'\x1b[91m'
ANSI_LIGHT_GREEN=$'\x1b[92m'
ANSI_LIGHT_YELLOW=$'\x1b[93m'
ANSI_LIGHT_BLUE="\e[94m"
ANSI_NOCOLOR=$'\x1b[0m'
if ! [[ "${{ runner.os }}" == "macOS" || "${{ runner.os }}" == "Linux" || "${{ runner.os }}" == "Windows" ]]; then
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "Unsupported runner OS '${{ runner.os }}'."
exit 1
fi
if [[ "${{ inputs.investigate }}" == "true" ]]; then
printf "::group::${ANSI_LIGHT_BLUE}%s${ANSI_NOCOLOR}\n" "List all shell options via 'shopt' ..."
shopt
printf "::endgroup::\n"
fi
if [[ "${{ runner.os }}" == "macOS" ]]; then
printf "::group::${ANSI_LIGHT_BLUE}%s${ANSI_NOCOLOR}\n" "Install newer 'bash' via homebrew ..."
brew install bash
printf "::endgroup::\n"
tarProg="gtar"
else
tarProg="tar"
fi
if [[ "${{ inputs.working-directory }}" != "" ]]; then
printf "%s" "Changing artifact root directory to '${{ inputs.working-directory }}' ... "
if [[ -d "${{ inputs.working-directory }}" ]]; then
pushd "${{ inputs.working-directory }}" > /dev/null
if [[ $? -ne 0 ]]; then
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}"
exit 1
else
printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
dir="${{ inputs.working-directory }}"
tarDirectory=""
while [[ "${dir}" != "." ]]; do
tarDirectory="../${tarDirectory}"
dir=$(dirname -- "${dir}")
done
printf " %s\n" "tarDirectory: ${tarDirectory}"
fi
else
printf "%s\n" "echo ${ANSI_LIGHT_RED}[NO DIRECTORY]${ANSI_NOCOLOR}"
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "Directory '${{ inputs.working-directory }}' doesn't exist."
exit 1
fi
else
tarDirectory=""
fi
#if [[ "${{ inputs.include-hidden-files }}" == "true" ]]; then
# printf "%s" "Enable glob for dot-files (hidden files) ... "
# shopt -s dotglob
# if [[ $? -ne 0 ]]; then
# printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}"
# else
# printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
# fi
#fi
printf "%s" "Convert provided file patterns to a single line ... "
PATTERNS=()
while IFS=$'\r\n' read -r pattern; do
# skip empty or comment lines
[[ "${pattern}" == "" || "${pattern:0:1}" == "#" ]] && continue
PATTERNS+=("$pattern")
done <<<'${{ inputs.path }}'
printf "%s\n" "${ANSI_LIGHT_GREEN}[DONE]${ANSI_NOCOLOR}"
print_files_unique() {
for i in "$@"; do
compgen -G "$i" || true
done | sort | uniq
}
printf "::group::${ANSI_LIGHT_BLUE}List all pattern for '${tarProg}' ...${ANSI_NOCOLOR}\n"
while IFS=$'\r\n' read -r pattern; do
printf " %s\n" "${pattern}"
done <<<$(print_files_unique "${PATTERNS[@]}")
printf "::endgroup::\n"
printf "%s\n" "Checking ${tarProg} ($(which ${tarProg})): ${ANSI_CYAN}$(${tarProg} --version | head -n 1)${ANSI_NOCOLOR}"
printf "%s\n" "Assemble OS specific tar command line options ... ${ANSI_LIGHT_GREEN}[${{ runner.os }}]${ANSI_NOCOLOR}"
# Options for GNU tar
tarOptions=("--owner=root:0" "--group=root:0")
# Option to read filenames from file
filesFrom=("--verbatim-files-from" "--files-from")
printf "%s" "Creating temporary tarball '${tarDirectory}${{ inputs.tarball-name }}' ... "
msg=$(${tarProg} -cf "${tarDirectory}${{ inputs.tarball-name }}" "${tarOptions[@]}" "${filesFrom[@]}" <(print_files_unique "${PATTERNS[@]}"))
if [[ $? -ne 0 ]]; then
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}"
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "${tarProg}: ${msg}"
exit 1
else
printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
fi
dirCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
fileCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
printf "%s\n" "${ANSI_CYAN}Collected items:${ANSI_NOCOLOR}"
printf " %s\n" "${ANSI_CYAN}Directories: ${dirCount}${ANSI_NOCOLOR}"
printf " %s\n" "${ANSI_CYAN}Files: ${fileCount}${ANSI_NOCOLOR}"
if [[ $fileCount -eq 0 ]]; then
if [[ "${{ inputs.if-no-files-found }}" == "error" ]]; then
printf "::error title=%s::%s\n" "${{ github.job }} - pyTooling/upload-artifact" "No files found for given pattern."
exit 1
elif [[ "${{ inputs.if-no-files-found }}" == "warn" ]]; then
printf "::warning title=%s::%s\n" "${{ github.job }} - pyTooling/upload-artifact" "No files found for given pattern."
elif [[ "${{ inputs.if-no-files-found }}" == "ignore" ]]; then
printf "%s\n" "No files found for given pattern."
else
printf "%s\n" "Unknown option '${{ inputs.if-no-files-found }}'."
fi
fi
- name: Remove dot-files if not explicitly included
id: clean
if: inputs.include-hidden-files == 'false'
shell: bash
run: |
# Remove dot-files if not explicitly included
set +e
ANSI_CYAN=$'\x1b[36m'
ANSI_LIGHT_RED=$'\x1b[91m'
ANSI_LIGHT_GREEN=$'\x1b[92m'
ANSI_LIGHT_YELLOW=$'\x1b[93m'
ANSI_LIGHT_BLUE="\e[94m"
ANSI_NOCOLOR=$'\x1b[0m'
if [[ "${{ runner.os }}" == "macOS" ]]; then
tarProg="gtar"
else
tarProg="tar"
fi
printf "::group::${ANSI_LIGHT_BLUE}Removing unwanted files from '${{ inputs.tarball-name }}' ...:${ANSI_NOCOLOR}\n"
while IFS=$'\r\n' read -r file; do
printf " %s\n" "${file}"
${tarProg} -vf "${{ inputs.tarball-name }}" --delete "${file}"
done <<<$(${tarProg} -tf "${{ inputs.tarball-name }}" | grep -E '^\.|/\.')
printf "::endgroup::\n"
- name: List content of the generated tarball
id: investigate
if: inputs.mode == 'tar' && inputs.investigate == 'true'
shell: bash
run: |
# List content of the generated tarball
set +e
ANSI_CYAN=$'\x1b[36m'
ANSI_LIGHT_RED=$'\x1b[91m'
ANSI_LIGHT_GREEN=$'\x1b[92m'
ANSI_LIGHT_YELLOW=$'\x1b[93m'
ANSI_LIGHT_BLUE="\e[94m"
ANSI_NOCOLOR=$'\x1b[0m'
if [[ "${{ runner.os }}" == "macOS" ]]; then
tarProg="gtar"
else
tarProg="tar"
fi
printf "::group::${ANSI_LIGHT_BLUE}Content of '${{ inputs.tarball-name }}':${ANSI_NOCOLOR}\n"
${tarProg} -tvf "${{ inputs.tarball-name }}"
printf "\n"
dirCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
fileCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
printf "%s\n" "${ANSI_CYAN}Directories: ${dirCount} Files: ${fileCount}${ANSI_NOCOLOR}"
printf "::endgroup::\n"
# https://github.com/actions/upload-artifact
- name: 📤 Upload artifact (tarball)
uses: actions/upload-artifact@v4
id: upload
if: inputs.mode == 'tar'
with:
name: ${{ inputs.name }}
path: ${{ inputs.tarball-name }}
if-no-files-found: ${{ inputs.if-no-files-found }}
retention-days: ${{ inputs.retention-days }}
compression-level: ${{ inputs.compression-level }}
overwrite: ${{ inputs.overwrite }}
# include-hidden-files:
- name: Remove temporary tarball
id: cleanup
if: inputs.mode == 'tar'
shell: bash
run: |
# Remove temporary tarball
set +e
ANSI_CYAN=$'\x1b[36m'
ANSI_LIGHT_RED=$'\x1b[91m'
ANSI_LIGHT_GREEN=$'\x1b[92m'
ANSI_LIGHT_YELLOW=$'\x1b[93m'
ANSI_LIGHT_BLUE="\e[94m"
ANSI_NOCOLOR=$'\x1b[0m'
printf "%s" "Removing temporary tarball ... "
rm -f "${{ inputs.tarball-name }}"
if [[ $? -ne 0 ]]; then
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}"
printf "::warning title=%s::%s\n" "pyTooling/upload-artifact" "Can't remove tarball '${{ inputs.tarball-name }}'."
else
printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
fi
- name: 📤 Upload artifact (legacy)
uses: actions/upload-artifact@v4
id: upload-legacy
if: inputs.mode == 'legacy'
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
if-no-files-found: ${{ inputs.if-no-files-found }}
retention-days: ${{ inputs.retention-days }}
compression-level: ${{ inputs.compression-level }}
overwrite: ${{ inputs.overwrite }}
include-hidden-files: ${{ inputs.include-hidden-files }}