Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude hidden files by default #598

Merged
merged 9 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ There is also a new sub-action, `actions/upload-artifact/merge`. For more info,
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.

3. Limit of Artifacts for an individual job. Each job in a workflow run now has a limit of 500 artifacts.
4. With `v4.4` and later, hidden files are excluded by default.
SrRyan marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down Expand Up @@ -107,6 +108,10 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
# Does not fail if the artifact does not exist.
# Optional. Default is 'false'
overwrite:

# Whether to include hidden files in the provided path in the artifact
# Optional. Default is 'false'
include-hidden-files:
joshmgross marked this conversation as resolved.
Show resolved Hide resolved
```

### Outputs
Expand Down
54 changes: 54 additions & 0 deletions __tests__/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ const lonelyFilePath = path.join(
'lonely-file.txt'
)

const fileInHiddenFolderPath = path.join(
root,
'.hidden-folder',
'folder-in-hidden-folder',
'file.txt'
)
const hiddenFile = path.join(root, '.hidden-file.txt')
const fileInHiddenFolderInFolderA = path.join(
root,
'folder-a',
'.hidden-folder-in-folder-a',
'file.txt'
)

describe('Search', () => {
beforeAll(async () => {
// mock all output so that there is less noise when running tests
Expand Down Expand Up @@ -93,6 +107,14 @@ describe('Search', () => {
recursive: true
})

await fs.mkdir(
path.join(root, '.hidden-folder', 'folder-in-hidden-folder'),
{recursive: true}
)
await fs.mkdir(path.join(root, 'folder-a', '.hidden-folder-in-folder-a'), {
recursive: true
})

await fs.writeFile(searchItem1Path, 'search item1 file')
await fs.writeFile(searchItem2Path, 'search item2 file')
await fs.writeFile(searchItem3Path, 'search item3 file')
Expand All @@ -113,7 +135,12 @@ describe('Search', () => {
/*
Directory structure of files that get created:
root/
.hidden-folder/
folder-in-hidden-folder/
file.txt
folder-a/
.hidden-folder-in-folder-a/
file.txt
folder-b/
folder-c/
search-item1.txt
Expand All @@ -136,6 +163,7 @@ describe('Search', () => {
folder-j/
folder-k/
lonely-file.txt
.hidden-file.txt
search-item5.txt
*/
})
Expand Down Expand Up @@ -352,4 +380,30 @@ describe('Search', () => {
)
expect(searchResult.filesToUpload.includes(lonelyFilePath)).toEqual(true)
})

it('Hidden files ignored by default', async () => {
const searchPath = path.join(root, '**/*')
const searchResult = await findFilesToUpload(searchPath)

expect(searchResult.filesToUpload.includes(hiddenFile)).toEqual(false)
expect(searchResult.filesToUpload.includes(fileInHiddenFolderPath)).toEqual(
false
)
expect(
searchResult.filesToUpload.includes(fileInHiddenFolderInFolderA)
).toEqual(false)
})

it('Hidden files included', async () => {
const searchPath = path.join(root, '**/*')
const searchResult = await findFilesToUpload(searchPath, true)

expect(searchResult.filesToUpload.includes(hiddenFile)).toEqual(false)
expect(searchResult.filesToUpload.includes(fileInHiddenFolderPath)).toEqual(
false
)
expect(
searchResult.filesToUpload.includes(fileInHiddenFolderInFolderA)
).toEqual(false)
})
})
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ inputs:
If false, the action will fail if an artifact for the given name already exists.
Does not fail if the artifact does not exist.
default: 'false'
include-hidden-files:
description: >
If true, hidden files will be included in the merged artifact.
If false, hidden files will be excluded from the merged artifact.
joshmgross marked this conversation as resolved.
Show resolved Hide resolved
default: 'false'

outputs:
artifact-id:
Expand Down
16 changes: 10 additions & 6 deletions dist/merge/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125727,6 +125727,7 @@ var Inputs;
Inputs["RetentionDays"] = "retention-days";
Inputs["CompressionLevel"] = "compression-level";
Inputs["DeleteMerged"] = "delete-merged";
Inputs["IncludeHiddenFiles"] = "include-hidden-files";
})(Inputs = exports.Inputs || (exports.Inputs = {}));


Expand Down Expand Up @@ -125810,13 +125811,15 @@ function getInputs() {
const pattern = core.getInput(constants_1.Inputs.Pattern, { required: true });
const separateDirectories = core.getBooleanInput(constants_1.Inputs.SeparateDirectories);
const deleteMerged = core.getBooleanInput(constants_1.Inputs.DeleteMerged);
const includeHiddenFiles = core.getBooleanInput(constants_1.Inputs.IncludeHiddenFiles);
const inputs = {
name,
pattern,
separateDirectories,
deleteMerged,
retentionDays: 0,
compressionLevel: 6
compressionLevel: 6,
includeHiddenFiles,
};
const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays);
if (retentionDaysStr) {
Expand Down Expand Up @@ -125932,7 +125935,7 @@ function run() {
if (typeof inputs.compressionLevel !== 'undefined') {
options.compressionLevel = inputs.compressionLevel;
}
const searchResult = yield (0, search_1.findFilesToUpload)(tmpDir);
const searchResult = yield (0, search_1.findFilesToUpload)(tmpDir, inputs.includeHiddenFiles);
yield (0, upload_artifact_1.uploadArtifact)(inputs.name, searchResult.filesToUpload, searchResult.rootDirectory, options);
core.info(`The ${artifacts.length} artifact(s) have been successfully merged!`);
if (inputs.deleteMerged) {
Expand Down Expand Up @@ -125999,11 +126002,12 @@ const fs_1 = __nccwpck_require__(57147);
const path_1 = __nccwpck_require__(71017);
const util_1 = __nccwpck_require__(73837);
const stats = (0, util_1.promisify)(fs_1.stat);
function getDefaultGlobOptions() {
function getDefaultGlobOptions(_includeHiddenFiles) {
return {
followSymbolicLinks: true,
implicitDescendants: true,
omitBrokenSymbolicLinks: true
omitBrokenSymbolicLinks: true,
// excludeHiddenFiles: !includeHiddenFiles,
};
}
/**
Expand Down Expand Up @@ -126057,10 +126061,10 @@ function getMultiPathLCA(searchPaths) {
}
return path.join(...commonPaths);
}
function findFilesToUpload(searchPath, globOptions) {
function findFilesToUpload(searchPath, includeHiddenFiles) {
return __awaiter(this, void 0, void 0, function* () {
const searchResults = [];
const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions());
const globber = yield glob.create(searchPath, getDefaultGlobOptions(includeHiddenFiles || false));
const rawSearchResults = yield globber.glob();
/*
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
Expand Down
16 changes: 10 additions & 6 deletions dist/upload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125757,11 +125757,12 @@ const fs_1 = __nccwpck_require__(57147);
const path_1 = __nccwpck_require__(71017);
const util_1 = __nccwpck_require__(73837);
const stats = (0, util_1.promisify)(fs_1.stat);
function getDefaultGlobOptions() {
function getDefaultGlobOptions(_includeHiddenFiles) {
return {
followSymbolicLinks: true,
implicitDescendants: true,
omitBrokenSymbolicLinks: true
omitBrokenSymbolicLinks: true,
// excludeHiddenFiles: !includeHiddenFiles,
};
}
/**
Expand Down Expand Up @@ -125815,10 +125816,10 @@ function getMultiPathLCA(searchPaths) {
}
return path.join(...commonPaths);
}
function findFilesToUpload(searchPath, globOptions) {
function findFilesToUpload(searchPath, includeHiddenFiles) {
return __awaiter(this, void 0, void 0, function* () {
const searchResults = [];
const globber = yield glob.create(searchPath, globOptions || getDefaultGlobOptions());
const globber = yield glob.create(searchPath, getDefaultGlobOptions(includeHiddenFiles || false));
const rawSearchResults = yield globber.glob();
/*
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
Expand Down Expand Up @@ -125956,6 +125957,7 @@ var Inputs;
Inputs["RetentionDays"] = "retention-days";
Inputs["CompressionLevel"] = "compression-level";
Inputs["Overwrite"] = "overwrite";
Inputs["IncludeHiddenFiles"] = "include-hidden-files";
})(Inputs = exports.Inputs || (exports.Inputs = {}));
var NoFileOptions;
(function (NoFileOptions) {
Expand Down Expand Up @@ -126053,6 +126055,7 @@ function getInputs() {
const name = core.getInput(constants_1.Inputs.Name);
const path = core.getInput(constants_1.Inputs.Path, { required: true });
const overwrite = core.getBooleanInput(constants_1.Inputs.Overwrite);
const includeHiddenFiles = core.getBooleanInput(constants_1.Inputs.IncludeHiddenFiles);
const ifNoFilesFound = core.getInput(constants_1.Inputs.IfNoFilesFound);
const noFileBehavior = constants_1.NoFileOptions[ifNoFilesFound];
if (!noFileBehavior) {
Expand All @@ -126062,7 +126065,8 @@ function getInputs() {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior,
overwrite: overwrite
overwrite: overwrite,
includeHiddenFiles: includeHiddenFiles,
};
const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays);
if (retentionDaysStr) {
Expand Down Expand Up @@ -126151,7 +126155,7 @@ function deleteArtifactIfExists(artifactName) {
function run() {
return __awaiter(this, void 0, void 0, function* () {
const inputs = (0, input_helper_1.getInputs)();
const searchResult = yield (0, search_1.findFilesToUpload)(inputs.searchPath);
const searchResult = yield (0, search_1.findFilesToUpload)(inputs.searchPath, inputs.includeHiddenFiles);
if (searchResult.filesToUpload.length === 0) {
// No files were found, different use cases warrant different types of behavior if nothing is found
switch (inputs.ifNoFilesFound) {
Expand Down
61 changes: 50 additions & 11 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [Multiple uploads to the same named Artifact](#multiple-uploads-to-the-same-named-artifact)
- [Overwriting an Artifact](#overwriting-an-artifact)
- [Merging multiple artifacts](#merging-multiple-artifacts)
- [Hidden files](#hidden-files)

Several behavioral differences exist between Artifact actions `v3` and below vs `v4`. This document outlines common scenarios in `v3`, and how they would be handled in `v4`.

Expand Down Expand Up @@ -189,21 +190,59 @@ jobs:
- name: Create a File
run: echo "hello from ${{ matrix.runs-on }}" > file-${{ matrix.runs-on }}.txt
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: all-my-files
+ name: my-artifact-${{ matrix.runs-on }}
path: file-${{ matrix.runs-on }}.txt
+ merge:
+ runs-on: ubuntu-latest
+ needs: upload
+ steps:
+ - name: Merge Artifacts
+ uses: actions/upload-artifact/merge@v4
+ with:
+ name: all-my-files
+ pattern: my-artifact-*
+ merge:
+ runs-on: ubuntu-latest
+ needs: upload
+ steps:
+ - name: Merge Artifacts
+ uses: actions/upload-artifact/merge@v4
+ with:
+ name: all-my-files
+ pattern: my-artifact-*
```

