Repository: microsoft/terminal (language: cpp)

Issue:
confusing, conflicting version indication
I'm finding the version indication confusing. My use case is simple:

1. I want to see what version.
2. I have and compare that to the version currently released.
3. I want to check the changelog to see what has changed and see if I want to upgrade.

That seems to be a reasonable sequence of events for any software for a power user. But with Windows Terminal, this is what happens:

1. I look to see what file I installed Windows Terminal with. It looks like it was `Microsoft.WindowsTerminal_Win10_1.14.1962.0_8wekyb3d8bbwe.msixbundle`, because that's the last installer I have saved.
2. But going to `About` in Windows Terminal shows v1.15.2712.0. Did it auto-update at some point? Maybe; I don't remember. But no problem, I can just check the changelog, right?
3. I go to the [releases page](https://github.com/microsoft/terminal/releases) and search for `1.15.2712.0`. It isn't found.
4. In addition, the latest v1.15 release is [v1.15.252](https://github.com/microsoft/terminal/releases/tag/v1.15.2524.0)! In most version schemes I'm used to, "2712" is eons greater than "252". How did I get something much more recent?
5. I see that v1.15.252 is tagged with `v1.15.2524.0`. Oh, so maybe they are chopping off digits in the official version number? Is GitHub doing this?
6. Regardless of what is making the tags and version number and labels inconsistent, where is the changelog entry for 1.15.2712.0, and why is it so much later than what is shown as the latest on GitHub?

I'm a little confused here.


Discussion / hints:
Similar issue. Application stopped launching today so I installed the latest release version and received the following: 

_"Windows cannot install package Microsoft.WindowsTerminal_1.15.2524.0_x64__8wekyb3d8bbwe because it has version 1.15.2524.0. A higher version 1.15.2712.0 of this package is already installed."_

I do not have the exact version that was originally installed, but it was installed in Nov 2021, so needless to say it wasn't 2524 or 2712. Was an update pushed too early? Also confused....
Thanks for bringing this up! It's definitely an issue, but more one of poor communication than anything else.

Every build of Terminal that we publish to the store is actually two packages, targeting different versions of Windows. For various reasons, those packages cannot have the same version number; they are, however, built from the same code. For various _other_ reasons, the final version component must be `0`.

Because of that, building Terminal will produce two packages versioned `1.0.101.0` and `1.0.102.0`. You're right about the chopping: those two packages are considered part of the `1.0.10` release cycle (stripping the final digit that indicates which one built first).

I've therefore been releasing them both under the "1.0.10" banner, but I've been tagging the release to match the first-produced package (in this case, `v1.0.101.0`)

The feedback here indicates that I should change:
- Tag the commit with the "pretty" release cycle version (`v1.0.10`)
- In the About dialog, strip off the `1.0` or `2.0` (or really, the ones place from the revision and the vestigial `.0`)

The last bit is that I did not publish the changelog for the 1.15.271 release cycle. Sorry about that. ☹️ 
> …  two packages versioned `1.0.101.0` and `1.0.102.0`. You're right about the chopping: those two packages are considered part of the `1.0.10` release cycle …

This is completely nonstandard and in conflict with [Semantic Versioning](https://semver.org/) comparison rules. It will break any automated admin tools that makes decisions about upgrading, not to mention causing humans the type of confusion that happened here. Pretending that `101` is really `10` is wrong on so many levels. The reasons versions have dots to begin with is to serve as delimiters so that we don't have to guess where an arbitrary convention is dividing the version number.

Please consider changing to a conventional approach. Semantic versioning has "metadata" for exactly this kind of situation. If Windows can't handle semantic versioning, well, that's another story. But arbitrarily placing invisible delimiters within the version string is not a good workaround.
> The feedback here indicates that I should change:

Sorry if I jumped the gun and commented before I saw the rest of your reply.

As for what you should do, above all you should be following [Semantic Versioning](https://semver.org/). This would mean:
* If you want to use `100` and `101` somewhere to mean `10` "under the covers" so to speak, fine, as long as the "never see the light of day". There should only be one version number, and they should be in sequence sorted by each component. (See semantic version comparison rules.)
* If this is a `1.0.10` release cycle, then yes, the Git commit should be tagged with something like `v1.0.10`.
* Anywhere that you want the version to show up (e.g. the about box), the _main part of the version_ should show exactly `1.0.10`.
* If you want to distinguish between the two packages, you can add them as semantic version _metadata_, e.g. `1.0.10+0`/`1.0.10+1` or `1.0.10+a`/`1.0.10+b` or `1.0.10+win.10`/`1.0.10+win.11`. (The latter is probably closer to what you want.). There is lots of leeway for the metadata, because the semver spec makes it clear that it does not affect the version comparison.
Oh, I see now that the `1.0` and `2.0` are actually a separate versioning scheme you've appended to the main "release cycle" version number. So another easy approach for you would be to simply insert a `+` before the `1.0`/`2.0`, producing `1.0.10+1.0`/`1.0.10+2.0`. This meets your needs, removes all confuses, brings semver compatibility, and (hopefully) can be done with the most trivial of code changes.
Oh, it's so much worse than all that. We were never intentionally trying to follow SemVer (though I do hold it in high regard, and wish I could stay within its light), but until recently we somewhat were.

> _NOTE:_ This ended up longer than I was intending. Please feel free to ignore it or skim it.

The real issue here is the Windows Store. In an ideal world, Terminal would just follow semantic versioning and call it a day. Unfortunately, we're regretfully hampered by a couple limitations.

- Application (and OS!) versions comprise four components, `maj.min.rev.build`
	- Each component is roughly 14 bits wide (limitation 1)
	- On upload to the store, the final component (`build`) _must be `0`_ (limitation 2)
- The store doesn't support semver (!) with all of its high-fidelity metadata
- (Limitation 4 to be called out later)

Under the hood, we actually use a date-based versioning scheme. It's "okay" for most purposes and always monotonically increasing. That is, `maj.min.YYMM.DDBBB` where `BBB` is the build number from that day (just to deduplicate multiple builds produced on the same day.) That results in this mouthful (for executable files packaged with Terminal):

<img width="244" alt="image" src="https://user-images.githubusercontent.com/189190/194965501-d8cd4184-868c-44b8-b1c9-80c7888f7c9a.png">

Now, for limitation 4: we want to follow this versioning scheme because that's the one used by all internally-produced Windows applications that build outside the operating system. I know, it's not a great reason. It could even be called an artificial limitation.

Anyway, due to limitation 2 above, we get to compress the available version space into three components for the final package file that gets uploaded to the store. Thanks to limitation 1, we can't exactly store `YYMMDDBBB` (or even `YYMMDDB`) in 14 bits. _There's probably a way for us to do it that would break around the decade rollover, but... I digress_.

The internally-popular versioning implementation has an answer to this, though! Epoch and day count. `maj.min.EDDDB.0`. `E` is the number of years since `maj.min` was minted, `DDD` is the 3-digit day-of-year, and `B` is of course the same deduplicating build number. Leading zeroes are dropped.

If taken as a historical relic that we shouldn't talk about, all of this would be fine...

...until I had to produce two nearly identical versions of the application during the same build. The format doesn't leave us a lot of fields to work with, so we opted to increment the `B` portion of the version number. That's where the `1.0` and `2.0` are coming from: `1` is the first build of the day, and `2` is its fraternal twin counterpart. It's kinda like we stuck the `1.0` and `2.0` on afterwards, but they were derived from the above calculation.

Anyway, all this so that now I'm looking for options that reduce the cognitive dissonance.

> as long as the "never see the light of day"

The store APIs (and those for package servicing) will expose any version number we encode in our package, even if it's for mechanical/deployment purposes only. I don't think I could ever get rid of it from the public eye entirely.

> `+`

I wish! I think the store just compares the version as a 64-bit number.

---

### Thoughts

I'd love to switch over to semver, and I think Azure DevOps supports storing an ever-incrementing variable across runs that we could key on the `maj.min` version number pair; that could be an easy way to fix this issue... for future releases. Admittedly, that would mean the builds that never see the light of day take up version number slots. I don't know if I care about that.

---

### Citing sources

#### The part of the code that increments `B` for the twin package

https://github.com/microsoft/terminal/blob/21a9c557529212c08db8fadecd0f6135c48a9f2b/custom.props#L5-L15

#### The commit whose body describes (in brief) how all this versioning works for our different product outputs

https://github.com/microsoft/terminal/commit/e22487d10b583053515a8f5afff27b64e86fd77e
I wish GitHub had 😱 as a reaction to posts, that was literally me when reading this explanation.
> I wish GitHub had 😱 as a reaction to posts, that was literally me when reading this explanation.

Don't forget this one: 🤦‍♂️ 
Looping back on this - I'm yanking triage and converting this to track specifically: 


> The feedback here indicates that I should change:
> 
> * Tag the commit with the "pretty" release cycle version (`v1.0.10`)
> * In the About dialog, strip off the `1.0` or `2.0` (or really, the ones place from the revision and the vestigial `.0`)


FWIW I think this might do the second bit, ~but I'm not quite sure how to fake this. Might need to trick VS into building and signing a straight up appx...~

```diff
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
index c9aa9ff8e..3c6378c66 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
@@ -1015,7 +1015,7 @@ winrt::hstring CascadiaSettings::ApplicationVersion()
     {
         const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
         const auto version{ package.Id().Version() };
-        winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) };
+        winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u", version.Major, version.Minor, version.Build / 10) };
         return formatted;
     }
     CATCH_LOG();

```

![image](https://user-images.githubusercontent.com/18356694/210593202-e8887aac-b1bb-499a-8c25-73553286260a.png)

The first bit is just paperwork. 

Fix patch:
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
index c9aa9ff8e81..a1cc857a542 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
@@ -1015,7 +1015,12 @@ winrt::hstring CascadiaSettings::ApplicationVersion()
     {
         const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
         const auto version{ package.Id().Version() };
-        winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) };
+        // As of about 2022, the ones digit of the Build of our version is a
+        // placeholder value to differentiate the Windows 10 build from the
+        // Windows 11 build. Let's trim that out. For additional clarity,
+        // let's omit the Revision, which _must_ be .0, and doesn't provide any
+        // value to report.
+        winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u", version.Major, version.Minor, version.Build / 10) };
         return formatted;
     }
     CATCH_LOG();


Test patch: