Skip to content

Conversation

brandtkeller
Copy link
Member

@brandtkeller brandtkeller commented Jul 31, 2025

Nightly Release

Purpose

A nightly release of Zarf provides daily feedback on the result of release-artifacts ability to be built and distributed. It also includes confidence in the underlying infrastructure and tooling used to produce releases given that they are not all entirely static (IE hosted Github runner images).

Context

Zarf now has a goreleaser pro license and can be used to build nightly releases.

We will not yet be making any changes to the official release process until specific features are identified.

See nightlies documentation for more information on nightly releases.

Acknowledges the cost of our current release infrastructure relying on the larger runners.

Workflow

This nightly attempts to mirror the release workflow as much as possible, with the exception of the following:

  • CLI_VERSION increments the patch of the current release semver and adds a -nightly suffix
    • example: current version v0.60.0 -> nightly release v0.60.1-nightly
  • The nightly github tag will be created and maintained as the sole tag
  • The file structure resembles that of goreleaser
    • The pro features being set in .goreleaser-pro.yaml and then importing the .goreleaser.yaml

What does this look like?

  • The agent image is built with a CLI_VERSION tag and pushed to ghcr
    • IE v0.60.1-nightly
  • The CLI is built with a CLI_VERSION version
    • IE v0.60.1-nightly
  • Using this CLI binary - the corresponding Zarf init package is built and published to ghcr
    • IE zarf-init-amd64-v0.60.1-nightly.tar.zst
    • This allows zarf init and zarf tools download-init to natively use the cli version
  • The nightly goreleaser config contains keep_single_release: true
    • This ensures there is only ever a single release for the nightly
  • The nightly goreleaser config contains tag_name: nightly
    • Under the repository tags you will only find a single nightly tag
  • The nightly goreleaser config contains version_template: "{{ .Version }}"
    • this inherits CLI_VERSION from GORELEASER_CURRENT_TAG in the workflow
    • Under releases you will only find a single nightly release with the patch version incremented
    • IE if latest equals v0.60.0 - then the nightly will be v0.60.1-nightly until the latest version is changed.

Assumptions

  • Assuming that functionality not configured for nightly releases will not be used given the skipped items.

Additional Notes

  • Does the project want to use nightly or devel or similar as the tag?
  • Do we care about the many nightly tags for the init package?

Future Work

  • deduplicate release logic between nightly and primary release
  • investigate other goreleaser pro features we may want to implement

Related Issue

Fixes #3928

Checklist before merging

Signed-off-by: Brandt Keller <brandt.keller@defenseunicorns.com>
@brandtkeller brandtkeller self-assigned this Jul 31, 2025
Copy link

netlify bot commented Jul 31, 2025

Deploy Preview for zarf-docs ready!

Name Link
🔨 Latest commit a4cee81
🔍 Latest deploy log https://app.netlify.com/projects/zarf-docs/deploys/68a39dd6e12b780008821abb
😎 Deploy Preview https://deploy-preview-4035--zarf-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

codecov bot commented Jul 31, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: Brandt Keller <brandt.keller@defenseunicorns.com>
Signed-off-by: Brandt Keller <brandt.keller@defenseunicorns.com>
@brandtkeller brandtkeller marked this pull request as ready for review August 4, 2025 21:07
@brandtkeller brandtkeller requested review from a team as code owners August 4, 2025 21:07
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we make a common workflow that accepts the goreleaser file and tag as variables?

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe that is what we'll want to trend towards as we understand the process and implications.

What I didn't want to do is bury the implementation and core decisions (tags, versions, etc) in too much abstraction.

Need to look at variables and workflow-dispatch further as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good, I definitely don't want to have to make changes in two spots long term, but I think it would make sense to get this working then abstract afterwards

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to look at this overlay this morning.

Also considering immutable releases and if they are compatible with goreleaser.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good. Also to be clear, I'm good with merging before we abstract then doing that work in a future PR. May even be the optimal path given that these things are hard to test

@AustinAbro321
Copy link
Contributor

Two more questions? Does this create a tag that sdk users will be able to consume? What will the UI look like for releases. When someone opens up the main repo page will they see the nightly or most recent regular release in this block? I'd assume the latter, but just want to double check.
image

@brandtkeller
Copy link
Member Author

Two more questions? Does this create a tag that sdk users will be able to consume?

This may be a gap to be honest. The tag is re-used - so it indeed can be used. But this would not be the advisable method as opposed to using commit sha's directly.

What will the UI look like for releases. When someone opens up the main repo page will they see the nightly or most recent regular release in this block? I'd assume the latter, but just want to double check.

The nightly should be marked as a pre-release and thus the latest will still be the primary release when opening the repository on the web.

I added a What does this look like? section to the PR description above.

@AustinAbro321
Copy link
Contributor

I would prefer nightly tags are not the default option for the agent and init shown by github here https://github.com/zarf-dev/zarf/pkgs/container/packages%2Finit, but I don't think that's possible to configure, and it's necessary to publish them for true nightly builds imo. Most users will not check that repo anyway.

The one worry I do have for these cases is how they will affect renovate or dependabot updates? Will those tools skip them because there is a nightly? Looking at repo1/ironbank I think so, given that it looks at the github releases https://repo1.dso.mil/dsop/opensource/zarf-dev/zarf/zarf-agent/-/blob/development/renovate.json?ref_type=heads, so I would assume it doesn't include pre-release. However, if a user was to instead use renovate on the init package or images, they might get a renovate / dependabot PR every night

@brandtkeller
Copy link
Member Author

I would prefer nightly tags are not the default option for the agent and init shown by github here https://github.com/zarf-dev/zarf/pkgs/container/packages%2Finit, but I don't think that's possible to configure, and it's necessary to publish them for true nightly builds imo. Most users will not check that repo anyway.

This is certainly a tradeoff for the process.

The one worry I do have for these cases is how they will affect renovate or dependabot updates? Will those tools skip them because there is a nightly? Looking at repo1/ironbank I think so, given that it looks at the github releases https://repo1.dso.mil/dsop/opensource/zarf-dev/zarf/zarf-agent/-/blob/development/renovate.json?ref_type=heads, so I would assume it doesn't include pre-release. However, if a user was to instead use renovate on the init package or images, they might get a renovate / dependabot PR every night

The answer should be no - these updates will not affect renovate/dependabot. Both treat a suffix such as -nightly as a Semantic-Versioning pre-release label. Their default behaviour is to ignore pre-release versions unless the project is already pinned to a pre-release of the same series or you explicitly opt-in to them.

This does raise a question for whether we want to be able to debug potentially older nightly releases - IE to identify when some regression might have occurred (current implementation). Or whether we focus on a static nightly tag which can reduce how many items we see in the packages pages. I'll take a look at that strategy.

@AustinAbro321
Copy link
Contributor

Gotcha, and from what I can gather currently the agent would have a nightly tag and be replaced each night while the init package would have a unique tag since the init package version and zarf version and tightly coupled. Zarf itself is coupled to the init package given that the init process references component names, so I don't think we're yet in a position to break that coupling. We could make the CLI version nightly, though then knowing which nightly you have is more difficult to determine. So tradeoffs here on both sides, and I can see an argument for either decision.

@brandtkeller
Copy link
Member Author

brandtkeller commented Aug 15, 2025

Mapping this out:

