Skip to content

Commit

Permalink
Added mode and debug parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
Paebbels committed Dec 25, 2024
1 parent fa51267 commit cf36582
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 30 deletions.
54 changes: 28 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@
This composite action, based on [`actions/upload-artifact`](https://github.com/actions/upload-artifact) and packaging
the artifact's content in a tarball, will preserve file attributes like **file permissions**. This essential capability
is not implemented by GitHub until now (requested on [05.12.2019](https://github.com/actions/upload-artifact/issues/38))
and still delayed and/or refused? to be implemented in the future. According to GitHub, the internal API doesn't allow
the implementation of such a feature, but this actions is demonstrating a working solution.
and still delayed and/or rejected(?) to be implemented in the future. According to GitHub, the internal API doesn't
allow the implementation of such a feature, but this actions is demonstrating a working solution.

📥 See [pyTooling/download-artifact](https://github.com/pyTooling/download-artifact) for the matching download action.


## Additional Features compared to `actions/upload-artifact`

* Select an operation mode of `tar` or `legacy`. The latter will collect the files in an artifact without a tarball.
* Enabled debug mode, to list all gathered files in an artifact.
* Override the tarballs name in case of naming collisions.

See [pyTooling/download-artifact](https://github.com/pyTooling/download-artifact) for the matching download action.

## Advantages Compared to Competing GitHub Actions

* Support all parameters of `actions/upload-artifact`.
(Others support only a subset.)
* Supports Ubuntu, Windows and macOS GitHub Runner images.
(Others are created for Linux only.)
(Others are created for Linux in mind.)
* Well-defined behavior of tarball internal directory/file structure.
(No silent and "unpredictable" removal of common prefixes.)
* Store files in tarball without owner and group information.
* Testcases implemented as a pipeline verifying uploads/downloads using a tarball.
* Testcases are implemented as a pipeline, verifying uploads/downloads using a tarball.


## Usage

Expand Down Expand Up @@ -46,17 +55,19 @@ jobs:
### Input Parameters
| Parameter | Required | Default | Description |
|------------------------|:--------:|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | no | `'artifact'` | Name of the artifact to upload. |
| `working-directory` | no | `''` | |
| `path` | yes | | A list of files, directories or wildcard patterns that describes what to upload. |
| `if-no-files-found` | no | `'warn'` | The desired behavior if no files are found using the provided path. <br/> Available Options:<br/>  warn: Output a warning but do not fail the action<br/>  error: Fail the action with an error message<br/>  ignore: Do not output any warnings or errors, the action does not fail |
| `retention-days` | no | repository settings | Duration after which artifact will expire in days. 0 means using default retention. <br/> Minimum 1 day.<br/> Maximum 90 days unless changed from the repository settings page. |
| `compression-level` | no | `6` | The level of compression for Zlib to be applied to the artifact archive.<br/> The value can range from 0 to 9.<br/> For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads. |
| `overwrite` | no | `false` | If true, an artifact with a matching name will be deleted before a new one is uploaded.<br/> If false, the action will fail if an artifact for the given name already exists.<br/> Does not fail if the artifact does not exist. |
| `include-hidden-files` | no | `false` | Whether to include hidden files in the provided path in the artifact.<br/> The file contents of any hidden files in the path should be validated before enabled this to avoid uploading sensitive information. |
| `tarball-name` | no | [^1] | |
| Parameter | Required | Default | Description |
|------------------------|:--------:|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | no | `'artifact'` | Name of the artifact to upload. |
| `working-directory` | no | `''` | |
| `path` | yes | | A list of files, directories or wildcard patterns that describes what to upload. |
| `if-no-files-found` | no | `'warn'` | The desired behavior if no files are found using the provided path.<br/>Available Options:<br/> • `warn`: Output a warning but do not fail the action<br/> • `error`: Fail the action with an error message<br/> • `ignore`: Do not output any warnings or errors, the action does not fail |
| `retention-days` | no | repository settings | Duration after which artifact will expire in days. 0 means using default retention. <br/> Minimum 1 day.<br/> Maximum 90 days unless changed from the repository settings page. |
| `compression-level` | no | `6` | The level of compression for Zlib to be applied to the artifact archive.<br/> The value can range from 0 to 9.<br/> For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads. |
| `overwrite` | no | `false` | If true, an artifact with a matching name will be deleted before a new one is uploaded.<br/> If false, the action will fail if an artifact for the given name already exists.<br/> Does not fail if the artifact does not exist. |
| `include-hidden-files` | no | `false` | Whether to include hidden files in the provided path in the artifact.<br/> The file contents of any hidden files in the path should be validated before enabled this to avoid uploading sensitive information. |
| `mode` | no | `'tar'` | Mode of operation. Allowed modes:<br/> • `tar` (default),<br/> • `legacy` |
| `debug` | no | `false` | Enabled debug mode. List content of the created tarball. |
| `tarball-name` | no | [^1] | Filename of the embedded tarball. |

[^1]: `'__pyTooling_upload_artifact__.tar'`

Expand Down Expand Up @@ -85,7 +96,7 @@ jobs:

This action uses `tar` as provided by the GitHub runner's operating system images.

### On Linux (GNU tar)
### On Linux and Windows (GNU tar)

To ensure files starting with a dash aren't considered command line options to `tar`, `tar` is called with
`--verbatim-files-from` option.
Expand All @@ -112,15 +123,6 @@ To ensure files are extracted and assigned to the owner/group of the extracting
`--uname=root` and `--uid=0` are used when creating the tarball.


### On Windows (GNU tar)

To ensure files starting with a dash aren't considered command line options to `tar`, `tar` is called with
`--verbatim-files-from` option.

To ensure files are extracted and assigned to the owner/group of the extracting user, options `--owner=root:0` and
`--group=root:0` are used when creating the tarball.


## Dependencies

* [actions/upload-artifact@v4](https://github.com/actions/upload-artifact)
Expand Down
55 changes: 51 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,30 +80,51 @@ inputs:
type: boolean
required: false
default: false
mode:
description: |
Mode of operation. Allowed modes: tar (default), legacy
type: string
required: false
default: 'tar'
debug:
description: |
Enabled debug mode. List content of the created tarball.
type: boolean
required: false
default: false
tarball-name:
description: |
Filename of the embedded tarball.
type: string
required: false
default: '__pyTooling_upload_artifact__.tar'

outputs:
artifact-id:
description: "GitHub ID of an Artifact, can be used by the REST API"
value: ${{ steps.upload.outputs.artifact-id }}
description: |
GitHub ID of an Artifact, can be used by the REST API.
value: ${{ steps.upload.outputs.artifact-id || steps.upload-legacy.outputs.artifact-id }}
artifact-url:
description: |
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.
value: ${{ steps.upload.outputs.artifact-url }}
value: ${{ steps.upload.outputs.artifact-url || steps.upload-legacy.outputs.artifact-url}}

runs:
using: composite
steps:
- name: Create tarball from given file patterns
id: prepare
if: inputs.mode == 'tar'
shell: bash
run: |
# Create tarball from given file patterns
printf "::group::List all shell options via 'shopt' ..."
shopt
printf "::endgroup::"
set +e
shopt -s globstar
Expand Down Expand Up @@ -200,9 +221,20 @@ runs:
fileCount=$(tar -tf "${tarDirectory}${{ inputs.tarball-name }}" | wc -l)
printf "%s\n" "${ANSI_CYAN}Files collected: $fileCount${ANSI_NOCOLOR}"
- name: List content of the generated tarball
id: prepare
if: inputs.mode == 'tar' && inputs.debug == 'true'
shell: bash
run: |
# List content of the generated tarball
set +e
tar -tvf "${{ inputs.tarball-name }}"
# https://github.com/actions/upload-artifact
- name: Upload artifact
- name: Upload artifact (tarball)
id: upload
if: inputs.mode == 'tar'
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
Expand All @@ -215,8 +247,10 @@ runs:

- name: Remove temporary tarball
id: cleanup
if: inputs.mode == 'tar'
shell: bash
run: |
# Remove temporary tarball
set +e
ANSI_LIGHT_RED=$'\x1b[91m'
Expand All @@ -230,3 +264,16 @@ runs:
else
printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
fi
- name: Upload artifact (legacy)
id: upload-legacy
if: inputs.mode == 'legacy'
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
if-no-files-found: ${{ inputs.if-no-files-found }}
retention-days: ${{ inputs.retention-days }}
compression-level: ${{ inputs.compression-level }}
overwrite: ${{ inputs.overwrite }}
include-hidden-files: ${{ inputs.include-hidden-files }}

0 comments on commit cf36582

Please sign in to comment.