Compare commits

..

3 Commits

Author SHA1 Message Date
f626d210e8 linting 2024-08-15 20:37:17 -04:00
fa37431cef npm ci and npm run release 2024-08-15 20:34:01 -04:00
3412bb46a4 Exclude the .git directory by default 2024-08-15 20:29:20 -04:00
27 changed files with 532 additions and 3446 deletions

View File

@ -17,11 +17,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
@ -29,7 +29,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -43,4 +43,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2

View File

@ -1,20 +0,0 @@
name: 'Publish Immutable Action Version'
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
- name: Checking out
uses: actions/checkout@v4
- name: Publish
id: publish
uses: actions/publish-immutable-action@0.0.3

View File

@ -46,19 +46,14 @@ jobs:
- name: Test
run: npm run test
# Test end-to-end by uploading a few artifacts and then downloading them
# Test end-to-end by uploading two artifacts and then downloading them
- name: Create artifact files
run: |
mkdir -p path/to/dir-1
mkdir -p path/to/dir-2
mkdir -p path/to/dir-3
mkdir -p symlink/
echo "Lorem ipsum dolor sit amet" > path/to/dir-1/file1.txt
echo "Hello world from file #2" > path/to/dir-2/file2.txt
echo "Hello from a symlinked file" > symlink/original.txt
ln -s $(pwd)/symlink/original.txt symlink/abs.txt
ln -s original.txt symlink/rel.txt
shell: bash
# Upload a single file artifact
- name: 'Upload artifact #1'
@ -84,14 +79,6 @@ jobs:
path/to/dir-[23]/*
!path/to/dir-3/*.txt
- name: 'Upload symlinked artifact'
uses: ./
with:
name: 'Symlinked-Artifact-${{ matrix.runs-on }}'
path: |
symlink/abs.txt
symlink/rel.txt
# Download Artifact #1 and verify the correctness of the content
- name: 'Download artifact #1'
uses: actions/download-artifact@v4
@ -154,34 +141,6 @@ jobs:
}
shell: pwsh
- name: 'Download symlinked artifact'
uses: actions/download-artifact@v4
with:
name: 'Symlinked-Artifact-${{ matrix.runs-on }}'
path: from/symlink
- name: 'Verify symlinked artifact'
run: |
$abs = "from/symlink/abs.txt"
if(!(Test-Path -path $abs))
{
Write-Error "Expected file does not exist"
}
if(!((Get-Content $abs) -ceq "Hello from a symlinked file"))
{
Write-Error "File contents of downloaded artifact are incorrect"
}
$rel = "from/symlink/rel.txt"
if(!(Test-Path -path $rel))
{
Write-Error "Expected file does not exist"
}
if(!((Get-Content $rel) -ceq "Hello from a symlinked file"))
{
Write-Error "File contents of downloaded artifact are incorrect"
}
shell: pwsh
- name: 'Alter file 1 content'
run: |
echo "This file has changed" > path/to/dir-1/file1.txt

View File

@ -1,9 +1,9 @@
---
name: "@actions/artifact"
version: 2.2.0
version: 2.1.8
type: npm
summary: Actions artifact lib
homepage: https://github.com/actions/toolkit/tree/main/packages/artifact
summary:
homepage:
license: mit
licenses:
- sources: LICENSE.md

View File

@ -1,6 +1,6 @@
---
name: "@actions/core"
version: 1.11.1
version: 1.10.1
type: npm
summary:
homepage:

View File

@ -1,6 +1,6 @@
---
name: "@actions/glob"
version: 0.5.0
version: 0.3.0
type: npm
summary:
homepage:

View File

@ -16,6 +16,7 @@ See also [download-artifact](https://github.com/actions/download-artifact).
- [Breaking Changes](#breaking-changes)
- [Usage](#usage)
- [Inputs](#inputs)
- [Uploading the `.git` directory](#uploading-the-git-directory)
- [Outputs](#outputs)
- [Examples](#examples)
- [Upload an Individual File](#upload-an-individual-file)
@ -64,7 +65,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.
4. With `v4.4` and later, the `.git` directory is excluded by default.
For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
@ -108,12 +109,30 @@ 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
# The file contents of any hidden files in the path should be validated before
# enabled this to avoid uploading sensitive information.
# Optional. Default is 'false'
include-hidden-files:
#### Uploading the `.git` directory
By default, files in a `.git` directory are ignored in the uploaded artifact.
This is intended to prevent accidentally uploading Git credentials into an artifact that could then
be extracted.
If files in the `.git` directory are needed, ensure that `actions/checkout` is being used with
`persist-credentials: false`.
```yaml
jobs:
upload:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false # Ensure credentials are not saved in `.git/config`
- uses: actions/upload-artifact@v4
with:
path: .
include-git-directory: true
```
### Outputs
@ -122,7 +141,6 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
| - | - | - |
| `artifact-id` | GitHub ID of an Artifact, can be used by the REST API | `1234` |
| `artifact-url` | 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 | `https://github.com/example-org/example-repo/actions/runs/1/artifacts/1234` |
| `artifact-digest` | SHA-256 digest of an Artifact | 0fde654d4c6e659b45783a725dc92f1bfb0baa6c2de64b34e814dc206ff4aaaf |
## Examples
@ -418,28 +436,6 @@ jobs:
overwrite: true
```
### Uploading Hidden Files
By default, hidden files are ignored by this action to avoid unintentionally uploading sensitive information.
If you need to upload hidden files, you can use the `include-hidden-files` input.
Any files that contain sensitive information that should not be in the uploaded artifact can be excluded
using the `path`:
```yaml
- uses: actions/upload-artifact@v4
with:
name: my-artifact
include-hidden-files: true
path: |
path/output/
!path/output/.production.env
```
Hidden files are defined as any file beginning with `.` or files within folders beginning with `.`.
On Windows, files and directories with the hidden attribute are not considered hidden files unless
they have the `.` prefix.
## Limitations
### Number of Artifacts

View File

@ -61,19 +61,11 @@ const lonelyFilePath = path.join(
'lonely-file.txt'
)
const hiddenFile = path.join(root, '.hidden-file.txt')
const fileInHiddenFolderPath = path.join(
root,
'.hidden-folder',
'folder-in-hidden-folder',
'file.txt'
)
const fileInHiddenFolderInFolderA = path.join(
root,
'folder-a',
'.hidden-folder-in-folder-a',
'file.txt'
)
const gitConfigPath = path.join(root, '.git', 'config')
const gitHeadPath = path.join(root, '.git', 'HEAD')
const nestedGitConfigPath = path.join(root, 'repository-name', '.git', 'config')
const nestedGitHeadPath = path.join(root, 'repository-name', '.git', 'HEAD')
describe('Search', () => {
beforeAll(async () => {
@ -107,11 +99,8 @@ 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'), {
await fs.mkdir(path.join(root, '.git'))
await fs.mkdir(path.join(root, 'repository-name', '.git'), {
recursive: true
})
@ -133,18 +122,17 @@ describe('Search', () => {
await fs.writeFile(lonelyFilePath, 'all by itself')
await fs.writeFile(hiddenFile, 'hidden file')
await fs.writeFile(fileInHiddenFolderPath, 'file in hidden directory')
await fs.writeFile(fileInHiddenFolderInFolderA, 'file in hidden directory')
await fs.writeFile(gitConfigPath, 'git config file')
await fs.writeFile(gitHeadPath, 'git head file')
await fs.writeFile(nestedGitConfigPath, 'nested git config file')
await fs.writeFile(nestedGitHeadPath, 'nested git head file')
/*
Directory structure of files that get created:
root/
.hidden-folder/
folder-in-hidden-folder/
file.txt
.git/
config
HEAD
folder-a/
.hidden-folder-in-folder-a/
file.txt
folder-b/
folder-c/
search-item1.txt
@ -167,7 +155,10 @@ describe('Search', () => {
folder-j/
folder-k/
lonely-file.txt
.hidden-file.txt
repository-name/
.git/
config
HEAD
search-item5.txt
*/
})
@ -385,23 +376,17 @@ 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).not.toContain(hiddenFile)
expect(searchResult.filesToUpload).not.toContain(fileInHiddenFolderPath)
expect(searchResult.filesToUpload).not.toContain(
fileInHiddenFolderInFolderA
)
it('Excludes .git directory by default', async () => {
const searchResult = await findFilesToUpload(root)
expect(searchResult.filesToUpload.length).toEqual(13)
expect(searchResult.filesToUpload).not.toContain(gitConfigPath)
})
it('Hidden files included', async () => {
const searchPath = path.join(root, '**/*')
const searchResult = await findFilesToUpload(searchPath, true)
expect(searchResult.filesToUpload).toContain(hiddenFile)
expect(searchResult.filesToUpload).toContain(fileInHiddenFolderPath)
expect(searchResult.filesToUpload).toContain(fileInHiddenFolderInFolderA)
it('Includes .git directory when includeGitDirectory is true', async () => {
const searchResult = await findFilesToUpload(root, {
includeGitDirectory: true
})
expect(searchResult.filesToUpload.length).toEqual(17)
expect(searchResult.filesToUpload).toContain(gitConfigPath)
})
})

View File

@ -60,8 +60,7 @@ describe('upload', () => {
jest.spyOn(artifact, 'uploadArtifact').mockResolvedValue({
size: 123,
id: 1337,
digest: 'facefeed'
id: 1337
})
})
@ -96,7 +95,6 @@ describe('upload', () => {
await run()
expect(core.setOutput).toHaveBeenCalledWith('artifact-id', 1337)
expect(core.setOutput).toHaveBeenCalledWith('artifact-digest', 'facefeed')
expect(core.setOutput).toHaveBeenCalledWith(
'artifact-url',
`${github.context.serverUrl}/${github.context.repo.owner}/${

View File

@ -40,10 +40,8 @@ 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 artifact.
If false, hidden files will be excluded from the artifact.
include-git-directory:
description: 'Include files in the .git directory in the artifact.'
default: 'false'
outputs:
@ -61,9 +59,6 @@ outputs:
This URL will be valid for as long as the artifact exists and the workflow run and repository exists. Once an artifact has expired this URL will no longer work.
Common uses cases for such a download URL can be adding download links to artifacts in descriptions or comments on pull requests or issues.
artifact-digest:
description: >
SHA-256 digest for the artifact that was just uploaded. Empty if the artifact upload failed.
runs:
using: 'node20'
main: 'dist/upload/index.js'

1723
dist/merge/index.js vendored

File diff suppressed because it is too large Load Diff

1723
dist/upload/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
- [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`.
@ -190,45 +189,44 @@ 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
## `.git` Directory
By default, hidden files are ignored by this action to avoid unintentionally uploading sensitive
information.
By default, files in the `.git` directory are ignored to avoid unintentionally uploading
credentials.
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.
In versions of this action before `v4.4.0`, files in the `.git` directory were included by default.
If this directory is required, ensure credentials are not saved in `.git/config` and then
enable the `include-git-directory` input.
```yaml
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a Hidden File
run: echo "hello from a hidden file" > .hidden-file.txt
- uses: actions/checkout@v4
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
path: .hidden-file.txt
path: .
```
@ -237,12 +235,13 @@ jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a Hidden File
run: echo "hello from a hidden file" > .hidden-file.txt
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: .hidden-file.txt
+ include-hidden-files: true
path: .
+ include-git-directory: true
```

View File

@ -5,6 +5,7 @@ Merge multiple [Actions Artifacts](https://docs.github.com/en/actions/using-work
- [`@actions/upload-artifact/merge`](#actionsupload-artifactmerge)
- [Usage](#usage)
- [Inputs](#inputs)
- [Uploading the `.git` directory](#uploading-the-git-directory)
- [Outputs](#outputs)
- [Examples](#examples)
- [Combining all artifacts in a workflow run](#combining-all-artifacts-in-a-workflow-run)
@ -59,13 +60,50 @@ For most cases, this may not be the most efficient solution. See [the migration
compression-level:
```
#### Uploading the `.git` directory
By default, files in a `.git` directory are ignored in the merged artifact.
This is intended to prevent accidentally uploading Git credentials into an artifact that could then
be extracted.
If files in the `.git` directory are needed, ensure that `actions/checkout` is being used with
`persist-credentials: false`.
```yaml
jobs:
upload:
runs-on: ubuntu-latest
strategy:
matrix:
foo: [a, b, c]
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false # Ensure credentials are not saved in `.git/config`
- name: Upload
uses: actions/upload-artifact@v4
with:
name: my-artifact-${{ matrix.foo }}
path: .
include-git-directory: true
merge:
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact/merge@v4
with:
include-git-directory: true
```
### Outputs
| Name | Description | Example |
| - | - | - |
| `artifact-id` | GitHub ID of an Artifact, can be used by the REST API | `1234` |
| `artifact-url` | 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 | `https://github.com/example-org/example-repo/actions/runs/1/artifacts/1234` |
| `artifact-digest` | SHA-256 digest of an Artifact | 0fde654d4c6e659b45783a725dc92f1bfb0baa6c2de64b34e814dc206ff4aaaf |
## Examples

View File

@ -36,10 +36,8 @@ inputs:
If true, the artifacts that were merged will be deleted.
If false, the artifacts will still 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.
include-git-directory:
description: 'Include files in the .git directory in the merged artifact.'
default: 'false'
outputs:
@ -57,9 +55,6 @@ outputs:
This URL will be valid for as long as the artifact exists and the workflow run and repository exists. Once an artifact has expired this URL will no longer work.
Common uses cases for such a download URL can be adding download links to artifacts in descriptions or comments on pull requests or issues.
artifact-digest:
description: >
SHA-256 digest for the artifact that was just uploaded. Empty if the artifact upload failed.
runs:
using: 'node20'
main: '../dist/merge/index.js'

133
package-lock.json generated
View File

@ -1,18 +1,18 @@
{
"name": "upload-artifact",
"version": "4.5.0",
"version": "4.3.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "upload-artifact",
"version": "4.5.0",
"version": "4.3.6",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^2.2.0",
"@actions/core": "^1.11.1",
"@actions/artifact": "2.1.8",
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@actions/glob": "^0.5.0",
"@actions/glob": "^0.3.0",
"@actions/io": "^1.1.2",
"minimatch": "^9.0.3"
},
@ -34,10 +34,9 @@
}
},
"node_modules/@actions/artifact": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.2.0.tgz",
"integrity": "sha512-nDEyBsphN148zHe6ihq1a/UX92MDgC2GS9XmeFx2xs/wztZxzARYllviiP5U1nTDp2n9dEhnUig9RP9eSDcU5g==",
"license": "MIT",
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.1.8.tgz",
"integrity": "sha512-kxgbllgF5f6mEdMeSW6WXlUbV1U77V9ECpA7LOYaY+Tm6RfXOm36EdXbpm+T9VPeaVqXK4QHLAgqay9GSyClgw==",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
@ -49,6 +48,7 @@
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
@ -66,22 +66,12 @@
}
},
"node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"license": "MIT",
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1"
}
},
"node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"license": "MIT",
"dependencies": {
"@actions/io": "^1.0.1"
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/github": {
@ -201,11 +191,11 @@
}
},
"node_modules/@actions/glob": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.5.0.tgz",
"integrity": "sha512-tST2rjPvJLRZLuT9NMUtyBjvj9Yo0MiJS3ow004slMvm8GFM+Zv9HvMJ7HWzfUyJnGrJvDsYkWBaaG3YKXRtCw==",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
"dependencies": {
"@actions/core": "^1.9.1",
"@actions/core": "^1.2.6",
"minimatch": "^3.0.4"
}
},
@ -3239,6 +3229,12 @@
"which": "^2.0.1"
}
},
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
},
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@ -6105,13 +6101,12 @@
}
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"braces": "^3.0.2",
"picomatch": "^2.3.1"
},
"engines": {
@ -6468,10 +6463,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
"license": "MIT"
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
},
"node_modules/path-type": {
"version": "4.0.0",
@ -7606,10 +7600,9 @@
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
},
"node_modules/unzip-stream": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.4.tgz",
"integrity": "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw==",
"license": "MIT",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.1.tgz",
"integrity": "sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw==",
"dependencies": {
"binary": "^0.3.0",
"mkdirp": "^0.5.1"
@ -7909,9 +7902,9 @@
},
"dependencies": {
"@actions/artifact": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.2.0.tgz",
"integrity": "sha512-nDEyBsphN148zHe6ihq1a/UX92MDgC2GS9XmeFx2xs/wztZxzARYllviiP5U1nTDp2n9dEhnUig9RP9eSDcU5g==",
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-2.1.8.tgz",
"integrity": "sha512-kxgbllgF5f6mEdMeSW6WXlUbV1U77V9ECpA7LOYaY+Tm6RfXOm36EdXbpm+T9VPeaVqXK4QHLAgqay9GSyClgw==",
"requires": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
@ -7923,6 +7916,7 @@
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
@ -7942,20 +7936,12 @@
}
},
"@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
"requires": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1"
}
},
"@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"requires": {
"@actions/io": "^1.0.1"
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"@actions/github": {
@ -8050,11 +8036,11 @@
}
},
"@actions/glob": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.5.0.tgz",
"integrity": "sha512-tST2rjPvJLRZLuT9NMUtyBjvj9Yo0MiJS3ow004slMvm8GFM+Zv9HvMJ7HWzfUyJnGrJvDsYkWBaaG3YKXRtCw==",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
"requires": {
"@actions/core": "^1.9.1",
"@actions/core": "^1.2.6",
"minimatch": "^3.0.4"
},
"dependencies": {
@ -10387,6 +10373,11 @@
"which": "^2.0.1"
}
},
"crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
},
"damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@ -12571,12 +12562,12 @@
"dev": true
},
"micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
"requires": {
"braces": "^3.0.3",
"braces": "^3.0.2",
"picomatch": "^2.3.1"
}
},
@ -12831,9 +12822,9 @@
}
},
"path-to-regexp": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
},
"path-type": {
"version": "4.0.0",
@ -13660,9 +13651,9 @@
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
},
"unzip-stream": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.4.tgz",
"integrity": "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.1.tgz",
"integrity": "sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw==",
"requires": {
"binary": "^0.3.0",
"mkdirp": "^0.5.1"

View File

@ -1,6 +1,6 @@
{
"name": "upload-artifact",
"version": "4.5.0",
"version": "4.4.0",
"description": "Upload an Actions Artifact in a workflow run",
"main": "dist/upload/index.js",
"scripts": {
@ -29,10 +29,10 @@
},
"homepage": "https://github.com/actions/upload-artifact#readme",
"dependencies": {
"@actions/artifact": "^2.2.0",
"@actions/core": "^1.11.1",
"@actions/artifact": "2.1.8",
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@actions/glob": "^0.5.0",
"@actions/glob": "^0.3.0",
"@actions/io": "^1.1.2",
"minimatch": "^9.0.3"
},

View File

@ -6,5 +6,5 @@ export enum Inputs {
RetentionDays = 'retention-days',
CompressionLevel = 'compression-level',
DeleteMerged = 'delete-merged',
IncludeHiddenFiles = 'include-hidden-files'
IncludeGitDirectory = 'include-git-directory'
}

View File

@ -10,7 +10,7 @@ export function getInputs(): MergeInputs {
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 includeGitDirectory = core.getBooleanInput(Inputs.IncludeGitDirectory)
const inputs = {
name,
@ -19,7 +19,7 @@ export function getInputs(): MergeInputs {
deleteMerged,
retentionDays: 0,
compressionLevel: 6,
includeHiddenFiles
includeGitDirectory
} as MergeInputs
const retentionDaysStr = core.getInput(Inputs.RetentionDays)

View File

@ -62,10 +62,9 @@ export async function run(): Promise<void> {
options.compressionLevel = inputs.compressionLevel
}
const searchResult = await findFilesToUpload(
tmpDir,
inputs.includeHiddenFiles
)
const searchResult = await findFilesToUpload(tmpDir, {
includeGitDirectory: inputs.includeGitDirectory
})
await uploadArtifact(
inputs.name,

View File

@ -32,7 +32,7 @@ export interface MergeInputs {
separateDirectories: boolean
/**
* Whether or not to include hidden files in the artifact
* Include files in the `.git` directory in the artifact
*/
includeHiddenFiles: boolean
includeGitDirectory: boolean
}

View File

@ -11,12 +11,11 @@ export interface SearchResult {
rootDirectory: string
}
function getDefaultGlobOptions(includeHiddenFiles: boolean): glob.GlobOptions {
function getDefaultGlobOptions(): glob.GlobOptions {
return {
followSymbolicLinks: true,
implicitDescendants: true,
omitBrokenSymbolicLinks: true,
excludeHiddenFiles: !includeHiddenFiles
omitBrokenSymbolicLinks: true
}
}
@ -79,15 +78,21 @@ function getMultiPathLCA(searchPaths: string[]): string {
return path.join(...commonPaths)
}
export interface SearchOptions {
/**
* Indicates whether files in the .git directory should be included in the artifact
*
* @default false
*/
includeGitDirectory: boolean
}
export async function findFilesToUpload(
searchPath: string,
includeHiddenFiles?: boolean
searchOptions?: SearchOptions
): Promise<SearchResult> {
const searchResults: string[] = []
const globber = await glob.create(
searchPath,
getDefaultGlobOptions(includeHiddenFiles || false)
)
const globber = await glob.create(searchPath, getDefaultGlobOptions())
const rawSearchResults: string[] = await globber.glob()
/*
@ -105,6 +110,12 @@ export async function findFilesToUpload(
// isDirectory() returns false for symlinks if using fs.lstat(), make sure to use fs.stat() instead
if (!fileStats.isDirectory()) {
debug(`File:${searchResult} was found using the provided searchPath`)
if (!searchOptions?.includeGitDirectory && inGitDirectory(searchResult)) {
debug(`Ignoring ${searchResult} because it is in the .git directory`)
continue
}
searchResults.push(searchResult)
// detect any files that would be overwritten because of case insensitivity
@ -156,3 +167,15 @@ export async function findFilesToUpload(
rootDirectory: searchPaths[0]
}
}
function inGitDirectory(filePath: string): boolean {
// The .git directory is a directory, so we need to check if the file path is a directory
// and if it is a .git directory
for (const part of filePath.split(path.sep)) {
if (part === '.git') {
return true
}
}
return false
}

View File

@ -19,7 +19,6 @@ export async function uploadArtifact(
`Artifact ${artifactName} has been successfully uploaded! Final size is ${uploadResponse.size} bytes. Artifact ID is ${uploadResponse.id}`
)
core.setOutput('artifact-id', uploadResponse.id)
core.setOutput('artifact-digest', uploadResponse.digest)
const repository = github.context.repo
const artifactURL = `${github.context.serverUrl}/${repository.owner}/${repository.repo}/actions/runs/${github.context.runId}/artifacts/${uploadResponse.id}`

View File

@ -6,7 +6,7 @@ export enum Inputs {
RetentionDays = 'retention-days',
CompressionLevel = 'compression-level',
Overwrite = 'overwrite',
IncludeHiddenFiles = 'include-hidden-files'
IncludeGitDirectory = 'include-git-directory'
}
export enum NoFileOptions {

View File

@ -9,7 +9,7 @@ export function getInputs(): UploadInputs {
const name = core.getInput(Inputs.Name)
const path = core.getInput(Inputs.Path, {required: true})
const overwrite = core.getBooleanInput(Inputs.Overwrite)
const includeHiddenFiles = core.getBooleanInput(Inputs.IncludeHiddenFiles)
const includeGitDirectory = core.getBooleanInput(Inputs.IncludeGitDirectory)
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
@ -29,7 +29,7 @@ export function getInputs(): UploadInputs {
searchPath: path,
ifNoFilesFound: noFileBehavior,
overwrite: overwrite,
includeHiddenFiles: includeHiddenFiles
includeGitDirectory: includeGitDirectory
} as UploadInputs
const retentionDaysStr = core.getInput(Inputs.RetentionDays)

View File

@ -24,10 +24,9 @@ async function deleteArtifactIfExists(artifactName: string): Promise<void> {
export async function run(): Promise<void> {
const inputs = getInputs()
const searchResult = await findFilesToUpload(
inputs.searchPath,
inputs.includeHiddenFiles
)
const searchResult = await findFilesToUpload(inputs.searchPath, {
includeGitDirectory: inputs.includeGitDirectory
})
if (searchResult.filesToUpload.length === 0) {
// No files were found, different use cases warrant different types of behavior if nothing is found
switch (inputs.ifNoFilesFound) {

View File

@ -32,7 +32,7 @@ export interface UploadInputs {
overwrite: boolean
/**
* Whether or not to include hidden files in the artifact
* Include files in the `.git` directory in the artifact
*/
includeHiddenFiles: boolean
includeGitDirectory: boolean
}