Adopt Annual Release Cycle (DEP 20)#109
Conversation
| Django will use Calendar Versioning in the form ``YYYY.N``, where: | ||
|
|
||
| * ``YYYY`` is the four-digit calendar year of the major release. | ||
| * ``N`` is a monotonically incrementing counter within that year, starting |
There was a problem hiding this comment.
I wonder if this could either start at 0 or be of the format NNN. The point here is not to create the assumption that this number represents the month in said year. Especially given that there is a monthly release.
Unless of course we do want to closely match the month, but not quite if there is an urgent security release?
There was a problem hiding this comment.
And also later in the cycle (years 2 and 3) many months may pass between releases. Making the second number the month was rejected (via the Forum discussion IIRC) because it would leave a question as to "Did I miss one" in such a case.
NN might work.
My preference is for .1 over .0 — it's the number of the release in the cycle.
General point: Discussing this over the last few months, it's become clear that the exact numbering scheme is a "What shade?" question (vs falling into line with the Python release process, and removing the gap between LTSs, which are the substance)
As such, I'm happy to go with whatever emerges as consensus on the numbering scheme. The text presented here captures what I think was the balance of opinion so far. (I use YY for the year in my own projects, and initially favoured that, for example.)
There was a problem hiding this comment.
@carltongibson that would be different from Python, which starts patch releases with a .0. I know they don't use CalVer, but most CS engineers start counting at zero anyway.
“Skipping” the 0 might lead to confusion. I would certainly in my case.
Let's compare it to the biggest adopter of CalVar, that small 4 trillion dollar startup; they use iOS 26.0 (I hate the missing 20).
Lastly, 2028.1 would be the “first” patch for v2028. It feels easier to community care with a colleague in the office.
There was a problem hiding this comment.
Yeah, again, for 0-based or 1-based I’m happy to go with the consensus. As I had it “1” is the first release. “2” is the second release and so on. (1-based is quite normal for CalVer schemes, I think. I certainly use them that way elsewhere.)
I think beyond the first viewing either way would be clear enough.
There was a problem hiding this comment.
Another +1 for starting at 0.
pip and packaging come to mind as starting at 0. attrs starts at 1.
.0 better aligns with the "major release" wording used elsewhere; "2028.1 is the major release" is a bit confusing at first, this sounds like a patch release.
(As an aside, I try and use "feature release" for CPython 3.x over "major release" to avoid no-we're-not-semver confusion.)
| * ``N`` is a monotonically incrementing counter within that year, starting | ||
| at ``1`` for the major release. Each subsequent bugfix release | ||
| increments ``N``. | ||
|
|
||
| For example: | ||
|
|
||
| * ``2028.1`` is the major release made in January 2028. | ||
| * ``2028.2`` is the first bugfix release following ``2028.1``. | ||
| * ``2029.1`` is the next major release, made in January 2029. |
There was a problem hiding this comment.
This is amazing, btw!
The "within that year" wording is ambiguous and may cause confusion. (Unless I'm confused by your intent.)
Maybe it's worth spelling out or showing an example that even if one of those patches in the series lands in 2029, it might still remain in 2028.N series.
(updated to switch from .x to .N to match the proposed change)
There was a problem hiding this comment.
Yes, this wasn't overly clear to me too. I presume a security fix released in 2029 would be applied to the 2028 release train as 2028.x?
There was a problem hiding this comment.
Thanks, I'll clarify.
The idea is to the December of the third year. (I said this better elsewhere...)
| only. At any given time, three major versions are in support. The existing | ||
| two-tier feature-release/LTS distinction is retired, with every release | ||
| receiving what was previously the LTS-level commitment. |
There was a problem hiding this comment.
As someone who's spent years warning clients that LTS releases offer a false sense of safety, I welcome this change! There was never a clear upgrade path / unified changelog from one LTS to the next, so migrating between LTS releases was always A LOT more stressful than upgrading to every single release in between.
Having no distinction between the LST/non-LTS releases makes things much clearer and easier!
|
|
||
| * An alpha release in early October, following the corresponding CPython | ||
| final release. | ||
| * A beta release approximately four weeks before the release candidate. |
There was a problem hiding this comment.
Question: This puts the beta release just as people are likely ramping down work for Christmas (other holidays also available). Is there concern that the beta will receive less testing because of that?
There was a problem hiding this comment.
We probably want a month between each:
- alpha: mid oct
- beta: mid nov
- rc: mid dec
- final: mid jan
So the beta will fall mid nov, not dec 1, and releasers can do the last RC before going "away" over holidays, and merge and backport any last minute bugs in early jan
Dropping the beta in mid nov seems fine, the flip side of work "ramping down" after november is that you have more "unexpected" time to play with the beta 😉
There was a problem hiding this comment.
I also had a similar comment:
If 2028.1 is released mid Jan, then 2028.rc1 (is that is what we will name it? or 2028.1.rc1) will be released 2 weeks before being roughly January 1st. I think that is logistically tough with Fellows vacation and likely vacation of translators. So perhaps 4 weeks before we do the release candidate, roughly mid December, 4 weeks before that the beta, roughly mid November, the alpha at the start of October
There was a problem hiding this comment.
Is there any reason to wait for the new Python final release to publish Django's alpha?
Python's RC1 is early August and RC2 is early September so it's already very representative of what will ship.
How about this calendar?
- Alpha: mid September (so Django's CI can run against Python RC1 in August and against RC2 before publishing it)
- Beta: mid October (after Python's final release)
- RC: mid November
- Final: early December (if two weeks between RC and final)
That way, Django is even closer to Python's schedule and everything is wrapped by the time of the Christmas/New Year holidays.
(With such a calendar, the version released in December 2027 would be called 2028)
There was a problem hiding this comment.
Is there any reason to wait for the new Python final release to publish Django's alpha?
I don't think there's a reason to wait for Python pre-releases, no. (We have a daily build against the in-development Python already.) Extrapolating from my experience last year, we'll get about a month's worth of "interesting" bugs relating to the new python into early November.
What I like about @rik's proposal:
- aligning even closer with the Python calendar. Under the "plus last yellow" plan, I think we still have Django support for an EOL python for about 3 months (from October to the end of the year). Your proposal shaves off a month there.
What I like less:
- dealing with a stream of release blockers over the holidays
- if we're going full "car versioning" instead of "cal versioning" by releasing "early", then let's just back up another month and release in November so that we can drop the last python as soon as it goes red at the end of October.
| Python Version Support | ||
| ---------------------- | ||
|
|
||
| Each Django major release supports three Python versions: the two Python |
There was a problem hiding this comment.
Question: Do older Django versions receive support for newer Python versions? My reading is no, since supporting a newly-released Python version isn't a "bugfix [or] security release".
The downside of this being developers not only have to wait for 3 months before adopting newer Python versions, but they also need to upgrade Django too.
There was a problem hiding this comment.
I need to flesh this out more...
The idea is that the current version picks up the new Python whilst it's within its first year, but the older two versions would not.
There's no requirement to update your Python immediately to the newest version released, as the Django you're on will support 4, and the new one will only drop the last (that your current version supports) — If that makes sense.
I'll spell this out more clearly.
There was a problem hiding this comment.
Hm… that's a lot of dinosaurs burned to test all versions. Especially since 3rd parties will have to support multiple Django versions. @tim-schilling has made a similar point previously. I'd like to hear his opinion too.
Personally, if a Python version doesn't receive bug fixes, any bugs like the garbage collection bug may need a backport in Django because an old Python version doesn't receive a patch.
People don't need to update neither Django nor Python for quite a while, wichout each Django version supporting a large Python version ragenes.
In short, I'd only support the 2 active Python versions at the time of release (without a hard pinned upper bound) so people can try a newer Python release.
There was a problem hiding this comment.
@codingjoe OK... so the alternative there would be a Green Only policy. (Just the current two Pythons at release) which brings it down another one. ("Another" because the current policy has the old LTS supporting five full versions at EOL.)
I'm not 100% anti that. I went Plus last yellow because that seemed to be the community vibe.
But this is a topic we can decide on, and probably settle in a giant Zoom call 😅
There was a problem hiding this comment.
I can live with both, as I have been living with the current system. But in reality I believe there are two kinds of Django projects. The fossil that hasn't been updated since some agency wrote it and still runs on Django 1.8. And people who are on the prev. LTS but have an active ticket to upgrade.
Never have I experienced upgrading a Python version as a big consideration since Python 3. But mileage may vary.
| advance notice. | ||
|
|
||
| No change is proposed to the support commitments already made for Django | ||
| 5.2 LTS or Django 6.2 LTS under the existing schedule. |
There was a problem hiding this comment.
Thought: Depending on how long it would take to implement, should this be introduced for 6.2 instead? It means the "new world order" is fully migrated to earlier, resulting in less confusion in the interim
There was a problem hiding this comment.
That seemed a bit quick to me 😬
There was a problem hiding this comment.
I think 7.0 works. If I count right, making 6.2 the first annual release would shorten its feature development period from 8 to 5 months this time. Better to roll this out with a more supple set of features, no? ("Django took a whole year and did what exactly?")
There was a problem hiding this comment.
@jacobtylerwalls so are you saying that on Jan 2027 we should do the final release of 7.0? (per my proposal of versioning, 2027.0 per this DEP).
I sort of like that, but we need to be fully aware that [202]7.0 will have effectively 4.5 months of feature development (from May 20th till Oct ~7th, when the new feature freeze would be in effect).
There was a problem hiding this comment.
I was saying we should stick to the existing schedule for 6.2, which gives a feature freeze in January 2027, final release in April 2027. In January 2027 we start developing Django 7/2028, feature freeze October 2027, release January 2028.
If we don't accept this DEP, Django 7 would come out in December 2027. With this DEP, we move it by one month to January 2028. Very smooth 🙏
There was a problem hiding this comment.
Makes sense, thanks Jacob! but the release version would not be 7.0, correct? it would be 2028.0 (or 28.0 or 8.0).
There was a problem hiding this comment.
I'm unsure what the numbering scheme we will settle on, but yes, whatever number comes after 6.2, if that's what you're asking?
| References to, for example, Steering Council terms that are grounded in LTS | ||
| cycles will need to be updated to simply state two-years, or as appropriate. |
There was a problem hiding this comment.
Suggestion: Given LTS release are 3 years, it might make sense to align to that? It means everything follows a 3-year cycle. Granted it does increase the term substantially which may not be ideal.
There was a problem hiding this comment.
My personal take is that two years on the SC is just about right.
But 🤷
(Either way, out of scope for this DEP — the note here is only that other docs will need to adjust phrasing.)
There was a problem hiding this comment.
Thank you Carlton, I am very much in favor of all that is proposed here, with a minor concern on the versioning side (after some pondering).
I take your point that the numbering scheme is somewhat secondary to the substance, and I agree the substance is what matters. That said, I would rather we get the numbering right precisely because it is the part we cannot easily revisit later.
My concern is that CalVer feels like a one-way door. If the community later wants to return to a different cadence or scheme, the version numbers make that awkward in a way that 7.0, 8.0 style versioning simply does not. There is also a cross-year confusion I think is worth avoiding: a release of 2028.7 in March 2029 looks like a 2028 release but is arriving in 2029.
I would rather keep sequential versioning and bump the major once a year. No cross-year confusion (8.7 released in 2030 is unambiguously part of the 8.x series), no tooling changes, no one-way doors. And I think this also addresses most of the Backwards Compatibility concerns raised in the DEP: version string format stays the same shape, classifiers and tox environments need no format changes, and packaging tools keep working as-is. The only real migration work left is the LTS label and the schedule documentation, which we need to do regardless of the numbering scheme.
The only thing I think we lose is "at a glance you know the release year", but for that I propose:
- release 8.0 in January 2028 and increment by one per year
- documented that year of release = major + 2020 (possible a one-liner in the docs and on the download page)
(The skip of 7.x is a one-time cost and a natural signal to the ecosystem that something changed -- I much rather do math adding 2020 than 2019.)
Co-authored-by: nessita <[email protected]>
|
@nessita I don't dislike your suggestion. Thanks. My personal preference would be for CalVer because it carries additional semantic information (or carries it more clearly: you don't have to be an insider to understand when the EOL date is: Year + 3) I think we should carry on this discussion and agenda it for the Giant Zoom Call™ (See reply to @codingjoe above/below 🥳) |
|
@carltongibson I have a question and maybe a suggestion: I remember my first contributions and how daunting the feature freeze was. I was young, life was short, and the next release was an eternity away. With releases becoming an even rarer event, this might lead to more broken hearts. And it may also elevate the perception that Django is old (as in outdated), not my opinion, but I have JavaScript acquaintances… What would it mean to go from a feature freeze to a feature cutoff? E.G., we create a 2028 branch at a certain cutoff day, but new features could be merged to main all year round. Patches get applied to all active version branches, including 2028. My thought is this might prevent the awkward development if a feature misses the deadline (IMHO a real momentum killer). I fear we are all looking at this with maintainer glasses, which is important, but the majority of people are Django users. And something like this could improve the narrative: Yes, one stable release a year, but we develop features all year round. As a former fellow, or maybe also the current fellows: Is something like that even feasible, or am I daydreaming? |
|
@codingjoe What you describe is, essentially, the way things have always worked. E.g. the |
I like this. I would just comment that if we can skip one version number, we might as well skip 21, and get a lot of the benefits of your suggestion while keeping the year hint intact. That is, release 28.0 (or 28.1) in January 2028. |
sarahboyce
left a comment
There was a problem hiding this comment.
I really like the idea of an annual cycle. I have no strong opinions of the naming. I have added some minor logistical comments
| * ``N`` is a monotonically incrementing counter within that year, starting | ||
| at ``1`` for the major release. Each subsequent bugfix release |
There was a problem hiding this comment.
Given the quantity of security reports, it is likely we will have a release like 2028.36, I think that's fine but just wanted to highlight it
| Each Django major release supports three Python versions: the two Python | ||
| versions with active upstream support at the start of the Django | ||
| pre-release phase ("green"), plus the most recent Python version to have | ||
| moved to security-only or end-of-life status ("plus last yellow"). |
There was a problem hiding this comment.
During the active support of bugfix and security releases for 2028.1 (actually should we just call this 2028 when referring to that release in general?) there will be a new Python released in the October of 2028 (Python 3.17), I assume we will backport support of this Python to 2028.1?
| by Python packaging tools. No third number is used; there is no separate | ||
| "patch" component. | ||
|
|
||
| Support Window |
There was a problem hiding this comment.
This is maybe controversial but I am tempted that we end security support in the third Year after the October release. This aligns to when our oldest supported version of Python would drop security support.
As a compromise, I would release new versions of the pre-released Django with the security fixes (as 2029.a2 for example) so that folks can upgrade to a pre-release on production (if they wanted) knowing they will still get the security fixes.
This means that we are only ever managing 3 branches, all with supported versions of Python (so no back-porting Python security fixes)
There was a problem hiding this comment.
This is maybe controversial but I am tempted that we end security support in the third Year after the October release.
Or, we could achieve the same thing by just starting the three year cycles on November, a few weeks after the Python cycles start. Similar to @rik's idea above, but just backing up another month. (For example, release Django 2028.0-or-1 in Nov 2027.)
There was a problem hiding this comment.
As a rough sketch of the updated calendar:
- Alpha: mid August (most GSOC projects finish in August, occasionally would tight to include but not a huge issue)
- Beta: mid September (usually around DjangoCon US but think that isn't a problem, beta is quite a simple release and talks on the upcoming release are possible)
- RC: mid October
- Final: early November
I like it 👍
There was a problem hiding this comment.
The idea with October alpha is that it picks up the newly released Python version at that point.
Final in early November misses the whole "New Year, New Django" feel. (I feel this is more important than we're inclined to think it, as mere programmers: Not paying attention to how Django is perceived is a large part of the complaints we see in the ecosystem.)
🤔
There was a problem hiding this comment.
To the original point:
... aligns to when our oldest supported version of Python would drop security support.
We could find some phrasing that says that we won't consider reports that affect only the EOL Python version for those last two months.
(And, just to note, if we were to opt for the Green Only policy, this concern wouldn't apply)
There was a problem hiding this comment.
Final in early November misses the whole "New Year, New Django" feel.
It's my birthday; I'd be OK 🤷♂️
Jokes aside, I agree with the sentiment to include "politics/perception" in our consideration as well as the community ergonomics.
A new Django version means updating Django support on community packages. Depending on your family, you have a lot of time during the holidays or none at all. Or you ditch your family for the annual CCC conference. 😏
Considering that most companies will be stuck in let's hit that milestone before x-mas mode, I don't believe many will actually update before New Year's. That probably matters to Django, as adoption is a driver for regression detection. So ideally a release is situated to enable rapid community adoption.
|
|
||
| * An alpha release in early October, following the corresponding CPython | ||
| final release. | ||
| * A beta release approximately four weeks before the release candidate. |
There was a problem hiding this comment.
I also had a similar comment:
If 2028.1 is released mid Jan, then 2028.rc1 (is that is what we will name it? or 2028.1.rc1) will be released 2 weeks before being roughly January 1st. I think that is logistically tough with Fellows vacation and likely vacation of translators. So perhaps 4 weeks before we do the release candidate, roughly mid December, 4 weeks before that the beta, roughly mid November, the alpha at the start of October
hugovk
left a comment
There was a problem hiding this comment.
+1 for annual release cycle. I also like CalVer (well, I am the author of PEP 2026 :)
As a CPython release manager, the predictable annual release cycle makes things much easier. Also as a CPython developer, I know when the feature freeze and so on will happen, without having to always look things up.
Similarly as CPython user and library maintainer, it helps me plan: I know when to expect new and drop EOL versions. At Pillow, we have quarterly releases, and have aligned the October one to fall after the new CPython release.
| Django will use Calendar Versioning in the form ``YYYY.N``, where: | ||
|
|
||
| * ``YYYY`` is the four-digit calendar year of the major release. | ||
| * ``N`` is a monotonically incrementing counter within that year, starting |
There was a problem hiding this comment.
Another +1 for starting at 0.
pip and packaging come to mind as starting at 0. attrs starts at 1.
.0 better aligns with the "major release" wording used elsewhere; "2028.1 is the major release" is a bit confusing at first, this sounds like a patch release.
(As an aside, I try and use "feature release" for CPython 3.x over "major release" to avoid no-we're-not-semver confusion.)
| Django will use Calendar Versioning in the form ``YYYY.N``, where: | ||
|
|
||
| * ``YYYY`` is the four-digit calendar year of the major release. | ||
| * ``N`` is a monotonically incrementing counter within that year, starting |
There was a problem hiding this comment.
Because there will be a 2028.13 in 2029 (or something like that), perhaps:
| * ``N`` is a monotonically incrementing counter within that year, starting | |
| * ``N`` is a monotonically incrementing counter within that major release, starting |
| For example: | ||
|
|
||
| * ``2028.1`` is the major release made in January 2028. | ||
| * ``2028.2`` is the first bugfix release following ``2028.1``. |
There was a problem hiding this comment.
Perhaps include an example 2028.x that happens in 2029.
| Versioning | ||
| ---------- | ||
|
|
||
| Django will use Calendar Versioning in the form ``YYYY.N``, where: |
There was a problem hiding this comment.
Maybe link to https://calver.org/?
| Django will use Calendar Versioning in the form ``YYYY.N``, where: | |
| Django will use `Calendar Versioning <https://calver.org/>`__ in the form ``YYYY.N``, where: |
| API stability commitments under this DEP are preserved: deprecated | ||
| features continue to warn for at least two major releases before removal, | ||
| and security support extends for three years from each release. |
There was a problem hiding this comment.
Another plus: not only are stability commitments preserved, but the deprecation period is longer now, giving people more time to react.
| * **Version string format.** ``YYYY.N`` is a new shape for Django's | ||
| version number. Code that parses or compares Django versions using | ||
| standard packaging tools (``packaging.version``, ``pip``'s resolver, | ||
| and similar) continues to work, since ``YYYY.N`` remains a | ||
| PEP 440-compliant, orderable version. Code that relies on ``X.Y`` | ||
| having a bounded major component, or that uses ad hoc string parsing, | ||
| will need updating. |
There was a problem hiding this comment.
Aside: this is a good opportunity to introduce tooling to identify code that makes assumptions about django.VERSION comparisons, similar to Ruff’s YTT rules and Flake8’s flake8-2020 plugin.
rik
left a comment
There was a problem hiding this comment.
Very positive on the whole idea! Let's do this!
|
|
||
| * An alpha release in early October, following the corresponding CPython | ||
| final release. | ||
| * A beta release approximately four weeks before the release candidate. |
There was a problem hiding this comment.
Is there any reason to wait for the new Python final release to publish Django's alpha?
Python's RC1 is early August and RC2 is early September so it's already very representative of what will ship.
How about this calendar?
- Alpha: mid September (so Django's CI can run against Python RC1 in August and against RC2 before publishing it)
- Beta: mid October (after Python's final release)
- RC: mid November
- Final: early December (if two weeks between RC and final)
That way, Django is even closer to Python's schedule and everything is wrapped by the time of the Christmas/New Year holidays.
(With such a calendar, the version released in December 2027 would be called 2028)
|
|
||
| Django will use Calendar Versioning in the form ``YYYY.N``, where: | ||
|
|
||
| * ``YYYY`` is the four-digit calendar year of the major release. |
There was a problem hiding this comment.
Starting a thread to gather the conversation on the major version format. I think of @nessita's comment as "comment 0" of this thread.
I'm strongly in favour of using the year in the version number. I believe it greatly clarifies communication. It will probably help Django's users upgrade: it's easier to communicate to managers and other stakeholders that you need time to upgrade something called "Django 2023" than it is something called "Django 5".
I also believe it is great for Django's marketing. Many people not using Django believe it is old and does not receive meaningful updates. When those people read titles such as "Here's what's new in Django 2028", they get a more positive impression than reading "Here's what's new in Django 8".
|
|
||
| * An alpha release in early October, following the corresponding CPython | ||
| final release. | ||
| * A beta release approximately four weeks before the release candidate. |
There was a problem hiding this comment.
Is there any reason to wait for the new Python final release to publish Django's alpha?
I don't think there's a reason to wait for Python pre-releases, no. (We have a daily build against the in-development Python already.) Extrapolating from my experience last year, we'll get about a month's worth of "interesting" bugs relating to the new python into early November.
What I like about @rik's proposal:
- aligning even closer with the Python calendar. Under the "plus last yellow" plan, I think we still have Django support for an EOL python for about 3 months (from October to the end of the year). Your proposal shaves off a month there.
What I like less:
- dealing with a stream of release blockers over the holidays
- if we're going full "car versioning" instead of "cal versioning" by releasing "early", then let's just back up another month and release in November so that we can drop the last python as soon as it goes red at the end of October.
| by Python packaging tools. No third number is used; there is no separate | ||
| "patch" component. | ||
|
|
||
| Support Window |
There was a problem hiding this comment.
This is maybe controversial but I am tempted that we end security support in the third Year after the October release.
Or, we could achieve the same thing by just starting the three year cycles on November, a few weeks after the Python cycles start. Similar to @rik's idea above, but just backing up another month. (For example, release Django 2028.0-or-1 in Nov 2027.)
| * **Removing the gap between LTS cycles.** Under the current policy, users | ||
| on an LTS release do not receive most bugfixes, which land only on the | ||
| current feature release. There are reports of users ceasing to file | ||
| issues with Django and instead maintaining private patches against | ||
| their LTS version. Making every release an LTS closes this gap: every | ||
| supported user receives bugfixes for a full year. |
There was a problem hiding this comment.
Glad to see this here, I'm happy about the bugfix window widening from 8 to 12 months. (I'm always sad about the regressions that just barely miss the shot clock.)
|
Just throwing a general comment here: thanks everybody for the constructive engagement. Keep it coming! — I will go through it, make clarifications and identify the open TBD topics probably over the weekend. (i.e. beginning of May, if you're reading from the future.) |
Proposal to move Django to an Annual Release Cycle.
As discussed:
Current status I still need to work the motivation section fully, not yet ported from the introductory essay, but opening now to begin discussion.
Aside: given DEP 4 and DEP 44, I half wanted to number this DEP 444.