Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Pack to pin only project references #1648

Closed
jam40jeff opened this issue Apr 27, 2016 · 19 comments
Closed

Allow Pack to pin only project references #1648

jam40jeff opened this issue Apr 27, 2016 · 19 comments

Comments

@jam40jeff
Copy link
Contributor

jam40jeff commented Apr 27, 2016

Description

Currently, the pack command allows for specifying lock-dependencies to force all generated dependencies to be specific (picked up from the paket.lock file) rather than use the version specification from the paket.dependencies file.

However, the version specification of generated project reference dependencies is also controlled by this setting. If lock-dependencies is specified, the project reference versions are pinned (=), but if it is not specified, they are minimums (>=). A new setting could be introduced (pinned-project-references) to allow for the project references to be pinned while still using the version specification from paket.dependencies for any external dependencies.

Repro steps

This is a feature request.

Expected behavior

The two settings lock-dependencies and pinned-project-references would work together as follows:

Neither pinned-project-references nor lock-dependencies specified:
External dependencies: Version specification picked up from paket.dependencies.
Project references: Version specification is minimum (>=).

pinned-project-references is specified, but lock-dependencies is not specified:
External dependencies: Version specification picked up from paket.dependencies.
Project references: Version specification is pinned (=).

lock-dependencies is specified (pinned-project-references does not matter):
External dependencies: Version specification picked up from paket.lock (pinned).
Project references: Version specification is pinned (=).

Actual behavior

Either external dependencies and project references must both be pinned, or neither be pinned.

Known workarounds

There is no known workaround.

Related information

N/A

@jam40jeff
Copy link
Contributor Author

Related to #1360.

If lock-dependencies is removed, then whether or not project references are pinned would only be affected by this setting.

I believe it still makes sense even if lock-dependencies is removed, because dependencies generated for project references should be automatic and not have to be specified in the nuspec file, but this setting would be the only way to determine whether the behavior is pinned (=) or minimum (>=).

@forki
Copy link
Member

forki commented Apr 27, 2016

/cc @inosik

@jam40jeff
Copy link
Contributor Author

I decided to change this option's name to pin-project-references to match the verb nature of the other options.

@inosik
Copy link
Contributor

inosik commented Apr 27, 2016

I would just advocate KISS here and simply use paket.template, CURRENTVERSION and the specific-version parameter.

One other reason I think lock-dependencies is not very useful, is because my build script calls paket pack in the root directory. Now, if lock-dependencies (or the new pin-project-references) would be set, every generated package gets its dependencies locked. In most cases (or actually, always), this is not what I want. Because otherwise, they wouldn't even be separate packages.

@jam40jeff
Copy link
Contributor Author

jam40jeff commented Apr 27, 2016

I don't believe users should have to call out every dependency in paket.template. Too much room for error. It's a really nice feature of both nuget pack and paket pack that it will generate dependencies automatically. For external dependencies, these are called out in paket.dependencies with a version scheme. Therefore, you have complete control over what the dependency's version scheme is as well. I believe this makes the lock-dependencies option not very useful. However, there is no way to control whether generated dependencies for project references use a minimum or specific versioning scheme without pin-project-references. This would only lock dependencies for project references, which I believe definitely has a use case.

@inosik
Copy link
Contributor

inosik commented Apr 27, 2016

Then I think the real issue isn't actually about pinning, but about having better control of project dependencies. But how would that look like?

@jam40jeff
Copy link
Contributor Author

Correct, that is the issue I am trying to tackle. The way I implemented it is as simple as possible in that it only allows you to specify either = (with the pin-project-references option) or >= (without the pin-project-references option), which is exactly the behavior that was coded for project references for the lock-dependencies option (although I think it was a mistake to tie lock-dependencies to both project references and external dependencies).

I suppose you could support more options, but I was trying to keep it simple and support what I have encountered as the two most likely paths people wish to take.

@inosik
Copy link
Contributor

inosik commented Apr 27, 2016

you could support more options

Which you can with paket.template already. It is somewhat obvious, instead of being buried in a build script somewhere, and (again, in my opinion) better than the pin-all-or-pin-none approach.

The reason I made lock-dependencies work for projects and external packages, is that in the end, it's all about packages. As soon as you install one, it doesn't really matter if it's an external or a homegrown package.

But as I already wrote, it wasn't a good idea in the first place 😄

@jam40jeff
Copy link
Contributor Author

jam40jeff commented Apr 27, 2016

