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

Add xtask msrv #3189

Merged
merged 19 commits into from
Nov 11, 2023
Merged

Add xtask msrv #3189

merged 19 commits into from
Nov 11, 2023

Conversation

iwyatt
Copy link
Contributor

@iwyatt iwyatt commented Oct 10, 2023

Description

Adds a placeholder function for xtask called msrv with arguments (x,y) that starts work on taskwarrior issue 3142: Automate synchronization of MSRV

Additional information...

  • I added placeholder function with 'hello world' and x,y parameter output.

  • I ran cargo run msrv arg1 arg2 to confirm function is called and outputs as expected

  • I ran cargo test to confirm no warnings or errors

Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

This looks good so far! Let's continue working on this branch.

I think the next step will be to take the new MSRV given on the command-line and substitute it into the necessary files. I think the trick will be to identify the precise spot in those files to write the MSRV, without accidentally changing anything else. It's fine to add some comments to the files that the cargo xtask msrv command can use to find it. For example, in the .github/workflow files, that could be

        # MSRV - update with `cargo xtask msrv`
        - "1.64"

It's probably easiest to do this by reading each file into memory with std::fs::read_to_string, then manipulating it with regular expressions (using the regex crate). But, you could also do this by iterating over lines in the file and using some basic string operations like s.ends_with("# MSRV").

Give that a try, and let me know if you get stuck!

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 13, 2023

Hi @djmitche - happy Friday!

