Skip to content

Commit b4a0a98

Browse files
authored
Merge branch 'main' into fix/deprecated-nodejs-usage-in-action
2 parents a954e16 + b4b15b8 commit b4a0a98

23 files changed

+233821
-261825
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: 'Publish Immutable Action Version'
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
publish:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
id-token: write
13+
packages: write
14+
15+
steps:
16+
- name: Checking out
17+
uses: actions/checkout@v4
18+
- name: Publish
19+
id: publish
20+
uses: actions/[email protected]

.github/workflows/test.yml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,19 @@ jobs:
4646
- name: Test
4747
run: npm run test
4848

49-
# Test end-to-end by uploading two artifacts and then downloading them
49+
# Test end-to-end by uploading a few artifacts and then downloading them
5050
- name: Create artifact files
5151
run: |
5252
mkdir -p path/to/dir-1
5353
mkdir -p path/to/dir-2
5454
mkdir -p path/to/dir-3
55+
mkdir -p symlink/
5556
echo "Lorem ipsum dolor sit amet" > path/to/dir-1/file1.txt
5657
echo "Hello world from file #2" > path/to/dir-2/file2.txt
58+
echo "Hello from a symlinked file" > symlink/original.txt
59+
ln -s $(pwd)/symlink/original.txt symlink/abs.txt
60+
ln -s original.txt symlink/rel.txt
61+
shell: bash
5762

5863
# Upload a single file artifact
5964
- name: 'Upload artifact #1'
@@ -79,6 +84,14 @@ jobs:
7984
path/to/dir-[23]/*
8085
!path/to/dir-3/*.txt
8186
87+
- name: 'Upload symlinked artifact'
88+
uses: ./
89+
with:
90+
name: 'Symlinked-Artifact-${{ matrix.runs-on }}'
91+
path: |
92+
symlink/abs.txt
93+
symlink/rel.txt
94+
8295
# Download Artifact #1 and verify the correctness of the content
8396
- name: 'Download artifact #1'
8497
uses: actions/download-artifact@v4
@@ -141,6 +154,34 @@ jobs:
141154
}
142155
shell: pwsh
143156

157+
- name: 'Download symlinked artifact'
158+
uses: actions/download-artifact@v4
159+
with:
160+
name: 'Symlinked-Artifact-${{ matrix.runs-on }}'
161+
path: from/symlink
162+
163+
- name: 'Verify symlinked artifact'
164+
run: |
165+
$abs = "from/symlink/abs.txt"
166+
if(!(Test-Path -path $abs))
167+
{
168+
Write-Error "Expected file does not exist"
169+
}
170+
if(!((Get-Content $abs) -ceq "Hello from a symlinked file"))
171+
{
172+
Write-Error "File contents of downloaded artifact are incorrect"
173+
}
174+
$rel = "from/symlink/rel.txt"
175+
if(!(Test-Path -path $rel))
176+
{
177+
Write-Error "Expected file does not exist"
178+
}
179+
if(!((Get-Content $rel) -ceq "Hello from a symlinked file"))
180+
{
181+
Write-Error "File contents of downloaded artifact are incorrect"
182+
}
183+
shell: pwsh
184+
144185
- name: 'Alter file 1 content'
145186
run: |
146187
echo "This file has changed" > path/to/dir-1/file1.txt

.licenses/npm/@actions/artifact.dep.yml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.licenses/npm/@actions/core.dep.yml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.licenses/npm/@actions/glob.dep.yml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ There is also a new sub-action, `actions/upload-artifact/merge`. For more info,
6464
Due to how Artifacts are created in this new version, it is no longer possible to upload to the same named Artifact multiple times. You must either split the uploads into multiple Artifacts with different names, or only upload once. Otherwise you _will_ encounter an error.
6565

6666
3. Limit of Artifacts for an individual job. Each job in a workflow run now has a limit of 500 artifacts.
67+
4. With `v4.4` and later, hidden files are excluded by default.
6768

6869
For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
6970

@@ -107,6 +108,12 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
107108
# Does not fail if the artifact does not exist.
108109
# Optional. Default is 'false'
109110
overwrite:
111+
112+
# Whether to include hidden files in the provided path in the artifact
113+
# The file contents of any hidden files in the path should be validated before
114+
# enabled this to avoid uploading sensitive information.
115+
# Optional. Default is 'false'
116+
include-hidden-files:
110117
```
111118
112119
### Outputs
@@ -410,6 +417,28 @@ jobs:
410417
overwrite: true
411418
```
412419

420+
### Uploading Hidden Files
421+
422+
By default, hidden files are ignored by this action to avoid unintentionally uploading sensitive information.
423+
424+
If you need to upload hidden files, you can use the `include-hidden-files` input.
425+
Any files that contain sensitive information that should not be in the uploaded artifact can be excluded
426+
using the `path`:
427+
428+
```yaml
429+
- uses: actions/upload-artifact@v4
430+
with:
431+
name: my-artifact
432+
include-hidden-files: true
433+
path: |
434+
path/output/
435+
!path/output/.production.env
436+
```
437+
438+
Hidden files are defined as any file beginning with `.` or files within folders beginning with `.`.
439+
On Windows, files and directories with the hidden attribute are not considered hidden files unless
440+
they have the `.` prefix.
441+
413442
## Limitations
414443

415444
### Number of Artifacts

__tests__/search.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ const lonelyFilePath = path.join(
6161
'lonely-file.txt'
6262
)
6363

64+
const hiddenFile = path.join(root, '.hidden-file.txt')
65+
const fileInHiddenFolderPath = path.join(
66+
root,
67+
'.hidden-folder',
68+
'folder-in-hidden-folder',
69+
'file.txt'
70+
)
71+
const fileInHiddenFolderInFolderA = path.join(
72+
root,
73+
'folder-a',
74+
'.hidden-folder-in-folder-a',
75+
'file.txt'
76+
)
77+
6478
describe('Search', () => {
6579
beforeAll(async () => {
6680
// mock all output so that there is less noise when running tests
@@ -93,6 +107,14 @@ describe('Search', () => {
93107
recursive: true
94108
})
95109

110+
await fs.mkdir(
111+
path.join(root, '.hidden-folder', 'folder-in-hidden-folder'),
112+
{recursive: true}
113+
)
114+
await fs.mkdir(path.join(root, 'folder-a', '.hidden-folder-in-folder-a'), {
115+
recursive: true
116+
})
117+
96118
await fs.writeFile(searchItem1Path, 'search item1 file')
97119
await fs.writeFile(searchItem2Path, 'search item2 file')
98120
await fs.writeFile(searchItem3Path, 'search item3 file')
@@ -110,10 +132,19 @@ describe('Search', () => {
110132
await fs.writeFile(amazingFileInFolderHPath, 'amazing file')
111133

112134
await fs.writeFile(lonelyFilePath, 'all by itself')
135+
136+
await fs.writeFile(hiddenFile, 'hidden file')
137+
await fs.writeFile(fileInHiddenFolderPath, 'file in hidden directory')
138+
await fs.writeFile(fileInHiddenFolderInFolderA, 'file in hidden directory')
113139
/*
114140
Directory structure of files that get created:
115141
root/
142+
.hidden-folder/
143+
folder-in-hidden-folder/
144+
file.txt
116145
folder-a/
146+
.hidden-folder-in-folder-a/
147+
file.txt
117148
folder-b/
118149
folder-c/
119150
search-item1.txt
@@ -136,6 +167,7 @@ describe('Search', () => {
136167
folder-j/
137168
folder-k/
138169
lonely-file.txt
170+
.hidden-file.txt
139171
search-item5.txt
140172
*/
141173
})
@@ -352,4 +384,24 @@ describe('Search', () => {
352384
)
353385
expect(searchResult.filesToUpload.includes(lonelyFilePath)).toEqual(true)
354386
})
387+
388+
it('Hidden files ignored by default', async () => {
389+
const searchPath = path.join(root, '**/*')
390+
const searchResult = await findFilesToUpload(searchPath)
391+
392+
expect(searchResult.filesToUpload).not.toContain(hiddenFile)
393+
expect(searchResult.filesToUpload).not.toContain(fileInHiddenFolderPath)
394+
expect(searchResult.filesToUpload).not.toContain(
395+
fileInHiddenFolderInFolderA
396+
)
397+
})
398+
399+
it('Hidden files included', async () => {
400+
const searchPath = path.join(root, '**/*')
401+
const searchResult = await findFilesToUpload(searchPath, true)
402+
403+
expect(searchResult.filesToUpload).toContain(hiddenFile)
404+
expect(searchResult.filesToUpload).toContain(fileInHiddenFolderPath)
405+
expect(searchResult.filesToUpload).toContain(fileInHiddenFolderInFolderA)
406+
})
355407
})

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ inputs:
4040
If false, the action will fail if an artifact for the given name already exists.
4141
Does not fail if the artifact does not exist.
4242
default: 'false'
43+
include-hidden-files:
44+
description: >
45+
If true, hidden files will be included in the artifact.
46+
If false, hidden files will be excluded from the artifact.
47+
default: 'false'
4348

4449
outputs:
4550
artifact-id:

0 commit comments

Comments
 (0)