{"id":13594256,"url":"https://github.com/leonardochaia/dotnet-affected","last_synced_at":"2025-04-09T07:31:11.757Z","repository":{"id":42189069,"uuid":"349784582","full_name":"leonardochaia/dotnet-affected","owner":"leonardochaia","description":".NET tool for determining which projects are affected by a set of changes. Useful for large projects or monorepos.","archived":false,"fork":false,"pushed_at":"2024-10-18T23:15:56.000Z","size":333,"stargazers_count":209,"open_issues_count":7,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-10-19T15:07:11.966Z","etag":null,"topics":["build-tool","dotnet","dotnet-tools","monorepo","msbuild"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leonardochaia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["leonardochaia"]}},"created_at":"2021-03-20T16:56:02.000Z","updated_at":"2024-10-18T23:11:18.000Z","dependencies_parsed_at":"2024-01-13T16:24:50.808Z","dependency_job_id":"76ecf91b-9d95-4455-9e18-0d917b20c998","html_url":"https://github.com/leonardochaia/dotnet-affected","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardochaia%2Fdotnet-affected","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardochaia%2Fdotnet-affected/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardochaia%2Fdotnet-affected/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonardochaia%2Fdotnet-affected/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leonardochaia","download_url":"https://codeload.github.com/leonardochaia/dotnet-affected/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223375235,"owners_count":17135330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-tool","dotnet","dotnet-tools","monorepo","msbuild"],"created_at":"2024-08-01T16:01:30.920Z","updated_at":"2024-11-06T16:30:54.201Z","avatar_url":"https://github.com/leonardochaia.png","language":"C#","funding_links":["https://github.com/sponsors/leonardochaia"],"categories":["C#","C\\#"],"sub_categories":[],"readme":"# dotnet-affected\n\nA .NET Tool for determining which projects are affected by a set of changes. This tool is particularly useful for large\nprojects or mono-repositories.\n\n## Features\n\ndotnet-affected works by comparing two versions of your code, usually by a commit range in CI, or HEAD against your\ncurrent working directory.\n\n1. Detects which MSBuild Projects have changed based on the files that changed.\n2. When using Central Package Management, detects which NuGet Packages have changed.\n3. Detects which projects are affected by projects or packages that have changed.\n4. Detects changes to `Directory.Build.props`/`.targets` and other input files.\n5. Detects changes to any file referenced by the MSBuild project.\n6. Outputs an [MSBuild Traversal SDK](https://github.com/microsoft/MSBuildSdks/tree/main/src/Traversal) Project that can\n   be used to `dotnet build` and `test` which projects where changed/affected.\n7. Outputs a text file which can be used to deploy only what's needed or feed to other tools.\n8. Supports `.csproj`, `.fsproj` and `.vbproj`.\n9. Supports SDK and non-SDK style projects.\n\n## How it works\n\ndotnet-affected discovers all `.csproj`, `.fsproj` and `.vbproj` from filesystem. Then, uses MSBuild to build\na `ProjectGraph` of all projects and which projects they depend on.\n\nThen `git diff` is ran, to determine which files have changed. These files are then mapped to which project they belong\nto, and we get a list of which projects have any changes.\n\ndotnet-affected will also detect changes to `Directory.Packages.props` and determine which NuGet packages have been\nadded/deleted/updated.\n\nWith the changed projects, and changed NuGet Packages, it uses the `ProjectGraph` to find which projects are affected by\nthose changes.\n\nFor example, given this project structure:\n\n1. Inventory.Shared\n2. Inventory (depends on .1)\n3. Inventory.Tests (depends on .2)\n4. Inventory.Shared.Tests (depends on .1)\n\nWhen .2 changes, .3 will be affected so we will build and test .2 and .3. There's no need to build and test .4 since .1\nhas not changed.\n\nWhen 1. changes, everything needs to be built/test, since, transitively, they all depend on .1.\n\n## Installation\n\nThe tool can be installed using `dotnet install`:\n\n```shell\ndotnet tool install dotnet-affected\n```\n\nIt can also be installed globally with the `--global` flag but installing using local tools is recommended so all devs\nshare the same version, and so you share the same version in CI as well.\n\nYou can then run the tool using `dotnet affected` in the root of your repository.\n\n```text\n$ dotnet affected --help\nDescription:\n  Determines which projects are affected by a set of changes.\n\nUsage:\n  affected [command] [options]\n\nOptions:\n  -p, --repository-path \u003crepository-path\u003e  Path to the root of the repository, where the .git directory is.\n                                           [Defaults to current directory, or solution's directory when using --solution-path]\n  --solution-path \u003csolution-path\u003e          Path to a Solution file (.sln) used to discover projects that may be affected.\n                                           When omitted, will search for project files inside --repository-path.\n  -v, --verbose                            Write useful messages or just the desired output. [default: False]\n  --assume-changes \u003cassume-changes\u003e        Hypothetically assume that given projects have changed instead of using Git diff to determine them.\n  --from \u003cfrom\u003e                            A branch or commit to compare against --to.\n  --to \u003cto\u003e                                A branch or commit to compare against --from\n  -f, --format \u003cformat\u003e                    Space separated list of formatters to write the output. [default: traversal]\n  --dry-run                                Doesn't create files, outputs to stdout instead. [default: False]\n  --output-dir \u003coutput-dir\u003e                The directory where the output file(s) will be generated\n                                           If relative, it's relative to the --repository-path\n  --output-name \u003coutput-name\u003e              The name for the file to create for each format.\n                                           Format extension is appended to this name. [default: affected]\n  --version                                Show version information\n  -?, -h, --help                           Show help and usage information\n\nCommands:\n  describe  Prints the current changed and affected projects.\n```\n\n## SDK based installation\n\nAlternatively, dotnet-affected can be executed directly by MSBuild without using the dotnet-affected CLI.\n\n**File**: `ci.props`\n\n```xml\n\n\u003cProject Sdk=\"DotnetAffected.Tasks/3.0.0;Microsoft.Build.Traversal/3.2.0\"\u003e\n    \u003cTarget Name=\"_DotnetAffectedCheck\" AfterTargets=\"DotnetAffectedCheck\"\u003e\n        \u003c!-- Print all affected projects --\u003e\n        \u003cMessage Text=\"  \u003e\u003e %(ProjectReference.Identity)\" Importance=\"high\"/\u003e\n    \u003c/Target\u003e\n\u003c/Project\u003e\n\n```\n\nNow when you execute\n\n```shell\ndotnet build ci.props\n```\n\nOnly the affected projects are built!\n\nFor more information see [DotnetAffected.Tasks](./src/DotnetAffected.Tasks/README.md)\n\n## Locating Git Repository\n\ndotnet-affected needs the path to your Git repository (where the `.git` folder is) so it can run `git diff`. By default,\ndotnet-affected will attempt to interpret the current working directory as a git repository.\n\nThis can be customized using `--repository-path`, shorthand `-p`.\n\nLocally, it's recommended to run the tool at the repository root to simplify things. In CI, you usually provide the\nworking directory that your CI provider gives you in an environment variable.\n\n## Project Discovery\n\nBy default, projects are discovered by recursively searching the `--repository-path`, or current working directory if\nnot specified.\n\nThis is quite useful for projects that do not have Solution Files and are using something\nlike [SlnGen](https://microsoft.github.io/slngen/)\nto generate solutions.\n\nHowever, when you do have a Solution File, the `--solution-file` can be used to discover projects from the Solution\ninstead. This can also be used to filter down which projects the tool discovers, if you don't want to discover all\npresent in file system.\n\nWhen using `--solution-file`, only the projects included in the Solution will be considered for changes.\n\nFor example, if changes are made to projects that are not referenced by the Solution file, those changes will be ignored\nand dotnet-affected will output that nothing.\n\nNote that, if your Solution file is not at the root of your Git Repository (where the `.git` directory is), you still\nneed to specify `--repository-path`. For example:\n\n```shell\ndotnet affected --repository-path /home/lchaia/monorepo --solution-path /home/lchaia/monorepo/my-big-project/MyBigProjectSolution.sln\n```\n\n## Build/test affected projects\n\nIn order to build only what is affected, the tool outputs an MSBuild Traversal project that can can then be feed\nto `dotnet build`.\n\nFor example, the below command outputs `affected.proj` at the current directory, by comparing your changes against the\ncurrent HEAD.\n\n```text\n$ dotnet affected --verbose\nDiscovering projects from /home/lchaia/dev/dotnet-affected\nBuilding Dependency Graph\nBuilt Graph with 8 Projects in 0.31s\n1 files have changed inside 1 projects\n0 NuGet Packages have changed\n1 projects are affected by these changes\nChanged Projects\nName  Path\n      /home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\n\nAffected Projects\nName                   Path\ndotnet-affected.Tests  /home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\nWRITE: /home/lchaia/dev/dotnet-affected/affected.proj\n```\n\nThe contents of `affected.proj` are:\n\n```xml\n\n\u003cProject Sdk=\"Microsoft.Build.Traversal/3.0.3\"\u003e\n    \u003cItemGroup\u003e\n        \u003cProjectReference\n            Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\"/\u003e\n        \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\"/\u003e\n    \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\nYou can then use `dotnet test` (or any other `dotnet` commands) against the resulting `affected.proj` file:\n\n```shell\ndotnet test affected.proj\n```\n\n## Affected projects between commit ranges\n\nBy default, dotnet-affected will compare changes between your working directory against the current HEAD. This can be\nchanged by providing the `--from` and `--to` parameters. Commit sha or branch names can be used.\n\nExamples:\n\n```shell\n# Compares HEAD against working directory\ndotnet affected\n\n# Compares HEAD against branch chore/target-net7\ndotnet affected --from chore/target-net7\n\n# Compares main against branch chore/target-net7\ndotnet affected --from chore/target-net7 --to main\n```\n\n## Output Formatting\nThe `--format` command line option can be used to choose which output formats will be used.\n\ndotnet-affected currently supports following **format options**:\n- `traversal`: Traversal SDK project file.\n- `text`: Plain text file containing all affected project paths.\n- `json`: JSON file containing all affected project names and paths.\n\nExample:\n```text\n$ dotnet affected -v --format text\nDiscovering projects from /home/lchaia/dev/dotnet-affected\nBuilding Dependency Graph\nBuilt Graph with 8 Projects in 0.31s\n1 files have changed inside 1 projects\n0 NuGet Packages have changed\n1 projects are affected by these changes\nChanged Projects\nName  Path\n      /home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\n\nAffected Projects\nName                   Path\ndotnet-affected.Tests  /home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\nWRITE: /home/lchaia/dev/dotnet-affected/affected.txt\n```\n\n```text\n$ cat affected.txt                                                                                                                                         ✔\n/home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\n/home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\n```\n\n### Multiple Output Formats\n\nThis tool supports generating multiple output files by providing space-seperated format options to the `--format` flag.\n\nExample:\n```text\n$ dotnet affected -v --format text traversal json\nDiscovering projects from /home/lchaia/dev/dotnet-affected\nBuilding Dependency Graph\nBuilt Graph with 8 Projects in 0.39s\n1 files have changed inside 1 projects\n0 NuGet Packages have changed\n1 projects are affected by these changes\nChanged Projects\nName  Path\n      /home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\n\nAffected Projects\nName                   Path\ndotnet-affected.Tests  /home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\nWRITE: /home/lchaia/dev/dotnet-affected/affected.txt\nWRITE: /home/lchaia/dev/dotnet-affected/affected.proj\nWRITE: /home/lchaia/dev/dotnet-affected/affected.json\n```\n\n## Excluding Projects\n\nProjects can be excluded by using the `--exclude` (shorthand `-e`) argument. It expects a dotnet Regular Expression\nthat will be matched against each Project's Full Path.\n\nIn the below example, `dotnet-affected.Tests` is excluded due to the regular expression provided.\n```shell\n$ dotnet affected --dry-run --verbose -e .Tests.\n1 files have changed referenced by 1 projects\n0 NuGet Packages have changed\n1 projects are affected by these changes\n1 projects were excluded\nChanged Projects\nName                        Path                                                                                                    \ndotnet-affected             /home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj                             \n                 \nAffected Projects\nName                        Path                                                                                                    \ndotnet-affected.Benchmarks  /home/lchaia/dev/dotnet-affected/benchmarks/dotnet-affected.Benchmarks/dotnet-affected.Benchmarks.csproj\n                 \nExcluded Projects\nName                   Path                                                                                    \ndotnet-affected.Tests  /home/lchaia/dev/dotnet-affected/test/dotnet-affected.Tests/dotnet-affected.Tests.csproj\nDRY-RUN: WRITE /home/lchaia/dev/dotnet-affected/affected.proj\nDRY-RUN: CONTENTS:\n\u003cProject Sdk=\"Microsoft.Build.Traversal/3.0.3\"\u003e\n  \u003cItemGroup\u003e\n    \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/benchmarks/dotnet-affected.Benchmarks/dotnet-affected.Benchmarks.csproj\" /\u003e\n    \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\" /\u003e\n  \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\n## Continuous Integration\n\nFor usage in CI, it's recommended to use the `--from` and `--to` options with the environment variables provided by your\nbuild tool.\n\ndotnet-affected can be used in any CI system where you `dotnet` is present. You can install the tool and run\n`dotnet affected` commands as if locally.\n\nHowever, an action is provided for [Github actions](https://github.com/leonardochaia/dotnet-affected-action)\nand having a way to simplify this for other CI systems would be welcome.\n\n### Building branches/tags\n\nFor example, for building a branch a setup like this could be used:\n\n```shell\n# Replace env vars with what your CI system gives you\ndotnet affected \\\n    --from $LAST_SUCCESSFUL_BUILD_COMMIT \\\n    --to $CURRENT_COMMIT_HASH\ndotnet test affected.proj\n```\n\nIt's important to note that CI system triggers a build per push, not per commit. Which means a set of commits may be\nbuilt, instead of just one. There is also the case where the previous build/s have failed, so we need to build from the\nlatest commit that has a successful build.\n\nThere's an in-depth explanation of the problem in [here](https://github.com/nrwl/last-successful-commit-action#problem)\n\nWhen using GitHub Actions, `leonardochaia/dotnet-affected@v1` can be used to execute dotnet-affected. This can be\ncombined with [nrwl/last-successful-commit-action](https://github.com/nrwl/last-successful-commit-action) to\nbuild/test only what's affected since last succesful commit.\n\nYou can see a complete example\nfor [building branches with GitHub actions here](https://github.com/leonardochaia/dotnet-affected-action#for-building-branches).\n\n### Building Pull Requests\n\nFor building PRs, we need to provide the target branch/commit and the PR branch/commit.\n\n```shell\ndotnet affected generate --from origin/main --to $CURRENT_COMMIT_HASH\ndotnet test affected.proj\n```\n\nYou can see a complete example\nfor [building PRs with GitHub actions here](https://github.com/leonardochaia/dotnet-affected-action#for-building-prs).\n\n## Don't build/test/deploy when no projects have changed\n\nIf nothing has changed, or the changes are not related to any of the discovered projects, there is no need to\nrun `dotnet test`.\n\nIn order to detect this, dotnet affected will exit with an exit status code `166`. You can use this to prevent spending\ntime on unnecessary tasks when nothing has changed.\n\nNote that dotnet affected returns `166` when nothing has changed, not to be confused when nothing is affected. If\nprojects have changed, but nothing is affected by those changes, we still need to build those that changed.\n\n```shell\ndotnet affected # [..] other args\nif [ \"$?\" -eq 0 ]; then\n    dotnet build affected.proj\nfi\n```\n\nWhen using GitHub Actions, conditions can be added to skip steps when nothing has changed or is affected:\n\n```yaml\n-   name: Install dependencies\n    if: success() \u0026\u0026 steps.affected.outputs.affected != ''\n    run: dotnet restore affected.proj\n```\n\n[Complete example](https://github.com/leonardochaia/dotnet-affected-action#for-building-prs)\n\n## Which projects do I need to re deploy\n\nIn order to determine what projects need to be deployed since our previous release, we can use dotnet-affected to\ndetermine which projects were affected from the previous release to the current one.\n\n```shell\ndotnet affected --from releases/v1.0.0 --to releases/v2.0.0\n```\n\nOf course this assumes that your .NET dependencies also represent system's dependencies. For example, if your systems\ncommunicate through HTTP and you don't share any assemblies between them, this won't work. But, if your systems share a\ncommon assembly with data transfer objects, or auto-generated HttpClients for example, this works wonderful.\n\n## Describe Command\n\ndotnet-affected includes a `describe` command that outputs to stdout in a readable fashion which projects have changed\nand which projects are affected by those changes.\n\n```text\n$ dotnet affected describe\n1 files have changed inside 1 projects\n0 NuGet Packages have changed\n1 projects are affected by these changes\nChanged Projects\nName  Path\n      /home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\n\nAffected Projects\nName                   Path\ndotnet-affected.Tests  /home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\n```\n\n## Troubleshooting\n\nSome useful commands and flags are included for troubleshooting or just observing what would be affected by a small\nchange to a system.\n\n### Dry Running\n\nSometimes it is useful to see what the tool would do under certain situation.\n\nWhen adding the `--dry-run` flag, dotnet-affected will write to stdout instead of generating output files.\n\n```text\n$ dotnet affected --dry-run\nDRY-RUN: WRITE /home/lchaia/dev/dotnet-affected/affected.proj\nDRY-RUN: CONTENTS:\n\u003cProject Sdk=\"Microsoft.Build.Traversal/3.0.3\"\u003e\n  \u003cItemGroup\u003e\n    \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\" /\u003e\n    \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected/dotnet-affected.csproj\" /\u003e\n  \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\n### Assume Changes\n\nYou can also use `--assume-changes some-project-name` in order to fake changes being made to a certain project. This\nlet's you see what would be affected if that project changed.\n\n```text\n$ dotnet-affected --dry-run --assume-changes dotnet-affected.Tests\nDRY-RUN: WRITE /home/lchaia/dev/dotnet-affected/affected.proj\nDRY-RUN: CONTENTS:\n\u003cProject Sdk=\"Microsoft.Build.Traversal/3.0.3\"\u003e\n  \u003cItemGroup\u003e\n    \u003cProjectReference Include=\"/home/lchaia/dev/dotnet-affected/src/dotnet-affected.Tests/dotnet-affected.Tests.csproj\" /\u003e\n  \u003c/ItemGroup\u003e\n\u003c/Project\u003e\n```\n\n## Contributing\n\nWe accept PRs! Feel free to file issues if you encounter any problem.\n\nIf you wanna build the solution, these are the steps:\n\nNote: Windows users, you can either use WSL or GitBash, or use PowerShell replacing `.sh` scripts with `.ps1`\n\n### Installing the SDK\n\nFirst run this script to locally install the proper versions of the .NET SDKs we are using. This won't affect other .NET\nprojects that you have.\n\n```shell\n./eng/install-sdk.sh\n```\n\nIt will install the SDKs at `./eng/.dotnet`.\n\n### Activating your console\n\nBefore running any `dotnet` commands, you need to activate the SDK by running:\n\n```shell\n. ./eng/activate.sh\n```\n\nIf you run `dotnet --info` you should see all SDK installed.\n\nYou can then build using.\n\n```shell\ndotnet build\n```\n\nOr open your favorite ide through the activated command line and it will use the locally installed .NET\n\n```shell\nsource ./eng/activate.sh\nrider Affected.sln\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonardochaia%2Fdotnet-affected","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleonardochaia%2Fdotnet-affected","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonardochaia%2Fdotnet-affected/lists"}