Skip to content

Commit

Permalink
add new overwrite input & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
robherley committed Jan 18, 2024
1 parent 1eb3cb2 commit 11ff42c
Show file tree
Hide file tree
Showing 10 changed files with 536 additions and 26 deletions.
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ See also [download-artifact](https://github.com/actions/download-artifact).
- [Using Outputs](#using-outputs)
- [Example output between steps](#example-output-between-steps)
- [Example output between jobs](#example-output-between-jobs)
- [Overwriting an Artifact](#overwriting-an-artifact)
- [Limitations](#limitations)
- [Number of Artifacts](#number-of-artifacts)
- [Zip archives](#zip-archives)
Expand All @@ -44,7 +45,7 @@ For more information, see the [`@actions/artifact`](https://github.com/actions/t

1. Uploads are significantly faster, upwards of 90% improvement in worst case scenarios.
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.
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.
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.
4. The compression level of an Artifact can be manually tweaked for speed or size reduction.

### Breaking Changes
Expand Down Expand Up @@ -365,6 +366,36 @@ jobs:
run: echo "Artifact ID from previous job is $OUTPUT1"
```

### Overwriting an Artifact

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:

```yaml
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a file
run: echo "hello world" > my-file.txt
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
upload-again:
needs: upload
runs-on: ubuntu-latest
steps:
- name: Create a different file
run: echo "goodbye world" > my-file.txt
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
overwrite: true
```

## Limitations

### Number of Artifacts
Expand Down
6 changes: 6 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ inputs:
Higher levels will result in better compression, but will take longer to complete.
For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
default: '6'
overwrite:
description: >
If true, an artifact 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.
default: 'false'

outputs:
artifact-id:
Expand Down
406 changes: 393 additions & 13 deletions dist/index.js

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

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 @@ -78,3 +79,66 @@ jobs:
```

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.

## Overwriting an Artifact

In `v3`, the contents of an Artifact were mutable so something like the following was possible:

```yaml
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a file
run: echo "hello world" > my-file.txt
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
upload-again:
needs: upload
runs-on: ubuntu-latest
steps:
- name: Create a different file
run: echo "goodbye world" > my-file.txt
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
```
The resulting `my-file.txt` in `my-artifact` will have "goodbye world" as the content.

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:

```diff
jobs:
upload:
runs-on: ubuntu-latest
steps:
- name: Create a file
run: echo "hello world" > my-file.txt
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
upload-again:
needs: upload
runs-on: ubuntu-latest
steps:
- name: Create a different file
run: echo "goodbye world" > my-file.txt
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: my-artifact # NOTE: same artifact name
path: my-file.txt
+ overwrite: true
```

Note that this will create an _entirely_ new Artifact, with a different ID from the previous.
14 changes: 7 additions & 7 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "upload-artifact",
"version": "4.0.0",
"version": "4.2.0",
"description": "Upload an Actions Artifact in a workflow run",
"main": "dist/index.js",
"scripts": {
Expand Down Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/actions/upload-artifact#readme",
"dependencies": {
"@actions/artifact": "^2.0.0",
"@actions/artifact": "^2.1.0",
"@actions/core": "^1.10.0",
"@actions/github": "^6.0.0",
"@actions/glob": "^0.3.0",
Expand Down
3 changes: 2 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export enum Inputs {
Path = 'path',
IfNoFilesFound = 'if-no-files-found',
RetentionDays = 'retention-days',
CompressionLevel = 'compression-level'
CompressionLevel = 'compression-level',
Overwrite = 'overwrite'
}

export enum NoFileOptions {
Expand Down
4 changes: 3 additions & 1 deletion src/input-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {UploadInputs} from './upload-inputs'
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 ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
Expand All @@ -25,7 +26,8 @@ export function getInputs(): UploadInputs {
const inputs = {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior
ifNoFilesFound: noFileBehavior,
overwrite: overwrite
} as UploadInputs

const retentionDaysStr = core.getInput(Inputs.RetentionDays)
Expand Down
23 changes: 22 additions & 1 deletion src/upload-artifact.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import artifact, {UploadArtifactOptions} from '@actions/artifact'
import artifact, {
UploadArtifactOptions,
ArtifactNotFoundError
} from '@actions/artifact'
import {findFilesToUpload} from './search'
import {getInputs} from './input-helper'
import {NoFileOptions} from './constants'

async function deleteArtifactIfExists(artifactName: string): Promise<void> {
try {
await artifact.deleteArtifact(artifactName)
} catch (error) {
if (error instanceof ArtifactNotFoundError) {
core.debug(`Skipping deletion of '${artifactName}', it does not exist`)
return
}

// Best effort, we don't want to fail the action if this fails
core.debug(`Unable to delete artifact: ${(error as Error).message}`)
}
}

async function run(): Promise<void> {
try {
const inputs = getInputs()
Expand Down Expand Up @@ -38,6 +55,10 @@ async function run(): Promise<void> {
)
core.debug(`Root artifact directory is ${searchResult.rootDirectory}`)

if (inputs.overwrite) {
await deleteArtifactIfExists(inputs.artifactName)
}

const options: UploadArtifactOptions = {}
if (inputs.retentionDays) {
options.retentionDays = inputs.retentionDays
Expand Down
5 changes: 5 additions & 0 deletions src/upload-inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ export interface UploadInputs {
* The level of compression for Zlib to be applied to the artifact archive.
*/
compressionLevel?: number

/**
* Whether or not to replace an existing artifact with the same name
*/
overwrite: boolean
}

0 comments on commit 11ff42c

Please sign in to comment.