Skip to content

tidy: move rustdoc js stuff into a tidy extra check #142924

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

lolbinarycat
Copy link
Contributor

Most of these were factored out of CI scripts, but eslint in particular was previously implemented with its own special cased logic.

A new option has been added to bootstrap, build.tidy-extra-checks, which serves as a default value for the --extra-checks flag. This is mostly for the benefit of rustdoc js maintainers, but should also help bootstrap py maintainers.

Additionally, --extra-checks=cpp has been documented.

I'm not super happy with how long the extra check names are in comparison to the others (in particular typecheck), but I couldn't think of anything better (I didn't want to name it tsc on the off chance we want to switch to a different typechecking engine in the future).

It would be nice to convert the extra checks arg into a proper enum, both for warning on unknown values and to provide better shell completion.

r? @GuillaumeGomez

@rustbot rustbot added A-testsuite Area: The testsuite used to check the correctness of rustc A-tidy Area: The tidy tool S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-infra Relevant to the infrastructure team, which will review and decide on the PR/issue. labels Jun 23, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 23, 2025

This PR modifies bootstrap.example.toml.

If appropriate, please update CONFIG_CHANGE_HISTORY in src/bootstrap/src/utils/change_tracker.rs.

There are changes to the tidy tool.

cc @jieyouxu

This PR modifies src/bootstrap/src/core/config.

If appropriate, please update CONFIG_CHANGE_HISTORY in src/bootstrap/src/utils/change_tracker.rs.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Collaborator

bors commented Jun 24, 2025

☔ The latest upstream changes (presumably #142929) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Contributor

@Kobzol Kobzol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Moving this from CI scripts to tidy is definitely an improvement. Left a few comments.

@@ -382,7 +382,7 @@ pub enum Subcommand {
bless: bool,
#[arg(long)]
/// comma-separated list of other files types to check (accepts py, py:lint,
/// py:fmt, shell)
/// py:fmt, shell, cpp, cpp:fmt, js, js:lint, js:typecheck, js:es-check)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to separate type checking and eslint? It's essentially the same category of "checking code" to me, at least in the world of JavaScript. Unless it runs for too long, I'd just collapse both into "lint" or "check". When you develop on JS, you'd set your bootstrap.toml file to contain both anyway, I imagine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsc generally checks correctness, while eslint mostly checks style... thought i suppose if you want fast typechecking, it would be best to run tsc directly...

also calling an extra check "check" feels unhelpful.

# Runs checks to ensure that there are no issues in our JS code.
es-check es2019 ../src/librustdoc/html/static/js/*.js && \
tsc --project ../src/librustdoc/html/static/js/tsconfig.json
src/tools/tidy --extra-checks=js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is now part of tidy, I think that we can move it out of this CI runner and just put it into mingw-check-tidy, to have centralized execution of all tidy checks on one place.

@@ -224,6 +248,18 @@ fn check_impl(
shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?;
}

if js_lint {
rustdoc_js::lint(librustdoc_path, tools_path, src_path)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we say that the checks would be run if the JS files were modified too? Having them never run unless an extra arguments is passed is very inconvenient.

Copy link
Contributor Author

@lolbinarycat lolbinarycat Jun 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it wasn't too long ago that they were never run locally.

i was gonna have a warning for modifying files and not enabling their extra checks....

i suppose i could add a new "auto" value to --extra-checks, and make that the default.

i would prefer a design which still lets people manually disable these checks if they want.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if you modify JS files, seems like you do want these checks by default, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you don't have the tools installed, and have limited or no network connectivity, but still want to run tidy?

I agree that running the tools based on modification is a good default, but there's very little cost to letting people disable it.

I think I would want to add 3 new special values, actually:

  1. all, run everything, possibly used in CI (currently shellcheck isn't run in CI, so we would need to do that first).
  2. auto, run checks for modified files
  3. none, run no extra checks, same as the empty string

This would give a robust system that would be easy to add any future checks into, and would also help improve the existing checks, instead of just improving js checks.

@@ -171,7 +170,17 @@ fn main() {
};
check!(unstable_book, &src_path, collected);

check!(ext_tool_checks, &root_path, &output_directory, bless, extra_checks, pos_args);
check!(
ext_tool_checks,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being added to a single check module? AFAICS ext_tools is running external programs serially, so the wall-time of all those tools adds up. The check! macro exists to run things in threads so they can run in parallel to cut down on walltime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in ext_tools because that's where --extra-checks is parsed. I definitely agree that the parsing logic and stuff could use a big upgrade, and that tools should be run concurrently, but I think that can be done within ext_tools. It doesn't even technically need threads, just to spawn processes then wait for them all simultaneously. I could get working on a system for that if you want. It would probably involve making a struct or trait to represent an extra-check instead of having it be ad-hoc. This would also be a good opportunity to refactor the parsing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the macro also limits concurrency to obey -j, so having thread per check is the easiest way to get that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, should I inline every --extra-check as its own call to check!, probably doubling the size of main() in the process, or do you have a better idea?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, before doing more work I think it'd make sense to check how long it takes to run all the commands and compare that to the overall runtime of tidy. If it's the longest chain then parallelizing makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#143032 happens to have some numbers. We should probably move some of the longer-running tests to the front of main so that other ones get a chance to execute in parallel with them.

@lolbinarycat lolbinarycat force-pushed the tidy-js-extra-checks branch from 575be8c to b023137 Compare June 24, 2025 19:36
@bors
Copy link
Collaborator

bors commented Jun 26, 2025

☔ The latest upstream changes (presumably #142581) made this pull request unmergeable. Please resolve the merge conflicts.

@lolbinarycat lolbinarycat force-pushed the tidy-js-extra-checks branch from b023137 to 36cd096 Compare June 26, 2025 17:54
}

pub(super) fn typecheck(librustdoc_path: &Path) -> Result<(), super::Error> {
// use npx to ensure correct version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this comment makes much sense :)

// Having the correct `eslint` version installed via `npm` isn't strictly necessary, since we're invoking it via `npx`,
// but this check allows the vast majority that is not working on the rustdoc frontend to avoid the penalty of running
// `eslint` in tidy. See also: https://github.com/rust-lang/rust/pull/142851
match get_eslint_version() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think we can get rid of this check. I wanted to remove it in #142851 (in the first iteration, before I moved everything to be gated under the --extra-checks flag), but it would've made skipping eslint harder.
If we're going in the direction of only running eslint when needed, not just for everyone, then there's absolutely no reason to ask the user to explicitly install it, and not just use npx as it was intended to be used.
(just take care to run npx eslint@<version we pinned>)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npx might also not be installed, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but then most likely npm isn't either (unless someone is running a really cursed environment [with s/python/node/] 😁)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this PR anyway makes it a hard error to not have npm/npx when requesting JS checks? I guess that requires explicit opt-in?

Comment on lines 109 to 113
let mut child = Command::new("npx")
.arg("tsc")
.arg("-p")
.arg(librustdoc_path.join("html/static/js/tsconfig.json"))
.spawn()?;
Copy link
Member

@RalfJung RalfJung Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, uh, do all of these npx invocations basically mean "download random JS from the web and run it locally"? Without any kind of lockfile ensuring integrity of the download? That seems... bad? Definitely not something I want to see happen on my dev machine.

Copy link
Contributor

@yotamofek yotamofek Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, npx will first look for an eslint installed with npm install [-g], but otherwise yeah. See #142902 (which I intend to get to, but am waiting for this PR to be merged first, since it will probably conflict with the PR I'll open for that).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, npm install eslint@some.specific.version && npx eslint is the same as npx eslint@some.specific.version,
in the sense that without a package-lock.json file (and an --frozen flag, I think?) both will run a certain version of eslint, but might run any semver-compatible version of the direct and transient deps.

Copy link
Member

@RalfJung RalfJung Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't think we should do any of that without explicit consent from the user. Running arbitrary code without integrity checks is a complete no-go.

Also, as far as I can see the commands here don't do the @some-version part.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #142902 (which I intend to get to, but am waiting for this PR to be merged first, since it will probably conflict with the PR I'll open for that).

I think it is crucial that we start having proper lockfiles before we do do any sort of remote code execution from npm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state right now, before this PR, is that running tidy will ask you to run npm install eslint@some-version, and then will run that version of eslint the next time.

That is a way of asking for explicit consent, and very different from running npm install on the user's behalf.

Yeah, but since npx won't be invoked unless the correct (i.e. rustc-repo-specified) version of eslint is installed, it has the same effect.

That is because of the check which you suggested could be removed, right? Also, this comment here is attached to something doing npx tsc, not eslint, so -- I don't follow.

whether we check if that version is already installed and then run it with npx, or just run it with npx eslint@that-version doesn't make that much of a difference IMHO.

It makes a huge difference whether you ask the user to do something vs whether you just do it without asking them. Asking for consent is different from just assuming consent!

Copy link
Member

@RalfJung RalfJung Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state right now, before this PR, is that running tidy will ask you to run npm install eslint@some-version, and then will run that version of eslint the next time.

I would say the state before the PR is that tidy asks me to install eslint, and then I just don't do that, and everything is fine. I don't touch the JS files in this repo anyway, so I will happily ignore tidy's warning.

If even with this PR eslint is only run if it is already installed, then why use npx at all? Without a lockfile I feel like every single npx invocation needs a comment explaining why this is not remote code execution without integrity checks but just running something the user has already installed -- which defeats the entire purpose of npx as I understand it (but I may well misunderstand it, I am not familiar with the JS ecosystem).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is because of the check which you #142924 (comment) could be removed, right? Also, this comment here is attached to something doing npx tsc, not eslint, so -- I don't follow.

Oh woops, completely missed that this was a different npx invocation. Sorry about the confusion! So yeah, the versoin of tsc that npx will run here is completely arbitrary (tsc and all its transitive dependencies).

It makes a huge difference whether you ask the user to do something vs whether you just do it without asking them. Asking for consent is different from just assuming consent!

Absolutely. I just meant that asking for consent does not absolve "us" (as in, the rustc repo) from also including a package-lock.json file so that the user is downloading/installing, either implicitly or explicitly, a pre-determined set of packages that won't change just because some left-pad maintainer decided to release a new patch version of his npm package.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we had that, I think that a comment about what it means to run --extra-checks=eslint would suffice, in terms of getting the user's permission to run npx install --frozen eslint (not sure if --frozen is the correct flag but consider it pseudo-shell)

Copy link
Contributor

@yotamofek yotamofek Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state right now, before this PR, is that running tidy will ask you to run npm install eslint@some-version, and then will run that version of eslint the next time.

I would say the state before the PR is that tidy asks me to install eslint, and then I just don't do that, and everything is fine. I don't touch the JS files in this repo anyway, so I will happily ignore tidy's warning.

If even with this PR eslint is only run if it is already installed, then why use npx at all? Without a lockfile I feel like every single npx invocation needs a comment explaining why this is not remote code execution without integrity checks but just running something the user has already installed -- which defeats the entire purpose of npx as I understand it (but I may well misunderstand it, I am not familiar with the JS ecosystem).

Oh yeah, absolutely. Having the user run npm install and then running npx doesn't make a lot of sense. I was suggesting just doing the latter, but I agree that it might be better to just do the former (and then run it with npm run instead of npx).

(sorry for the multiple comments, I didn't see that you had already replied when I posted my previous ones)

@rust-log-analyzer

This comment has been minimized.

this makes us less vulnerable to MITM and supply chain attacks.

it also means that the CI scripts are no longer responsible for
tracking the versions of these tools.

it should also avoid the situation where local tsc and CI
disagree on the presense of errors due to them being different versions.
@lolbinarycat lolbinarycat force-pushed the tidy-js-extra-checks branch from 1e602f3 to ec37d89 Compare June 27, 2025 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-testsuite Area: The testsuite used to check the correctness of rustc A-tidy Area: The tidy tool S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-infra Relevant to the infrastructure team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy