-
Notifications
You must be signed in to change notification settings - Fork 703
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
Require Release Tags #1051
Comments
That's not quite true, you can depend on a specific commit hash. |
I can depend on a specific git hash, but that doesn't actually fix the problem. If someone puts their package on Nimble, they are effectively saying "I want people to use this." If they want people to use their package, it is their responsibility (not their users' responsibility) to make sure that users don't have to comb through commits to find a version that's usable. Maybe instead of git tags, people could have a list of stable hashes in their readmes, with changelogs describing the changes since the last stable hash. That would clutter up the readme though, so maybe such a capability should be directly integrated into git. Oh wait, that's just a git tag. |
It sounds like you're fine with git hashes or versions, as long as the software is usable. Is that right? |
I am absolutely not fine with JUST a git hash. If someone expects users to filter through a tree of commits to find a hash that's usable, then they clearly don't care if people actually use their package or not. Such a package does not belong in a public package distribution system like Nimble. A release tag is just a commit (with its corresponding hash) that's been tagged to denote a version that is suitable for regular use. While semantic versioning would be much preferred, I'll take any tags at all over nothing. At least I wouldn't have to scroll through a couple hundred commits to find a revision that actually works. If you're going to have a package manger, it should actually manage packages. Nimble packages seem to suffer from a horrible epidemic of:
|
The premise is that people check in junk code into master. That typically does not happen when things get serious. People should work in branches and only push to master when CI passes. Then it doesn't matter whether you tag or not. A better logic is to check if the package works but that depends on tests which again some packagers may not care about. Overall, it is hard to assess quality by just tags. |
The moment you submit your package to Nimble is the moment your package becomes serious. If you aren't going to take basic steps to document (including, but not limited to, tagging) your package, then it doesn't belong on Nimble, period. On the topic of pushing directly to master, it took me about 15 seconds to find an example of that happening with a nimble package. One of the most recently-added packages, whose name I will spare, did exactly that about 24 hours ago at the time of this post. If you'd like more examples, I'd be happy to dig up more.
That would be fine if people actually automated their tests. The fact of the matter is that a large number of people don't do that, and there's some packages where remote automated tests simply are not possible without creating security concerns. Passing/failing automated tests also doesn't tell you if one version of a package is compatible with another, hence proper versioning practice. As an aside, that package I used as an example earlier also doesn't have a CI pipeline, nor does it have any tags, or any commit with an obvious message indicating that it is a stable enough version for regular use.
It's impossible to assess quality of a program by just tags, but it would at least make it possible for me to know which commit the developer wants me to use. I don't expect every nimble package to be a masterpiece of project management, I just want to be able find a package on nimble.directory without having to sort through a dozen broken, undocumented, neglected abominations. |
Versioning would be nice as an example, the latest tagged version of the opengl package is broken (v1.2.0). It is broken because the x11 package doesn't use tagging and only pushes to master. The x11 package changed the way it structures its files so the imports are not the same. If x11 had a tagged version, this would not have been an issue. Moving the files around would have been a bump in the major version number. To avoid this issue, the opengl package could have used a specific git hash but that keeps from getting updates for patch level package changes and could even lead to security issues. |
I don't like |
Tags certainly have their flaws, that's for sure. That said, I think they still have a correlation with good project management habits. That, combined with the problems you and @GoogleBot42 mention, are good reasons for Nimble to require their use. I apologize if my last message came off a bit heated. As silly as it may sound, I have very strong feelings on proper documentation and versioning habits. With Nim's ecosystem being so young, it can be very frustrating to see packages being neglected by their maintainers, and I hope that some higher standards for inclusion in packages.json will serve as a "kick in the pants" for some package maintainers, while potentially drawing the attention of more serious contributors. |
Yeah, I understand the annoyance of installing a package and it not working. This usually happens because people forget that once they tag, Nimble will not install So yeah, I support this. |
I think everyone understands your frustration, and to a large extent, we all share your concerns both with Nim and other language ecosystems, but the point I'm trying to make is that if you want to assert that your software WILL work (for any given static input), a couple things MUST happen:
Anything else is just wishin', and wishin' won't make it so. If you still don't believe me, consider the scenario in which all parties are performing proper maintenance and a bug is fixed in a dependency which changes behavior which you (intentionally or not) depended upon. The semver gets updated correctly with a new patchlevel. Nimble presumes correctness. That presumption is simply wrong when it comes to your software, though it may be correct for other packages which share the dependency. Now, we could build a canary that monitors packages and does things like executing earlier test suites against newer code, or is smart enough to identify which tags tests were developed against. I'm not trying to say that there aren't solutions. I'm trying to say that as long as the proposed solution is not curative and provably hygienic, we will continue to propagate bugs via semver-based package management. |
@disruptek If your application is dependent on a bug in the implementation of promised behavior, that isn't the fault of the package you are using. I do not see what you bring up as an issue. Although, if is isn't clear what the promised functionality is (bad/incomplete API documentation), or if the package violates the versioning system, that would be the fault of the dependent package. |
While it is possible that a dependent package can violate versioning rules, implement incorrect behavior, and bugs, this is inevitable regardless if nimble requires release tags or not. |
The specific issue you brought up could be prevented if every package used a specific git hash version. I see this as bringing in even more problems than it solves. Not trying to be rude but patch level versioning exists for a reason. In the extreme case, imagine depending on a specific git hash for a crypto library and it has a critical vulnerability. With patch level versioning (and depending a what the vulnerability is) that could be solved by just recompiling your application with the newer version and no changes to your code are needed. Yes, it doesn't always work out so well. As a consequence, the possibility of using a specific library version based on git hash should still be available imo. But I don't think anyone was suggesting its removal only the requirement of tags. |
Hey man, out here in the real world, the theory breaks down. Often, I'm sorry to report. The fact that bugs exist at all, in any form, is proof that sometimes software developers get it wrong. I count myself in that group, and as long as we continue to fail at preventing bugs from changing any behavior, we must allow that we may not always be able to assign a version tag perfectly.
Correct, but it doesn't matter who is responsible -- my users don't care why my software stopped working, and I don't have the resources to debug all the interactions between all the permutations of all my dependencies' versions (and those users' environments) in which defects can be traced to changes which violate the reproducibility of my software build. I'm surprised that there are members of the Nim community who can afford that amount of work, especially given the pre-1.0 nature of the ecosystem. Is anyone really finding it easy to debug everyone else's software across the myriad of platforms and backends supported by Nim?
Not trying to be rude, but shared libraries exist for a reason. 😉 If you want to decouple your code from that of your crypto dependency, you link to the dependency as a shared library. Use majors, minors, whatever you want -- go nuts. Then you don't even need to recompile your software (let alone change its code) to achieve the fix you want; clearly, a superior approach. I don't know about you, but I don't have any static crypto libraries on my system and I recommend against building crypto directly into your Nim products. On the other hand, if you build your software as a product of both your code and that of all your dependencies, your program will be no more reliable than your least reliable dependency. This thread is literally about your fellow developers, who craft dependencies, violating a vague social contract; it's exactly this that @ryukoposting is railing against. To suggest that the solution is to whitewash over the problem with another unreliable social contract doesn't make much sense to me. No one is suggesting that you can't use semver. If you're happy depending on it, great. I personally will never depend on it in any of my software, and if I cannot control my dependencies with Nimble, I simply won't use Nimble. I'm totally fine with that and I'm not trying to change anyone's mind; I'm just trying to highlight the technical argument against codifying a reliable on semver that does not serve all users.
Exactly, and the point is that as an author such as @ryukoposting, without depending upon semver, I have the ability to control whether those bugs are exhibited by my software. I don't know how to make that any clearer. Imagine never having to read a thread like this again. We can do it! We have the technology! 😄 |
@disruptek you sound like you think you're the only one in this thread with a job. If you'd tone down the arrogance for a second, I think you might notice a pattern: you're the only one in this thread whose had these problems to such an incredible extent. If you want to link against the same unpatched version of OpenSSL for the next 7 years because of "muh reproducible builds," that's fine with me. Just let me know so I can stay as far away from your software as possible. |
@disruptek
I address this later.
Yes, do you have a better system? I am not sure what your point is. If anything required tags improves this it won't make it worse. ... Or is just pushing to master better?
Yes shared libs are good for this. But this isn't how nim works. You can compile a nim into a shared lib but that lib is a c/c++ object. So you would need a wrapper for the nim lib to be usable in a nim program. It could probably be generated. As far as I know, using nim as a shared lib for a nim program isn't a common workflow and isn't something that is easy nor is supported by nimble. So this strategy of shared libs is only good for creating an api wrapper for an existing c/c++ lib. Since this discussion is about how to improve nimble and nim packages (which are not shared libs) not how to better use c/c++ libs, this isn't relevant in how to improve package stability in the package manager. If you think nim/nimble should have the ability to create shared libs from nim code, maybe a new issue/suggestion but this isn't the right place.
That's not how shared libs work. The numbers indicate if the api and/or functionality changed and by how much...
I agree. It doesn't change my point though. I acknowledged it is an extreme example. There are much less extreme examples (see my first post in this thread). To counter your example, what if the wrapper around openssl had a little active code to translate nim and c (maybe just memory handling) and it didn't initialize memory right so the previous value of the memory could be accessed if poked right. What if that memory had a key in it? A shared lib won't help you but tag versioning could assist you when updating since the update/fix might be just a patch. Granted maybe not a real world situation because I don't know how the openssl wrapper is actually written and I haven't written one myself. Point is, a dynamic lib is not some solution that will save you from all package updating problems. Sometimes, no matter what language you use, the problem is in your own code even if it is code to just enable use of openssl.
I am not sure what your issue is... this actually makes your life better. All this means is that devs cannot just have HEAD of master be how they distribute call their code in nimble. Since tagging would be enforced, you would have the option of using a tag version for all packages. That said, you can always just use a git hash if you want to use specific code. This change makes it easier not harder to tighten dependencies and avoid breaking. If you want it to be perfectly consistent though, you can just use a git hash.
Just use git hashes. No one is taking that away. What is the concern you have? What were you using before? Because, the only thing that does what you seem to want has always been specifying a version of code through git hashes.
Again, what you are trying to argue for? This doesn't change anything you seem to care about.
No one is suggesting removing specifying a package version through git hash. I would be against it if someone was. As @ryukoposting wrote,
Note that he said "JUST". |
@disruptek If you wouldn't mind me interrupting your holy war with semver, I'd like to emphasize this. If you want to choose a specific version of a package, and always link against that no matter what, that's fine by me, I really don't care. I think it's short-sighted and your rationale for it is hand-wavey at best, but it's your work, not mine. |
If you want to talk about your technical challenges (which are mine, as I depend upon your software!) and how we might work together to solve them, well, you can always reach out on IRC. 😉 I'm not going to spend time composing technical arguments (purely for the benefit of others) just to be told I'm being arrogant. I'm sorry if my passionate distrust of software communicated anything but a desire for Nim products to exemplify the best possible development experience for you, my peers, and the many who will come after us. I don't code in Rust, but there are aspects of its development and tooling which I admire (okay, which I covet. I said it!)[0][1]. In particular, I appreciate what I would characterize as a fearless dissatisfaction with the status quo. Of course, there's a certain amount of this inherent in the development of any new language, and Nim continues to demonstrate this contempt for "good enough" nearly 15 years after its inception. I'm thinking of Araq's newruntime here; some might say an unnecessary innovation, but I would argue that it's another in a long line of developments that are critical to its future. Nim is, as it says on the tin, an expressive, elegant, and immensely powerful tool while still being portable and performant. It solves real, practical problems that we have today, without bloodletting or boilerplate. You don't have to dig deep to find real innovation in this thing; it's clearly state of the art in many ways. And not least, it's fun. 😄 However, make no mistake -- we are in competition (or, holy war, as your prefer) for programmers. By growing the community, we stand a better chance of surviving as the development of these and future languages accelerate. I honestly don't know if I'll be able to afford to code in Nim in five years, and that worries me. When one of our own exhibits the kind of frustration @ryukoposting did, I see a chance for Nim to again look to the future and both distinguish itself from other languages steeped in 1970's tradition while simultaneously offering yet another compelling incentive to those programmers that represent our lifeblood. Nim is still small, but we all know that this lean featherweight can easily punch above its weight class, and the years of careful polishing of this language have yielded a very sharp instrument. I'm simply asking that we consider whether Nim's packaging system may offer another chance to take a major step forward in software reliability by knocking out an entire class of software errors via surgical, technical, solutions powered by that same fearless dissatisfaction that has served you (and now me, thanks!) so well. Araq doesn't have to be the only one to get some glory around here. 😛 [0] "not rocket science" (the story of monotone and bors) |
Sorry, I think I beat you here, https://github.com/Araq/nawabs ;-) |
I like it, I use it, I recommend it, and I think it's part of the solution, but the fact that this thread exists suggests that the problem remains. 🙁 |
We can agree on this much, at least. I tried my best to like Rust, but (hot opinion incoming) it exchanges readability and maintainability for safety to a counterproductive extent. However, Rust's tooling is genuinely incredible. Any other package management tool should consider it a compliment to be compared to Cargo. The rest of your post seems like something that isn't particularly relevant to this thread, so I'll leave it for IRC or the forum. Regardless, you lead us to a valuable question that pertains to the topic of this thread: what can Nimble learn from other package managers? What did they get right? What did they get wrong? One answer that's pretty obvious is that, semver or not, good package managers emphasize structured, formally-defined versioning semantics. Cargo explicitly states that packages use semver, and semver is a part of its formal grammar for package IDs. Maven, which is a critical part of the shared ecosystem of the big JVM langs, also has a formally-defined standard for version numbers. Cargo gives absolutely no exceptions to its standard- semver is a part of its grammar, and that's that. Maven is more lax, though it still gives us this tidbit:
Maven is effectively saying "here's the standard, if you don't use it, don't blame us when your users come banging down your door because something broke." Maven recognizes that a single versioning model can't possibly be a perfect fit for every single Java/Kotlin/Scala/whatever program on earth. Rust seems satisfied that semver will to the job well enough for all use cases. Both have this in common: structured versioning is standardized and required. I'm just a passionate idealist who writes Nim libraries- it's up to @Araq et al. to decide where Nimble actually goes on this issue. I hope to see it move towards some kind of formal versioning requirements, regardless of what they may be. |
What package management generally gets wrong, in my opinion, is that it makes developers opt-in to most of the workflow that best promotes quality, and it puts newcomers to the codebase in the position of either guessing at whether a problem is on their end or upstream, or having to repeat the same debugging efforts that others have already performed given the same environment. These are developers who are inexpert in the codebase; exactly the users who are least well-equipped to perform this debugging and least willing to invest resources into software that has not yet yielded any value to them, whatsoever.
But maybe you don't think this is relevant to the thread. If you only want to talk about semver, what I think they got wrong are two things:
Here is a flexible use of semver that may work for everyone, both in the early days of the ecosystem and much later, when we wish to converge on tighter control:
The syntax isn't important; the semantics are what matter. Examples:
Did I miss anything? Of course, I believe there needs to be a declarative specification above each library, so that you can say something to the effect of "I can use foo-1.0 or a combination of (bar-HEAD and bif-2.2)", but that can come later. |
I think this conversation is drifting/colliding with the lock files thread: nim-lang/nimble#127. I agree that releases provide something to target that is supposed to be reliable at one point and less costly for a developer to implement than a full one master+devel branches development model. For rapid prototyping though, I'd like to be able to set nimble requirements to latest commit available when libraries are developed in parallel and have a |
Agreed. I can see where this could be very useful in the development process for multiple large, codependent packages. Sadly, my day job's tooling consists of "makefiles and RTFM" so I can't speak to any specific examples the way you can. I think the easiest temporary solution would be this: When a package gets submitted to packages.json, whoever accepts the PR should check that there's at least one release tag. There's already a manual step for getting packages accepted, so this isn't really adding a whole lot to the process. As for a long-term solution, we should consider:
|
Sounds good
I have no preference but we shouldn't be too strict as I expect many packages will be wrappers for C/C++ libraries and will follow their upstream project versioning.
I'd rather have explicit Also ideally you could have task level requirements from nim-lang/nimble#482, like: task build_stable:
requires
"foo >= 0.1.0",
"foo <= 0.2.0"
setCommand "c --outdir build"
task build_devel:
requires "foo#master"
setCommand "c --outdir build"
task fuzzer:
requires "fuzzer >= 0.2.0"
setCommand "c --outdir:build test/fuzzer.nim" Note: the outdir flag has been introduced in https://github.com/nim-lang/Nim/pull/10729/files#diff-42ba1d994f4fa8c6ad17a7efae7936ccR198 |
Looks like an easy near term fix is to no longer install #head unless explicitly instructed to. If no tags are found then just error. That way, package writers will be forced to tag in order to get their packages normally used. And if they don't then users immediately know and can then decide to use #head or not. |
That might be true in the short term, but the long-term hope (my long-term hope, at least) is that people will have incentive to create Nim libraries that work for both the native (C and/or C++) and JS backends. I think the versioning semantics should be flexible nevertheless, but the top priorities should be making sure it is easy for both humans and Nimble to understand. |
Quick additional idea, that I have not thought out at all and have absolutely no idea how hard it would be to implement: maybe have some kind of default versioning semantics, then if a package wants to define its own versioning semantics, then they can define something like this in their package.nimble file? proc `>`(l, r: Version): bool This would be cool as a feature, but I can see it going south very quickly if someone cooks up a versioning grammar that they don't fully think through. |
Having versioning semantics that are not shared by all packages will add an expensive burden to all tooling despite the requirement of such semantics existing for perhaps only a small subset of all packages. Additionally, it's hard to believe that the requirement cannot be met without static human-readable text in a simple grammar. requires
"foo >= 0.1.0",
"foo <= 0.2.0" Regardless of how versions are specified, again I must ask that there be a means by which we can specify not only which versions are acceptable, but which versions are not acceptable. The following would suffice, though I think we could do better: requires
"foo >= 0.1.0",
"foo <= 0.1.2",
# ie. omit 0.1.3
"foo >= 0.1.4",
"foo <= 0.2.0" |
all this tag stuff sort of assumes there's only one package per git repo. sounds pretty limiting - works for tiny stuff but anything slightly more serious will want to be a monorepo with multiple projects in it, perhaps versioned separately. slightly tougher nut to crack, to get the resolution of version to hash stable. here's an example of a language for version specs: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html - it covers all the use cases and follows semver - before inventing a new one, make sure it's an actual improvement. as pointed out by others, the rust tooling is hard to complain about, comparatively speaking, to most PM's out there - similarly its approach to lock files, as pointed out in the other thread. versions are and remain a social tool, they have no value to accurately point out specific code - that's better left to hashes. a tag can be moved for example to point to a different hash, and this has been used to create exploits in the wild. it might have been ok 10 years ago but it would be sad to build a tool that doesn't deal with this well-known problem in 2019. since versions a social tool, it makes sense that they come with a social contract that's useful and meaningful for humans - semver is one such contract that works adequately / really has no competition that works better. you use them not for creating reproducible builds, but for managing complexity at specific points in the development process - those points when it's time to find a candidate mixture of compatible packages to test. this is why package managers exist and are useful, to begin with - otherwise we'd all be using submodules which already solve the repro-build part just fine. at the end of the day, you still need to test your software even if the upstream developer promises that it'll be compatible, unless your software is sufficiently unimportant that it doesn't matter if it breaks occasionally - you should be able to enable this unsafe practice for those occasions. if the poor and broken method is the default, that's what most people will do, decreasing the overall value of the nim package community and entrenching its reputation for poor quality, over time. |
I just reread this entire discussion and still don't see any real next steps. I made the suggestion to no longer install head unless explicitly requested. Was there anything else that can be done to make this easier? |
I just read this discussion. In response to @genotrance, we are ok that everybody use git or anything version control system that use tag. So, it can be possible to check if version number in the nimble file corresponds to a existing tag. When a dev use a package without a corresponding tag, a warning can inform his. Also, to be very strict, the CI of nim-lang/packages can reject a pull request of package without this constraint. I thinks it is necessary, to improve the serious of nim package manager and improve Nim development practice. |
The Problem
There are a ton of packages on nimble.directory that have no releases. These packages are completely and totally unusable for any project that takes itself seriously. Without releases, there is no way for me to confirm that all users of my own packages have the correct version of my package's dependencies.
The Solution
Require all Nimble packages to have at least one release tag before they are accepted into the package list.
In addition, if I were to have it my way (though the problem may be so bad at this point that doing this would be self-destructive), any package currently in the list that doesn't have release tags should be removed until they have at least one release tag.
The text was updated successfully, but these errors were encountered: