ploeh / ZeroToNine

A tool for maintaining .NET Assembly versions across multiple files.
MIT License
147 stars 16 forks source link

Parameter switch to decrement the version value #11

Closed huorswords closed 10 years ago

huorswords commented 10 years ago

As -i <major|minor|patch|revision> increments the version of all AssemblyInfo files on solution, I think that could be interesting to define a new parameter switch:

This option allows the user, in example, to undo changes generated by an incorrect Zero29 -i call without the need of discarding changes over these files using source control.

ploeh commented 10 years ago

What would the behavior be for the following test cases?

decrement major 4.0.0.0 -> ?
decrement major 2.3.0.0 -> ?
decrement minor 3.9.0.0 -> ?
decrement minor 5.2.5.0 -> ?
decrement minor 5.2.5.7 -> ?
decrement patch 7.0.3.0 -> ?
decrement patch 1.1.5.8 -> ?
huorswords commented 10 years ago

To be consistent with increment, the behavior would be:

decrement major 4.0.0.0 -> 3.0.0.0
decrement major 2.3.0.0 -> 1.0.0.0
decrement minor 3.9.0.0 -> 3.8.0.0
decrement minor 5.2.5.0 -> 5.1.0.0
decrement minor 5.2.5.7 -> 5.1.0.0
decrement patch 7.0.3.0 -> 7.0.2.0
decrement patch 1.1.5.8 -> 1.1.4.0

But I think that it also could be:

decrement major 4.0.0.0 -> 3.0.0.0
decrement major 2.3.0.0 -> 1.3.0.0
decrement minor 3.9.0.0 -> 3.8.0.0
decrement minor 5.2.5.0 -> 5.1.5.0
decrement minor 5.2.5.7 -> 5.1.5.7
decrement patch 7.0.3.0 -> 7.0.2.0
decrement patch 1.1.5.8 -> 1.1.4.8

What do you think about it?

ploeh commented 10 years ago

The problem is that the increment operation is inherently lossy, so no matter how a hypothetical decrement operation is defined, it will be only by coincidence if it turns out to work akin to an undo operation.

huorswords commented 10 years ago

Then, if we consider decrement operation as an undo operation, then I think that the correct results would be:

decrement major 4.0.0.0 -> 3.0.0.0
decrement major 2.3.0.0 -> 1.3.0.0
decrement minor 3.9.0.0 -> 3.8.0.0
decrement minor 5.2.5.0 -> 5.1.5.0
decrement minor 5.2.5.7 -> 5.1.5.7
decrement patch 7.0.3.0 -> 7.0.2.0
decrement patch 1.1.5.8 -> 1.1.4.8

There is an additional special case: Version values cannot be less than zero (0).

In this case, the correct result would be don't decrement the value, just keep the zero.

decrement minor 1.0.5.8 -> 1.0.5.8
ploeh commented 10 years ago

If the intended semantics of a decrement operation is to serve as an undo operation, then this doesn't look correct to me:

decrement major 2.3.0.0 -> 1.3.0.0

The problem is that, by using the increment operation, it's impossible to do a major incrementation and go from 1.3.0.0. to 2.3.0.0 in a single operation. Incrementing the major version always resets all the inferior version numbers, and so on for minor and patch. Thus, the fastest way to move from 1.3.0.0 to 2.3.0.0 is

increment major 1.3.0.0 -> 2.0.0.0
increment minor 2.0.0.0 -> 2.1.0.0
increment minor 2.1.0.0 -> 2.2.0.0
increment minor 2.2.0.0 -> 2.3.0.0

In order to even give a decrement operation a chance to undo an increment operation, it would have to decrement the version number to something which would have been at least possible. However, several of these operations are impossible to reverse in a single operation:

decrement major 4.0.0.0 -> 3.0.0.0
decrement major 2.3.0.0 -> 1.0.0.0
decrement minor 3.9.0.0 -> 3.8.0.0
decrement minor 5.2.5.0 -> 5.1.0.0
decrement minor 5.2.5.7 -> 5.1.0.0
decrement patch 7.0.3.0 -> 7.0.2.0
decrement patch 1.1.5.8 -> 1.1.4.0

Consider, for example, decrement minor 5.2.5.0 -> 5.1.0.0. It's impossible to go from 5.1.0.0 to 5.2.5.0 in a single operation, but if it had instead been decrement minor 5.2.5.0 -> 5.1.5.0, it would still have been impossible to go the other way.

Furthermore, it's a problem that many increment operations can lead to the same result:

increment major 2.0.0.0 -> 3.0.0.0
increment major 2.1.0.0 -> 3.0.0.0
increment major 2.3.0.0 -> 3.0.0.0
increment major 2.3.4.0 -> 3.0.0.0
increment major 2.3.6.9 -> 3.0.0.0
increment major 2.3.0.9 -> 3.0.0.0

