Skip to content

ROX-33792: optimize CLI artifact upload by removing tar/gzip bundling#20662

Open
janisz wants to merge 7 commits into
masterfrom
upliad-full-directory
Open

ROX-33792: optimize CLI artifact upload by removing tar/gzip bundling#20662
janisz wants to merge 7 commits into
masterfrom
upliad-full-directory

Conversation

@janisz
Copy link
Copy Markdown
Contributor

@janisz janisz commented May 18, 2026

Description

Problem: tar -cvzf bundling in artifact uploads took ~60s per artifact due to gzip compression overhead.

Solution: Replace gzip with faster approach:

  • Use tar -cf (bundling without compression)
  • Set compression-level: 1 (fast zstd compression by GitHub Actions)
  • Tar still required as single-file artifacts download more reliably than multi-file directories

Considered alternatives:

  • Direct directory upload: Attempted but failed - GitHub Actions has reliability issues downloading large multi-file artifacts (hundreds
    of binaries)
  • Higher compression levels: Slower with minimal size benefit for already-optimized binaries
  • No bundling at all: Single files download reliably, directories don't

Why tar without gzip:

  • Tar provides bundling (single file) for reliable downloads
  • GitHub Actions v7+ applies zstd compression (faster than gzip)
  • Binaries compress poorly, so CPU time saved > network transfer penalty
  • compression-level: 1 uses fast zstd mode

Performance results:

  • Go binaries ~60s → 22s (38s improvement)

User-facing documentation

Testing and quality

  • the change is production ready: the change is GA, or otherwise the
    functionality is gated by a feature flag
  • CI results are
    inspected

Automated testing

  • added unit tests
  • added e2e tests
  • added regression tests
  • added compatibility tests
  • modified existing tests

How I validated my change

  • Tested with PR build (run 26050731779): all build-and-push-main jobs
    passed
  • Verified artifact upload/download/extract works correctly:
    • CLI: tar bundling + upload in ~1s (vs ~60s before)
    • Go binaries amd64: tar bundling + upload in ~22s (vs ~60s before)
  • Confirmed binaries remain executable and Docker builds succeed
  • No changes to test logic or build outputs, only CI workflow optimization

Problem: The workflow uses tar/gzip to bundle CLI binaries before upload,
taking ~1 minute per build. The original rationale was to preserve file
permissions, but actions/upload-artifact@v7 preserves permissions natively.

Solution (Phase 1 of 3):
- Remove tar bundling step in pre-build-cli job
- Upload bin/ directory directly instead of creating cli-build.tgz
- Update 2 download locations to use path: . (preserves directory structure)
- Remove tar extraction steps (no longer needed)
- Add verification step to confirm binaries remain executable

Expected savings: ~30-40 seconds per build for CLI artifacts.
This is Phase 1 - Phase 2 will optimize Go binaries artifacts similarly.

User request: "Look this step in .github/workflows/build.yaml 'Run tar -cvzf
go-binaries-build.tgz bin/linux_amd64' take about a minute, do we really need it?
Maybe it will be faster if we use native upload artifact upload of a full directory"

Note: This change was partially generated with AI assistance.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new verification step uses stat -c '%a', which is GNU-specific; if any jobs ever run on macOS runners this will fail, so consider either guarding by OS or using a more portable way to print permissions.
  • Since the workflow now relies on actions/upload-artifact@v7 preserving permissions, it may be helpful to explicitly pin or assert that minimum version in the workflow (or add a brief comment) so future upgrades don’t unintentionally break this assumption.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new verification step uses `stat -c '%a'`, which is GNU-specific; if any jobs ever run on macOS runners this will fail, so consider either guarding by OS or using a more portable way to print permissions.
- Since the workflow now relies on `actions/upload-artifact@v7` preserving permissions, it may be helpful to explicitly pin or assert that minimum version in the workflow (or add a brief comment) so future upgrades don’t unintentionally break this assumption.

## Individual Comments

### Comment 1
<location path=".github/workflows/build.yaml" line_range="576-588" />
<code_context>
         run: |
-          tar xvzf cli-build.tgz
+          # Verify binaries are executable
+          for binary in bin/*/roxctl bin/*/roxagent; do
+            if [ -f "$binary" ]; then
+              if [ ! -x "$binary" ]; then
+                echo "ERROR: $binary is not executable"
+                ls -la "$binary"
+                exit 1
+              fi
+              echo "✓ $binary is executable ($(stat -c '%a' "$binary"))"
+            fi
</code_context>
<issue_to_address>
**suggestion:** The loop silently passes if no binaries match the glob, which may mask missing artifacts.

