I've used this as an opportunity to prove out some of the benefits of the CommandDotNet v3 preview which provides tools to ease troubleshooting. Documentation for these tools is pending so I'll summarize here.
A console app is an interface to business logic, much the same as a web api is. In this way, commands are analagous to endpoints.
This app is designed the similar to a web api. Let's compare the layers...
Layer | Web API | Console |
---|---|---|
Host | Program | Program |
API | Endpoints | Commands |
Business Logic | Business Logic | Business Logic |
The same business logic could be hosted in both types of app and the console can provides types of interaction, feedback and long lived processes that require additional components in a web app.
Jira2AzureDevOps
contains just the program and configuration logicJira2AzureDevOps.Console
contains all of the commands and middleware logicJira2AzureDevOps.Logic
contains aall of the migration busines logic
The working directory serves as the local data store for a migration. A migration file is stored for each migration to track it's import status.
Export & Import use the same IJiraApi stack. Export is a by-produce of the CachedJiraApi
using LocalDirJiraApi
. Due to this design, Import also performs an Export for issues that aren't already exported. This ensures all issues in the cache and available for archive.
C# classes were created for Json deserialization. I used QuickType to generate the classes from json data with some tweaks afterward. The classes do not contain a comprehensive list of every field. They contain what I needed for the project and extra where I didn't remove the unused properties. Enhance these objects if you need to import more fields. I found this approach useful for interrogating the data.
described in the README.md
described in the README.md
enabled by SetDefaultsFromConfigMiddleware
Debugging console apps can be a hassle. Changing the arguments in the project properties is a lot of extra steps.
CommandDotNet includes a useful feature for debugging called a Debug Directive initially created by the System.CommandLine project.
By specifying [debug]
as the first argument, you'll be prompted to attach a debugger to the current process.
$ jira2ado [debug] export issues-by-id
Attach your debugger to process 18640 (dotnet).
This makes it easy to debug with different arguments every time.
I used NLog for structured logging and to take advantage of that ecosystem of appenders without lock-in. Some options include:
Console logging is enabled by default at INFO level and above. Commands who's output should not contain console logs (eg. report commands) can disable console logging with the DisableConsoleLoggingAttribute
enabled by DisableConsoleLoggingMiddleware
When a command is run, Repro Headers (arguments and other system information) are included at the start of the run. These can be disabled for a command with the NoReproHeadersAttribute
.
[I][09:20:22]
***************************************
Command: export issues-by-project
Options:
projects = APP
issue-list-source = Cache
workspace = C:\jira2ado\jira-cache (default)
jira-username = me@jira (default)
jira-token = ***** (default)
jira-url = https://company_slug.atlassian.net (default)
jira-batch-size = 100 (default)
Original input:
export issues-by-project -P APP --issue-list-source Cache
Tool version = Jira2AzureDevOps.exe 1.0.0.0
.Net version = .NET Framework 4.8.3815.0
OS version = Microsoft Windows 10.0.18362
Machine = my-laptop
Username = my-laptop\me
***************************************
(default)
indicates the value wasn't provided in the command line, as can be seen from the Original input section.
I've found this incredibly helpful when trying to repro a bug or simply confirm what I've already done.
The Solidify team had a version of this as well and I've included the environment data they added.
Tip: Repro headers are not logged to console when a command is decorated with DisableConsoleLoggingAttribute
. The headers will still output to the log file, so this is generally preferred over NoReproHeadersAttribute
enabled by ReproHeadersMiddleware
Argument models allow defining arguments as properties in a class for reuse.
Implement ISelfValidatingArgumentModel
to provide validation errors for the model.
enabled by SelfValidatingArgumentsMiddleware
the ConsoleEnumerator provides the EnumerateOperation
extension method to provide a consistent experience for
- tracking count of processed and errored and elapsed time
- estimated time remaining and estimated time complete
- writing to failure files
- responding to Ctrl+C cancellations by stopping the enumeration