Lifecycle of a change¶
Software in Ubuntu is delivered via packages and there might be various reasons to change them. A change might appear as a fix to a bug, as an update to a new version of a package or customizing the build and runtime configuration to the needs of all Ubuntu users.
Getting such a change into Ubuntu involves various steps to enable worldwide collaboration and to ensure the quality of an upload containing that change to the Ubuntu Archive.
The diagrams here show the path a change takes, each stage then refined in later sections, some with optional paths where applicable.
This overview of the involved mechanisms allows a contributor to know what topic to study next and can be considered a different point of view to the content aligned to the lifecycle of a change and its way into Ubuntu.
flowchart LR
BugReport["<a href='#lc-bug-report-and-triage'>Bug Report<br/>& Triage</a>"]
PrepareTest["<a href='#lc-prepare-fix'>Prepare<br/>& Test</a>"]
Review["<a href='#lc-review'>Propose<br/>& Review</a>"]
Upload["<a href='#lc-upload'>Sponsorship<br/>or Upload</a>"]
Migration["<a href='#lc-proposed-migration'>Proposed<br/>Migration</a>"]
SRU["<a href='#lc-sru'>Stable Release<br/>Update (SRU)</a>"]
BugReport --> PrepareTest
PrepareTest --> Review
Review --> Upload
Upload --> Migration
Upload -.-> |"active release"| SRU
SRU --> Migration
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class BugReport,PrepareTest,Review,Migration,Upload,SRU ubuntuStyle
Bug reporting and triage¶
Almost every change begins with filing a bug on Launchpad. A well-written report states how to reproduce the problem, which package is affected, and what the expected behaviour is. Ideally it includes references to related upstream changes or reports. Once filed, the bug is triaged: confirmed as real, assigned the appropriate importance, given a status, tagged (see Bug tags and Bug types), and routed to the right package. The bug serves as the central record that links all subsequent work (patch, merge proposal, upload).
flowchart LR
File["<a href=https://documentation.ubuntu.com/project/contributors/qa-and-testing/report-a-bug/>File bug on Launchpad</a><br/>with reproduction steps<br/>and system details"] --> Triage
Triage{"<a href=https://documentation.ubuntu.com/project/contributors/bug-triage/>Triage</a>:<br/>enough information?<br/>right package?<br/>assignee?"}
PrepareFix(["<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/lifecycle-of-a-change/#preparing-and-testing-the-fix>Prepare change</a>"])
Triage -.-> |"needs more info"| File
Triage --> |"actionable"| PrepareFix
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class File ubuntuStyle
classDef gateStyle fill:#D0E8FF,stroke:#3366CC,stroke-width:2px
class Triage gateStyle
classDef terminalStyle fill:#E0E0E0,stroke:#666666,stroke-width:2px
class PrepareFix terminalStyle
Preparing and testing the change¶
The most common type of change is a targeted patch: the fix
is written, the debian/changelog entry is updated, and the change is
proposed against a git-ubuntu branch.
Other change types include merges from a newer Debian version of the package (Merges & syncs), syncs where the Debian package is copied verbatim (Merges & syncs), and new packages — which, if destined for main or restricted, must also pass a Main Inclusion Review.
Before proposing the change for review, it should be proven to build correctly and not break existing functionality. The recommended approach is a PPA build on Launchpad — the same infrastructure that builds official Ubuntu packages. Once built, PPA packages can be shared with the bug reporter for smoke-testing, and automated DEP-8 tests can be run against them — see Automatic package testing: autopkgtest for how these tests are defined and integrated into packages. Building locally with sbuild is also an option for iterative debug cycles.
flowchart LR
Fix["Prepare change:<br/><a href=https://documentation.ubuntu.com/project/contributors/bug-fix/fix-a-bug-in-a-package/>patch</a> · <a href=https://documentation.ubuntu.com/project/contributors/merging/>merge</a> · <a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/merges-and-syncs/>sync</a>"]
Fix --> Build
Build["<a href=https://documentation.ubuntu.com/project/contributors/bug-fix/build-packages-in-a-ppa/>PPA build</a> on Launchpad<br/>(all architectures)"]
Build -.-> |"build fails"| Fix
Build --> |"build OK"| Test
Test["Run <a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/automatic-package-testing-autopkgtest/>autopkgtests</a><br/>against <a href=https://documentation.ubuntu.com/project/contributors/bug-fix/build-packages-in-a-ppa/>PPA</a> packages"]
Test -.-> |"test regressions"| Fix
ProposeChange(["<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/lifecycle-of-a-change/#proposing-and-reviewing>Propose change</a>"])
Test --> |"ready"| ProposeChange
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class Fix,Build,Test ubuntuStyle
classDef terminalStyle fill:#E0E0E0,stroke:#666666,stroke-width:2px
class ProposeChange terminalStyle
Proposing and reviewing¶
Once the fix builds and tests pass, it is
submitted as a merge proposal (MP)
against the relevant git-ubuntu branch on Launchpad. The merge proposal
links the fix to the bug, describes what was done
and why, and refers to a PPA and test results as far as they already exist.
Reviewers leave comments, the contributor iterates until the merge proposal
is approved.
A reviewer (typically a developer with upload rights)
checks the proposal against a
review checklist. This covers correctness
of the fix, packaging correctness (debian/changelog, version string,
copyright), DEP-3 patch headers, and adherence to Debian and Ubuntu policy.
Trivial or low-risk changes may receive a lighter-weight review.
flowchart LR
MP["<a href=https://documentation.ubuntu.com/project/contributors/patching/submit-a-merge-proposal/>Submit Merge Proposal</a><br/>on Launchpad"] --> Review
Review{"<a href=https://documentation.ubuntu.com/project/contributors/advanced/review-a-merge-proposal/>Code review</a>"}
Review -.-> |"changes requested"| Revise["Revise change</a>"]
Revise --> Review
Upload(["<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/lifecycle-of-a-change/#sponsorship-and-upload>Upload</a>"])
Review --> |"approved"| Upload
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class MP,Revise ubuntuStyle
classDef gateStyle fill:#D0E8FF,stroke:#3366CC,stroke-width:2px
class Review gateStyle
classDef terminalStyle fill:#E0E0E0,stroke:#666666,stroke-width:2px
class Upload terminalStyle
Sponsorship and uploads¶
Once approved, the change must be uploaded to the Ubuntu Archive.
Direct upload access is granted only after a developer has demonstrated consistent packaging quality (see the Uploader journey).
Until then, a contributor finds a sponsor — a
developer who reviews the change, signs the .changes file with their own
key, and runs dput on the contributor’s behalf.
Ideally the uploader is the person who did the review of the merge proposal, there is no need to be reviewed twice. Otherwise they might apply their own review before signing and uploading.
If you want to apply for upload rights later, you should keep track of your work and who has were your sponsors, as sponsors become endorsers for your application.
flowchart LR
Rights{"<a href=https://documentation.ubuntu.com/project/who-makes-ubuntu/developers/#path-to-upload-rights>Upload rights</a><br/>for this package?"}
Rights --> |"no: <a href=https://documentation.ubuntu.com/project/contributors/uploading/find-a-sponsor/>Find sponsor</a>"| Sponsor
Sponsor["sponsor <a href=https://documentation.ubuntu.com/project/contributors/advanced/review-a-merge-proposal/>re-reviews</a>"]
Sponsor --> |"sponsor approves"| Upload
Rights --> |"yes"| Upload
Upload(["<a href=https://documentation.ubuntu.com/project/contributors/uploading/>Upload to Ubuntu Archive</a>"])
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class Sponsor ubuntuStyle
classDef gateStyle fill:#D0E8FF,stroke:#3366CC,stroke-width:2px
class Rights gateStyle
classDef terminalStyle fill:#E0E0E0,stroke:#666666,stroke-width:2px
class Upload terminalStyle
Proposed migration¶
All accepted uploads land in the -proposed pocket
([codename]-proposed) first. From there, Launchpad builds binary packages
for every supported architecture. A series of automated quality gates must
then be passed before the package is allowed to migrate to the -release
or -updates pocket and thereby reach users.
Any regression must be investigated as it otherwise stays stuck in -proposed.
To migrate from the staging area, the update must:
Build Successfully The source package must not fail to build from source (FTBFS) on any architecture. In case of failure, the uploader must investigate the build log and upload a corrected source package.
Pass Autopkgtest (DEP-8) Automated functional tests in
debian/tests/inside the changed package and all its reverse-dependencies must pass.Pass Archive consistency check The tooling then verifies that the new binaries are installable together with everything else in the archive, that all required dependencies are present at the right version, and that nothing else becomes uninstallable as a side-effect. Any findings are reported as Issues preventing migration.
Progress for the current development release is visible on the update excuses page.
See How to resolve a migration issue for practical guidance on tackling such blockers.
flowchart TD
Build{Builds}
Fix["Please fix & re-upload"]
Autopkg{"<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/automatic-package-testing-autopkgtest/>Autopkgtests</a>"}
InvestigateAPKGT["<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/proposed-migration/autopkgtest-regressions/>Investigate regressions</a>"]
ArchiveChecks{"<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/proposed-migration/issues-preventing-migration/>Archive consistency</a><br/>(<a href=https://ubuntu-archive-team.ubuntu.com/proposed-migration/update_excuses.html>Britney</a>)"}
Done(["Migrates"])
Build -.-> |"<a href=https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/proposed-migration/failure-to-build-from-source-ftbfs/>FTBFS"</a>| Fix
Build --> |"all builds OK"| Autopkg
Autopkg -.-> |"regressions"| InvestigateAPKGT
Autopkg --> |"all pass"| ArchiveChecks
InvestigateAPKGT -.-> |"Real problem"| Fix
InvestigateAPKGT --> |"Transient issues, now resolved"| ArchiveChecks
ArchiveChecks -.-> |"blocked by dependencies"| Fix
ArchiveChecks --> |"all checks OK"| Done
classDef ubuntuStyle fill:#FFDAB9,stroke:#E95420,stroke-width:2px
class Fix,InvestigateAPKGT ubuntuStyle
classDef gateStyle fill:#D0E8FF,stroke:#3366CC,stroke-width:2px
class Build,Autopkg,ArchiveChecks gateStyle
classDef terminalStyle fill:#E0E0E0,stroke:#666666,stroke-width:2px
class Done terminalStyle
Stable release updates (SRU)¶
Updates for the current Ubuntu development version can directly be released.
But after publication of an Ubuntu release (such as 26.04), its package archive is
frozen for updates.
Bug fixes, security patches, and important improvements can still be provided
for users through the Stable Release Update
(SRU) process — but only under strict requirements
designed to avoid regressions by an update.
A lot of the machinery is shared, an SRU upload passes through the same Proposed migration as any other. At the beginning the SRU team reviews and accepts from the -unapproved queue, and at the end the SRU team verifies the case to be ready to then releases it to -updates.
See SRU pipeline for the flow of these extra steps.