Skip to content

CI: don't push versions to stable#26365

Merged
mrpollo merged 1 commit intomainfrom
pr-fix-qgc-stable
Feb 13, 2026
Merged

CI: don't push versions to stable#26365
mrpollo merged 1 commit intomainfrom
pr-fix-qgc-stable

Conversation

@julianoes
Copy link
Copy Markdown
Contributor

From what I understand, we should only update to stable based on the where the stable branch points, but not any release automatically.

Addresses #26340.

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Jan 28, 2026

@julianoes LMK if this matches your expectations, I also sent a commit to the backport branch

@julianoes
Copy link
Copy Markdown
Contributor Author

julianoes commented Jan 29, 2026

NOTE: The 'stable' and 'beta' branches are NOT triggers. These branches are
reset to match release tags, so the tag push handles the upload. This avoids
race conditions where branch and tag builds could overwrite each other.

I think I'm ok with this but that's not how it used to be as far as I'm aware.

Also, it doesn't work when triggering stable builds from release. What if we have v1.17.0 -> supposedly stable, but we decide to make a release for v1.16.2 to bugfix something? I think that should be possible.

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 2, 2026

That's a valid case, however sadly QGC will always fetch from the stable directory which will contain whatever was pushed there last, which could be either 1.16.2 or 1.17.0 depending on which tag was pushed last.

Once we move to the firmware manifest strategy we will be able to avoid this entirely.

As far as I'm aware this is how it's always worked.

@julianoes
Copy link
Copy Markdown
Contributor Author

As far as I'm aware the stable brunch is what triggered the push to stable and thus into QGC. I'm fairly sure on this because I had made releases in the past and forgot to push/update the stable branch (because I didn't know and it wasn't documented) and QGC did not actually update!

@julianoes
Copy link
Copy Markdown
Contributor Author

@mrpollo I reverted your commit because we (@dagar and @MaEtUgR) agreed on the call that stable is only updated on tag AND stable branch, as it was and as it was the intention.

@julianoes julianoes requested a review from dagar February 4, 2026 17:18
@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 6, 2026

Hey Julian, I wanted to explain the reasoning behind my commit so you can factor it in as you decide how to move forward.

The main concern I was trying to address is the double-trigger scenario. The current workflow triggers on both tags and branches:

on:
  push:
    tags:
      - 'v*'
    branches:
      - 'main'
      - 'stable'
      - 'beta'

When a release is made, two things typically happen close together: a version tag is pushed (e.g., v1.16.1) and the stable branch is reset to point at that tag. GitHub Actions treats these as two separate push events, so two independent workflow runs fire nearly simultaneously:

  • Run 1 (tag trigger): Checks out the code at v1.16.1, builds all targets, uploads to v1.16.1/ in S3
  • Run 2 (branch trigger): Checks out the code at the stable branch head, builds all targets, uploads to stable/ in S3

Beyond the wasted CI resources of building everything twice, this creates a real problem with version identification. PX4's CMake build uses git describe to embed the version into the binary and the .px4 file. The tag-triggered run will resolve correctly because it checks out the tag directly. But the branch-triggered run depends on the tag being available in the checkout at the time it runs. If the stable branch is pushed before the tag ref is fully propagated, or if fetch-depth doesn't pull in the tag, git describe won't resolve to the tag and the artifacts will end up with an incorrect version string (something like v1.16.0-123-gabcdef instead of v1.16.1). These misidentified binaries then get uploaded to stable/ and served to QGC users. This has been documented as an issue before.

The other thing my commit addressed was pre-release classification. Without distinguishing tag suffixes, any v* tag that happens to land on the stable branch would push to stable/ - which is what caused #26340 in the first place. My approach parsed the tag to route pre-releases (-alpha, -beta, -rc) to beta/ and only clean version tags (vX.Y.Z) to stable/. This also carried over to GitHub Releases, automatically marking pre-releases as such.

I understand the team's preference to keep the stable branch as the mechanism that controls what goes into the stable/ S3 directory. That raises a few questions though: what should the behavior be for pre-releases? Should the same logic apply, where pre-releases only upload to beta/ when someone pushes to the beta branch? And if the branch pushes are the intended triggers for uploading to stable/ and beta/, should we remove the tag triggers altogether to avoid the double-build race condition? Happy to rework the commit to match whatever approach you all decide on.

@julianoes
Copy link
Copy Markdown
Contributor Author

Thanks for explaining this @mrpollo.

If the stable branch is pushed before the tag ref is fully propagated, or if fetch-depth doesn't pull in the tag, git describe won't resolve to the tag and the artifacts will end up with an incorrect version string

I agree this is a tricky one. My suggestion would be to document the release process to make sure the tag and branch are pushed together. If they are pushed together, both CI runs should pick up the tag, right?

Should the same logic apply, where pre-releases only upload to beta/ when someone pushes to the beta branch?

Yes!

And if the branch pushes are the intended triggers for uploading to stable/ and beta/, should we remove the tag triggers altogether to avoid the double-build race condition? Happy to rework the commit to match whatever approach you all decide on.

I think we still need it for the case where we have the stable branch pointing to v1.17.0 but we create the release v1.16.2 containing a few backports. If we decide we never do that, then we shouldn't need it ineed.

@MaEtUgR and @dagar, do you agree? I really would like you to chime in here because this is currently broken (wrong) in QGC and needs resolving ASAP.

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 8, 2026

Here's the release process draft #26272

@julianoes
Copy link
Copy Markdown
Contributor Author

Well, I'm not sure what I should do here. @mrpollo you don't seem convinced of what I suggest and no one else seems to be bothered enough that QGC has been flashing v1.17 instead of v1.16 for more than two weeks to chime in here and help out.

I can either merge and try it out myself, or close it and walk away.

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 10, 2026

I think we are close here. The main decision we have to make is what triggers the release builds. My view is that it should always be the tag, where you seem to have gotten feedback from @dagar and @MaEtUgR that the stable branch reset, and push should do it.

Either works, but as you found out, I'm the only one maintaining this part of the codebase, so I'm going to overrule them unless they chime here and explain why they think their approach is better.

I can take care of the branch from here if you have spent enough time on it. I will bring it up on this week's call and make a decision.

MaEtUgR
MaEtUgR previously approved these changes Feb 11, 2026
Copy link
Copy Markdown
Member

@MaEtUgR MaEtUgR left a comment

Choose a reason for hiding this comment

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

The available stable build on S3 should be determined only by the stable branch 👍

Workflow:

  1. Tag e.g. 1.16.2 -> gets uploaded to 1.16 stable bucket
  2. Move branch stable to that commit -> gets uploaded to stable bucket

@julianoes
Copy link
Copy Markdown
Contributor Author

@mrpollo did you come to a conclusion in the dev call?

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 11, 2026

Pretty much what @MaEtUgR suggested, I will bring back my commit and tweak it to address the current goals, I will ping you when I'm done for a quick review before merging

@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 12, 2026

@julianoes I forced push to this branch so only one commit gets pushed, cleaner history, and it matches what was agreed upon. We are ready to merge.

Here's an excerpt from the workflow file leaving this in as guide for whoever comes next in the future trying to find answers, I will also document this at a later point in another PR I am preparing.

# ===================================================================================
# RELEASE UPLOAD LOGIC
# ===================================================================================
# This workflow handles building firmware and uploading to S3 + GitHub Releases.
#
# S3 Bucket Structure (s3://px4-travis/Firmware/):
#   - master/          <- Latest main branch build (for QGC compatibility)
#   - stable/          <- Latest stable release, controlled by 'stable' branch
#   - beta/            <- Latest pre-release, controlled by 'beta' branch
#   - vX.Y.Z/          <- Archived stable release
#   - vX.Y.Z-beta1/    <- Archived pre-release
#
# Trigger Behavior:
#   - Tag v1.16.1        -> Upload to: v1.16.1/ only (versioned archive)
#   - Tag v1.17.0-beta1  -> Upload to: v1.17.0-beta1/ only (versioned archive)
#   - Branch main        -> Upload to: master/ (for QGC compatibility)
#   - Branch stable      -> Upload to: stable/ (QGC stable firmware)
#   - Branch beta        -> Upload to: beta/ (QGC beta firmware)
#   - Branch release/**  -> Build only, no S3 upload (CI validation)
#   - Pull requests      -> Build only, no S3 upload (CI validation)
#
# GitHub Releases:
#   - All version tags create a draft GitHub Release
#   - Pre-releases (alpha/beta/rc suffixes) are automatically marked as such
#
# IMPORTANT: Version tags do NOT upload to stable/ or beta/. Only the
# corresponding branch pushes control those directories. This prevents
# pre-release tags from accidentally overwriting stable firmware (#26340)
# and avoids race conditions between tag and branch builds.
# ===================================================================================

Copy link
Copy Markdown
Contributor Author

@julianoes julianoes left a comment

Choose a reason for hiding this comment

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

I think that makes sense now.

Remove the step that uploaded every version tag to the stable/ S3
directory, which caused QGC users selecting "stable" to receive
pre-release firmware (#26340). The stable/ and beta/ directories
are now controlled exclusively by their respective branch pushes,
while version tags only upload to their versioned archive directory
(e.g., v1.16.1/). Pre-release tags are also correctly marked on
GitHub Releases.

Co-authored-by: Julian Oes <julian@oes.ch>

Fixes #26340

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
@mrpollo mrpollo merged commit 32c94bd into main Feb 13, 2026
77 checks passed
@mrpollo mrpollo deleted the pr-fix-qgc-stable branch February 13, 2026 14:29
@mrpollo
Copy link
Copy Markdown
Contributor

mrpollo commented Feb 13, 2026

🎉 thanks everyone

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.

3 participants