Note that this will download all artifacts to a temporary directory and reupload them as a single artifact. For more information on inputs and other use cases for `actions/upload-artifact/merge@v4`, see [the action documentation](../merge/README.md).

## Hidden Files

By default, hidden files are ignored by this action to avoid unintentionally uploading sensitive
information.

In versions of this action before v4.4.0, these hidden files were included by default.

If you need to upload hidden files, you can use the `include-hidden-files` input.
SrRyan marked this conversation as resolved.
Show resolved Hide resolved

```yaml
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a Hidden File
run: echo "hello from a hidden file" > .hidden-file.txt
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
path: .hidden-file.txt
```


```diff
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a Hidden File
run: echo "hello from a hidden file" > .hidden-file.txt
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: .hidden-file.txt
+ include-hidden-files: true
```
5 changes: 5 additions & 0 deletions merge/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ inputs:
If true, the artifacts that were merged will be deleted.
If false, the artifacts will still exist.
default: 'false'
include-hidden-files:
joshmgross marked this conversation as resolved.
Show resolved Hide resolved
description: >
If true, hidden files will be included in the merged artifact.
If false, hidden files will be excluded from the merged artifact.
default: 'false'

outputs:
artifact-id:
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "upload-artifact",
"version": "4.3.6",
"version": "4.4.0",
"description": "Upload an Actions Artifact in a workflow run",
"main": "dist/upload/index.js",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion src/merge/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
SeparateDirectories = 'separate-directories',
RetentionDays = 'retention-days',
CompressionLevel = 'compression-level',
DeleteMerged = 'delete-merged'
DeleteMerged = 'delete-merged',
IncludeHiddenFiles = 'include-hidden-files',