flowchart TD
  %% -------- Repo gating (fork safety) --------
  subgraph RepoGuard
    RG0["env.UPSTREAM_REPO = <code>zarf-dev/zarf</code>"] --> RG1{"github.repository == env.UPSTREAM_REPO?"}
    RG1 -- No --> RGX["Skip all jobs"]
    RG1 -- Yes --> BuildAndPublish
  end

  %% -------- Build & Publish path --------
  subgraph BuildAndPublish
    A["Checkout<br/>(fetch-depth: 0, tags available)"] --> B["Compute <b>CLI_VERSION</b><br/>&bull; Find highest semver tag (preserve 'v')<br/>&bull; incpatch + <code>-nightly</code><br/>e.g., <code>v0.60.0</code> → <code>v0.60.1-nightly</code>"]
    B --> C["Build CLI with <b>CLI_VERSION</b>"]
    C --> D["Build Agent Image"]
    D --> E["Push to GHCR<br/><code>ghcr.io/zarf-dev/zarf/agent:<b>CLI_VERSION</b></code>"]
    E --> F["Inspect image and capture digest"]
    F --> G["Cosign sign by digest<br/>annotation <code>version=<b>CLI_VERSION</b></code>"]
    G --> H["Build init packages<br/><code>AGENT_IMAGE_TAG=<b>CLI_VERSION</b></code>"]
    H --> I["Publish init packages (OCI + skeleton)<br/>uses <b>CLI_VERSION</b>"]
    I --> J["Upload build artifacts"]
    I --> R["Native use:<br/>&bull; <code>zarf init</code><br/>&bull; <code>zarf tools download-init</code><br/>(uses <b>CLI_VERSION</b>)"]
  end

  %% -------- Validate path --------
  subgraph Validate
    J --> V1["Download artifacts"]
    V1 --> V2["Run e2e tests<br/>(<code>CLI_VERSION</code>, appliance mode)"]
    V2 --> V3["Save logs (always)"]
  end

  %% -------- Release with GoReleaser --------
  subgraph ReleaseWithGoReleaser
    J --> GR1["GoReleaser (Pro) <code>--nightly</code>"]
    GR1 --> GR2["Env: <code>GORELEASER_CURRENT_TAG=<b>CLI_VERSION</b></code>"]
    GR2 --> GR3["<code>.Version</code>/<code>.Tag</code> resolve to <b>CLI_VERSION</b> in config"]
    GR3 --> GR4["Produce nightly release artifacts for <b>CLI_VERSION</b>"]
  end


Loading

@AustinAbro321
Copy link
Contributor

That map checks out, and I believe presents a good solution. To make sure I understand this correctly, this will produce a tag in the git repository v0.60.1-nightly, however the value of the Zarf CLI CLIVersion variable for that nightly will be v0.60.1-<commit-hash>-nightly?

@brandtkeller
Copy link
Member Author

That map checks out, and I believe presents a good solution. To make sure I understand this correctly, this will produce a tag in the git repository v0.60.1-nightly, however the value of the Zarf CLI CLIVersion variable for that nightly will be v0.60.1-<commit-hash>-nightly?

As it stands currently:
git tag = nightly - never changes
CLIVersion = <semver-patch+1>-<commit-hash>-nightly (CLI and zarf init package tagged accordingly)
Release Name = <semver-patch+1>-nightly

I am considering removing the commit hash. So that it reduces the sprawl down to:
git tag = nighty (keeps this from being noisy during search)
release name / CLI Version = <semver-patch+1>-nightly

So if current version is v0.60.0 then the current nightly will be v0.60.1-nightly. I don't believe we need the commit hash versioning. If the nightly fails we should be responding promptly.

Thoughts?

@AustinAbro321
Copy link
Contributor

Ah gotcha, I was missing the differentiation between git tag and release name.

Yeah, I think the latter strategy would make sense, I like starting simpler and adding more if we need it.

@brandtkeller
Copy link
Member Author

Updated the mermaid diagram and the PR description to reflect the latter strategy.

Copy link
Contributor

@AustinAbro321 AustinAbro321 left a comment

Choose a reason for hiding this comment

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

LGTM

@brandtkeller brandtkeller added this pull request to the merge queue Aug 19, 2025
Merged via the queue into main with commit ca7ede3 Aug 19, 2025
27 checks passed
@brandtkeller brandtkeller deleted the 3928_nightly_build branch August 19, 2025 21:23
Ansible-man pushed a commit to Ansible-man/zarf that referenced this pull request Sep 6, 2025
Signed-off-by: Brandt Keller <brandt.keller@defenseunicorns.com>
Signed-off-by: Cade Thomas <cadethomas23@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nightly Build
2 participants