-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Rustfmt stability #2437
Rustfmt stability #2437
Conversation
I suspect that anybody worried about
I feel like major formatting changes probably are API breaking changes, since a formatting change implies new configurable options to tweak, and if the new options can't be set to mimic the previous behaviour then they can't default to that behaviour, which means the API has changed in an incompatible way.
I guess, if (for example) a new syntax feature like async/await or
RLS comes from the same place as |
For projects using unstable features definitely. Otherwise, not worrying about this is the point of the whole stability thing. |
"Worrying" is a relative concept. Rust's tolerance for incompatible changes is not quite zero, and stable-channel breakage does occur occasionally. As a concrete example, I recently encountered a project that broke because the standard library added a trait implementation. While that project was easy to fix manually, |
I don't think we need to rev rustfmt's major version if formatting changes somewhat. With respect to formatting alone (ignoring API changes and similar), I would suggest the following versioning scheme:
|
I think the largest pain-point here is for contributors to projects using rustfmt as a CI step (diesel being one example of a project doing this). In this case, the user has to make sure they're using the exact same version of rustfmt as is running on CI or else they'll have to manually apply the formatting changes. When contributing to multiple projects with differing rustfmt versions this is quite annoying. Anything that can be done to make this case easier would be great. |
I can't think of any way to remove the hassle of "my rustfmt doesn't match CI" other than forcing rustfmt to support a --ruleset or --version or --edition argument and just guaranteeing that |
@Diggsey is this really annoying? I've faired quite well with |
rustc and cargo have very strong backwards compatibility guarantees and we should have them for rustfmt too.
I was referring to changes to formatting which don't add or change configuration options, i.e., affect users using the default options
This is true, however, the case we're trying to avoid is that a PR fails its CI because the Rust version (and thus Rustfmt version) got bumped, we'd like some kind of pinning or back compat guarantee which means users have to opt in to breakage.
This is ignorning the CI use case in the motivation. Consider CI under this proposal: the repo is formatted using rustfmt 1.0, the CI checks each PR is formatted correctly using rustfmt 1.0. A Rust release happens and that bumps rustfmt to 1.1 which changes its formatting algorithm. The next PR to run is still using rustfmt 1.0 and now fails the CI, this innocent contributor has to format the entire repo for their PR to pass CI. Similarly, if someone downloads the repo and runs the CI locally with rustfmt 1.1, they'll see that the repo is failing tests.
We're hearing from multiple users that this is very annoying. I think it can be addressed with either pinning or internal versioning though. |
I guess I fundamentally disagree with/don't understand the premise. Right now, So if we assume that
I think I'd be happy with any of those scenarios. |
To clarify, you don't need different versions of rustfmt, in fact I'm not even considering that case. The case I'm considering is just a regular 6-weekly update, say from version 1.29 to 1.30 (Rust and Rustfmt versions). So just like rustc there aren't API breaking changes, but there are other important facets of stability. For example, imagine if from 1.29 and 1.30 we swapped the meaning of
This is basically what I am proposing, except that the 6-monthly breaking release would actually have a major version number change. |
Thank you @nrc for writing up the RFC! I would rather manage stability externally, as doing it internally seems to add a considerable complexity to the code (e.g. gating formatting fixes based on versioning - what happens when we decide to revert the change after the later version?). I would like to propose supporting different level of stability in different channels: rustfmt on stable channel should be as stable as possible, whereas rustfmt on nightly channel may introduce breaking formatting changes in minor version updates. I would suggest the following version scheme after 1.0:
E.g. We should only bump the major version once a few years or so (maybe when the new epoch is introduced?). We do not support stability between major versions (no LTS release). We do not support stability between minor versions (e.g. The benefit of the above scheme is that
The downside I am aware of is that
|
Thanks for the comments @topecongiro ! The downside of the external scheme is that we would have to maintain multiple branches (possibly only two, depending on how we decide on the details). In that scenario we would have to backport, and I don't think it would be any worse in your proposal than in my external proposal. The major downside I see to your proposal is that Rustfmt wouldn't ride the trains in the usual way for Rust components. I'm not sure how we would implement that. I would also worry that minor version increments would not get enough testing. It could also cause people problems on CI - they would not be able to run Rustfmt on CI on all branches even if they can build on all branches because it might require different formatting. That is not the end of the world, but would be confusing.
I expect maintainers would build from source? We could also distribute a different version on Cargo vs Rustup.
I think we need to backport bug fixes and new code formatting to the stable version, however, we cannot change the formatting. |
With any luck, Rustfmt 1.0 will happen very soon. The Rust community takes promises of stability very seriously, and Rustfmt (due to being a tool as well as a library) has some interesting constraints on stability. Users should be able to update Rustfmt without hurting their workflow. Where it is used in scripts or on CI, updating Rustfmt should not cause operational errors or unexpected failure. Some changes would clearly be non-breaking (e.g., performance improvements) or clearly breaking (e.g., removing an API function or changing formatting in violation of the specification). However, there is a large grey area of changes (e.g., changing unspecified formatting) that must be addressed so that Rustfmt can evolve without hurting users. The goal is for formatting to only ever change when a user deliberately upgrades Rustfmt. For a project using Rustfmt, the version of Rustfmt (and thus the exact formatting) can be controlled by some artifact which can be checked-in to version control; thus all project developers and continuous integration will have the same formatting (until Rustfmt is explicitly upgraded). I propose two possible solutions: versioning is handled by Rustfmt (by formatting according to the rules of previous versions), or versioning is handled by Cargo (by treating Rustfmt as a dev dependency).
@rfcbot fcp merge Summary: The RFC proposes handling versioning internally to Rustfmt and having users opt-in to breaking formatting changes (similar to how the editions will work for Rust). This means running Rustfmt on a project in CI versus locally should have the same results no matter which version of formatting is used. |
Team member @nrc has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
text/0000-rustfmt-stability.md
Outdated
Examples: | ||
|
||
* remove a stable option (config or command line) | ||
* remove or change some variants of a stable option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth clarifying, this is strictly talking about the existence of options and not their behavior.
As it stands this line is a bit confusing, at first I interpreted it as "changing how stable options format code", which is not a breaking change as long as the options that are changed are not the default ones.
@rfcbot reviewed |
I've raised my concerns on the internals announcement (https://internals.rust-lang.org/t/2018-edition-end-of-week-post-2018-08-04/8123/2?u=gnzlbg). They can be summarized in: if
I use I would rate the experience of using A If we can't dogfood it yet, doing a 1.0 release just feels wrong and the only thing it will achieve is frustrate end users and generate reactions about how bad |
I don't think it not being dogfooded in rustc or servo means anything relevant. Rustc and servo are huge. Moving them to rustfmt is a nontrivial process if you want to review the code, and it will also break all the PRs in flight. The reason servo hasn't rustfmted yet isn't that rustfmt isn't ready, it's that we haven't really decided what defaults we want and that's low priority. I brought this up once on the mailing list. It's used on most of the other small crates. |
It's best to do nothing than to mess stuff up: I'd think breaking builds/tests should prevent rustfmt being declared v1.0, irrespective of whether it's used on some distinguished project or not. Also, if it mangles simple macros, then it should avoid touching macros all together, unless users specifically request macros. |
@rfcbot reviewed |
@rfcbot reviewed |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Note that it is possible to automate the reformatting process (without introducing new commits or other such things). As deployed, this is currently only done when requested rather than as soon as errors are found. The logic we use to do this starts here though there are some parts "hidden" in dependent crates (namely |
This is jumping in a little late, but I want to make an argument for externally-managed versions for a couple of reasons: Minor formatting changes are pretty common (both in rustfmt but in other tools too) I've used a couple of different auto-formatters before (mostly YAPF and Black for Python, gofmt, and a little bit of clang-format), and I've found that minor formatting changes happen fairly regularly. For the Python auto-formatters (possibly because they're new), there are probably minor formatting changes every two months or so. Go, for both 1.10 and 1.11 made formatting changes to Looking at the Rustfmt repo and looking at the issues tagged with "poor-formatting", and assuming closing those issues means making formatting changes, it looks like Rustfmt also makes minor formatting changes at least once a month. If I understand the current proposal correctly, that means that either rustfmt would have to release major versions pretty regularly and handle a lot of complexity about choosing the right "format version" internally, or it would have to batch formatting fixes together at a much slower cadence than their actually fixed. Neither one of those seems that nice to me. For CI, I think pinning a rustc version is ok I agree with @Screwtapello that in-practice, I think that Right now, for both Rust and Go, I only run
should be true (if the "test" is just that (In Python, we just directly pin |
The final comment period, with a disposition to merge, as per the review above, is now complete. |
Huzzah! This RFC has been merged! Tracking issue: rust-lang/rust#54504 |
With any luck, Rustfmt 1.0 will happen very soon. The Rust community takes promises of stability very seriously, and Rustfmt (due to being a tool as well as a library) has some interesting constraints on stability. Users should be able to update Rustfmt without hurting their workflow. Where it is used in scripts or on CI, updating Rustfmt should not cause operational errors or unexpected failure.
Some changes would clearly be non-breaking (e.g., performance improvements) or clearly breaking (e.g., removing an API function or changing formatting in violation of the specification). However, there is a large grey area of changes (e.g., changing unspecified formatting) that must be addressed so that Rustfmt can evolve without hurting users.
The goal is for formatting to only ever change when a user deliberately upgrades Rustfmt. For a project using Rustfmt, the version of Rustfmt (and thus the exact formatting) can be controlled by some artifact which can be checked-in to version control; thus all project developers and continuous integration will have the same formatting (until Rustfmt is explicitly upgraded).
I propose two possible solutions: versioning is handled by Rustfmt (by formatting according to the rules of previous versions), or versioning is handled by Cargo (by treating Rustfmt as a dev dependency).
Rendered
Tracking issue