├── .github └── workflows │ └── publish_to_nuget.yml ├── .gitignore ├── DotnetVersion.sln ├── README.md ├── azure-pipelines.yml ├── src └── DotnetVersion │ ├── CliException.cs │ ├── DotnetVersion.csproj │ └── Program.cs └── tests └── DotnetVersion.Tests ├── DotnetVersion.Tests.csproj └── Program.cs /.github/workflows/publish_to_nuget.yml: -------------------------------------------------------------------------------- 1 | name: Publish to Nuget 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | 15 | - name: Install .NET 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: '6.0.x' 19 | 20 | - name: Build and publish 21 | run: | 22 | dotnet pack -o output src/DotnetVersion/DotnetVersion.csproj 23 | dotnet nuget push output/ -s https://nuget.org -k ${NUGET_API_KEY} 24 | env: 25 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/macos,linux,window,clion+all,rider,intellij+all,visualstudiio,jetbrains+all,monodevelop,visualstudio,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=macos,linux,window,clion+all,rider,intellij+all,visualstudiio,jetbrains+all,monodevelop,visualstudio,visualstudiocode 4 | 5 | ### CLion+all ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | 40 | # CMake 41 | cmake-build-*/ 42 | 43 | # Mongo Explorer plugin 44 | .idea/**/mongoSettings.xml 45 | 46 | # File-based project format 47 | *.iws 48 | 49 | # IntelliJ 50 | out/ 51 | 52 | # mpeltonen/sbt-idea plugin 53 | .idea_modules/ 54 | 55 | # JIRA plugin 56 | atlassian-ide-plugin.xml 57 | 58 | # Cursive Clojure plugin 59 | .idea/replstate.xml 60 | 61 | # Crashlytics plugin (for Android Studio and IntelliJ) 62 | com_crashlytics_export_strings.xml 63 | crashlytics.properties 64 | crashlytics-build.properties 65 | fabric.properties 66 | 67 | # Editor-based Rest Client 68 | .idea/httpRequests 69 | 70 | # Android studio 3.1+ serialized cache file 71 | .idea/caches/build_file_checksums.ser 72 | 73 | # JetBrains templates 74 | **___jb_tmp___ 75 | 76 | ### CLion+all Patch ### 77 | # Ignores the whole .idea folder and all .iml files 78 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 79 | 80 | .idea/ 81 | 82 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 83 | 84 | *.iml 85 | modules.xml 86 | .idea/misc.xml 87 | *.ipr 88 | 89 | # Sonarlint plugin 90 | .idea/sonarlint 91 | 92 | ### Intellij+all ### 93 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 94 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 95 | 96 | # User-specific stuff 97 | 98 | # Generated files 99 | 100 | # Sensitive or high-churn files 101 | 102 | # Gradle 103 | 104 | # Gradle and Maven with auto-import 105 | # When using Gradle or Maven with auto-import, you should exclude module files, 106 | # since they will be recreated, and may cause churn. Uncomment if using 107 | # auto-import. 108 | # .idea/modules.xml 109 | # .idea/*.iml 110 | # .idea/modules 111 | 112 | # CMake 113 | 114 | # Mongo Explorer plugin 115 | 116 | # File-based project format 117 | 118 | # IntelliJ 119 | 120 | # mpeltonen/sbt-idea plugin 121 | 122 | # JIRA plugin 123 | 124 | # Cursive Clojure plugin 125 | 126 | # Crashlytics plugin (for Android Studio and IntelliJ) 127 | 128 | # Editor-based Rest Client 129 | 130 | # Android studio 3.1+ serialized cache file 131 | 132 | # JetBrains templates 133 | 134 | ### Intellij+all Patch ### 135 | # Ignores the whole .idea folder and all .iml files 136 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 137 | 138 | 139 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 140 | 141 | 142 | # Sonarlint plugin 143 | 144 | ### JetBrains+all ### 145 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 146 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 147 | 148 | # User-specific stuff 149 | 150 | # Generated files 151 | 152 | # Sensitive or high-churn files 153 | 154 | # Gradle 155 | 156 | # Gradle and Maven with auto-import 157 | # When using Gradle or Maven with auto-import, you should exclude module files, 158 | # since they will be recreated, and may cause churn. Uncomment if using 159 | # auto-import. 160 | # .idea/modules.xml 161 | # .idea/*.iml 162 | # .idea/modules 163 | 164 | # CMake 165 | 166 | # Mongo Explorer plugin 167 | 168 | # File-based project format 169 | 170 | # IntelliJ 171 | 172 | # mpeltonen/sbt-idea plugin 173 | 174 | # JIRA plugin 175 | 176 | # Cursive Clojure plugin 177 | 178 | # Crashlytics plugin (for Android Studio and IntelliJ) 179 | 180 | # Editor-based Rest Client 181 | 182 | # Android studio 3.1+ serialized cache file 183 | 184 | # JetBrains templates 185 | 186 | ### JetBrains+all Patch ### 187 | # Ignores the whole .idea folder and all .iml files 188 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 189 | 190 | 191 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 192 | 193 | 194 | # Sonarlint plugin 195 | 196 | ### Linux ### 197 | *~ 198 | 199 | # temporary files which can be created if a process still has a handle open of a deleted file 200 | .fuse_hidden* 201 | 202 | # KDE directory preferences 203 | .directory 204 | 205 | # Linux trash folder which might appear on any partition or disk 206 | .Trash-* 207 | 208 | # .nfs files are created when an open file is removed but is still being accessed 209 | .nfs* 210 | 211 | ### macOS ### 212 | # General 213 | .DS_Store 214 | .AppleDouble 215 | .LSOverride 216 | 217 | # Icon must end with two \r 218 | Icon 219 | 220 | # Thumbnails 221 | ._* 222 | 223 | # Files that might appear in the root of a volume 224 | .DocumentRevisions-V100 225 | .fseventsd 226 | .Spotlight-V100 227 | .TemporaryItems 228 | .Trashes 229 | .VolumeIcon.icns 230 | .com.apple.timemachine.donotpresent 231 | 232 | # Directories potentially created on remote AFP share 233 | .AppleDB 234 | .AppleDesktop 235 | Network Trash Folder 236 | Temporary Items 237 | .apdisk 238 | 239 | ### MonoDevelop ### 240 | #User Specific 241 | *.userprefs 242 | *.usertasks 243 | 244 | #Mono Project Files 245 | *.pidb 246 | *.resources 247 | test-results/ 248 | 249 | ### Rider ### 250 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 251 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 252 | 253 | # User-specific stuff 254 | 255 | # Generated files 256 | 257 | # Sensitive or high-churn files 258 | 259 | # Gradle 260 | 261 | # Gradle and Maven with auto-import 262 | # When using Gradle or Maven with auto-import, you should exclude module files, 263 | # since they will be recreated, and may cause churn. Uncomment if using 264 | # auto-import. 265 | # .idea/modules.xml 266 | # .idea/*.iml 267 | # .idea/modules 268 | 269 | # CMake 270 | 271 | # Mongo Explorer plugin 272 | 273 | # File-based project format 274 | 275 | # IntelliJ 276 | 277 | # mpeltonen/sbt-idea plugin 278 | 279 | # JIRA plugin 280 | 281 | # Cursive Clojure plugin 282 | 283 | # Crashlytics plugin (for Android Studio and IntelliJ) 284 | 285 | # Editor-based Rest Client 286 | 287 | # Android studio 3.1+ serialized cache file 288 | 289 | # JetBrains templates 290 | 291 | #!! ERROR: visualstudiio is undefined. Use list command to see defined gitignore types !!# 292 | 293 | ### VisualStudioCode ### 294 | .vscode/* 295 | !.vscode/settings.json 296 | !.vscode/tasks.json 297 | !.vscode/launch.json 298 | !.vscode/extensions.json 299 | 300 | ### VisualStudioCode Patch ### 301 | # Ignore all local history of files 302 | .history 303 | 304 | #!! ERROR: window is undefined. Use list command to see defined gitignore types !!# 305 | 306 | ### VisualStudio ### 307 | ## Ignore Visual Studio temporary files, build results, and 308 | ## files generated by popular Visual Studio add-ons. 309 | ## 310 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 311 | 312 | # User-specific files 313 | *.rsuser 314 | *.suo 315 | *.user 316 | *.userosscache 317 | *.sln.docstates 318 | 319 | # User-specific files (MonoDevelop/Xamarin Studio) 320 | 321 | # Mono auto generated files 322 | mono_crash.* 323 | 324 | # Build results 325 | [Dd]ebug/ 326 | [Dd]ebugPublic/ 327 | [Rr]elease/ 328 | [Rr]eleases/ 329 | x64/ 330 | x86/ 331 | [Aa][Rr][Mm]/ 332 | [Aa][Rr][Mm]64/ 333 | bld/ 334 | [Bb]in/ 335 | [Oo]bj/ 336 | [Ll]og/ 337 | 338 | # Visual Studio 2015/2017 cache/options directory 339 | .vs/ 340 | # Uncomment if you have tasks that create the project's static files in wwwroot 341 | #wwwroot/ 342 | 343 | # Visual Studio 2017 auto generated files 344 | Generated\ Files/ 345 | 346 | # MSTest test Results 347 | [Tt]est[Rr]esult*/ 348 | [Bb]uild[Ll]og.* 349 | 350 | # NUNIT 351 | *.VisualState.xml 352 | TestResult.xml 353 | 354 | # Build Results of an ATL Project 355 | [Dd]ebugPS/ 356 | [Rr]eleasePS/ 357 | dlldata.c 358 | 359 | # Benchmark Results 360 | BenchmarkDotNet.Artifacts/ 361 | 362 | # .NET Core 363 | project.lock.json 364 | project.fragment.lock.json 365 | artifacts/ 366 | 367 | # StyleCop 368 | StyleCopReport.xml 369 | 370 | # Files built by Visual Studio 371 | *_i.c 372 | *_p.c 373 | *_h.h 374 | *.ilk 375 | *.meta 376 | *.obj 377 | *.iobj 378 | *.pch 379 | *.pdb 380 | *.ipdb 381 | *.pgc 382 | *.pgd 383 | *.rsp 384 | *.sbr 385 | *.tlb 386 | *.tli 387 | *.tlh 388 | *.tmp 389 | *.tmp_proj 390 | *_wpftmp.csproj 391 | *.log 392 | *.vspscc 393 | *.vssscc 394 | .builds 395 | *.svclog 396 | *.scc 397 | 398 | # Chutzpah Test files 399 | _Chutzpah* 400 | 401 | # Visual C++ cache files 402 | ipch/ 403 | *.aps 404 | *.ncb 405 | *.opendb 406 | *.opensdf 407 | *.sdf 408 | *.cachefile 409 | *.VC.db 410 | *.VC.VC.opendb 411 | 412 | # Visual Studio profiler 413 | *.psess 414 | *.vsp 415 | *.vspx 416 | *.sap 417 | 418 | # Visual Studio Trace Files 419 | *.e2e 420 | 421 | # TFS 2012 Local Workspace 422 | $tf/ 423 | 424 | # Guidance Automation Toolkit 425 | *.gpState 426 | 427 | # ReSharper is a .NET coding add-in 428 | _ReSharper*/ 429 | *.[Rr]e[Ss]harper 430 | *.DotSettings.user 431 | 432 | # JustCode is a .NET coding add-in 433 | .JustCode 434 | 435 | # TeamCity is a build add-in 436 | _TeamCity* 437 | 438 | # DotCover is a Code Coverage Tool 439 | *.dotCover 440 | 441 | # AxoCover is a Code Coverage Tool 442 | .axoCover/* 443 | !.axoCover/settings.json 444 | 445 | # Visual Studio code coverage results 446 | *.coverage 447 | *.coveragexml 448 | 449 | # NCrunch 450 | _NCrunch_* 451 | .*crunch*.local.xml 452 | nCrunchTemp_* 453 | 454 | # MightyMoose 455 | *.mm.* 456 | AutoTest.Net/ 457 | 458 | # Web workbench (sass) 459 | .sass-cache/ 460 | 461 | # Installshield output folder 462 | [Ee]xpress/ 463 | 464 | # DocProject is a documentation generator add-in 465 | DocProject/buildhelp/ 466 | DocProject/Help/*.HxT 467 | DocProject/Help/*.HxC 468 | DocProject/Help/*.hhc 469 | DocProject/Help/*.hhk 470 | DocProject/Help/*.hhp 471 | DocProject/Help/Html2 472 | DocProject/Help/html 473 | 474 | # Click-Once directory 475 | publish/ 476 | 477 | # Publish Web Output 478 | *.[Pp]ublish.xml 479 | *.azurePubxml 480 | # Note: Comment the next line if you want to checkin your web deploy settings, 481 | # but database connection strings (with potential passwords) will be unencrypted 482 | *.pubxml 483 | *.publishproj 484 | 485 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 486 | # checkin your Azure Web App publish settings, but sensitive information contained 487 | # in these scripts will be unencrypted 488 | PublishScripts/ 489 | 490 | # NuGet Packages 491 | *.nupkg 492 | # The packages folder can be ignored because of Package Restore 493 | **/[Pp]ackages/* 494 | # except build/, which is used as an MSBuild target. 495 | !**/[Pp]ackages/build/ 496 | # Uncomment if necessary however generally it will be regenerated when needed 497 | #!**/[Pp]ackages/repositories.config 498 | # NuGet v3's project.json files produces more ignorable files 499 | *.nuget.props 500 | *.nuget.targets 501 | 502 | # Microsoft Azure Build Output 503 | csx/ 504 | *.build.csdef 505 | 506 | # Microsoft Azure Emulator 507 | ecf/ 508 | rcf/ 509 | 510 | # Windows Store app package directories and files 511 | AppPackages/ 512 | BundleArtifacts/ 513 | Package.StoreAssociation.xml 514 | _pkginfo.txt 515 | *.appx 516 | *.appxbundle 517 | *.appxupload 518 | 519 | # Visual Studio cache files 520 | # files ending in .cache can be ignored 521 | *.[Cc]ache 522 | # but keep track of directories ending in .cache 523 | !?*.[Cc]ache/ 524 | 525 | # Others 526 | ClientBin/ 527 | ~$* 528 | *.dbmdl 529 | *.dbproj.schemaview 530 | *.jfm 531 | *.pfx 532 | *.publishsettings 533 | orleans.codegen.cs 534 | 535 | # Including strong name files can present a security risk 536 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 537 | #*.snk 538 | 539 | # Since there are multiple workflows, uncomment next line to ignore bower_components 540 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 541 | #bower_components/ 542 | 543 | # RIA/Silverlight projects 544 | Generated_Code/ 545 | 546 | # Backup & report files from converting an old project file 547 | # to a newer Visual Studio version. Backup files are not needed, 548 | # because we have git ;-) 549 | _UpgradeReport_Files/ 550 | Backup*/ 551 | UpgradeLog*.XML 552 | UpgradeLog*.htm 553 | ServiceFabricBackup/ 554 | *.rptproj.bak 555 | 556 | # SQL Server files 557 | *.mdf 558 | *.ldf 559 | *.ndf 560 | 561 | # Business Intelligence projects 562 | *.rdl.data 563 | *.bim.layout 564 | *.bim_*.settings 565 | *.rptproj.rsuser 566 | *- Backup*.rdl 567 | 568 | # Microsoft Fakes 569 | FakesAssemblies/ 570 | 571 | # GhostDoc plugin setting file 572 | *.GhostDoc.xml 573 | 574 | # Node.js Tools for Visual Studio 575 | .ntvs_analysis.dat 576 | node_modules/ 577 | 578 | # Visual Studio 6 build log 579 | *.plg 580 | 581 | # Visual Studio 6 workspace options file 582 | *.opt 583 | 584 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 585 | *.vbw 586 | 587 | # Visual Studio LightSwitch build output 588 | **/*.HTMLClient/GeneratedArtifacts 589 | **/*.DesktopClient/GeneratedArtifacts 590 | **/*.DesktopClient/ModelManifest.xml 591 | **/*.Server/GeneratedArtifacts 592 | **/*.Server/ModelManifest.xml 593 | _Pvt_Extensions 594 | 595 | # Paket dependency manager 596 | .paket/paket.exe 597 | paket-files/ 598 | 599 | # FAKE - F# Make 600 | .fake/ 601 | 602 | # CodeRush personal settings 603 | .cr/personal 604 | 605 | # Python Tools for Visual Studio (PTVS) 606 | __pycache__/ 607 | *.pyc 608 | 609 | # Cake - Uncomment if you are using it 610 | # tools/** 611 | # !tools/packages.config 612 | 613 | # Tabs Studio 614 | *.tss 615 | 616 | # Telerik's JustMock configuration file 617 | *.jmconfig 618 | 619 | # BizTalk build output 620 | *.btp.cs 621 | *.btm.cs 622 | *.odx.cs 623 | *.xsd.cs 624 | 625 | # OpenCover UI analysis results 626 | OpenCover/ 627 | 628 | # Azure Stream Analytics local run output 629 | ASALocalRun/ 630 | 631 | # MSBuild Binary and Structured Log 632 | *.binlog 633 | 634 | # NVidia Nsight GPU debugger configuration file 635 | *.nvuser 636 | 637 | # MFractors (Xamarin productivity tool) working folder 638 | .mfractor/ 639 | 640 | # Local History for Visual Studio 641 | .localhistory/ 642 | 643 | # BeatPulse healthcheck temp database 644 | healthchecksdb 645 | 646 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 647 | MigrationBackup/ 648 | 649 | # End of https://www.gitignore.io/api/macos,linux,window,clion+all,rider,intellij+all,visualstudiio,jetbrains+all,monodevelop,visualstudio,visualstudiocode 650 | -------------------------------------------------------------------------------- /DotnetVersion.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetVersion", "src\DotnetVersion\DotnetVersion.csproj", "{62B311E7-30A8-4DC0-ABB7-81B3AD9230C2}" 4 | EndProject 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2C06B68A-F0E0-416F-A012-CDB57DB52B63}" 6 | ProjectSection(SolutionItems) = preProject 7 | README.md = README.md 8 | EndProjectSection 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetVersion.Tests", "tests\DotnetVersion.Tests\DotnetVersion.Tests.csproj", "{91A8B883-92E0-4E2D-A570-D6B6D0C0A9B2}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {62B311E7-30A8-4DC0-ABB7-81B3AD9230C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {62B311E7-30A8-4DC0-ABB7-81B3AD9230C2}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {62B311E7-30A8-4DC0-ABB7-81B3AD9230C2}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {62B311E7-30A8-4DC0-ABB7-81B3AD9230C2}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {91A8B883-92E0-4E2D-A570-D6B6D0C0A9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {91A8B883-92E0-4E2D-A570-D6B6D0C0A9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {91A8B883-92E0-4E2D-A570-D6B6D0C0A9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {91A8B883-92E0-4E2D-A570-D6B6D0C0A9B2}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DotnetVersion 2 | 3 | A simple tool to update the version number of your project. If you know of `yarn version`, this is that for .NET. 4 | 5 | ## Usage 6 | 7 | ### Basic usage 8 | The simplest way to use the tool is to run the command with no input: 9 | 10 | ```bash 11 | dotnet version 12 | ``` 13 | 14 | This will ask you to specify the desired version number. 15 | 16 | ### Specifying version change 17 | 18 | To prevent the prompt you can use the `--new-version` option to specify the version number: 19 | 20 | ```bash 21 | dotnet version --new-version 1.2.3 22 | ``` 23 | 24 | You can let the tool automatically figure out the proper version by specifying which part of the version should be incremented: 25 | 26 | ```bash 27 | # Given version is 1.2.3 28 | 29 | # Make the version 1.2.4 30 | dotnet version --patch 31 | 32 | # Make the version 1.3.0 33 | dotnet version --minor 34 | 35 | # Make the version 2.0.0 36 | dotnet version --major 37 | ``` 38 | 39 | ### Custom project file path 40 | 41 | By default, the tool will look for a `csproj` file in the current directory. You can use `--project-file` to specify a custom path: 42 | 43 | ```bash 44 | # Increment major version number of specified project file 45 | dotnet version --project-file path/to/project/file --major 46 | ``` 47 | 48 | ### Git integration 49 | 50 | By default the tool will commit immediately after changing the version and tag the commit with the version number. This can be disabled by passing `--no-git`: 51 | 52 | ```bash 53 | # Increment minor version number, but don't commit it 54 | dotnet version --no-git --minor 55 | ``` 56 | 57 | The message of the commit will be the version number. Use `--message` to override the commit message: 58 | 59 | ```bash 60 | # Increment minor version number and commit with custom message 61 | dotnet version --minor --message "Bump the minor version" 62 | ``` 63 | 64 | Use `--no-git-tag` to prevent a tag being added to the commit: 65 | 66 | ```bash 67 | # Increment patch version number, but don't add a tag 68 | dotnet version --patch --no-git-tag 69 | ``` 70 | 71 | To specify a prefix to the version number, use `--git-version-prefix`. This prefix is added to both the commit message (if it's not overridden) and the tag: 72 | 73 | ```bash 74 | # Increment patch version number and prefix the version with 'v' 75 | dotnet version --patch --git-version-prefix v 76 | ``` 77 | 78 | Help output: 79 | 80 | ```bash 81 | Update project version 82 | 83 | Usage: dotnet-version [options] 84 | 85 | Options: 86 | -V|--version Show version of the tool 87 | --show Only show the current version number 88 | --new-version New version 89 | --major Auto-increment major version number 90 | --minor Auto-increment minor version number 91 | --patch Auto-increment patch version number 92 | --alpha Auto-increment alpha version number 93 | --beta Auto-increment beta version number 94 | --rc Auto-increment release candidate version number 95 | --final Remove prerelease version number 96 | -p|--project-file Path to project file 97 | --no-git Do not make any changes in git 98 | --message git commit message 99 | --no-git-tag Do not generate a git tag 100 | --git-version-prefix Prefix before version in git 101 | -?|-h|--help Show help information 102 | ``` 103 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - refs/tags/* 3 | 4 | pool: 5 | vmImage: 'ubuntu-latest' 6 | 7 | steps: 8 | - task: DotNetCoreCLI@2 9 | inputs: 10 | command: 'pack' 11 | packagesToPack: 'src/**/*.csproj' 12 | versioningScheme: 'off' 13 | 14 | - task: NuGetCommand@2 15 | inputs: 16 | command: 'push' 17 | packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' 18 | nuGetFeedType: 'external' 19 | publishFeedCredentials: 'NuGet' -------------------------------------------------------------------------------- /src/DotnetVersion/CliException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotnetVersion 4 | { 5 | public class CliException : Exception 6 | { 7 | public int ExitCode { get; } 8 | 9 | public CliException(int exitCode, string message): base(message) 10 | { 11 | ExitCode = exitCode; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/DotnetVersion/DotnetVersion.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp3.1;net5.0;net6.0 5 | 2.0.0 6 | DotnetVersion 7 | jonstodle 8 | true 9 | dotnet-version 10 | Update project version, through an easy API. 11 | MIT 12 | version;git;semver 13 | https://github.com/jonstodle/DotnetVersion 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/DotnetVersion/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading; 6 | using System.Xml.Linq; 7 | using McMaster.Extensions.CommandLineUtils; 8 | using Semver; 9 | using static System.Console; 10 | 11 | namespace DotnetVersion 12 | { 13 | [Command("dotnet-version", Description = "Update project version")] 14 | public class Program 15 | { 16 | public static void Main(string[] args) => 17 | CommandLineApplication.Execute(args); 18 | 19 | private const string AlphaString = "alpha"; 20 | private const string BetaString = "beta"; 21 | private const string ReleaseCandidateString = "rc"; 22 | 23 | // ReSharper disable UnassignedGetOnlyAutoProperty 24 | [Option("-V|--version", Description = "Show version of the tool")] 25 | public bool ShowVersion { get; } 26 | 27 | [Option("--show", Description = "Only show the current version number")] 28 | public bool Show { get; } 29 | 30 | [Option("--new-version", Description = "New version")] 31 | public string NewVersion { get; } 32 | 33 | [Option("--major", Description = "Auto-increment major version number")] 34 | public bool Major { get; } 35 | 36 | [Option("--minor", Description = "Auto-increment minor version number")] 37 | public bool Minor { get; } 38 | 39 | [Option("--patch", Description = "Auto-increment patch version number")] 40 | public bool Patch { get; } 41 | 42 | [Option("--alpha", Description = "Auto-increment alpha version number")] 43 | public bool Alpha { get; } 44 | 45 | [Option("--beta", Description = "Auto-increment beta version number")] 46 | public bool Beta { get; } 47 | 48 | [Option("--rc", Description = "Auto-increment release candidate version number")] 49 | public bool ReleaseCandidate { get; } 50 | 51 | [Option("--final", Description = "Remove prerelease version number")] 52 | public bool Final { get; } 53 | 54 | [Option("-p|--project-file", Description = "Path to project file")] 55 | public string ProjectFilePath { get; } 56 | 57 | [Option("--no-git", Description = "Do not make any changes in git")] 58 | public bool NoGit { get; } 59 | 60 | [Option("--message", Description = "git commit message")] 61 | public string CommitMessage { get; } 62 | 63 | [Option("--no-git-tag", Description = "Do not generate a git tag")] 64 | public bool NoGitTag { get; } 65 | 66 | [Option("--git-version-prefix", Description = "Prefix before version in git")] 67 | public string GitVersionPrefix { get; } 68 | // ReSharper restore UnassignedGetOnlyAutoProperty 69 | 70 | // ReSharper disable once UnusedMember.Local 71 | private void OnExecute() 72 | { 73 | try 74 | { 75 | Run(); 76 | } 77 | catch (CliException e) 78 | { 79 | Error.WriteLine(e.Message); 80 | Environment.Exit(e.ExitCode); 81 | } 82 | } 83 | 84 | private void Run() 85 | { 86 | if (ShowVersion) 87 | { 88 | if (SemVersion.TryParse( 89 | FileVersionInfo.GetVersionInfo(typeof(Program).Assembly.Location).ProductVersion, 90 | out var toolVersion)) 91 | WriteLine(toolVersion); 92 | else 93 | WriteLine(typeof(Program).Assembly.GetName().Version.ToString(3)); 94 | return; 95 | } 96 | 97 | var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); 98 | 99 | var projectFile = !string.IsNullOrWhiteSpace(ProjectFilePath) 100 | ? new FileInfo(ProjectFilePath) 101 | : currentDirectory.EnumerateFiles("*.csproj").FirstOrDefault(); 102 | 103 | if (projectFile is null || 104 | projectFile.Exists == false) 105 | throw new CliException(1, $"Unable to find a project file in directory '{currentDirectory}'."); 106 | 107 | var projectFileFullName = projectFile.FullName; 108 | 109 | var xDocument = XDocument.Load(projectFileFullName); 110 | var versionElement = xDocument.Root?.Descendants("Version").FirstOrDefault(); 111 | var currentVersion = ParseVersion(versionElement?.Value ?? "0.0.0"); 112 | 113 | WriteLine($"Current version: {currentVersion}"); 114 | 115 | if (Show) 116 | return; 117 | 118 | SemVersion version = null; 119 | 120 | if (!string.IsNullOrWhiteSpace(NewVersion)) 121 | { 122 | version = ParseVersion(NewVersion); 123 | } 124 | else 125 | { 126 | if (Major) 127 | { 128 | version = currentVersion.Change( 129 | currentVersion.Major + 1, 130 | 0, 131 | 0, 132 | "", 133 | ""); 134 | } 135 | else if (Minor) 136 | { 137 | version = currentVersion.Change( 138 | minor: currentVersion.Minor + 1, 139 | patch: 0, 140 | prerelease: "", 141 | build: ""); 142 | } 143 | else if (Patch) 144 | { 145 | version = currentVersion.Change( 146 | patch: currentVersion.Patch + 1, 147 | prerelease: "", 148 | build: ""); 149 | } 150 | 151 | if (Final) 152 | { 153 | version = (version ?? currentVersion).Change( 154 | prerelease: string.Empty); 155 | } 156 | 157 | if (ReleaseCandidate) 158 | { 159 | if (Final) 160 | throw new CliException(1, "Can't increment release candidate number of the final version."); 161 | 162 | version = (version ?? currentVersion).Change( 163 | prerelease: CreatePreReleaseString( 164 | ReleaseCandidateString, 165 | version is null ? currentVersion.Prerelease : ""), 166 | build: ""); 167 | } 168 | else if (Beta) 169 | { 170 | if (Final) 171 | throw new CliException(1, "Can't increment beta number of the final version."); 172 | 173 | if (version is null && 174 | currentVersion.Prerelease.StartsWith(ReleaseCandidateString, 175 | StringComparison.OrdinalIgnoreCase)) 176 | throw new CliException(1, 177 | "Can't increment beta version number of a release candidate version number."); 178 | 179 | version = (version ?? currentVersion).Change( 180 | prerelease: CreatePreReleaseString(BetaString, 181 | version is null ? currentVersion.Prerelease : ""), 182 | build: ""); 183 | } 184 | else if (Alpha) 185 | { 186 | if (Final) 187 | throw new CliException(1, "Can't increment alpha number of the final version."); 188 | 189 | if (version is null && 190 | currentVersion.Prerelease.StartsWith(ReleaseCandidateString, 191 | StringComparison.OrdinalIgnoreCase)) 192 | throw new CliException(1, 193 | "Can't increment alpha version number of a release candidate version number."); 194 | 195 | if (version is null && 196 | currentVersion.Prerelease.StartsWith(BetaString, StringComparison.OrdinalIgnoreCase)) 197 | throw new CliException(1, "Can't increment alpha version number of a beta version number."); 198 | 199 | version = (version ?? currentVersion).Change( 200 | prerelease: CreatePreReleaseString(AlphaString, 201 | version is null ? currentVersion.Prerelease : ""), 202 | build: ""); 203 | } 204 | } 205 | 206 | if (version is null) 207 | { 208 | var inputVersion = Prompt.GetString("New version:"); 209 | version = ParseVersion(inputVersion); 210 | } 211 | else 212 | { 213 | WriteLine($"New version: {version}"); 214 | } 215 | 216 | if (versionElement is null) 217 | { 218 | var propertyGroupElement = xDocument.Root?.Descendants("PropertyGroup").FirstOrDefault(); 219 | if (propertyGroupElement is null) 220 | { 221 | propertyGroupElement = new XElement("PropertyGroup"); 222 | xDocument.Root?.Add(propertyGroupElement); 223 | } 224 | 225 | propertyGroupElement.Add(new XElement("Version", version)); 226 | } 227 | else 228 | { 229 | versionElement.Value = version.ToString(); 230 | } 231 | 232 | File.WriteAllText(projectFileFullName, xDocument.ToString()); 233 | 234 | if (!NoGit) 235 | { 236 | if (string.IsNullOrWhiteSpace(ProjectFilePath)) 237 | { 238 | try 239 | { 240 | var tag = $"{GitVersionPrefix}{version}"; 241 | var message = !string.IsNullOrWhiteSpace(CommitMessage) 242 | ? CommitMessage 243 | : tag; 244 | 245 | Process.Start(new ProcessStartInfo("git", $"commit -am \"{message}\"") 246 | { 247 | RedirectStandardError = true, 248 | RedirectStandardOutput = true, 249 | })?.WaitForExit(); 250 | 251 | if (!NoGitTag) 252 | { 253 | // Hack to make sure the wrong commit is tagged 254 | Thread.Sleep(200); 255 | Process.Start(new ProcessStartInfo("git", $"tag {tag}") 256 | { 257 | RedirectStandardError = true, 258 | RedirectStandardOutput = true, 259 | })?.WaitForExit(); 260 | } 261 | } 262 | catch 263 | { 264 | /* Ignored */ 265 | } 266 | } 267 | else 268 | { 269 | WriteLine( 270 | "Not running git integration when project file has been specified, to prevent running git in wrong directory."); 271 | } 272 | } 273 | 274 | WriteLine($"Successfully set version to {version}"); 275 | } 276 | 277 | private SemVersion ParseVersion(string version) 278 | { 279 | try 280 | { 281 | return SemVersion.Parse(version); 282 | } 283 | catch 284 | { 285 | throw new CliException(1, $"Unable to parse version '{version}'."); 286 | } 287 | } 288 | 289 | private string CreatePreReleaseString(string preReleaseName, string preReleaseVersion) 290 | { 291 | var version = 0; 292 | if (preReleaseVersion.StartsWith(preReleaseName, StringComparison.OrdinalIgnoreCase)) 293 | { 294 | var versionString = String.Join("", preReleaseVersion 295 | .Reverse() 296 | .TakeWhile(char.IsDigit) 297 | .Reverse()); 298 | int.TryParse(versionString, out version); 299 | } 300 | 301 | return $"{preReleaseName}.{version + 1}"; 302 | } 303 | } 304 | } -------------------------------------------------------------------------------- /tests/DotnetVersion.Tests/DotnetVersion.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/DotnetVersion.Tests/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using Shouldly; 5 | using Xunit; 6 | 7 | namespace DotnetVersion.Tests 8 | { 9 | public class Program : IDisposable 10 | 11 | { 12 | private readonly StringWriter consoleOut; 13 | private readonly string tempFilePath; 14 | 15 | public Program() 16 | { 17 | consoleOut = new StringWriter(); 18 | Console.SetOut(consoleOut); 19 | 20 | var tempDirectoryPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), nameof(DotnetVersion))); 21 | tempFilePath = Path.Combine(tempDirectoryPath.FullName, $"{Guid.NewGuid()}.xml"); 22 | File.WriteAllLines(tempFilePath, new[] 23 | { 24 | @"", 25 | "", 26 | "1.2.3", 27 | "", 28 | "", 29 | }); 30 | } 31 | 32 | [Fact(Skip = "No automated way to check version number. Yet.")] 33 | public void ShowsTheToolVersion() 34 | { 35 | DotnetVersion.Program.Main(Args("-V")); 36 | 37 | consoleOut.ToString().ShouldBe("1.2.3" + Environment.NewLine); 38 | } 39 | 40 | [Fact] 41 | public void ShowsTheCurrentProjectVersionOnly() 42 | { 43 | DotnetVersion.Program.Main(Args("--show")); 44 | 45 | consoleOut.ToString().ShouldBe("Current version: 1.2.3" + Environment.NewLine); 46 | } 47 | 48 | [Theory] 49 | [InlineData("1.0.0")] 50 | [InlineData("1.5.0")] 51 | [InlineData("2.0.0")] 52 | public void SetsTheCorrectVersion(string newVersion) 53 | { 54 | DotnetVersion.Program.Main(Args("--new-version", newVersion)); 55 | 56 | consoleOut.ToString().ShouldBe(string.Join( 57 | Environment.NewLine, 58 | "Current version: 1.2.3", 59 | $"New version: {newVersion}", 60 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 61 | $"Successfully set version to {newVersion}{Environment.NewLine}")); 62 | } 63 | 64 | [Fact] 65 | public void SetsNewMajorVersion() 66 | { 67 | DotnetVersion.Program.Main(Args("--major")); 68 | 69 | consoleOut.ToString().ShouldBe(string.Join( 70 | Environment.NewLine, 71 | "Current version: 1.2.3", 72 | "New version: 2.0.0", 73 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 74 | $"Successfully set version to 2.0.0{Environment.NewLine}")); 75 | } 76 | 77 | [Fact] 78 | public void SetsNewMinorVersion() 79 | { 80 | DotnetVersion.Program.Main(Args("--minor")); 81 | 82 | consoleOut.ToString().ShouldBe(string.Join( 83 | Environment.NewLine, 84 | "Current version: 1.2.3", 85 | "New version: 1.3.0", 86 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 87 | $"Successfully set version to 1.3.0{Environment.NewLine}")); 88 | } 89 | 90 | [Fact] 91 | public void SetsNewPatchVersion() 92 | { 93 | DotnetVersion.Program.Main(Args("--patch")); 94 | 95 | consoleOut.ToString().ShouldBe(string.Join( 96 | Environment.NewLine, 97 | "Current version: 1.2.3", 98 | "New version: 1.2.4", 99 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 100 | $"Successfully set version to 1.2.4{Environment.NewLine}")); 101 | } 102 | 103 | [Fact] 104 | public void SetsCorrectAlphaVersion() 105 | { 106 | DotnetVersion.Program.Main(Args("--major", "--alpha")); 107 | DotnetVersion.Program.Main(Args("--alpha")); 108 | 109 | consoleOut.ToString().ShouldBe(string.Join( 110 | Environment.NewLine, 111 | "Current version: 1.2.3", 112 | "New version: 2.0.0-alpha.1", 113 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 114 | "Successfully set version to 2.0.0-alpha.1", 115 | "Current version: 2.0.0-alpha.1", 116 | "New version: 2.0.0-alpha.2", 117 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 118 | $"Successfully set version to 2.0.0-alpha.2{Environment.NewLine}")); 119 | } 120 | 121 | [Fact] 122 | public void SetsCorrectBetaVersion() 123 | { 124 | DotnetVersion.Program.Main(Args("--major", "--beta")); 125 | DotnetVersion.Program.Main(Args("--beta")); 126 | 127 | consoleOut.ToString().ShouldBe(string.Join( 128 | Environment.NewLine, 129 | "Current version: 1.2.3", 130 | "New version: 2.0.0-beta.1", 131 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 132 | "Successfully set version to 2.0.0-beta.1", 133 | "Current version: 2.0.0-beta.1", 134 | "New version: 2.0.0-beta.2", 135 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 136 | $"Successfully set version to 2.0.0-beta.2{Environment.NewLine}")); 137 | } 138 | 139 | [Fact] 140 | public void SetsCorrectReleaseCandidateVersion() 141 | { 142 | DotnetVersion.Program.Main(Args("--major", "--rc")); 143 | DotnetVersion.Program.Main(Args("--rc")); 144 | 145 | consoleOut.ToString().ShouldBe(string.Join( 146 | Environment.NewLine, 147 | "Current version: 1.2.3", 148 | "New version: 2.0.0-rc.1", 149 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 150 | "Successfully set version to 2.0.0-rc.1", 151 | "Current version: 2.0.0-rc.1", 152 | "New version: 2.0.0-rc.2", 153 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 154 | $"Successfully set version to 2.0.0-rc.2{Environment.NewLine}")); 155 | } 156 | 157 | [Fact] 158 | public void SetsCorrectFinalVersion() 159 | { 160 | DotnetVersion.Program.Main(Args("--major", "--rc")); 161 | DotnetVersion.Program.Main(Args("--final")); 162 | 163 | consoleOut.ToString().ShouldBe(string.Join( 164 | Environment.NewLine, 165 | "Current version: 1.2.3", 166 | "New version: 2.0.0-rc.1", 167 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 168 | "Successfully set version to 2.0.0-rc.1", 169 | "Current version: 2.0.0-rc.1", 170 | "New version: 2.0.0", 171 | "Not running git integration when project file has been specified, to prevent running git in wrong directory.", 172 | $"Successfully set version to 2.0.0{Environment.NewLine}")); 173 | } 174 | 175 | public void Dispose() 176 | { 177 | File.Delete(tempFilePath); 178 | } 179 | 180 | private string[] Args(params string[] args) => 181 | args.Concat(new[] {"-p", tempFilePath}).ToArray(); 182 | } 183 | } --------------------------------------------------------------------------------