If the artifact layout changes or these files are missing, the globs won’t match, `[ -f "$binary" ]` will always be false, and the step will still succeed, hiding missing/mis-packaged artifacts. Please add an explicit check for the “no matches” case (for example, by first expanding into positional parameters and checking `$#`, or using `nullglob` and failing when the resulting list is empty).

```suggestion
      - name: Verify binary permissions after artifact download
        run: |
          # Verify binaries are executable
          shopt -s nullglob
          binaries=(bin/*/roxctl bin/*/roxagent)

          if [ ${#binaries[@]} -eq 0 ]; then
            echo "ERROR: no binaries found matching bin/*/roxctl or bin/*/roxagent"
            exit 1
          fi

          for binary in "${binaries[@]}"; do
            if [ -f "$binary" ]; then
              if [ ! -x "$binary" ]; then
                echo "ERROR: $binary is not executable"
                ls -la "$binary"
                exit 1
              fi
              echo "✓ $binary is executable ($(stat -c '%a' "$binary"))"
            fi
          done
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread .github/workflows/build.yaml Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

GitHub workflow CI/CD changes migrate CLI build artifacts from tarball format to direct directory upload. The pre-build CLI job now exports bin/ as-is, and downstream workflows (build-and-push-main and scan-go-binaries) are updated to consume the new artifact format with added binary verification steps.

Changes

CLI Build Artifact Migration

Layer / File(s) Summary
Pre-build CLI artifact upload change
.github/workflows/build.yaml
The pre-build CLI job's cli-build artifact upload is changed to publish the bin/ directory directly (artifact path changed to bin/) instead of bundling a tarball.
Main build workflow artifact consumption and verification
.github/workflows/build.yaml
The main build workflow downloads the cli-build artifact to the workspace root and adds a verification loop that checks bin/*/roxctl and bin/*/roxagent are present and executable, replacing prior tarball extraction.
Go binary scanner artifact consumption
.github/workflows/build.yaml
The Go binary scanning workflow is updated to download the cli-build artifact with path: . for direct directory placement instead of unpacking cli-build.tgz.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title directly and clearly describes the main change: removing tar/gzip bundling for CLI artifact uploads. It accurately reflects the primary objective of the PR and matches the core focus of the changeset.
Description check ✅ Passed The PR description is comprehensive and complete, covering problem, solution, alternatives considered, performance results, and validation approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upliad-full-directory

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yaml:
- Around line 576-588: The verification loop that iterates over "for binary in
bin/*/roxctl bin/*/roxagent;" currently only checks executability if files
exist, allowing the step to succeed when the glob matches nothing; update the
step to detect the case where no binaries were found and fail the job—e.g.,
track whether any iteration found an existing file (a counter or flag) inside
the loop that checks "-f \"$binary\"" and after the loop exit with non-zero
status and an explanatory error if the counter is zero so the workflow fails
when no CLI binaries were downloaded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: d68dcc14-7b4f-4528-978a-7f4a82f67482

📥 Commits

Reviewing files that changed from the base of the PR and between 5531088 and 14840dd.

📒 Files selected for processing (1)
  • .github/workflows/build.yaml

Comment thread .github/workflows/build.yaml Outdated
Problem: The previous commit had two issues:1. CLI artifact uploaded with `path: bin/` (trailing slash) which uploads
   CONTENTS of bin/, not the bin/ directory itself, breaking directory structure
2. Go binaries still used tar/gzip bundling

Root cause: When uploading `path: dir/`, it uploads dir contents. When
downloading with `path: .`, files go to workspace root without the dir/ prefix.

Solution:- CLI: Change upload to `path: bin` (no trailing slash) to upload the directory itself
- Go binaries: Apply same optimization - remove tar bundling, upload directories directly
- Update all 4 go-binaries download locations to add `path: .` and remove tar extraction

This combines Phase 1 (CLI) fix and Phase 2 (Go binaries) optimization:
- Fixes directory structure for CLI stubs (PR builds work without ci-build-cli label)
- Removes tar/gzip overhead for go-binaries across all architectures
- Expected savings: ~2-3 minutes per PR build (CLI: 59s + Go binaries: ~90-110s per arch)

Verified: Permission check shows binaries remain executable (755).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@janisz janisz changed the title ci: optimize CLI artifact upload by removing tar/gzip bundling ROX-33792: optimize CLI artifact upload by removing tar/gzip bundling May 18, 2026
janisz and others added 4 commits May 18, 2026 19:18
Problem: Previous attempt to upload go-binaries as raw directory failed because:
- Uncompressed artifact was 434 MB (too large for reliable download)
- GitHub Actions download failed after 5 retries with network errors
- All build-and-push-main jobs failed

Root cause: Large directory artifacts are less reliable than single files.
The 434MB uncompressed directory exceeded GitHub's reliable transfer limits.

Solution: Hybrid approach for go-binaries only (CLI stays as-is):
- Use `tar -cf` (WITHOUT gzip compression) to bundle binaries
- Creates single tarball file (reliable download/extract)
- GitHub Actions applies fast zstd compression to the tarball
- Skips slow gzip compression step (~15-30s savings)
- Download/extract uses `tar -xf` (fast, no decompression needed)

Result:
- CLI: Direct directory upload (59s savings) - WORKING
- Go binaries: tar (no gzip) + GH Actions zstd (~15-30s savings per arch)
- Total expected savings: ~90-150s per PR build

Verified upload timings (from successful run):
- CLI: 1 second (vs 60s before)
- Go binaries arm64: 29 seconds (vs 60s before)
- Go binaries amd64: 44 seconds (vs 60s before)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes:
1. Add compression-level parameter to upload-artifact-with-retry wrapper
2. Set compression-level: 1 for both CLI and go-binaries uploads
3. Remove permission verification step (permissions confirmed preserved)

Rationale:
- compression-level: 1 provides minimal compression with maximum speed
- zstd level 1 is significantly faster than level 6 (default) with only slightly larger artifacts
- Permission check validated in previous runs - no longer needed

Expected improvement:
- Faster artifact upload due to minimal compression overhead
- Cleaner workflow without redundant verification step

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Problem: Unnecessarily using tar when compression-level: 1 makes it obsolete.

Solution: Upload directories directly with compression-level: 1:
- Removed tar bundling step for go-binaries
- Removed all 4 tar extraction steps
- Upload path: bin/linux_${{ matrix.arch }} directly
- Fast zstd level 1 compression handles everything

Result:
- Simpler workflow (no tar/untar steps)
- Faster: no tar creation overhead (~5-10s per arch)
- Same benefits: compression-level 1 is fast and efficient

Both CLI and go-binaries now use same approach:
- Direct directory upload
- compression-level: 1
- path: . for downloads

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Problem: Direct directory upload (even with compression-level: 1) still fails
during download. Artifact download failed after 5 retries for go-binaries.

Root cause: GitHub Actions artifact download is more reliable with single
files than directories containing many files. The 434MB directory with
hundreds of binary files is unreliable to download, regardless of compression.

Solution: Use tar as a BUNDLING mechanism (not for compression):
- tar -cf creates single tarball file (reliable for download/upload)
- compression-level: 1 applies to the tarball (fast zstd compression)
- tar -xf extracts on download (minimal overhead)

Key insight: tar's value is creating a SINGLE FILE, not compression.
Single files download reliably; large multi-file directories don't.

Performance vs original (tar+gzip):
- Original: tar -cvzf (slow gzip compression + bundling)
- New: tar -cf (bundling only) + compression-level: 1 (fast zstd)
- Savings: Skip gzip (~15-30s), use faster zstd level 1

CLI artifacts remain direct upload (small, works fine).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

🚀 Build Images Ready

Images are ready for commit 5d30617. To use with deploy scripts:

export MAIN_IMAGE_TAG=4.11.x-1033-g5d306174ea

@janisz janisz force-pushed the upliad-full-directory branch 2 times, most recently from 0f0c6fb to 745369e Compare May 18, 2026 18:23
Replace tar -cvzf (gzip) with tar -cf + compression-level: 1 (fast zstd)
to reduce artifact upload time in CI builds.

- tar -cvzf → tar -cf (no gzip)
- compression-level: 1 (fast zstd by GitHub Actions)
- tar xvzf → tar -xf

Tar bundling still required as single-file artifacts download more
reliably than multi-file directories.

Performance:
- CLI artifact: 60s → 1s (59s improvement)
- Go binaries amd64: 60s → 22s (38s improvement)
- Total: ~97s (1.6min) saved per build

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@janisz janisz force-pushed the upliad-full-directory branch from 745369e to 5d30617 Compare May 18, 2026 18:24
@janisz janisz requested a review from davdhacs May 18, 2026 18:27
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 18, 2026

@janisz: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/ocp-4-21-nongroovy-e2e-tests 5d30617 link false /test ocp-4-21-nongroovy-e2e-tests

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant