From 8208ca36e08e228889f18c3e1b2738f9d6d95915 Mon Sep 17 00:00:00 2001 From: Daniel Marbach Date: Wed, 21 Aug 2024 21:22:10 +0000 Subject: [PATCH] NUnit 3.x to 4.x semi-automatic migration support (#967) * Mention script * Update docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md * Update docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md * Update docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md * Update docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md --------- Co-authored-by: Sean Killeen --- .../release-notes/Nunit4.0-MigrationGuide.md | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md b/docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md index 1861771d1..31bcb9974 100644 --- a/docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md +++ b/docs/articles/nunit/release-notes/Nunit4.0-MigrationGuide.md @@ -108,6 +108,219 @@ Assert.That(actualText, Does.StartWith("42"), $"Expected '{actualText}' to start There are no code fixers for `FileAssert` and `DirectoryAssert`. They could be added, but we don't expect these to be used too much. +Should you be migrating a larger number of repositories to the constraint model +the following script can be used as a good starting point: + +```bash +#!/bin/bash + +# This script automates the process of adding and configuring the NUnit.Analyzers package to .NET projects. +# It performs the following steps: +# - Checks if a directory is provided as an argument, and defaults to the current directory if not. +# - Changes to the target directory to ensure all operations are performed within the correct git repository. +# - Creates a dedicated branch that will contain the changes +# - Searches for Directory.Packages.props in the target directory and its subdirectories. +# - Fails the script when multiple are found +# - If one is found it adds the NUnit.Analyzer there and makes sure the modifications to the project files follow the nomenclature +# for centralized packages +# - Searches for all .csproj files in the target directory. +# - For each .csproj file: +# - Checks if NUnit.Analyzers is already referenced, skipping if it is. +# - Adds NUnit.Analyzers after the NUnit reference if not already present. +# - Skips the .csproj file if no NUnit reference is found. +# - Stages the modified .csproj and/or Directory.Packages.props files for commit and prompts the user to review before committing. +# - Restores NuGet packages for all .sln files found in the directory. +# - Applies each diagnostic rule sequantially to the projects in parallel: +# - Checks for NUnit.Analyzers reference, and creates or modifies .editor_config for each .csproj file. +# - Applies the formatting using dotnet format for each diagnostic. +# - Discards or deletes changes to .editor_config. +# - Commits the changes for each diagnostic. +# - Returns to the original directory after completing the operations. +# +# Usage: +# chmod +x nunit-analyzer-automation.sh +# ./nunit-analyzer-automation.sh target/directory/path +# +# Requirements: +# - sed +# - git +# - gh +# +# Installation Requirements MacOS: +# - brew install gnused +# - Make it the default sed as outlined in the hints in the installation step of the brew package or replaced "sed" with "gsed" in the script in case you don't want to override the default sed of MacOS +# - brew install gh +# - gh auth login +# The gh client needs to be authenticated +# - gh auth refresh -s project +# The gh client requires project scope + +# Check if a directory is provided as an argument, if not, use the current directory +TARGET_DIR="${1:-.}" + +PACKAGE_NAME="NUnit.Analyzers" +PACKAGE_VERSION="4.3.0" # Replace with the desired version +BRANCH_NAME="nunit-assertions-migration" +PROJECT_ID="XXX" +ORG="ZZZ" + +# Define the XML snippet to insert +INSERT_SNIPPET_CSPROJ=" " +INSERT_SNIPPET_CSPROJ_PROPS=" " +INSERT_SNIPPET_PROPS=" " + +# Change to the TARGET_DIR to ensure all commands are executed in the context of its git repository +pushd "$TARGET_DIR" || { echo "Failed to change directory to $TARGET_DIR"; exit 1; } + +git checkout -b $BRANCH_NAME + +# Find all Directory.Packages.props files in the target directory and its subdirectories +prop_files=($(find . -name "Directory.Packages.props")) +prop_file= + +# Check if there are multiple Directory.Packages.props files +if [ ${#prop_files[@]} -gt 1 ]; then + echo "Error: Multiple Directory.Packages.props files found. The script cannot proceed." + exit 1 +elif [ ${#prop_files[@]} -eq 1 ]; then + prop_file="${prop_files[0]}" + echo "Found Directory.Packages.props: $prop_file" + # Check if the project already has NUnit.Analyzers + if grep -qi "> "$editor_config" + fi + + echo "Appending to $editor_config" + echo "dotnet_diagnostic.$diagnostic.severity = warning" >> "$editor_config" + + echo "Formatting $csproj with diagnostic $diagnostic" + dotnet format analyzers $csproj --diagnostics $diagnostic --severity info --no-restore --verbosity diagnostic + + else + echo "Skipping $csproj - No NUnit.Analyzer reference found" + fi + ) & + + formatting_jobs+=($!) + done < <(find . -name "*.csproj") + + echo "Waiting for formatting jobs to complete" + for formatting_job in "${formatting_jobs[@]}"; do + wait $formatting_job + done + + echo "Committing formatting changes" + git add "*.cs" + git commit -m "Autoformat of test projects for $diagnostic" + + echo "Discarding all unrelated changes" + git reset --hard + git clean -f + + formatting_jobs=() +done + +echo "Pushing the branch upstream" +git push --set-upstream origin $BRANCH_NAME + +echo "Creating the pull request" +pull_request_url=$(gh pr create --title "Migrate NUnit assertions to the constraint model in preparation of the NUnit 4 upgrade" --body " +This PR contains all changes related to assertion model according to the [constraint assertion model](https://docs.nunit.org/articles/nunit/writing-tests/assertions/assertion-models/constraint.html). + +Using a script, we apply all [assertion rules](https://docs.nunit.org/articles/nunit-analyzers/NUnit-Analyzers.html#assertion-rules-nunit2001---) provided by the NUnit.Analyzers package. In addition, some manual interventions are done when applicable. + +## Plan of action + +- [ ] ⚠️ Build the solution and resolve any remaining errors or warnings +- [ ] ✅ Review the assertions commit by commit +- [ ] 👀 Invite another pair of eyes to re-review +" --assignee "@me" --head $BRANCH_NAME) + +gh project item-add $PROJECT_ID --owner $ORG --url $pull_request_url +gh pr merge $pull_request_url --auto --squash + +popd +``` + +The script is provided as is and might require further tweaks to the specific use cases. +It was written assuming a few structural conventions that might not apply to every use case. + #### Updating from Classic Asserts in NUnit 4.x If you want to keep the Classic Asserts and not convert them to the constraint model -- but do want to use the new NUnit