Ok, so based on your feedback and some of my own assumptions and updated the code accordingly:

  • implemented upsert functionality which looks for a known pattern in a comment block (if the MSRV comment block isn't present, it will be added)
  • added partial validation check for the version X.Y argument (noted in my testing that emojis can really mess up the rest of document)
  • added checks for valid paths, successful write to disk, and placing comment block AFTER library-doc comments //! as req'd by cargo
  • left lots of comments that explain my thinking in attempting to keep formatting nice

I see that the CICD test rust / rust stable on windows-latest (pull_request) has failed, which appears to be due to use std::os::unix::prelude::FileExt; not being available on windows platforms. I think I see what is going on, which will require changing some of my code to not depend on the write_at() function, so will fix in the next pull request.

Q: Is there a way to run all the CICD tests locally before push my pull request?

@iwyatt iwyatt marked this pull request as ready for review October 13, 2023 21:00
@djmitche
Copy link
Collaborator

Q: Is there a way to run all the CICD tests locally before push my pull request?

Other than on a platform you have locally, I don't think so. It may be possible to run a codespace in other platforms (like Windows), but I don't have any experience doing so. Still, if tests run locally then it's usually fine to use the PR for testing other platforms.

Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

Looking good so far! Hopefully these comments help with next steps.

Worth considering, too: /// is not a comment in YAML, but # is. Can you abstract that away? Or maybe have different functions for .rs and .yml files? We'll also need to modify a .toml file (Cargo.toml) when the rust version is added there.

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
use std::path::{Path, PathBuf};

// Increment length of array when adding more paths.
const MSRV_FILE_PATHS: [&str; 2] = [r"main.rs", r"src/main.rs"];
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can't quite tell where these paths are relative to?

Cargo sets $CARGO_MANIFEST_DIR to the taskchampion/xtask directory, so you might be able to build paths relative to there, and then use that environment variable to make xtask msrv independent of the current directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I'm sorry. These are left over test paths. One fails, one succeeds.

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 14, 2023

Thank you for taking the time to provide thorough and articulate comments! Will get started on these changes this upcoming week.

@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 17, 2023

Next push to this pr will include three updates:

  • fix the rust version dependency for the regex crate. Downgrading from 1.10 to 1.9x should fix
  • fix some trailing bytes written to file when updating MSRV from a longer string to a shorter string and
  • removing test paths from CONST

@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 18, 2023

Hi @djmitche - I think this is ready for another review. Thanks for your patience.

  • I implemented regex per your earlier suggestion. Now that I understand that you envision developers to add MSRV to a file themselves and also add the path to xtask (rather than just the latter), the use of regex masks sense to me.

  • I implemented a variety of checks for unwrapping Results - particularly for file IO. I wasn't sure whether or not it is a bit unnecessary for the size/scope of the project, though.

  • I wasn't sure if your comment about environment paths was a suggestion for my local testing or for something to implement, so I didn't change the behavior of the script. I did remove my own tests paths from this commit, however.

  • I made the changes you suggested in the last review.

  • I had to try a few times to figure out that cargo.lock was why my regex version was causing the automated tests were failing, but I think I have that sorted now and it appears the latest version is passing.

There are two limitations I am aware of that I didn't address:

  1. the regex pattern is case-sensitive and assumes 'MSRV' will always appear in caps. I felt like this was a reasonable assumption.
  2. the regex pattern assumes a general pattern of MSRV = X.Y but does not search for Minimum Supported Rust Version . I think this is reasonable and reduces chances of false-positive matches and over-writing parts of files that shouldn't be.

Please let me know what else can I clean up before it is ready to be merged and used!

@iwyatt iwyatt requested a review from djmitche October 18, 2023 20:17
Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

There are a few clippy checks below that I've highlighted. But, I'm a bit confused about what this is doing right now. It looks like, in a Rust file for example, it would look for a line like

    let x = y; // MSRV = 1.59

and if found turn that into

// MSRV = 1.60
    let x = y; // MSRV = 1.59

Maybe I can give a clearer description of how this typically works in other projects. Somewhere in the middle of ``, there appears

      - uses: actions-rs/toolchain@v1
        with:
          toolchain: "1.64" # MSRV - update with 'cargo xtask msrv' 
          override: true

(I've added the comment; you can do the same in the PR)

So, to update that MSRV:

  • look for a line ending with # MSRV update with 'cargo xtask msrv'
  • if not found, output the existing line
  • if found, replace [0-9]\.[0-9]{2,} with the new version within the line and output it.

Does that make more sense?

This might be easier to test if you factor out the "replace the MSRV" operation into a function that operates on a string. Then the msrv function can read the file content to a string, call the replacement function, and write the result back out. And tests can just provide a test string to the replacement function.

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 24, 2023

Thanks for the feedback @djmitche . I had incorrectly understood and assumed that the intent was to update comments in files that specify the MSRV to be used, therefore my approach was to look for comments in files that contained MSRV and replace those comments with the X.Y argument.

Instead, it sounds like the intent is to update any given configuration file's specifications. So, similar to what you wrote above, in checks.yml where the following appears...

      - uses: actions-rs/toolchain@v1
        with:
          # Same as the MSRV in rust-tests.yml
          toolchain: "1.64"

...the version in the line toolchain: "1.64" should be updated to whatever X.Y is passed as an argument to xtask msrv.

If that is the case, then my approach would be to look for a different X.Y and update it with the new X.Y where MSRV (and similar phrases) appears on the same line, or the preceding line.

Do I have that correct?

@iwyatt
Copy link
Contributor Author

iwyatt commented Oct 26, 2023

Pushed a commit to fix clippy issues, but still working on functionality to update file contents (instead of just file comments). (Had much less time this week).

@djmitche
Copy link
Collaborator

I think you have that correct!

Here is an example of doing something similar, but in JS. This code writes out a new version number in a bunch of places. The modifyRepoFile method reads a file, calls a function with the content, then writes the result back to the file. As you can see, each file has a special way of replacing the content, that only matches the place to change the value, and not anywhere else. Those have needed a bit of a tweak now and then, but have been pretty reliable. In my memory, some of them used a comment to help find the right place to modify, but that appears not to be the case!

Anyway, within Taskwarrior, as long as we can be pretty confident that only the correct value will be changed, and other parts of the file won't be accidentally modified, any kind of replacement strategy is fine.

@iwyatt
Copy link
Contributor Author

iwyatt commented Nov 3, 2023

Good afternoon @djmitche - I changed out the script action to update the actual version number content of a file instead of managing the comments.

I examined the example you linked and found that the onus for configuration is put on the developer to 1) add their file to the path list and 2) specify the regex that is used to properly find the line containing the MSRV.

Taking a similar approach in this script, a developer would add the appropriate file path and regex to the CONST tuple array. For which they would need to be responsible for assuring that their provided regex does not result in inadvertent matches within the file they specify.

  • I'm still a little unsure if how I specified relative paths in the MSRV_PATH_REGEX for check.yml and rust-tests.yml is how these would work for all developers. Guidance there would be welcome.