Yes, packages are packages. But there is already a way to control the versioning scheme of an external dependency, even when those external dependencies are generated by pack. However, there is no control for generated project references. I think this is especially important, because those are the references you are more likely to miss when manually maintaining paket.template, especially when tools such as Resharper can add project references for you automatically (but won't update paket.template).

My whole point is that it should not be necessary (and is error prone) to maintain all references in paket.template, but currently there is no way to control the versioning scheme of project references (although you have complete control over external dependencies). I am trying to add support for the most common versioning schemes I have seen used (the 95% case), but if you think there's a better way to support more (or all) then I would be open to suggestions. However, I don't believe that saying "you must just manually manage the paket.template file for project references" is an acceptable path.

@inosik
Copy link
Contributor

inosik commented Apr 28, 2016

the 95% case

Not sure about this, though. I have a small toolkit with 3 projects, only A referencing B (no C here), and no external dependencies. >= x and = x are both not good enough for me there. Now imagine a solution with 10 or 20 projects which get packaged up.

I had the idea of defining the version constraint in the project file, like this:

<ProjectReference Include="..\Foo.Core\Foo.Core.csproj">
  <Project>The guid ...</Project>
  <Name>Foo.Core</Name>
  <!--
  M, m and p are tokens which get replaced with Major, Minor and Patch, respectively. Then
  the content of this element gets parsed with Paket's constraint parser.
  -->
  <PaketVersionConstraint>~> M.m.p</PaketVersionConstraint>
</ProjectReference>

I actually started implementing it, but realized that it isn't any better than manually maintaining paket.template. And the template file approach isn't that bad, because it's (mostly) a one time task.

I agree that it's too easy to forget to update paket.template, but pinning all the versions simply can't be the one-size-fits-all solution for this.

@jam40jeff
Copy link
Contributor Author

jam40jeff commented Apr 28, 2016

Now imagine a solution with 10 or 20 projects which get packaged up.

The solutions I wish to apply this to all have over 10 projects.

pinning all the versions simply can't be the one-size-fits-all solution for this.

Automatically generated dependencies from project references by definition MUST use a single algorithm. Currently, the only choice is (>=), which I think is a bad default. (I know it's the default in nuget pack, but we've all left NuGet's client for Paket for a reason, right?) How many times do you really want to say that all future versions of your referenced project will be backwards compatible with your current package? I would think (=) would be a much more sensible default, in which case I'd be happy to not be asking for this option to be added.

Anything more complex than these versioning schemes, and yes, you're pretty much forced to manage the dependencies manually in paket.template.

So I guess if we don't want to add another option to paket pack, could we at least change the default behavior of versioning discovered project references to be the more sensible Specific (=) instead of the current Minimum (>=)?

@inosik
Copy link
Contributor

inosik commented Apr 28, 2016

MUST use a single algorithm.

Might be okay for projects where all packages have the same version and get released together. Then a pin-project-references could be useful.

The other approach is to version and release them independently, which is what I try to do. Because otherwise I'm forced to release a new version of A, even if only B changed. I hope this clarifies why I consider pinning a rather bad idea.

could we at least change the default behavior [...] to be the more sensible (=) instead of the current (>=)?

Or some kind of option (command line or config setting), which lets you override the default behavior with whatever you like?

@jam40jeff
Copy link
Contributor Author

Or some kind of option (command line or config setting), which lets you override the default behavior with whatever you like?

That sounds like a good idea. I think a command line option would make the most sense. Do you have any thoughts on what versioning schemes it should support and syntax (should it allow placeholders, etc)?

Something like --project-reference-versioning="= {version}" or something?

Should it allow access to major/minor/etc?

I was trying to keep it simple, but if you think flexible and complex would be better, I'm OK with that. I only need it to support (=), so I'm OK with anything from removing the option and making (=) the default to implementing substitutions so more complex versioning could be put in place.

Let me know what you have in mind. Thanks.

@pms1969
Copy link
Contributor

pms1969 commented Apr 29, 2016

Not sure if it fits the bill, but there is already a pack flag "minimum-from-lock-file" that doesn't pin the version number of the dependencies at exact versions.

@lexarchik
Copy link
Contributor

So, what about this issue?) This would be very useful.

@tsibelman
Copy link
Contributor

It would be very usefull to controll project references default behavior , any one can add this ? @forki ?

@jam40jeff
Copy link
Contributor Author

jam40jeff commented Jul 26, 2016

Revisiting the discussion above, I do not believe a more complex setting for controlling project dependencies should be pursued. In the interest of keeping things simple, I believe this setting alone (on or off) allows for the two most common scenarios to be handled automatically when using automatic dependencies inferred from project references.

If projects within a solution are guaranteed to maintain backwards compatibility, then the default setting (pin-project-references not being specified) yields the current behavior, which is desired.

However, if backwards compatibility between the projects within a solution is not guaranteed, then a user upgrading a package for one of the projects should be forced to upgrade to the corresponding version for any other packages built from the same solution to ensure they all stay in sync. The (=) specification is the only way to enforce this, and would be able to be specified using this new pin-project-references setting.

@Allon-Guralnek
Copy link

The pin-project-references is working great. It's just what we needed. Thanks to all involved!

@enricosada
Copy link
Collaborator

The pin-project-references is working great. It's just what we needed. Thanks to all involved!

Closing

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

No branches or pull requests

8 participants