Skip to content

fly-action/upload behaves differently from actions/upload-artifact when uploading directories #51

Description

@yahavi

Context

The start-working-with-fly skill (Phase 3 -- Generic Artifacts) replaces actions/upload-artifact steps with jfrog/fly-action/upload@v1 "as is" -- copying the same path / name inputs over to the Fly upload step.

This produces a working but semantically different upload, because the two actions handle directories very differently.

The difference

actions/upload-artifact@v7

  • A path: input that resolves to a directory uploads the entire directory tree, preserving relative paths.
  • The artifact is delivered to consumers as a single zip archive named <name>.zip. Internally the action streams files into one artifact entry on the GitHub Actions Artifact Service.
  • Wildcards are expanded, but directory contents are walked recursively.
- uses: actions/upload-artifact@v7
  with:
    name: dist
    path: build/         # uploads everything under build/, preserves structure, delivered as dist.zip

jfrog/fly-action/upload@v1

  • The files: input is a list of glob patterns that resolve to individual files. Only the basename is used as the remote filename (see upload/action.yml).
  • Directories are not archived. Passing build/ does not recursively upload its contents -- the user has to pass build/** (or similar) to collect files, and the directory structure is flattened because only basenames are kept.
  • Each matched file is uploaded as a separate artifact entry. There is no zip wrapper.
- uses: jfrog/fly-action/upload@v1
  with:
    name: dist
    version: \${{ github.sha }}
    files: build/        # NOT equivalent -- does not recursively upload, structure not preserved

Why this matters for start-working-with-fly

Today, the skill performs a 1:1 replacement of actions/upload-artifact@v7 -> jfrog/fly-action/upload@v1 and reuses the same path / name. After the migration:

  1. Directory uploads silently break or behave differently. A path: build/ becomes an upload that either matches nothing (if treated as literal) or a flattened set of basenames (if the user expanded to build/**), losing directory structure.
  2. Consumers expecting a single zip get N individual files instead. Anything downstream that did unzip dist.zip no longer works.
  3. Filename collisions become possible because we drop directory paths and only keep basenames (related to issue Upload silently overwrites files with the same basename #50).
  4. The replacement looks fine in the diff but produces a different artifact shape at runtime.

Proposed direction

A few options to discuss:

  1. Document the difference in the upload/README and in the start-working-with-fly skill, and have the skill rewrite directory inputs as explicit glob patterns when migrating (e.g. path: build/ -> files: build/**).
  2. Support directory inputs natively in jfrog/fly-action/upload@v1 -- when a files: entry resolves to a directory, recurse into it and preserve relative paths in the remote filename (matching actions/upload-artifact semantics more closely).
  3. Add an opt-in archive: true mode that zips matched files into a single archive before uploading, so users migrating from upload-artifact can preserve the "single zip" delivery shape.

Whatever we pick, the skill's current "replace as-is" step should be updated so users aren't surprised post-migration.

References

Metadata

Metadata

Assignees

Labels

improvementAutomatically generated release notes

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions