Skip to content

Commit 11ff42c

Browse files
committed
add new overwrite input & docs
1 parent 1eb3cb2 commit 11ff42c

10 files changed

+536
-26
lines changed

README.md

+32-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ See also [download-artifact](https://github.com/actions/download-artifact).
2424
- [Using Outputs](#using-outputs)
2525
- [Example output between steps](#example-output-between-steps)
2626
- [Example output between jobs](#example-output-between-jobs)
27+
- [Overwriting an Artifact](#overwriting-an-artifact)
2728
- [Limitations](#limitations)
2829
- [Number of Artifacts](#number-of-artifacts)
2930
- [Zip archives](#zip-archives)
@@ -44,7 +45,7 @@ For more information, see the [`@actions/artifact`](https://github.com/actions/t
4445

4546
1. Uploads are significantly faster, upwards of 90% improvement in worst case scenarios.
4647
2. Once uploaded, an Artifact ID is returned and Artifacts are immediately available in the UI and [REST API](https://docs.github.com/en/rest/actions/artifacts). Previously, you would have to wait for the run to be completed before an ID was available or any APIs could be utilized.
47-
3. The contents of an Artifact are uploaded together into an _immutable_ archive. They cannot be altered by subsequent jobs. Both of these factors help reduce the possibility of accidentally corrupting Artifact files.
48+
3. The contents of an Artifact are uploaded together into an _immutable_ archive. They cannot be altered by subsequent jobs unless the Artifacts are deleted and recreated (where they will have a new ID). Both of these factors help reduce the possibility of accidentally corrupting Artifact files.
4849
4. The compression level of an Artifact can be manually tweaked for speed or size reduction.
4950

5051
### Breaking Changes
@@ -365,6 +366,36 @@ jobs:
365366
run: echo "Artifact ID from previous job is $OUTPUT1"
366367
```
367368

369+
### Overwriting an Artifact
370+
371+
Although it's not possible to mutate an Artifact, can completely overwrite one. But do note that this will give the Artifact a new ID, the previous one will no longer exist:
372+
373+
```yaml
374+
jobs:
375+
upload:
376+
runs-on: ubuntu-latest
377+
steps:
378+
- name: Create a file
379+
run: echo "hello world" > my-file.txt
380+
- name: Upload Artifact
381+
uses: actions/upload-artifact@v4
382+
with:
383+
name: my-artifact # NOTE: same artifact name
384+
path: my-file.txt
385+
upload-again:
386+
needs: upload
387+
runs-on: ubuntu-latest
388+
steps:
389+
- name: Create a different file
390+
run: echo "goodbye world" > my-file.txt
391+
- name: Upload Artifact
392+
uses: actions/upload-artifact@v4
393+
with:
394+
name: my-artifact # NOTE: same artifact name
395+
path: my-file.txt
396+
overwrite: true
397+
```
398+
368399
## Limitations
369400

370401
### Number of Artifacts

action.yml

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ inputs:
3434
Higher levels will result in better compression, but will take longer to complete.
3535
For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
3636
default: '6'
37+
overwrite:
38+
description: >
39+
If true, an artifact matching name will be deleted before a new one is uploaded.
40+
If false, the action will fail if an artifact for the given name already exists.
41+
Does not fail if the artifact does not exist.
42+
default: 'false'
3743

3844
outputs:
3945
artifact-id:

dist/index.js

+393-13
Large diffs are not rendered by default.

docs/MIGRATION.md

+64
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- [Migration](#migration)
44
- [Multiple uploads to the same named Artifact](#multiple-uploads-to-the-same-named-artifact)
5+
- [Overwriting an Artifact](#overwriting-an-artifact)
56

67
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`.
78

@@ -78,3 +79,66 @@ jobs:
7879
```
7980

8081
In `v4`, the new `pattern:` input will filter the downloaded Artifacts to match the name specified. The new `merge-multiple:` input will support downloading multiple Artifacts to the same directory. If the files within the Artifacts have the same name, the last writer wins.
82+
83+
## Overwriting an Artifact
84+
85+
In `v3`, the contents of an Artifact were mutable so something like the following was possible:
86+
87+
```yaml
88+
jobs:
89+
upload:
90+
runs-on: ubuntu-latest
91+
steps:
92+
- name: Create a file
93+
run: echo "hello world" > my-file.txt
94+
- name: Upload Artifact
95+
uses: actions/upload-artifact@v3
96+
with:
97+
name: my-artifact # NOTE: same artifact name
98+
path: my-file.txt
99+
upload-again:
100+
needs: upload
101+
runs-on: ubuntu-latest
102+
steps:
103+
- name: Create a different file
104+
run: echo "goodbye world" > my-file.txt
105+
- name: Upload Artifact
106+
uses: actions/upload-artifact@v3
107+
with:
108+
name: my-artifact # NOTE: same artifact name
109+
path: my-file.txt
110+
```
111+
112+
The resulting `my-file.txt` in `my-artifact` will have "goodbye world" as the content.
113+
114+
In `v4`, Artifacts are immutable unless deleted. To achieve this same behavior, you can use `overwrite: true` to delete the Artifact before a new one is created:
115+
116+
```diff
117+
jobs:
118+
upload:
119+
runs-on: ubuntu-latest
120+
steps:
121+
- name: Create a file
122+
run: echo "hello world" > my-file.txt
123+
- name: Upload Artifact
124+
- uses: actions/upload-artifact@v3
125+
+ uses: actions/upload-artifact@v4
126+
with:
127+
name: my-artifact # NOTE: same artifact name
128+
path: my-file.txt
129+
upload-again:
130+
needs: upload
131+
runs-on: ubuntu-latest
132+
steps:
133+
- name: Create a different file
134+
run: echo "goodbye world" > my-file.txt
135+
- name: Upload Artifact
136+
- uses: actions/upload-artifact@v3
137+
+ uses: actions/upload-artifact@v4
138+
with:
139+
name: my-artifact # NOTE: same artifact name
140+
path: my-file.txt
141+
+ overwrite: true
142+
```
143+
144+
Note that this will create an _entirely_ new Artifact, with a different ID from the previous.

package-lock.json

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "upload-artifact",
3-
"version": "4.0.0",
3+
"version": "4.2.0",
44
"description": "Upload an Actions Artifact in a workflow run",
55
"main": "dist/index.js",
66
"scripts": {
@@ -29,7 +29,7 @@
2929
},
3030
"homepage": "https://github.com/actions/upload-artifact#readme",
3131
"dependencies": {
32-
"@actions/artifact": "^2.0.0",
32+
"@actions/artifact": "^2.1.0",
3333
"@actions/core": "^1.10.0",
3434
"@actions/github": "^6.0.0",
3535
"@actions/glob": "^0.3.0",

src/constants.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export enum Inputs {
44
Path = 'path',
55
IfNoFilesFound = 'if-no-files-found',
66
RetentionDays = 'retention-days',
7-
CompressionLevel = 'compression-level'
7+
CompressionLevel = 'compression-level',
8+
Overwrite = 'overwrite'
89
}
910

1011
export enum NoFileOptions {

src/input-helper.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {UploadInputs} from './upload-inputs'
88
export function getInputs(): UploadInputs {
99
const name = core.getInput(Inputs.Name)
1010
const path = core.getInput(Inputs.Path, {required: true})
11+
const overwrite = core.getBooleanInput(Inputs.Overwrite)
1112

1213
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
1314
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
@@ -25,7 +26,8 @@ export function getInputs(): UploadInputs {
2526
const inputs = {
2627
artifactName: name,
2728
searchPath: path,
28-
ifNoFilesFound: noFileBehavior
29+
ifNoFilesFound: noFileBehavior,
30+
overwrite: overwrite
2931
} as UploadInputs
3032

3133
const retentionDaysStr = core.getInput(Inputs.RetentionDays)

src/upload-artifact.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
import * as core from '@actions/core'
22
import * as github from '@actions/github'
3-
import artifact, {UploadArtifactOptions} from '@actions/artifact'
3+
import artifact, {
4+
UploadArtifactOptions,
5+
ArtifactNotFoundError
6+
} from '@actions/artifact'
47
import {findFilesToUpload} from './search'
58
import {getInputs} from './input-helper'
69
import {NoFileOptions} from './constants'
710

11+
async function deleteArtifactIfExists(artifactName: string): Promise<void> {
12+
try {
13+
await artifact.deleteArtifact(artifactName)
14+
} catch (error) {
15+
if (error instanceof ArtifactNotFoundError) {
16+
core.debug(`Skipping deletion of '${artifactName}', it does not exist`)
17+
return
18+
}
19+
20+
// Best effort, we don't want to fail the action if this fails
21+
core.debug(`Unable to delete artifact: ${(error as Error).message}`)
22+
}
23+
}
24+
825
async function run(): Promise<void> {
926
try {
1027
const inputs = getInputs()
@@ -38,6 +55,10 @@ async function run(): Promise<void> {
3855
)
3956
core.debug(`Root artifact directory is ${searchResult.rootDirectory}`)
4057

58+
if (inputs.overwrite) {
59+
await deleteArtifactIfExists(inputs.artifactName)
60+
}
61+
4162
const options: UploadArtifactOptions = {}
4263
if (inputs.retentionDays) {
4364
options.retentionDays = inputs.retentionDays

src/upload-inputs.ts

+5
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ export interface UploadInputs {
2525
* The level of compression for Zlib to be applied to the artifact archive.
2626
*/
2727
compressionLevel?: number
28+
29+
/**
30+
* Whether or not to replace an existing artifact with the same name
31+
*/
32+
overwrite: boolean
2833
}

0 commit comments

Comments
 (0)