If there are any further updates needed, I should have more availability next week to get a quicker turn, so thanks for the patience this week as I had less capacity.

@iwyatt iwyatt requested a review from djmitche November 3, 2023 18:47
Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

This looks good and does the job!

I've left a few comments to suggest more concise code. I suspect there are more ways to "tighten up" this function. Removing some of the debugging prints, once you're happy with the functionality, would be good too.

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
@iwyatt
Copy link
Contributor Author

iwyatt commented Nov 8, 2023

Hi @djmitche - I think I've addressed your concerns in your feedback.

I assume that a developer would use this manually, infrequently, and specifically within the context of a particular project, so they would only add paths to xtask's main.rs that exist within the context of their current project or child projects.

So the .yml files that I had been using in testing, which are part of a cousin(uncle?) folder's project. As such, xtask would have to be run in origin/trunk project directory and add paths relative to that.

Because I'm not 100% familiar with how this type of tool gets used and I'm trying not to bother with too many questions, the assumption above may be incorrect. (But I am very grateful for the guidance and patience you've provided!).

Please let me know if there is anything else I can address for you!

@iwyatt iwyatt requested a review from djmitche November 8, 2023 02:51
@djmitche
Copy link
Collaborator

djmitche commented Nov 9, 2023

Hi @djmitche - I think I've addressed your concerns in your feedback.

I assume that a developer would use this manually, infrequently, and specifically within the context of a particular project, so they would only add paths to xtask's main.rs that exist within the context of their current project or child projects.

This tool would only be used by this repository, so it can definitely be specific to taskwarrior. I'm not sure if that's what you meant by "project" here -- but anything in the repo is fair game.

So the .yml files that I had been using in testing, which are part of a cousin(uncle?) folder's project. As such, xtask would have to be run in origin/trunk project directory and add paths relative to that.

Yep, that's the directory indicated by CARGO_MANIFEST_DIR.

Because I'm not 100% familiar with how this type of tool gets used and I'm trying not to bother with too many questions, the assumption above may be incorrect. (But I am very grateful for the guidance and patience you've provided!).

To be clear, this isn't a general MSRV-management tool. It's meant specifically for this repository, which is why it's OK to hard-code the filenames in the source flie.

Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

Some comments to make this a bit more idiomatic, but this is definitely looking more concise already!

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
Comment on lines 19 to 22
const MSRV_PATH_REGEX: [(&str, &str); 1] = [(
"xtask/Cargo.toml",
r#"rust-version = "[0-9]+("|\.|[0-9])+""#,
)];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Using a slice here, instead of an array, removes the need to specify the length. Let's also use the actual files we'd like to modify.

Suggested change
const MSRV_PATH_REGEX: [(&str, &str); 1] = [(
"xtask/Cargo.toml",
r#"rust-version = "[0-9]+("|\.|[0-9])+""#,
)];
const MSRV_PATH_REGEX: &[(&str, &str)] = &[
(
"../.github/workflows/checks.yml",
r#"toolchain: "[0-9.]+*" # MSRV"#,
),
("../.github/workflows/rust-tests.yml", r#""[0-9.]+" # MSRV"#),
(
"taskchampion/src/lib.rs",
r#"Rust version [0-9.]* and higher"#,
),
];

I also made the following changes in the github workflow files, so that the regexes above will work:

diff --git .github/workflows/checks.yml .github/workflows/checks.yml
index b1370c905..64de42ce6 100644
--- .github/workflows/checks.yml
+++ .github/workflows/checks.yml
@@ -24,19 +24,17 @@ jobs:
       - name: Cache cargo build
         uses: actions/cache@v3
         with:
           path: target
           key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
 
       - uses: actions-rs/toolchain@v1
         with:
-          # Fixed version for clippy lints.  Bump this as necesary.  It must not
-          # be older than the MSRV in tests.yml.
-          toolchain: "1.64"
+          toolchain: "1.64" # MSRV
           override: true
 
       - uses: actions-rs/cargo@v1.0.3
         with:
           command: check
 
       - run: rustup component add clippy
 
diff --git .github/workflows/rust-tests.yml .github/workflows/rust-tests.yml
index 776642ee6..be2b7c711 100644
--- .github/workflows/rust-tests.yml
+++ .github/workflows/rust-tests.yml
@@ -10,18 +10,17 @@ on:
   pull_request:
     types: [opened, reopened, synchronize]
 
 jobs:
   test:
     strategy:
       matrix:
         rust:
-          # MSRV; must not be higher than the clippy rust version in checks.yml
-          - "1.64"
+          - "1.64" # MSRV
           - "stable"
         os:
           - ubuntu-latest
           - macOS-latest
           - windows-latest
 
     name: "rust ${{ matrix.rust }} on ${{ matrix.os }}"
     runs-on: ${{ matrix.os }}

Copy link
Contributor Author

@iwyatt iwyatt Nov 10, 2023

Choose a reason for hiding this comment

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

I'm assuming I don't need to include the changes to these configuration files as part of my own PR, but please let me know if that is incorrect. I did change the array to a slice per your recommendation, which makes sense and hadn't considered that as an option.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, please do include these changes in .github as well -- without them, cargo xtask msrv won't update these files, so arguably the job isn't finished :)

taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
taskchampion/xtask/src/main.rs Outdated Show resolved Hide resolved
@djmitche
Copy link
Collaborator

This is looking great! I think the msrv function is a lot clearer now. Just get those .github/ changes in, and we can get this merged!

Thanks for sticking with this through all the revisions..

@iwyatt
Copy link
Contributor Author

iwyatt commented Nov 11, 2023

Hi @djmitche I updated the two .yml files . I also noticed in checks.yml has the rust version specified in two places, so I added # MSRV for the other one in that file in addition to the one you mentioned.

I also see that checks.yml has a version specification for mdbook-version with a comment to update it in publish-docs.yml. This would appear to follow the same use case as the MSRV project I'm working on. Is that something we want to do in a new project after we close out MSRV, or maybe save for another 'good first issue' ?

@iwyatt iwyatt requested a review from djmitche November 11, 2023 22:00
Copy link
Collaborator

@djmitche djmitche left a comment

Choose a reason for hiding this comment

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

Nice work! And good job spotting that other place in checks.yml.

Bumping the mdbook version is much less common, and less critical that it be done completely, so I don't think we need to add an xtask command for it.

I'll get this merged. Thanks again!

@djmitche djmitche merged commit 8f327db into GothenburgBitFactory:develop Nov 11, 2023
23 checks passed
@djmitche
Copy link
Collaborator

Did you have ideas what you'd like to work on next?

@iwyatt
Copy link
Contributor Author

iwyatt commented Nov 12, 2023

I haven't quite figured it out yet.

Here are some unvetted / initial ideas:

Unvetted Project Ideas

  • Website work to update tw.org:
    • Not ideal since there is little to no Rust involved. Helps task warrior ecosystem.
  • Nushell Shell Completer:
    • Little/no actual Rust involved, but helpful to my use case and interesting. Seems moderately straight forward.
  • Build a TaskWarrior PWA:
    • Most could be done in Rust. Big benefit to Task Warrior Ecosystem. Solve some personal requirements for a task manager.
  • Build a Firefox Extension to capture tasks from browser context (eg email / web pages):
    • No Rust involved. Something similar using Python and Bookmarks already exists. Would solve personal need for a task manager.

Objectives

The ideal project is an intersection of the following:

  1. is appropriate for my rust skills
  2. would be helpful to Taskwarrior
  3. would be helpful for me to learn given my goals:

Primary Goal:

  • learn rust
    • would be nice to have enough skill to be employable as a Rust developer
    • or have enough Rust skill to build something myself that I can make a dollar from

Secondary Goals:

  • Help make taskwarrior something I can use for my primary/only task manager todo app
    • requires browser extension, mobile app, sync

Advice?

I've been embarking on a journey to build, hone, and develop enough coding skill to call myself and actual 'programmer' (context). If I were an intern on your team in a professional setting, what feedback / advice would you give me?

If you don't mind, I'll ping you on Discord for a personal, non-public, response.

FYI

I'll be writing a short blog post about what I learned building xtask MSRV.

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

Successfully merging this pull request may close these issues.

2 participants