Check failure on line 9 in src/merge/constants.ts

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Delete `,`
}
4 changes: 3 additions & 1 deletion src/merge/input-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
const pattern = core.getInput(Inputs.Pattern, {required: true})
const separateDirectories = core.getBooleanInput(Inputs.SeparateDirectories)
const deleteMerged = core.getBooleanInput(Inputs.DeleteMerged)
const includeHiddenFiles = core.getBooleanInput(Inputs.IncludeHiddenFiles)

const inputs = {
name,
pattern,
separateDirectories,
deleteMerged,
retentionDays: 0,
compressionLevel: 6
compressionLevel: 6,
includeHiddenFiles,

Check failure on line 22 in src/merge/input-helper.ts

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Delete `,`
} as MergeInputs

const retentionDaysStr = core.getInput(Inputs.RetentionDays)
Expand Down
2 changes: 1 addition & 1 deletion src/merge/merge-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
options.compressionLevel = inputs.compressionLevel
}

const searchResult = await findFilesToUpload(tmpDir)
const searchResult = await findFilesToUpload(tmpDir, inputs.includeHiddenFiles)

Check failure on line 65 in src/merge/merge-artifacts.ts

View workflow job for this annotation

GitHub Actions / Build (windows-latest)

Replace `tmpDir,·inputs.includeHiddenFiles` with `⏎····tmpDir,⏎····inputs.includeHiddenFiles⏎··`

await uploadArtifact(
inputs.name,
Expand Down
Loading
Loading