Thus, decrement major 3.0.0.0 is meaningless from an undo perspective, because you don't have enough information to perform a real undo operation. It would be pure coincidence if decrement major 3.0.0.0 arrives at a correct result.

huorswords commented 10 years ago

Sorry, I have not thought about the whole scenario, only in my own specific problem .

I agree with your interpretation about undo operation. From an strict point of view, there is no way to undone an increment operation because it is lossy (in case of major, minor or build increments).

Then,

When I proposed this feature, I thought that would be great to have the possibility to avoid discarding changes on AssemblyInfo files in all solution projects when, by error, I incremented the revision number in one.

ploeh commented 10 years ago

Based on this discussion so far, I think it's difficult to provide a meaningful specification for a decrement operation - at least, I think such a specification still eludes us.

How about a set or assign operation?

For example,

Zero29 -a 2.1.4.0

would assign the version 2.1.4.0 to all AssemblyInfo.* files beneath the current working directory.

mexx commented 10 years ago

The decrement operation will be used in interactive mode, right?

So we can detect the problematic cases and report it to the user and let him decide which version to undo to.

huorswords commented 10 years ago

Sorry for the delay in my response. Too work and holidays for me on last week.

@ploeh, I think the assign operation is also very interesting (I can open another thread for that if you want), but I think that's not exactly the same case that I thought when I reported this issue.

For example, if we make the call

zero29 -a 5.1.3.0

this would set all the AssemblyInfo.* files with the value 5.1.3.0, regardless of the value they had before.

That is, if the version number of different projects in the same solution evolved differently, with that statement actually we would be doing a Version Rebase to start with versioning from scratch.

This can be very useful, for example, when you change the framework version for which the project has been prepared and decide that the major version indicates the version of the framework for which was generated (I have got a real case: 3.x.x.x > 4.0.0.0 when we migrated from .NET Framework 3.0 to .NET Framework 4.0).

However, if the goal is to go back dynamically, I think the decrement operation should be defined as the increment operation: lossy.

@mexx your proposal makes sense. What value should be proposed to the user when calling the following statement?

zero29 -d minor 5.1.3.0 -> 5.0.3.0          // Pure decrement
zero29 -d minor 5.1.3.0 -> 5.0.0.0          // Lossy decrement
zero29 -d minor 5.1.3.0 -> 5.1.0.0          // Go back to base minor version
zero29 -d minor 5.1.3.0 -> x.x.x.x          // Other
ploeh commented 10 years ago

The problem with the proposed goal of working as an undo operation is that, AFAICT, it's impossible to implement an algorithm that will meet that goal.

At least, none of the proposed solutions will meet that goal.

zero29 -d minor 5.1.3.0 -> 5.0.3.0          // Pure decrement

This doesn't meet the goal, because it's impossible to go from 5.0.3.0 to 5.1.3.0 in a single increment step. If you increment the minor version of 5.0.3.0, the result is 5.1.0.0, not 5.1.3.0. Thus, this proposed decrement specification doesn't meet the goal, because it 'undoes' something that could never have been done in the first place.

zero29 -d minor 5.1.3.0 -> 5.0.0.0          // Lossy decrement

This doesn't meet the goal either, and for the same reason. There's no way to go from 5.0.0.0 to 5.1.3.0 with a single increment operation. If you increment the minor version of 5.0.0.0, you get 5.1.0.0, not 5.1.3.0. Thus, this proposed decrement operation doesn't meet the goal, because it 'undoes' something that could never have been done in the first place.

zero29 -d minor 5.1.3.0 -> 5.1.0.0          // Go back to base minor version

This doesn't meet the goal either, and again for the same reason. There's no way to go from 5.1.0.0 to 5.1.3.0 with a single increment operation. If you increment the minor version of 5.1.0.0, you get 5.2.0.0, which is totally off. If you increment the patch version of 5.1.0.0, you get 5.1.1.0, not 5.1.3.0. Thus, this proposed decrement operation doesn't meet the goal, because it 'undoes' something that could never have been done in the first place.

zero29 -d minor 5.1.3.0 -> x.x.x.x          // Other

What would this be?


Regarding @mexx 's suggestion about an interactive mode, I can't think of any algorithm that would produce a good suggestion. If a good suggestion is impossible to produce, then such an interactive mode would have to ask the user to supply a value without proposing one. In that degenerate case we're back at my suggestion about an assign operation.


In the end, the easiest undo support is this:

git reset --hard
mexx commented 10 years ago

@ploeh, I agree the easiest undo is to use the version control. I tried to propose a way to deal with the situation described by @huorswords initially, i.e. without using source control. But after all the discussion I would let the source control do the job it's done for, following the motto: Right tool for the right job.

huorswords commented 10 years ago

Nothing to say. I agree with you.

I close this thread. Thank you both. ;)