├── .bundle └── config ├── .editorconfig ├── .editorconfig.inferred ├── .gitattributes ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ └── question-issue-feature.old ├── PULL_REQUEST_TEMPLATE │ └── default.md ├── dependabot.yml ├── label-actions.yml ├── labeler.yml ├── release.yml └── workflows │ ├── MigrationToolsTelemetery.yml │ ├── close-pr.yaml │ ├── code-review.yml │ ├── labal-action.yml │ ├── labeler.yml │ ├── main.yml │ ├── open-pr-describer.yml │ ├── opencommit.yml │ ├── stale.yml │ └── test-function.yml ├── .gitignore ├── .vs └── config │ └── applicationhost.config ├── .vscode ├── launch.json └── tasks.json ├── ApplicationInsights.config ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── Directory.Packages.props ├── Gemfile ├── Gemfile.lock ├── GitVersion.yml ├── GlobalUsings.cs ├── LICENSE ├── Local.testsettings ├── MigrationTools.lutconfig ├── MigrationTools.sln ├── README.md ├── _config.yml ├── appsettings.json ├── build ├── azure-pipeline.yml ├── build.ps1 ├── buildDocs.ps1 ├── changelogs.ps1 ├── compile-and-test.ps1 ├── include │ ├── Get-ReleaseDescription.ps1 │ ├── OpenAI.ps1 │ ├── ReleaseMan.ps1 │ └── test.ps1 ├── install-prerequsits.ps1 ├── mantainReleaseLog.ps1 ├── packageChocolatey.ps1 ├── packageExecutable.ps1 ├── packageExtension.ps1 ├── packageNuget.ps1 ├── packageWinget.ps1 ├── releaseExtension.ps1 ├── releaseGitHubRelease.ps1 ├── releaseWingetPackage.ps1 └── versioning.ps1 ├── buildDocs.ps1 ├── change-log.md ├── configuration-classic.json ├── configuration-classic2-pipeline.json ├── configuration-classic2-wit.json ├── configuration-classic2.json ├── configuration-default.json ├── configuration3-default.json ├── docs ├── 404.md ├── MigrationTools.Documentation.csproj ├── Reference │ ├── EndpointEnrichers │ │ └── index.md │ ├── Endpoints │ │ ├── TfsWorkItemEndpoint-notes.md │ │ └── index.md │ ├── FieldMaps │ │ ├── index.md │ │ └── index2.md │ ├── ProcessorEnrichers │ │ └── index.md │ ├── Processors │ │ ├── AzureDevOpsPipelineProcessor-introduction.md │ │ ├── AzureDevOpsPipelineProcessor-notes.md │ │ ├── ExportUsersForMappingProcessor-notes.md │ │ ├── ProcessDefinitionProcessor-introduction.md │ │ ├── ProcessDefinitionProcessor-notes.md │ │ ├── TfsTestPlansAndSuitesMigrationProcessor-notes.md │ │ ├── TfsWorkItemMigrationProcessor-introduction.md │ │ ├── TfsWorkItemMigrationProcessor-notes.md │ │ ├── WorkItemTrackingProcessor-notes.md │ │ ├── index.md │ │ └── index2.md │ ├── Tools │ │ ├── TfsNodeStructureTool-introduction.md │ │ └── TfsNodeStructureTool-notes.md │ └── index.md ├── _data │ ├── reference.endpoints.azuredevopsendpoint.yaml │ ├── reference.endpoints.filesystemworkitemendpoint.yaml │ ├── reference.endpoints.tfsendpoint.yaml │ ├── reference.endpoints.tfsteamprojectendpoint.yaml │ ├── reference.endpoints.tfsteamsettingsendpoint.yaml │ ├── reference.endpoints.tfsworkitemendpoint.yaml │ ├── reference.fieldmaps.fieldclearmap.yaml │ ├── reference.fieldmaps.fieldliteralmap.yaml │ ├── reference.fieldmaps.fieldmergemap.yaml │ ├── reference.fieldmaps.fieldskipmap.yaml │ ├── reference.fieldmaps.fieldtofieldmap.yaml │ ├── reference.fieldmaps.fieldtofieldmultimap.yaml │ ├── reference.fieldmaps.fieldtotagfieldmap.yaml │ ├── reference.fieldmaps.fieldvaluemap.yaml │ ├── reference.fieldmaps.multivalueconditionalmap.yaml │ ├── reference.fieldmaps.regexfieldmap.yaml │ ├── reference.fieldmaps.treetotagfieldmap.yaml │ ├── reference.processorenrichers.pauseaftereachitem.yaml │ ├── reference.processors.azuredevopspipelineprocessor.yaml │ ├── reference.processors.keepoutboundlinktargetprocessor.yaml │ ├── reference.processors.outboundlinkcheckingprocessor.yaml │ ├── reference.processors.processdefinitionprocessor.yaml │ ├── reference.processors.tfsexportprofilepicturefromadprocessor.yaml │ ├── reference.processors.tfsexportusersformappingprocessor.yaml │ ├── reference.processors.tfsimportprofilepictureprocessor.yaml │ ├── reference.processors.tfssharedqueryprocessor.yaml │ ├── reference.processors.tfsteamsettingsprocessor.yaml │ ├── reference.processors.tfstestconfigurationsmigrationprocessor.yaml │ ├── reference.processors.tfstestplansandsuitesmigrationprocessor.yaml │ ├── reference.processors.tfstestvariablesmigrationprocessor.yaml │ ├── reference.processors.tfsworkitembulkeditprocessor.yaml │ ├── reference.processors.tfsworkitemdeleteprocessor.yaml │ ├── reference.processors.tfsworkitemmigrationprocessor.yaml │ ├── reference.processors.tfsworkitemoverwriteareasastagsprocessor.yaml │ ├── reference.processors.tfsworkitemoverwriteprocessor.yaml │ ├── reference.processors.workitemtrackingprocessor.yaml │ ├── reference.tools.fieldmappingtool.yaml │ ├── reference.tools.stringmanipulatortool.yaml │ ├── reference.tools.tfsattachmenttool.yaml │ ├── reference.tools.tfschangesetmappingtool.yaml │ ├── reference.tools.tfsembededimagestool.yaml │ ├── reference.tools.tfsgitrepositorytool.yaml │ ├── reference.tools.tfsnodestructuretool.yaml │ ├── reference.tools.tfsrevisionmanagertool.yaml │ ├── reference.tools.tfsteamsettingstool.yaml │ ├── reference.tools.tfsusermappingtool.yaml │ ├── reference.tools.tfsvalidaterequiredfieldtool.yaml │ ├── reference.tools.tfsworkitemembededlinktool.yaml │ ├── reference.tools.tfsworkitemlinktool.yaml │ ├── reference.tools.workitemtypemappingtool.yaml │ ├── releases-grouped-major.json │ ├── releases-grouped-minor.json │ └── releases.json ├── _includes │ ├── article-alert.html │ ├── breadcrumbs.html │ ├── cardpanel-contribute.html │ ├── content-collection-table.html │ ├── content-collection.html │ ├── footer.html │ ├── header.html │ ├── sampleConfig │ │ ├── ProcessDefinitionProcessor-Full.json │ │ ├── configration-demo-v15.0.json │ │ ├── configuration-Fullv2.json │ │ ├── configuration-WorkItemTracking.json │ │ ├── configuration-full.json │ │ ├── configuration-getstarted.json │ │ ├── configuration-ref.json │ │ └── configuration.json │ ├── sidebar-collection-reference.html │ ├── sidebar-collection.html │ └── sidebar.html ├── _layouts │ ├── default.html │ ├── page.html │ └── reference.html ├── _meta │ ├── configuration.json │ ├── getting-started.json │ ├── index.json │ ├── server-configuration.json │ └── why.json ├── _plugins │ └── _capitalize_all.rb ├── assets │ ├── css │ │ ├── base16.css │ │ └── main.css │ └── images │ │ ├── Azure-DevOps-Migration-Tools-GithubSocial-Image.jpg │ │ └── naked-agility-Learn-Azure-DevOps-Migration-Tools-1600x900.jpg ├── change-log.md ├── collections │ ├── _faq │ │ ├── work-item-is-not-ready-to-save.md │ │ └── work-items-are-not-migrated.md │ ├── _howto │ │ ├── creating-iteration-and-area-maps.md │ │ ├── migrating-plans-and-suites.md │ │ └── user-mappings.md │ ├── _knownissues │ │ └── S402625.md │ └── _reference │ │ ├── reference.endpoints.azuredevopsendpoint.md │ │ ├── reference.endpoints.filesystemworkitemendpoint.md │ │ ├── reference.endpoints.tfsendpoint.md │ │ ├── reference.endpoints.tfsteamprojectendpoint.md │ │ ├── reference.endpoints.tfsteamsettingsendpoint.md │ │ ├── reference.endpoints.tfsworkitemendpoint.md │ │ ├── reference.fieldmaps.fieldclearmap.md │ │ ├── reference.fieldmaps.fieldliteralmap.md │ │ ├── reference.fieldmaps.fieldmergemap.md │ │ ├── reference.fieldmaps.fieldskipmap.md │ │ ├── reference.fieldmaps.fieldtofieldmap.md │ │ ├── reference.fieldmaps.fieldtofieldmultimap.md │ │ ├── reference.fieldmaps.fieldtotagfieldmap.md │ │ ├── reference.fieldmaps.fieldvaluemap.md │ │ ├── reference.fieldmaps.multivalueconditionalmap.md │ │ ├── reference.fieldmaps.regexfieldmap.md │ │ ├── reference.fieldmaps.treetotagfieldmap.md │ │ ├── reference.processorenrichers.pauseaftereachitem.md │ │ ├── reference.processors.azuredevopspipelineprocessor.md │ │ ├── reference.processors.keepoutboundlinktargetprocessor.md │ │ ├── reference.processors.outboundlinkcheckingprocessor.md │ │ ├── reference.processors.processdefinitionprocessor.md │ │ ├── reference.processors.tfsexportprofilepicturefromadprocessor.md │ │ ├── reference.processors.tfsexportusersformappingprocessor.md │ │ ├── reference.processors.tfsimportprofilepictureprocessor.md │ │ ├── reference.processors.tfssharedqueryprocessor.md │ │ ├── reference.processors.tfsteamsettingsprocessor.md │ │ ├── reference.processors.tfstestconfigurationsmigrationprocessor.md │ │ ├── reference.processors.tfstestplansandsuitesmigrationprocessor.md │ │ ├── reference.processors.tfstestvariablesmigrationprocessor.md │ │ ├── reference.processors.tfsworkitembulkeditprocessor.md │ │ ├── reference.processors.tfsworkitemdeleteprocessor.md │ │ ├── reference.processors.tfsworkitemmigrationprocessor.md │ │ ├── reference.processors.tfsworkitemoverwriteareasastagsprocessor.md │ │ ├── reference.processors.tfsworkitemoverwriteprocessor.md │ │ ├── reference.processors.workitemtrackingprocessor.md │ │ ├── reference.tools.fieldmappingtool.md │ │ ├── reference.tools.stringmanipulatortool.md │ │ ├── reference.tools.tfsattachmenttool.md │ │ ├── reference.tools.tfschangesetmappingtool.md │ │ ├── reference.tools.tfsembededimagestool.md │ │ ├── reference.tools.tfsgitrepositorytool.md │ │ ├── reference.tools.tfsnodestructuretool.md │ │ ├── reference.tools.tfsrevisionmanagertool.md │ │ ├── reference.tools.tfsteamsettingstool.md │ │ ├── reference.tools.tfsusermappingtool.md │ │ ├── reference.tools.tfsvalidaterequiredfieldtool.md │ │ ├── reference.tools.tfsworkitemembededlinktool.md │ │ ├── reference.tools.tfsworkitemlinktool.md │ │ └── reference.tools.workitemtypemappingtool.md ├── errors.md ├── faq.md ├── getstarted │ ├── index.md │ └── introvideos.md ├── index.md ├── setup │ ├── index.md │ ├── installation.md │ ├── permissions.md │ └── reflectedworkitemid.md ├── staticwebapp.config.json ├── support.md └── version-control.md ├── spellcheck.yaml ├── src ├── MigrationTools.Chocolatey │ ├── chocolateyInstall.ps1 │ ├── chocolateyUninstall.ps1 │ ├── nkdAgility.AzureDevOpsMigrationTools-Preview.nuspec │ └── nkdAgility.AzureDevOpsMigrationTools.nuspec ├── MigrationTools.Clients.AzureDevops.Rest.Tests │ ├── MigrationTools - Backup.Clients.AzureDevops.Rest.Tests.csproj │ ├── MigrationTools.Clients.AzureDevops.Rest.Tests.csproj │ └── Processors │ │ ├── AzureDevOpsPipelineProcessorTests.cs │ │ └── AzureDevOpsProcessorTests.cs ├── MigrationTools.Clients.AzureDevops.Rest │ ├── AzureDevOpsExtensions.cs │ ├── Endpoints │ │ ├── AzureDevOpsEndpoint.cs │ │ └── AzureDevOpsEndpointOptions.cs │ ├── MigrationTools.Clients.AzureDevops.Rest.csproj │ ├── Processors │ │ ├── AzureDevOpsPipelineProcessor.cs │ │ ├── AzureDevOpsPipelineProcessorOptions.cs │ │ ├── KeepOutboundLinkTargetProcessor.cs │ │ ├── KeepOutboundLinkTargetProcessorOptions.cs │ │ ├── OutboundLinkCheckingProcessor.cs │ │ ├── OutboundLinkCheckingProcessorOptions.cs │ │ ├── ProcessDefinitionProcessor.cs │ │ └── ProcessDefinitionProcessorOptions.cs │ └── ServiceCollectionExtensions.cs ├── MigrationTools.Clients.FileSystem.Tests │ ├── Endpoints │ │ └── FileSystemWorkItemEndpointTests.cs │ ├── MigrationTools.Clients.FileSystem.Tests.csproj │ └── ServiceProviderHelper.cs ├── MigrationTools.Clients.FileSystem │ ├── Endpoints │ │ ├── FileSystemWorkItemEndpoint.cs │ │ ├── FileSystemWorkItemEndpointOptions.cs │ │ └── FileSystemWorkItemQuery.cs │ ├── MigrationTools.Clients.FileSystem.csproj │ ├── MigrationTools.Sources.FileSystem.csproj │ └── ServiceCollectionExtensions.cs ├── MigrationTools.Clients.TfsObjectModel.Tests │ ├── Endpoints │ │ └── TfsWorkItemEndPointTests.cs │ ├── MigrationTools.Clients.TfsObjectModel.Tests.csproj │ ├── Processors │ │ ├── Infra │ │ │ └── FakeMigrationClientConfig.cs │ │ ├── TfsProcessorTests.cs │ │ ├── TfsSharedQueryProcessorTests.cs │ │ ├── TfsTeamSettingsProcessorTests.cs │ │ └── TfsWorkItemMigrationProcessorTests.cs │ ├── ServiceProviderHelper.cs │ └── Tools │ │ ├── TfsNodeStructureTests.cs │ │ └── TfsRevisionManagerTests.cs ├── MigrationTools.Clients.TfsObjectModel │ ├── Clients │ │ ├── TfsReflectedWorkItemId.cs │ │ ├── TfsTestPlanMigrationClient.cs │ │ ├── TfsWorkItemMigrationClient.cs │ │ └── TfsWorkItemQuery.cs │ ├── EndPoints │ │ ├── Infrastructure │ │ │ └── TfsTeamProjectAuthentication.cs │ │ └── TfsTeamProjectEndPointOptions.cs │ ├── Endpoints │ │ ├── TfsEndpoint.cs │ │ ├── TfsEndpointOptions.cs │ │ ├── TfsLanguageMapOptions.cs │ │ ├── TfsTeamProjectEndpoint.cs │ │ ├── TfsTeamSettingsEndpoint.cs │ │ ├── TfsTeamSettingsEndpointOptions.cs │ │ ├── TfsWorkItemConvertor.cs │ │ ├── TfsWorkItemEndpoint.cs │ │ └── TfsWorkItemEndpointOptions.cs │ ├── MigrationTools.Clients.TfsObjectModel.csproj │ ├── Processors │ │ ├── Infra │ │ │ ├── ConfigException.cs │ │ │ ├── TestManagementContext.cs │ │ │ └── TfsProcessor.cs │ │ ├── TfsCreateTeamFoldersProcessor.cs │ │ ├── TfsEmptyProcessorOptions.cs │ │ ├── TfsExportProfilePictureFromADProcessor.cs │ │ ├── TfsExportProfilePictureFromADProcessorOptions.cs │ │ ├── TfsExportTeamListProcessor.cs │ │ ├── TfsExportUsersForMappingProcessor.cs │ │ ├── TfsExportUsersForMappingProcessorOptions.cs │ │ ├── TfsFakeProcessor.cs │ │ ├── TfsImportProfilePictureProcessor.cs │ │ ├── TfsImportProfilePictureProcessorOptions.cs │ │ ├── TfsSharedQueryProcessor.cs │ │ ├── TfsSharedQueryProcessorOptions.cs │ │ ├── TfsTeamSettingsProcessor.cs │ │ ├── TfsTeamSettingsProcessorOptions.cs │ │ ├── TfsTestConfigurationsMigrationProcessor.cs │ │ ├── TfsTestConfigurationsMigrationProcessorOptions.cs │ │ ├── TfsTestPlansAndSuitesMigrationProcessor.cs │ │ ├── TfsTestPlansAndSuitesMigrationProcessorOptions.cs │ │ ├── TfsTestVariablesMigrationProcessor.cs │ │ ├── TfsTestVariablesMigrationProcessorOptions.cs │ │ ├── TfsWorkItemBulkEditProcessor.cs │ │ ├── TfsWorkItemBulkEditProcessorOptions.cs │ │ ├── TfsWorkItemDeleteProcessor.cs │ │ ├── TfsWorkItemDeleteProcessorOptions.cs │ │ ├── TfsWorkItemMigrationProcessor.cs │ │ ├── TfsWorkItemMigrationProcessorOptions.cs │ │ ├── TfsWorkItemMigrationProcessorOptionsValidator.cs │ │ ├── TfsWorkItemOverwriteAreasAsTagsProcessor.cs │ │ ├── TfsWorkItemOverwriteAreasAsTagsProcessorOptions.cs │ │ ├── TfsWorkItemOverwriteProcessor.cs │ │ └── TfsWorkItemOverwriteProcessorOptions.cs │ ├── ServiceCollectionExtensions.cs │ ├── TfsExtensions.cs │ └── Tools │ │ ├── FieldMappingTool │ │ └── FieldMaps │ │ │ ├── FieldClearMap.cs │ │ │ ├── FieldLiteralMap.cs │ │ │ ├── FieldMapBase.cs │ │ │ ├── FieldMergeMap.cs │ │ │ ├── FieldSkipMap.cs │ │ │ ├── FieldToFieldMap.cs │ │ │ ├── FieldToTagFieldMap.cs │ │ │ ├── FieldValueMap.cs │ │ │ ├── FieldValuetoTagMap.cs │ │ │ ├── FieldtoFieldMultiMap.cs │ │ │ ├── MultiValueConditionalMap.cs │ │ │ ├── NodePathNotAnchoredException.cs │ │ │ ├── RegexFieldMap.cs │ │ │ └── TreeToTagFieldMap.cs │ │ ├── TfsAttachmentTool.cs │ │ ├── TfsAttachmentToolOptions.cs │ │ ├── TfsChangeSetMappingTool.cs │ │ ├── TfsChangeSetMappingToolOptions.cs │ │ ├── TfsEmbededImagesTool.cs │ │ ├── TfsEmbededImagesToolOptions.cs │ │ ├── TfsGitRepositoryInfo.cs │ │ ├── TfsGitRepositoryTool.cs │ │ ├── TfsGitRepositoryToolOptions.cs │ │ ├── TfsGitRepositoryToolOptionsValidator.cs │ │ ├── TfsNodeStructureTool.cs │ │ ├── TfsNodeStructureToolOptions.cs │ │ ├── TfsRevisionManagerTool.cs │ │ ├── TfsRevisionManagerToolOptions.cs │ │ ├── TfsStaticTools.cs │ │ ├── TfsTeamSettingsTool.cs │ │ ├── TfsTeamSettingsToolOptions.cs │ │ ├── TfsUserMappingTool.cs │ │ ├── TfsUserMappingToolOptions.cs │ │ ├── TfsValidateRequiredFieldTool.cs │ │ ├── TfsValidateRequiredFieldToolOptions.cs │ │ ├── TfsWorkItemEmbededLinkTool.cs │ │ ├── TfsWorkItemEmbededLinkToolOptions.cs │ │ ├── TfsWorkItemLinkTool.cs │ │ └── TfsWorkItemLinkToolOptions.cs ├── MigrationTools.ConsoleCore │ ├── MigrationTools.ConsoleCore.csproj │ ├── Program.cs │ └── Properties │ │ └── launchSettings.json ├── MigrationTools.ConsoleDataGenerator │ ├── ClassDataLoader.cs │ ├── CodeDocumentation.cs │ ├── CodeFileFinder.cs │ ├── DataSerialization.cs │ ├── MarkdownLoader.cs │ ├── MigrationTools.ConsoleDataGenerator.csproj │ ├── Program.cs │ └── ReferenceData.cs ├── MigrationTools.ConsoleFull │ ├── MigrationTools.ConsoleFull.csproj │ ├── Program.cs │ └── Properties │ │ └── launchSettings.json ├── MigrationTools.Extension │ ├── LICENSE.txt │ ├── README.md │ ├── images │ │ ├── azure-devops-migration-tools-naked-agility-martin-hinshelwood.png │ │ ├── extension-icon.png │ │ └── screenshot-01.png │ └── vss-extension.json ├── MigrationTools.Helpers.Tests │ └── MigrationTools.Helpers.Tests.csproj ├── MigrationTools.Host.Tests │ ├── MigrationHostTests.cs │ ├── MigrationTools.Host.Tests.csproj │ └── Services │ │ ├── DetectOnlineServiceTests.cs │ │ ├── DetectVersionService2Tests.cs │ │ └── DetectVersionServiceTests.cs ├── MigrationTools.Host │ ├── BoilerplateCli.cs │ ├── Commands │ │ ├── CommandBase.cs │ │ ├── CommandSettingsBase.cs │ │ ├── ConfigurationBuilderCommand.cs │ │ ├── ConfigurationBuilderCommandSettings.cs │ │ ├── ExecuteMigrationCommand.cs │ │ ├── ExecuteMigrationCommandSettings.cs │ │ ├── InitMigrationCommand.cs │ │ ├── InitMigrationCommandSettings.cs │ │ ├── UpgradeConfigCommand.cs │ │ └── UpgradeConfigCommandSettings.cs │ ├── MigrationToolHost.cs │ ├── MigrationTools.Host.csproj │ ├── ServiceCollectionExtensions.cs │ └── Services │ │ ├── DetectOnlineService.cs │ │ ├── DetectVersionService2.cs │ │ ├── IDetectOnlineService.cs │ │ └── IDetectVersionService2.cs ├── MigrationTools.Samples │ ├── configuration-for-copy.json │ ├── configuration.json │ ├── demo-mapping-scrum2Agile.json │ ├── demo-migration-reset.json │ └── demo-migration.json ├── MigrationTools.Shadows │ ├── Clients │ │ └── WorkItemQueryBuilderFactoryFake.cs │ ├── Endpoints │ │ └── FakeEndpoint.cs │ ├── MigrationTools.Shadows.csproj │ ├── Processors │ │ └── Infrastructure │ │ │ ├── MockComplexProcessor.cs │ │ │ ├── MockComplexProcessorOptions.cs │ │ │ ├── MockSimpleProcessor.cs │ │ │ └── MockSimpleProcessorOptions.cs │ ├── ServiceCollectionExtensions.cs │ ├── Services │ │ ├── FakeMigrationToolVersion.cs │ │ ├── FakeMigrationToolVersionInfo.cs │ │ ├── MeterFactoryFake.cs │ │ └── TelemetryLoggerFake.cs │ └── Tools │ │ ├── MockFieldMappingTool.cs │ │ ├── MockSimpleFieldMap.cs │ │ ├── MockStringManipulatorTool.cs │ │ ├── MockWorkItemTypeMappingTool.cs │ │ └── SimpleFieldMapConfigMock.cs ├── MigrationTools.Telemetery │ ├── .gitignore │ ├── GetGraphWorkItemMetrics.cs │ ├── GetShieldIoWorkItemMetrics.cs │ ├── GetSvcWorkItemMetrics.cs │ ├── MigrationTools.Telemetery.csproj │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ └── MigrationToolsTelemetery - Web Deploy.pubxml │ │ ├── ServiceDependencies │ │ │ ├── MigrationToolsTelemetery - Web Deploy │ │ │ │ └── profile.arm.json │ │ │ └── MigrationToolsTelemetery │ │ │ │ ├── appInsights1.arm.json │ │ │ │ └── storage1.arm.json │ │ ├── launchSettings.json │ │ ├── serviceDependencies.MigrationToolsTelemetery - Web Deploy.json │ │ ├── serviceDependencies.MigrationToolsTelemetery.json │ │ ├── serviceDependencies.json │ │ └── serviceDependencies.local.json │ └── host.json ├── MigrationTools.Tests │ ├── Core │ │ ├── Clients │ │ │ ├── MigrationClientMock.cs │ │ │ ├── WorkItemMigrationClientMock.cs │ │ │ └── WorkItemMigrationClientTests.cs │ │ └── Configuration │ │ │ ├── FakeMigrationClientConfig.cs │ │ │ └── SerializationTests.cs │ ├── Endpoints │ │ └── Infrastructure │ │ │ └── EndpointRegistrationExtensionsTests.cs │ ├── MigrationTools.Tests.csproj │ ├── ProcessorEnrichers │ │ └── StringManipulatorEnricherTests.cs │ ├── Processors │ │ └── WorkItemMigrationProcessorTests.cs │ ├── ServiceProviderHelper.cs │ └── Services │ │ ├── MigrationToolVersionInfoTests.cs │ │ ├── TelemetryClientAdapterTests.cs │ │ └── TelemetryLoggerMock.cs ├── MigrationTools.WinGet │ ├── nkdAgility.AzureDevOpsMigrationTools.installer.yaml │ ├── nkdAgility.AzureDevOpsMigrationTools.locale.en-US.yaml │ └── nkdAgility.AzureDevOpsMigrationTools.yaml └── MigrationTools │ ├── AppDomainExtensions.cs │ ├── ConfigException.cs │ ├── Configuration │ └── MigrationToolsConfiguration.cs │ ├── ConfigurationSectionExtensions.cs │ ├── DataContracts │ ├── ApiPathAttribute.cs │ ├── EnricherData.cs │ ├── FieldItem.cs │ ├── IdentityItemData.cs │ ├── LinkItem.cs │ ├── Mapping.cs │ ├── NodeStructureMissingItem.cs │ ├── Pipelines │ │ ├── BuildDefinitions.cs │ │ ├── DeploymentGroup.cs │ │ ├── GitRepository.cs │ │ ├── ReleaseDefinitions.cs │ │ ├── ServiceConnection.cs │ │ ├── TaskAgentPool.cs │ │ ├── TaskGroups.cs │ │ ├── Tasks.cs │ │ └── VariableGroups.cs │ ├── Process │ │ └── ProcessDefinition.cs │ ├── RestApiDefinition.cs │ ├── RevisionItem.cs │ ├── WorkItemData.cs │ └── WorkItems │ │ └── WorkItem.cs │ ├── DisposableStopwatch.cs │ ├── EndpointEnrichers │ ├── EndpointEnricherContainer.cs │ ├── EndpointEnricherOptions.cs │ ├── IEndpointEnricher.cs │ ├── IEndpointEnricherOptions.cs │ └── WorkItemEndpointEnrichers │ │ ├── IWorkItemEndpointEnricher.cs │ │ ├── WorkItemAttachmentEnricher.cs │ │ ├── WorkItemAttachmentEnricherOptions.cs │ │ ├── WorkItemCreatedEnricher.cs │ │ ├── WorkItemCreatedEnricherOptions.cs │ │ ├── WorkItemEmbedEnricher.cs │ │ ├── WorkItemEmbedEnricherOptions.cs │ │ ├── WorkItemEndpointEnricher.cs │ │ ├── WorkItemFieldTableEnricher.cs │ │ ├── WorkItemFieldTableEnricherOptions.cs │ │ ├── WorkItemLinkEnricher.cs │ │ └── WorkItemLinkEnricherOptions.cs │ ├── Endpoints │ ├── AuthenticationMode.cs │ ├── IWorkItemQuery.cs │ └── Infrastructure │ │ ├── Endpoint.cs │ │ ├── EndpointOptions.cs │ │ ├── EndpointRegistrationExtensions.cs │ │ ├── IEndpoint.cs │ │ ├── IEndpointOptions.cs │ │ └── IWorkItemEndpoint.cs │ ├── Enrichers │ ├── IEnricher.cs │ └── IEnricherOptions.cs │ ├── Exceptions │ ├── ConfigurationValidationException.cs │ ├── MigrationToolsException.cs │ └── UnknownLinkTypeException.cs │ ├── Helpers │ └── NewtonsoftHelpers.cs │ ├── IMigrationEngine.cs │ ├── MigrationEngine.cs │ ├── MigrationTools.csproj │ ├── Options │ ├── ConfigurationMetadata.cs │ ├── IOptions.cs │ ├── Infrastructure │ │ └── DefaultOnlyConverter.cs │ ├── NetworkCredentialsOptions.cs │ ├── OptionsBinder.cs │ ├── OptionsConfigurationBuilder.cs │ ├── OptionsConfigurationCompiler.cs │ ├── OptionsConfigurationTemplates.cs │ ├── OptionsConfigurationUpgrader.cs │ ├── OptionsSerializationBinder.cs │ ├── OptionsSerializeContractResolver.cs │ ├── ProcessorOptionsConverter.cs │ ├── QueryOptions.cs │ ├── VersionOptions.cs │ └── WritableOptions.cs │ ├── Processors │ ├── Enrichers │ │ ├── IProcessorEnricher.cs │ │ ├── IProcessorEnricherOptions.cs │ │ ├── PauseAfterEachItem.cs │ │ ├── PauseAfterEachItemOptions.cs │ │ ├── ProcessorEnricherContainer.cs │ │ ├── ProcessorEnricherOptions.cs │ │ └── WorkItemProcessorEnrichers │ │ │ ├── IWorkItemProcessorEnricher.cs │ │ │ ├── IWorkItemProcessorSourceEnricher.cs │ │ │ ├── IWorkItemProcessorTargetEnricher.cs │ │ │ └── WorkItemProcessorEnricher.cs │ ├── Infrastructure │ │ ├── IProcessor.cs │ │ ├── IProcessor2.cs │ │ ├── IProcessorOptions.cs │ │ ├── InvalidProcessorException.cs │ │ ├── Processor.cs │ │ ├── ProcessorContainer.cs │ │ ├── ProcessorContainerOptions.cs │ │ ├── ProcessorOptions.cs │ │ ├── ProcessorStatus.cs │ │ └── ProcessorType.cs │ ├── WorkItemTrackingProcessor.cs │ └── WorkItemTrackingProcessorOptions.cs │ ├── ServiceCollectionExtensions.cs │ ├── Services │ ├── ActivitySourceProvider.cs │ ├── ITelemetryLogger.cs │ ├── LogLocationService.cs │ ├── MigrationToolVersionInfo.cs │ ├── ProcessorMetrics.cs │ ├── TelemetryClientAdapter.cs │ └── WorkItemMetrics.cs │ ├── StaticVariables.cs │ ├── Tests │ ├── TestHelpers.cs │ └── TestingConstants.cs │ ├── Tools │ ├── FieldMappingTool.cs │ ├── FieldMappingTool │ │ ├── FieldMaps │ │ │ ├── FieldClearMapOptions.cs │ │ │ ├── FieldLiteralMapOptions.cs │ │ │ ├── FieldMergeMapOptions.cs │ │ │ ├── FieldSkipMapOptions.cs │ │ │ ├── FieldValueMapOptions.cs │ │ │ ├── FieldValuetoTagMapOptions.cs │ │ │ ├── FieldtoFieldMapOptions.cs │ │ │ ├── FieldtoFieldMultiMapOptions.cs │ │ │ ├── FieldtoTagMapOptions.cs │ │ │ ├── MultiValueConditionalMapOptions.cs │ │ │ ├── RegexFieldMapOptions.cs │ │ │ └── TreeToTagFieldMapOptions.cs │ │ └── Infrastructure │ │ │ ├── FieldMapOptions.cs │ │ │ └── IFieldMapOptions.cs │ ├── FieldMappingToolOptions.cs │ ├── Infrastructure │ │ ├── EmbededImagesRepairEnricherBase.cs │ │ ├── ITool.cs │ │ ├── IToolOptions.cs │ │ ├── Tool.cs │ │ └── ToolOptions.cs │ ├── Interfaces │ │ ├── IFieldMappingTool.cs │ │ ├── IStringManipulatorTool.cs │ │ └── IWorkItemTypeMappingTool.cs │ ├── StaticTools.cs │ ├── StringManipulatorTool.cs │ ├── StringManipulatorToolOptions.cs │ ├── WorkItemTypeMappingTool.cs │ └── WorkItemTypeMappingToolOptions.cs │ ├── TypeExtensions.cs │ └── _EngineV1 │ ├── Clients │ ├── IMigrationClient.cs │ ├── ITestPlanMigrationClient.cs │ ├── IWorkItemMigrationClient.cs │ ├── IWorkItemQueryBuilder.cs │ ├── IWorkItemQueryBuilderFactory.cs │ ├── ReflectedWorkItemId.cs │ ├── WorkItemMigrationClientBase.cs │ ├── WorkItemQueryBase.cs │ ├── WorkItemQueryBuilder.cs │ └── WorkItemQueryBuilderFactory.cs │ ├── Configuration │ ├── IProcessorConfig.cs │ └── IWorkItemProcessorConfig.cs │ ├── Containers │ ├── EngineContainer.cs │ └── IFieldMap.cs │ └── DataContracts │ ├── ProjectData.cs │ └── TestPlanData.cs ├── triggertest.yml └── wordlist.txt /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_RETRY: "3" 3 | BUNDLE_JOBS: "4" 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # General Owners [Martin Hinshelwood] 5 | * @mrhinsh 6 | 7 | # The Hosting System [Ove Bastiansen] 8 | src/MigrationTools.Host/* @ovebastiansen 9 | src/MigrationTools.Host.Tests/* @ovebastiansen 10 | src/MigrationTools/*HostedService.cs @ovebastiansen 11 | 12 | # You can also use email addresses if you prefer. 13 | docs/* docs@example.com -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: nkdAgility 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Question 4 | url: https://github.com/nkdAgility/azure-devops-migration-tools/discussions/new?category=q-a 5 | about: Please ask and answer questions here. 6 | - name: Feature Idea 7 | url: https://github.com/nkdAgility/azure-devops-migration-tools/discussions/new?category=ideas 8 | about: If you have ideas fo changes or new capabilities please add them here 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/src" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "weekly" -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # Add 'Documentation' label to any changes within 'docs' folder or any subfolders 2 | documentation: 3 | - changed-files: 4 | - any-glob-to-any-file: docs/** 5 | 6 | # Add 'source' label to any change to src files within the source dir EXCEPT for the docs sub-folder 7 | build-action: 8 | - changed-files: 9 | - any-glob-to-any-file: ['build/**', '.github/workflows/**'] 10 | - head-branch: ['^build', 'build'] 11 | 12 | enhancement: 13 | - changed-files: 14 | - all-globs-to-any-file: ['src/**'] 15 | 16 | enhancement-classic: 17 | - changed-files: 18 | - any-glob-to-any-file: ['src/MigrationTools/_EngineV1/**', 'src/VstsSyncMigrator*/**'] 19 | 20 | enhancement-modern: 21 | - changed-files: 22 | - all-globs-to-any-file: ['src/**', '!src/MigrationTools/_EngineV1/**', '!src/VstsSyncMigrator*/**'] 23 | 24 | # Add 'feature' label to any PR where the head branch name starts with `feature` or has a `feature` section in the name 25 | feature: 26 | - head-branch: ['^feature', 'feature', '^topic', 'topic'] 27 | 28 | # Add 'bug' label to any PR 29 | bug: 30 | - head-branch: ['^fix', 'fix','^bug', 'bug'] 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | categories: 5 | - title: 🏕 Features 6 | labels: 7 | - '*' 8 | exclude: 9 | labels: 10 | - architecture 11 | - title: 👒 Architecture Improvements 12 | labels: 13 | - architecture 14 | -------------------------------------------------------------------------------- /.github/workflows/close-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Azure Static Web App PR Cleanup 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | 7 | jobs: 8 | pr_cleanup: 9 | runs-on: ubuntu-latest 10 | if: ${{ !(github.event.pull_request.head.repo.fork) }} 11 | steps: 12 | - uses: actions/create-github-app-token@v1 13 | id: app-token 14 | with: 15 | app-id: ${{ secrets.NKDAGILITY_BOT_APP_ID }} 16 | private-key: ${{ secrets.NKDAGILITY_BOT_CLIENTSECRET }} 17 | - name: Clean up pull request environment 18 | uses: Azure/static-web-apps-deploy@v1 19 | with: 20 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} 21 | action: 'close' 22 | deployment_environment: canary-${{ github.event.pull_request.number }} 23 | app_location: '' 24 | skip_app_build: true 25 | skip_api_build: true 26 | repo_token: ${{ secrets.GITHUB_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/code-review.yml: -------------------------------------------------------------------------------- 1 | name: OpenAI - Code Review 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | 7 | on: 8 | pull_request: 9 | types: [opened, reopened] 10 | 11 | jobs: 12 | code-review: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/create-github-app-token@v1 16 | id: app-token 17 | with: 18 | app-id: ${{ secrets.NKDAGILITY_BOT_APP_ID }} 19 | private-key: ${{ secrets.NKDAGILITY_BOT_CLIENTSECRET }} 20 | - uses: fitomad/github-chatgpt-integration@main 21 | with: 22 | openai-api-key: ${{ secrets.OPENAI_API_KEY }} 23 | github-token: ${{ steps.app-token.outputs.token }} 24 | github-pr-id: ${{ github.event.number }} 25 | dev-lang: c# 26 | openai-max-tokens: 4096 -------------------------------------------------------------------------------- /.github/workflows/labal-action.yml: -------------------------------------------------------------------------------- 1 | name: 'Label Actions' 2 | 3 | on: 4 | issues: 5 | types: [labeled] 6 | discussion: 7 | types: [labeled] 8 | pull_request_target: 9 | types: [labeled, unlabeled] 10 | 11 | permissions: 12 | contents: read 13 | issues: write 14 | discussions: write 15 | 16 | jobs: 17 | reaction: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/create-github-app-token@v1 21 | id: app-token 22 | with: 23 | app-id: ${{ secrets.NKDAGILITY_BOT_APP_ID }} 24 | private-key: ${{ secrets.NKDAGILITY_BOT_CLIENTSECRET }} 25 | - uses: dessant/label-actions@v4 26 | with: 27 | github-token: ${{ steps.app-token.outputs.token }} -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | # name: "Pull Request Labeler" 2 | # on: 3 | # - pull_request_target 4 | 5 | # jobs: 6 | # labeler: 7 | # permissions: 8 | # contents: read 9 | # pull-requests: write 10 | # runs-on: ubuntu-latest 11 | # steps: 12 | # - name: Checkout 13 | # uses: actions/checkout@v4 14 | # - uses: actions/create-github-app-token@v1 15 | # id: app-token 16 | # with: 17 | # app-id: ${{ secrets.NKDAGILITY_BOT_APP_ID }} 18 | # private-key: ${{ secrets.NKDAGILITY_BOT_CLIENTSECRET }} 19 | # - uses: actions/labeler@v5 20 | # with: 21 | # sync-labels: true 22 | # repo-token: ${{ steps.app-token.outputs.token }} -------------------------------------------------------------------------------- /.github/workflows/open-pr-describer.yml: -------------------------------------------------------------------------------- 1 | name: "OpenAI - PR Description Generator" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | 9 | permissions: 10 | pull-requests: write 11 | contents: read 12 | 13 | jobs: 14 | pull-request: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: Ant0wan/openai-pr@v1 19 | with: 20 | api-key: ${{ secrets.OPENAI_API_KEY }} 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v9 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | stale-issue-label: 'no-issue-activity' 17 | stale-pr-label: 'no-pr-activity' 18 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days' 19 | stale-pr-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days' 20 | days-before-stale: 90 21 | days-before-close: 30 22 | exempt-issue-label: 'enhancement' 23 | -------------------------------------------------------------------------------- /.github/workflows/test-function.yml: -------------------------------------------------------------------------------- 1 | name: Function Build & Release (Azure DevOps Migration Tools) 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | 7 | on: 8 | push: 9 | branches: ["main"] 10 | tags-ignore: ["v*-*"] 11 | pull_request: 12 | branches: ["main"] 13 | workflow_dispatch: 14 | inputs: 15 | ForceRelease: 16 | description: 'Force a release! Use when changes hapen out of sync and `src` and `docs` folder changes are not detected.' 17 | required: false 18 | default: false 19 | type: boolean 20 | 21 | concurrency: 22 | group: ${{ github.workflow }}-${{ github.ref }} 23 | cancel-in-progress: true 24 | 25 | defaults: 26 | run: 27 | shell: pwsh 28 | 29 | jobs: 30 | 31 | # Setup & Configuration 32 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "PowerShell Launch Current File", 9 | "type": "PowerShell", 10 | "request": "launch", 11 | "script": "${file}", 12 | "cwd": "${cwd}" 13 | }, 14 | { 15 | "name": "Full execute", 16 | "type": "clr", 17 | "request": "launch", 18 | "preLaunchTask": "build full framework", 19 | "program": "${workspaceFolder}/src/MigrationTools.ConsoleFull/bin/Debug/net472/migration.exe", 20 | "args": ["execute", "-c", "configuration.json"], 21 | "cwd": "${workspaceFolder}/src/MigrationTools.ConsoleFull/bin/Debug/net472/", 22 | "console": "externalTerminal", 23 | "stopAtEntry": false 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @global-owner1 and @global-owner2 will be requested for 7 | # review when someone opens a pull request. 8 | * @mrhinsh 9 | **/*Pipeline* tomfrenzel 10 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0.0.0.0 4 | 0.0.0.0 5 | 0.0.0-local 6 | Martin Hinshelwood 7 | naked Agility with Martin Hinshelwood 8 | MigrationTools.CommandLine 9 | default 10 | 1701;1702;1591 11 | true 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # gem "rails" 6 | gem 'jekyll-relative-links' 7 | gem 'jekyll-seo-tag' 8 | gem 'jekyll-sitemap' 9 | gem 'jekyll-toc' 10 | gem 'jekyll-time-to-read' 11 | gem 'jekyll-github-metadata' 12 | gem 'jekyll-last-modified-at' 13 | gem 'jekyll-optional-front-matter' 14 | gem 'jekyll-redirect-from' 15 | gem 'rouge' 16 | gem 'kramdown' 17 | gem 'pygments.rb' 18 | gem 'wdm' -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | assembly-versioning-scheme: MajorMinorPatch 2 | mode: ContinuousDelivery 3 | continuous-delivery-fallback-tag: 'Canary' 4 | next-version: 16.0.0 5 | branches: 6 | main: 7 | mode: ContinuousDelivery 8 | tag: 'Preview' 9 | increment: Patch 10 | is-mainline: true 11 | prevent-increment-of-merged-branch-version: false 12 | tracks-release-branches: true 13 | regex: ^master$|^main$ 14 | release: 15 | mode: ContinuousDelivery 16 | tag: "" 17 | increment: Patch 18 | track-merge-target: false 19 | regex: ^release(s)?[\/-] 20 | source-branches: 21 | - master 22 | - main 23 | is-release-branch: true 24 | is-mainline: false 25 | ignore: 26 | sha: [] 27 | merge-message-formats: {} -------------------------------------------------------------------------------- /GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Processors; 4 | using MigrationTools.Processors.Infrastructure; -------------------------------------------------------------------------------- /Local.testsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | These are default test settings for a local test run. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /MigrationTools.lutconfig: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 180000 6 | -------------------------------------------------------------------------------- /build/changelogs.ps1: -------------------------------------------------------------------------------- 1 | 2 | $releases = gh release list --json name,tagName -L 5009 --exclude-pre-releases | ConvertFrom-Json 3 | 4 | 5 | foreach ($release in $releases) { 6 | Write-Output "Release: $($release.name)" 7 | gren changelog --generate --override --tags=v15.0.4..$($release.tagName) --data-source=issues --changelog-filename=./changelogs/CHANGELOG-$($release.tagName)-issues.md 8 | } 9 | 10 | $tags = git tag -l 11 | $tags|%{[System.Version]$_}|sort -------------------------------------------------------------------------------- /build/compile-and-test.ps1: -------------------------------------------------------------------------------- 1 | $dotnetversion = where dotnet | dotnet --version 2 | 3 | Write-InfoLog "Run Compile & Test" 4 | Write-InfoLog "---------------" 5 | dotnet restore 6 | dotnet build /p:Version=$($versionInfo.AssemblySemVer) /p:FileVersion=$($versionInfo.AssemblySemVer) /p:InformationalVersion=$($versionInfo.InformationalVersion) 7 | 8 | dotnet test --collect "Code coverage" --no-build --filter "(TestCategory=L0|TestCategory=L1)" --logger trx --results-directory .\output\testresults 9 | dotnet test --collect "Code coverage" --no-build --filter "(TestCategory=L2|TestCategory=L3)" --logger trx --results-directory .\output\testresults 10 | dotnet test --collect "Code coverage" --no-build --filter "(TestCategory!=L0&TestCategory!=L1&TestCategory!=L2&TestCategory!=L3)" --logger trx --results-directory .\output\testresults 11 | 12 | Write-InfoLog "---------------" -------------------------------------------------------------------------------- /build/include/test.ps1: -------------------------------------------------------------------------------- 1 | 2 | #$Env:OPEN_AI_KEY = "" 3 | 4 | . ./build/include/Get-ReleaseDescription.ps1 5 | . ./build/include/OpenAI.ps1 6 | -------------------------------------------------------------------------------- /build/mantainReleaseLog.ps1: -------------------------------------------------------------------------------- 1 | # Load required functions 2 | . ./build/include/Get-ReleaseDescription.ps1 3 | . ./build/include/OpenAI.ps1 4 | . ./build/include/ReleaseMan.ps1 5 | 6 | # Define file paths 7 | $releaseFilePath = "./docs/_data/releases.json" 8 | $outputFilePath = "./docs/_data/releases-grouped.json" 9 | 10 | # Step 1: Update releases with the latest data 11 | $updatedReleases = Update-Releases -releaseFilePath $releaseFilePath -limit 10 12 | 13 | # Step 2: Add descriptions to all releases 14 | $updatedReleases = Update-ReleaseDescriptions -updatedReleases $updatedReleases -releaseFilePath $releaseFilePath 15 | 16 | # Output the total number of releases processed 17 | Write-Host "Total of $($updatedReleases.Count) releases found and processed." 18 | 19 | # Step 3: Group releases by major and minor versions 20 | 21 | 22 | Update-ReleaseGroups-Minor 23 | Update-ReleaseGroups-MinorSummaries 24 | Update-ReleaseGroups-Major 25 | Update-ReleaseGroups-MajorSummaries 26 | Get-ChangeLogMarkdown 27 | Get-ChangeLogLightMarkdown 28 | Get-ChangeLogLightMarkdownToReadme 29 | 30 | 31 | 32 | #============================================================================== -------------------------------------------------------------------------------- /build/packageNuget.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script description. 3 | 4 | Some notes. 5 | #> 6 | param ( 7 | # height of largest column without top bar 8 | [Parameter(Mandatory=$true)] 9 | [string]$version, 10 | 11 | # name of the output folder 12 | [Parameter(Mandatory=$true)] 13 | [string]$outfolder 14 | ) 15 | Write-Output "Azure DevOps Migration Tools (Nuget) Packaging" 16 | Write-Output "----------------------------------------" 17 | Write-Output "Version: $version" 18 | Write-Output "Output Folder: $outfolder" 19 | #============================================================================== 20 | 21 | Copy-Item -Path ".\src\MigrationTools\bin\**\*.nupkg" -Destination "$outfolder\" -Recurse 22 | -------------------------------------------------------------------------------- /build/packageWinget.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script description. 3 | 4 | Some notes. 5 | #> 6 | param ( 7 | # height of largest column without top bar 8 | [Parameter(Mandatory=$true)] 9 | [string]$version, 10 | 11 | # name of the output folder 12 | [Parameter(Mandatory=$true)] 13 | [string]$outfolder 14 | ) 15 | Write-Output "Azure DevOps Migration Tools (Winget) Packaging" 16 | Write-Output "----------------------------------------" 17 | Write-Output "Version: $version" 18 | Write-Output "Output Folder: $outfolder" 19 | #============================================================================== 20 | New-Item -Path $outfolder -Name "\WinGet\" -ItemType Directory 21 | Copy-Item -Path ".\src\MigrationTools.WinGet\**" -Destination "$outfolder\WinGet" -Recurse 22 | -------------------------------------------------------------------------------- /build/releaseExtension.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script description. 3 | 4 | Some notes. 5 | #> 6 | param ( 7 | # name of the output folder 8 | [Parameter(Mandatory=$true)] 9 | [string]$vsixFile, 10 | [Parameter(Mandatory=$true)] 11 | [string]$marketplaceToken 12 | ) 13 | Write-Output "Azure DevOps Migration Tools (Extension) Release" 14 | Write-Output "----------------------------------------" 15 | Write-Output "Extension file: $extensionFile" 16 | Write-Output "----------------------------------------" 17 | if (((npm list -g tfx-cli) -join "," ).Contains("empty")) { 18 | Write-Output "Installing tfx-cli" 19 | npm i -g tfx-cli 20 | } else { Write-Output "Detected tfx-cli"} 21 | Write-Output "----------------------------------------" 22 | # Login 23 | Write-Output ">>>>> Login" 24 | tfx login --service-url https://marketplace.visualstudio.com --token $marketplaceToken 25 | Write-Output "----------------------------------------" 26 | Write-Output "----------------------------------------" 27 | # Build TFS Extension 28 | Write-Output ">>>>> Send TFS Extension" 29 | tfx extension publish --vsix "$vsixFile" --token $marketplaceToken 30 | Write-Output "----------------------------------------" -------------------------------------------------------------------------------- /buildDocs.ps1: -------------------------------------------------------------------------------- 1 | $msBuildExe = 'C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe' 2 | & nuget restore 3 | & "$($msBuildExe)" "MigrationTools.sln" /t:Build /m 4 | 5 | & ".\src\MigrationTools.ConsoleFull\bin\Debug\net472\migration.exe" init --config ".\docs\Reference\Generated\configuration.config" 6 | & ".\src\MigrationTools.ConsoleFull\bin\Debug\net472\migration.exe" init --options Full --config ".\docs\Reference\Generated\configuration-Full.config" 7 | & ".\src\MigrationTools.ConsoleFull\bin\Debug\net472\migration.exe" init --options WorkItemTracking --config ".\docs\Reference\Generated\configuration-WorkItemTracking.config" 8 | & ".\src\MigrationTools.ConsoleFull\bin\Debug\net472\migration.exe" init --options Fullv2 --config ".\docs\Reference\Generated\configuration-Fullv2.config" 9 | & ".\src\MigrationTools.ConsoleFull\bin\Debug\net472\migration.exe" init --options WorkItemTrackingv2 --config ".\docs\Reference\Generated\configuration-WorkItemTrackingv2.config" 10 | 11 | 12 | 13 | & ".\src\MigrationTools.ConsoleConfigGenerator\bin\Debug\net472\ConfigGenerator.exe" -------------------------------------------------------------------------------- /docs/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 404 | Azure DevOps Migration Tools 3 | layout: page 4 | pageType: index 5 | template: index-template.md 6 | toc: false 7 | pageStatus: published 8 | discussionId: 9 | --- 10 | 11 | 12 | The page you are looking for may have been moved or deleted! Try to find what you want in the left navigation. -------------------------------------------------------------------------------- /docs/MigrationTools.Documentation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/Reference/EndpointEnrichers/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Endpoint Enrichers 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | Endpoint Enrichers are run within the context of the Endpoint that they are configured for. Many endpoints are flexible, however there are also enrichers that only work with certain Endpoints. 11 | 12 | {% include content-collection-table.html collection = "reference" typeName = "EndpointEnrichers" architecture = "v2" %} 13 | 14 | 15 | ### Endpoint Enricher Options 16 | 17 | All Endpoint Enrichers have a minimum set of options that are required to run. 18 | 19 | #### Minimum Options to run 20 | 21 | The `Enabled` options is common to all Endpoint Enrichers. 22 | 23 | 24 | ```JSON 25 | { 26 | "ObjectType": "EndpointEnrichersOptions", 27 | "Enabled": true, 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/Reference/Endpoints/TfsWorkItemEndpoint-notes.md: -------------------------------------------------------------------------------- 1 | The Work Item endpoint is super awesome. 2 | 3 | |Client | WriteTo/ReadFrom | Endpoint | Data Target | Description | 4 | |:-:|:-:|:-:|:-:|:-:| 5 | AzureDevops.ObjectModel | Tfs Object Model | `TfsWorkItemEndPoint` | WorkItems | TBA 6 | AzureDevops.Rest | Azure DevOps REST | ? 7 | FileSystem | Local Files | `FileSystemWorkItemEndpoint` | WorkItems | TBA 8 | 9 | -------------------------------------------------------------------------------- /docs/Reference/Endpoints/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Endpoints 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | >**_This documentation is for a preview version of the Azure DevOps Migration Tools._ If you are not using the preview version then please head over to the main [documentation](https://nkdagility.com/docs/azure-devops-migration-tools).** 11 | 12 | 13 | 14 | Azure DevOps Migration Tools provides _endpoints_ for reading and writing `WorkItems`, `PlansAndSuits`, `Teams`, or `Queries`. 15 | 16 | | Client | WriteTo/ReadFrom | Endpoint | Data Target | Description | 17 | |:-:|:-:|:-:|:-:|:-:| 18 | AzureDevops.ObjectModel | Tfs Object Model | `TfsWorkItemEndPoint` | WorkItems | TBA 19 | AzureDevops.Rest | Azure DevOps REST | ? 20 | FileSystem | Local Files | `FileSystemWorkItemEndpoint` | WorkItems | TBA 21 | 22 | 23 | ### Endpoints Options 24 | 25 | All Endpoints have a minimum set of options that are required to run. 26 | 27 | #### Minimum Options to run 28 | 29 | The `Direction` option is required to allow the system to set direction. At a minimum you need to set a `Source`. 30 | 31 | 32 | ```JSON 33 | { 34 | "ObjectType": "EndpointOptions", 35 | "Direction": "Source" 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/Reference/FieldMaps/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FieldMaps 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | These fieldMaps are provided to allow you to modify the data as you do the migration. 11 | 12 | {% include content-collection-table.html collection = "reference" typeName = "FieldMaps" architecture = "v1" %} 13 | -------------------------------------------------------------------------------- /docs/Reference/FieldMaps/index2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Field Maps 3 | layout: page 4 | template: default 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | redirect_from: 9 | - /Reference/v2/FieldMaps.html 10 | --- 11 | 12 | 13 | >**_This documentation is for a preview version of the Azure DevOps Migration Tools._ If you are not using the preview version then please head over to the main [documentation](https://nkdagility.com/docs/azure-devops-migration-tools).** 14 | 15 | 16 | 17 | ### Options 18 | 19 | 20 | 21 | ### Example JSON 22 | 23 | ```JSON 24 | 25 | ``` -------------------------------------------------------------------------------- /docs/Reference/ProcessorEnrichers/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Processor Enrichers 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | --- 8 | 9 | Processor Enrichers are run within the context of the ProcessorProcessor that they are 10 | configured for. Many Processor Enrichers are flexible, however there are also enrichers that only 11 | work with certain Processors. 12 | 13 | | Processor Enricher | Processor(s) | Description | 14 | | --------------------------------------- | ------------ | ----------- | 15 | | PauseAfterEachItem | Any | TBA | 16 | | AppendMigrationToolSignatureFooter | WorkItem | TBA | 17 | | FilterWorkItemsThatAlreadyExistInTarget | WorkItem | TBA | 18 | | SkipToFinalRevisedWorkItemType | WorkItem | TBA | 19 | 20 | ### Processor Pipline 21 | 22 | - ProcessorExecutionBegin 23 | - ProcessorExecutionAfterSource 24 | - ProcessorExecutionBeforeProcessWorkItem 25 | - ProcessorExecutionAfterProcessWorkItem 26 | - ProcessorExecutionEnd 27 | 28 | ### Processor Enricher Options 29 | 30 | All Processor Enrichers have a minimum set of options that are required to run. 31 | 32 | #### Minimum Options to run 33 | 34 | The `Enabled` options is common to all Processor Enrichers. 35 | 36 | ```JSON 37 | { 38 | "ObjectType": "ProcessorEnrichersOptions", 39 | "Enabled": true, 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/Reference/Processors/AzureDevOpsPipelineProcessor-introduction.md: -------------------------------------------------------------------------------- 1 | 2 | ## Features 3 | - Migrates service connections 4 | - Migrates variable groups 5 | - Migrates task groups 6 | - Migrates classic and yml build pipelines 7 | - Migrates release pipelines -------------------------------------------------------------------------------- /docs/Reference/Processors/ProcessDefinitionProcessor-introduction.md: -------------------------------------------------------------------------------- 1 | 2 | Source: https://github.com/nkdAgility/azure-devops-migration-tools/pull/918 3 | 4 | I've got a use case where I need to have a single inheritance process model that is standardized across organizations. My proposed solution to this is to build a processor that iterates all the source process definitions the processor has configured to synchronize and update the target process definitions accordingly. 5 | 6 | Below is a sample processor configuration that will synchronize a process model definition on the source called "Custom Agile Process", with a process model definition on the target called "Other Agile Process". It will only synchronize the work item types configured, in the below case, Bug. The synchronize will not destroy any target entities, but will move and update them according to the source. Meaning if the target has it's own custom fields, this sync process will not damage them, unless they are named the same in the source. 7 | 8 | It supports, new fields, updated fields, moved fields, new groups, updated groups, moved groups, new pages, updated pages, moved pages, behaviors and rules. -------------------------------------------------------------------------------- /docs/Reference/Processors/ProcessDefinitionProcessor-notes.md: -------------------------------------------------------------------------------- 1 | 2 | ## Example 3 | 4 | 5 | ```JSON 6 | { 7 | ... 8 | "Processors": [ 9 | { 10 | "$type": "ProcessDefinitionProcessorOptions", 11 | "Enabled": true, 12 | "Processes": { 13 | "Custom Agile Process": [ 14 | "Bug" 15 | ] 16 | }, 17 | "ProcessMaps": { 18 | "Custom Agile Process": "Other Agile Process" 19 | }, 20 | "SourceName": "Source", 21 | "TargetName": "Target", 22 | "UpdateProcessDetails": true 23 | } 24 | ] 25 | ... 26 | } 27 | ``` 28 | 29 | ## Example Full 30 | 31 | ``` 32 | {% include sampleConfig/ProcessDefinitionProcessor-Full.json %} 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/Reference/Processors/TfsTestPlansAndSuitesMigrationProcessor-notes.md: -------------------------------------------------------------------------------- 1 | ## Additional Samples & Info 2 | 3 | To run a full plans and suites you should run the three processors in this order below. `TestVariablesMigrationConfig` and `TestConfigurationsMigrationConfig` only need run once. 4 | 5 | ```json 6 | "Processors": [ 7 | { 8 | "$type": "TestVariablesMigrationConfig", 9 | "Enabled": false 10 | }, 11 | { 12 | "$type": "TestConfigurationsMigrationConfig", 13 | "Enabled": true 14 | }, 15 | { 16 | "$type": "TestPlansAndSuitesMigrationConfig", 17 | "Enabled": true, 18 | "PrefixProjectToNodes": false, 19 | "OnlyElementsWithTag": null, 20 | "TestPlanQueryBit": null, 21 | "RemoveAllLinks": false, 22 | "MigrationDelay": 0, 23 | "UseCommonNodeStructureEnricherConfig": false, 24 | "NodeBasePaths": [], 25 | "AreaMaps": null, 26 | "IterationMaps": null, 27 | "RemoveInvalidTestSuiteLinks": false, 28 | "FilterCompleted": false 29 | } 30 | ] 31 | ``` 32 | 33 | ## Known working TestPlanQueryBit filter fields names 34 | 35 | `AreaPath`, `PlanName` and `PlanState` 36 | 37 | ```json 38 | "TestPlanQueryBit": "PlanName = 'ABC'" 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/Reference/Processors/TfsWorkItemMigrationProcessor-introduction.md: -------------------------------------------------------------------------------- 1 | The `WorkItemMigrationContext` processor is used for migrating work items from one Azure DevOps instance to another. This encompasses a variety of activities: 2 | 3 | 1. **Transferring Work Items Between Instances**: The primary purpose of the processor is to transfer work items, including bugs, tasks, user stories, features, and more, from one Azure DevOps instance to another. 4 | 5 | 2. **Migrating Work Item History**: The processor can also replicate the entire revision history of work items, providing continuity and maintaining a record of changes. 6 | 7 | 3. **Migrating Attachments and Links**: The processor can transfer any attachments or links associated with work items. This includes both external links and internal links to other work items. 8 | 9 | 4. **Updating Metadata**: If configured, the processor can update the "Created Date" and "Created By" fields on migrated work items to match the original items in the source instance. 10 | 11 | 5. **Filtering Work Items**: The processor can be configured to only migrate certain work items based on their area or iteration paths. 12 | 13 | Overall, the `WorkItemMigrationContext` processor is a comprehensive tool for transferring work items and their associated data and metadata between Azure DevOps instances. It should be used whenever there is a need to move work items between instances while preserving as much information as possible. 14 | -------------------------------------------------------------------------------- /docs/Reference/Processors/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Processors 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | We provide a number of Processors that can be used to migrate diferent sorts of data. These processors are the original traditional processors. 11 | 12 | {% include content-collection-table.html collection = "reference" typeName = "Processors" architecture = "v1" %} 13 | 14 | 15 | ### Processor Options 16 | 17 | All processors have a minimum set of options that are required to run. 18 | 19 | #### Minimum Options to run 20 | The `Enabled` options is common to all processors. 21 | 22 | 23 | ```JSON 24 | { 25 | "$type": "ProcessorConfig", 26 | "Enabled": true, 27 | } 28 | ``` -------------------------------------------------------------------------------- /docs/Reference/Tools/TfsNodeStructureTool-introduction.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/docs/Reference/Tools/TfsNodeStructureTool-introduction.md -------------------------------------------------------------------------------- /docs/_includes/breadcrumbs.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
 › 
5 | 6 |
 › 
7 | 8 | {% assign crumbs = page.url | split: '/' %} 9 | {% for crumb in crumbs offset: 1 %} 10 | {% if forloop.last %} 11 |
 › 
12 | 13 | {% else %} 14 |
 › 
15 | 16 | {% endif %} 17 | {% endfor %} 18 |
19 |
20 | -------------------------------------------------------------------------------- /docs/_includes/content-collection-table.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% assign collection = site.collections | where: "label", include.collection | first %} 13 | {% if collection != null %} 14 | {% assign items = collection.docs | where: "typeName", include.typeName %} 15 | {% for item in items %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | {% else %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% endif %} 31 | 32 |
NameStatusTargetUsage
{{item.className}}{{item.status}}{{item.processingTarget}}{{item.description | markdownify }}
NONENONENONENONE
33 |
34 | 35 | -------------------------------------------------------------------------------- /docs/_includes/content-collection.html: -------------------------------------------------------------------------------- 1 | {% assign collection = site.collections | where: "label", include.collection | first %} 2 | {% if collection != null %} 3 | {% assign items = collection.docs | where: "typeName", include.typeName | where: "architecture", include.architecture | sort: "importance" | reverse %} 4 |
    5 | {% for item in items %} 6 |
  • 7 | 8 | {{ item.title }} 9 | {% if item.description != null %} - {{ item.description }}{% endif %} 10 |
  • 11 | {% endfor %} 12 |
13 | {% else %} 14 |

No items in collection

15 | {% endif %} -------------------------------------------------------------------------------- /docs/_includes/sampleConfig/configuration-Fullv2.json: -------------------------------------------------------------------------------- 1 | { 2 | "Serilog": { 3 | "MinimumLevel": "Information" 4 | }, 5 | "MigrationTools": { 6 | "Version": "0.0", 7 | "Endpoints": {}, 8 | "Processors": [ 9 | { 10 | "ProcessorType": "WorkItemTrackingProcessor", 11 | "Enabled": true, 12 | "ReplayRevisions": true, 13 | "CollapseRevisions": false, 14 | "WorkItemCreateRetryLimit": 5, 15 | "Enrichers": null, 16 | "SourceName": "Source", 17 | "TargetName": "Target", 18 | "RefName": null 19 | } 20 | ], 21 | "CommonTools": { 22 | "TfsChangeSetMappingTool": { 23 | "Enabled": true, 24 | "ChangeSetMappingFile": "" 25 | }, 26 | "TfsGitRepositoryTool": { 27 | "Enabled": true, 28 | "Mappings": null 29 | }, 30 | "FieldMappingTool": { 31 | "Enabled": true, 32 | "FieldMaps": [] 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /docs/_includes/sidebar-collection-reference.html: -------------------------------------------------------------------------------- 1 | {% assign collection = site.collections | where: "label", include.collection | first %} 2 |
  • 3 | {{include.typeName}} 4 |
      5 |
    • 6 | Overview 8 |
    • 9 | {% if collection != null %} 10 | {% assign items = collection.docs | where: "typeName", include.typeName | sort: "importance" %} 11 | {% if items != empty %} 12 | {% for item in items %} 13 |
    • 14 | {{ item.title }} 16 |
    • 17 | {% endfor %} {% endif %} {% else %} 18 |
    • No items
    • 19 | {% endif %} 20 |
    21 |
  • 22 | -------------------------------------------------------------------------------- /docs/_includes/sidebar-collection.html: -------------------------------------------------------------------------------- 1 | {% assign collection = site.collections | where: "label", include.collection | first %} 2 | {% if collection != null %} 3 | {% assign items = collection.docs | sort: "importance" %} 4 | {% if items != empty %} 5 | {% for item in items %} 6 |
  • 7 | {{ item.title }} 9 |
  • 10 | {% endfor %} {% endif %} {% else %} 11 |
  • No items
  • 12 | {% endif %} 13 | 14 | -------------------------------------------------------------------------------- /docs/_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
    5 |

    {{ page.title }}

    6 |
    7 |
    8 |

    Article

    9 |    10 |

    {{ content | reading_time_as_i }} to read

    11 |    12 |

    {{ page.last_modified_at }}

    13 |
    14 |
    15 | {% include article-alert.html %} 16 | {{ content | inject_anchors }} 17 |
    -------------------------------------------------------------------------------- /docs/_meta/configuration.json: -------------------------------------------------------------------------------- 1 | {"title":"configuration","uniqueId":"0d57df16-1c36-4a10-a49d-1a73e464055e"} -------------------------------------------------------------------------------- /docs/_meta/getting-started.json: -------------------------------------------------------------------------------- 1 | {"title":"getting started","uniqueId":"19d63307-e043-4b77-8dab-f24677081387"} -------------------------------------------------------------------------------- /docs/_meta/index.json: -------------------------------------------------------------------------------- 1 | {"title":"index","uniqueId":"a31563d0-bbbc-4823-b0a9-c2e533edfea6"} -------------------------------------------------------------------------------- /docs/_meta/server-configuration.json: -------------------------------------------------------------------------------- 1 | {"title":"server configuration","uniqueId":"4aae9f04-bc0a-4825-87c6-d26a477e40b9"} -------------------------------------------------------------------------------- /docs/_meta/why.json: -------------------------------------------------------------------------------- 1 | {"title":"why","uniqueId":"b54d7c24-54d3-4363-a557-99beedf3c5e7"} -------------------------------------------------------------------------------- /docs/_plugins/_capitalize_all.rb: -------------------------------------------------------------------------------- 1 | require 'liquid' 2 | require 'uri' 3 | 4 | # Capitalize all words of the input 5 | module Jekyll 6 | module CapitalizeAll 7 | def capitalize_all(words) 8 | return words.split(' ').map(&:capitalize).join(' ') 9 | end 10 | end 11 | end 12 | 13 | Liquid::Template.register_filter(Jekyll::CapitalizeAll) -------------------------------------------------------------------------------- /docs/assets/css/main.css: -------------------------------------------------------------------------------- 1 | .mainContainer 2 | { 3 | max-width: 1768px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | } 7 | 8 | .bg-brand-primary 9 | { 10 | background-color: #713183; 11 | } 12 | .bg-brand-secondary { 13 | background-color: #54595F; 14 | } 15 | 16 | .bg-brand-menu 17 | { 18 | background-color: #43464c; 19 | } 20 | 21 | pre { 22 | max-width: 1024px;; 23 | } 24 | 25 | .navbar-brand-topbaritem { 26 | font-size: 0.9em; 27 | } 28 | 29 | .nkda-text-primary { 30 | color: #713183; 31 | } 32 | 33 | .nkda-main-menu-item { 34 | 35 | } 36 | 37 | .nkda-main-menu-item:hover { 38 | color: white; 39 | background: #713183; 40 | } 41 | 42 | .btn-nkdprimary { 43 | background-color: #713183; 44 | color: white; 45 | } 46 | 47 | .btn-nkdprimary:hover { 48 | background-color: #54595F; 49 | color: white; 50 | } -------------------------------------------------------------------------------- /docs/assets/images/Azure-DevOps-Migration-Tools-GithubSocial-Image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/docs/assets/images/Azure-DevOps-Migration-Tools-GithubSocial-Image.jpg -------------------------------------------------------------------------------- /docs/assets/images/naked-agility-Learn-Azure-DevOps-Migration-Tools-1600x900.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/docs/assets/images/naked-agility-Learn-Azure-DevOps-Migration-Tools-1600x900.jpg -------------------------------------------------------------------------------- /docs/collections/_faq/work-item-is-not-ready-to-save.md: -------------------------------------------------------------------------------- 1 | --- 2 | redirectFrom: [] 3 | layout: page 4 | toc: true 5 | title: Work items are not migrated! 6 | categories: 7 | - Work Items 8 | --- 9 | 10 | Maybe you see a `TF237124: Work Item is not ready to save` error when you attempt to do a migration. 11 | 12 | Posible solutions are: 13 | 14 | - [Work items are not migrated!](work-items-are-not-migrated.md) 15 | -------------------------------------------------------------------------------- /docs/collections/_faq/work-items-are-not-migrated.md: -------------------------------------------------------------------------------- 1 | --- 2 | redirectFrom: [] 3 | layout: page 4 | toc: true 5 | title: Work items are not migrated! 6 | categories: 7 | - Work Items 8 | --- 9 | 10 | Maybe you see a `TF237124: Work Item is not ready to save` error when you attempt to do a migration. 11 | 12 | A number of processors have a setting `"PrefixProjectToNodes": false`. If set to true this inserts the name of the source Team Project into the created structure e.g. Area path, Iteration path, or Work Item queries. It is also used by the migration processor. 13 | 14 | This setting **must** be consistent across all processors in a configuration file. If it not it can often cause migrations to fail as expected paths are not present. 15 | -------------------------------------------------------------------------------- /docs/collections/_knownissues/S402625.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "S402625" 3 | layout: page 4 | toc: true 5 | discussionId: 6 | --- 7 | 8 | -------------------------------------------------------------------------------- /docs/errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Error Messages 3 | layout: page 4 | template: default 5 | pageType: index 6 | toc: true 7 | pageStatus: published 8 | discussionId: 9 | redirect_from: /errormessages.html 10 | --- 11 | 12 | These Error messages are a collection of those that may be generated by the tool and what they `might` mean! If you have an error message that is not listed here, please let us know and we will add it to the list. 13 | 14 | ## -------------------------------------------------------------------------------- /docs/getstarted/introvideos.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introductory Videos 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | - [Video Overview](https://youtu.be/RCJsST0xBCE) -------------------------------------------------------------------------------- /docs/setup/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setting up the Azure DevOps Migration Tools 3 | layout: page 4 | pageType: index 5 | toc: true 6 | pageStatus: published 7 | discussionId: 8 | --- 9 | 10 | To use these tools you will need to install them and configure your target environment (TFS or Azure DevOps). The following pages will guide you through the process: 11 | 12 | 1. [Installation](installation.md) 13 | 14 | The tools are run using `devopsmigration` from the command line. You can use the `--help` option to see the available commands. 15 | 16 | ```shell 17 | devopsmigration --help 18 | ``` 19 | 20 | 2. [Permissions](permissions.md) 21 | 22 | The tools require specific permissions on TFS or Azure DevOps to be able to run. This page will guide you through the minimum permissions required to run the tools. 23 | 24 | 3. [ReflectedWorkItemId](reflectedworkitemid.md) 25 | 26 | We use a field on the work item to track the migration of work items. This field is always referred to in the docs as `ReflectedWorkItemId` and is used to track the work item in the target. It enables the ability to resume migrations as well as to be able to scope the work items based on a query and have multiple runs overlap. 27 | 28 | 1. [Getting Started](../getstarted/) 29 | 30 | -------------------------------------------------------------------------------- /docs/staticwebapp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "responseOverrides": { 3 | "404": { 4 | "rewrite": "/404" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /spellcheck.yaml: -------------------------------------------------------------------------------- 1 | matrix: 2 | - name: Markdown 3 | sources: 4 | - 'docs/**/*.md' 5 | - 'src/**/*.md' 6 | - '*.md' 7 | default_encoding: utf-8 8 | aspell: 9 | lang: en 10 | dictionary: 11 | wordlists: 12 | - wordlist.txt 13 | encoding: utf-8 14 | pipeline: 15 | - pyspelling.filters.markdown: 16 | - pyspelling.filters.stylesheets: 17 | - pyspelling.filters.url: 18 | - pyspelling.filters.html: 19 | comments: false 20 | ignores: 21 | - code 22 | - pre 23 | - blockquote 24 | -------------------------------------------------------------------------------- /src/MigrationTools.Chocolatey/chocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | $toolsLoc = Get-ToolsLocation 2 | 3 | $vstssyncmigrationpath =Join-Path -Path $toolsLoc -ChildPath "\VSTSSyncMigration" 4 | $migrationtoolspath =Join-Path -Path $toolsLoc -ChildPath "\MigrationTools" 5 | 6 | if(test-path $vstssyncmigrationpath) { 7 | write-host "Cleaning out the contents of $vstssyncmigrationpath" 8 | Remove-Item "$($vstssyncmigrationpath)\*" -recurse -force -exclude *.json 9 | } 10 | 11 | if(test-path $migrationtoolspath) { 12 | write-host "Cleaning out the contents of $migrationtoolspath" 13 | Remove-Item "$($migrationtoolspath)\*" -recurse -force -exclude *.json 14 | } 15 | 16 | Install-ChocolateyZipPackage 'MigrationTools' 'https://github.com/nkdAgility/azure-devops-migration-tools/releases/download/v#{GITVERSION.SEMVER}#/MigrationTools-#{GITVERSION.SEMVER}#.zip' $migrationtoolspath -Checksum #{Chocolatey.FileHash}# -ChecksumType SHA256 17 | write-host 'Azure DevOps Migration have been installed. Call `migration` from the command line to see options. You may need to close and reopen the command shell.' 18 | -------------------------------------------------------------------------------- /src/MigrationTools.Chocolatey/chocolateyUninstall.ps1: -------------------------------------------------------------------------------- 1 | Uninstall-ChocolateyZipPackage 'vstssyncmigrator' 'vstssyncmigrator-#{GITVERSION.SEMVER}#.zip' 2 | Uninstall-ChocolateyZipPackage 'MigrationTools' 'MigrationTools-#{GITVERSION.SEMVER}#.zip' 3 | 4 | write-host 'Azure DevOps Migration Tools has been uninstalled.' 5 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest.Tests/MigrationTools.Clients.AzureDevops.Rest.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/AzureDevOpsExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; 3 | using MigrationTools.DataContracts; 4 | 5 | namespace MigrationTools.Clients.AzureDevops.Rest 6 | { 7 | public static class AzureDevOpsExtensions 8 | { 9 | public static WorkItemData ToWorkItemData(this WorkItem workItem) 10 | { 11 | var internalObject = new WorkItemData 12 | { 13 | Id = workItem.Id.ToString(), 14 | Type = "unknown", 15 | Title = "unknown", 16 | internalObject = workItem 17 | }; 18 | return internalObject; 19 | } 20 | 21 | public static WorkItem ToWorkItem(this WorkItemData workItemData) 22 | { 23 | if (!(workItemData.internalObject is WorkItem)) 24 | { 25 | throw new InvalidCastException($"The Work Item stored in the inner field must be of type {(typeof(WorkItem)).FullName}"); 26 | } 27 | return (WorkItem)workItemData.internalObject; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/Endpoints/AzureDevOpsEndpointOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using MigrationTools.Endpoints.Infrastructure; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Converters; 5 | 6 | namespace MigrationTools.Endpoints 7 | { 8 | public class AzureDevOpsEndpointOptions : EndpointOptions 9 | { 10 | [Required] 11 | [JsonConverter(typeof(StringEnumConverter))] 12 | public AuthenticationMode AuthenticationMode { get; set; } 13 | 14 | [Required] 15 | public string AccessToken { get; set; } 16 | 17 | [Required] 18 | public string Organisation { get; set; } 19 | 20 | [Required] 21 | public string Project { get; set; } 22 | 23 | [Required] 24 | public string ReflectedWorkItemIdField { get; set; } 25 | 26 | 27 | //public override void SetDefaults() 28 | //{ 29 | // base.SetDefaults(); 30 | // AccessToken = MigrationTools.Tests.TestingConstants.AccessToken; 31 | // Organisation = "https://dev.azure.com/nkdagility-preview/"; 32 | // Project = "NeedToSetThis"; 33 | // ReflectedWorkItemIdField = "Custom.ReflectedWorkItemId"; 34 | //} 35 | } 36 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/MigrationTools.Clients.AzureDevops.Rest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;net8.0 5 | MigrationTools.Clients.AzureDevops.Rest 6 | 7 | 8 | 9 | ..\..\docs\Reference\Generated\MigrationTools.Clients.AzureDevops.Rest.xml 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/Processors/KeepOutboundLinkTargetProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using MigrationTools.Processors; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Clients.AzureDevops.Rest.Processors 7 | { 8 | public class KeepOutboundLinkTargetProcessorOptions : ProcessorOptions 9 | { 10 | public KeepOutboundLinkTargetProcessorOptions() 11 | { 12 | WIQLQuery = "Select [System.Id] From WorkItems Where [System.TeamProject] = @project and not [System.WorkItemType] contains 'Test Suite, Test Plan,Shared Steps,Shared Parameter,Feedback Request'"; 13 | TargetLinksToKeepOrganization = "https://dev.azure.com/nkdagility"; 14 | TargetLinksToKeepProject = Guid.NewGuid().ToString(); 15 | DryRun = true; 16 | CleanupFileName = "c:/temp/OutboundLinkTargets.bat"; 17 | PrependCommand = "start"; 18 | } 19 | 20 | [Required] 21 | public string WIQLQuery { get; set; } 22 | 23 | public string TargetLinksToKeepOrganization { get; set; } 24 | public string TargetLinksToKeepProject { get; set; } 25 | public string CleanupFileName { get; set; } 26 | public string PrependCommand { get; set; } 27 | 28 | public bool DryRun { get; set; } 29 | 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/Processors/OutboundLinkCheckingProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using MigrationTools.Processors; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Clients.AzureDevops.Rest.Processors 7 | { 8 | public class OutboundLinkCheckingProcessorOptions : ProcessorOptions 9 | { 10 | [Required] 11 | public string WIQLQuery { get; set; } 12 | [Required] 13 | public string ResultFileName { get; set; } 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/Processors/ProcessDefinitionProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Processors.Infrastructure; 4 | 5 | namespace MigrationTools.Processors 6 | { 7 | public class ProcessDefinitionProcessorOptions : ProcessorOptions 8 | { 9 | public Dictionary> Processes { get; set; } 10 | public Dictionary ProcessMaps { get; set; } 11 | 12 | 13 | public bool UpdateProcessDetails { get; set; } 14 | public int MaxDegreeOfParallelism { get; set; } 15 | 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.AzureDevops.Rest/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Xml.Linq; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.TeamFoundation.TestManagement.WebApi; 6 | using MigrationTools.Clients.AzureDevops.Rest.Processors; 7 | using MigrationTools.Endpoints; 8 | using MigrationTools.Processors; 9 | 10 | namespace MigrationTools 11 | { 12 | public static partial class ServiceCollectionExtensions 13 | { 14 | public static void AddMigrationToolServicesForClientAzureDevopsRest(this IServiceCollection context, IConfiguration configuration) 15 | { 16 | context.AddConfiguredEndpoints(configuration); 17 | 18 | //TfsPipelines 19 | context.AddTransient(); 20 | context.AddTransient(); 21 | 22 | context.AddTransient(); 23 | context.AddTransient(); 24 | 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem.Tests/MigrationTools.Clients.FileSystem.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | MigrationTools.Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem.Tests/ServiceProviderHelper.cs: -------------------------------------------------------------------------------- 1 | //using Microsoft.Extensions.DependencyInjection; 2 | //using MigrationTools.Services; 3 | //using Microsoft.Extensions.Configuration; 4 | //using MigrationTools.Services.Shadows; 5 | //using MigrationTools.Shadows; 6 | 7 | //namespace MigrationTools.Tests 8 | //{ 9 | // internal static class ServiceProviderHelper 10 | // { 11 | // internal static ServiceProvider GetServices() 12 | // { 13 | // var configuration = new ConfigurationBuilder().Build(); 14 | // var services = new ServiceCollection(); 15 | // services.AddMigrationToolServicesForUnitTests(); 16 | 17 | // services.AddMigrationToolServices(configuration); 18 | // services.AddMigrationToolServicesForClientFileSystem(configuration); 19 | 20 | // services.AddSingleton(); 21 | // services.AddSingleton(); 22 | 23 | // return services.BuildServiceProvider(); 24 | // } 25 | // } 26 | //} -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem/Endpoints/FileSystemWorkItemEndpointOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Endpoints.Infrastructure; 2 | 3 | namespace MigrationTools.Endpoints 4 | { 5 | public class FileSystemWorkItemEndpointOptions : EndpointOptions 6 | { 7 | public string FileStore { get; set; } 8 | 9 | //public override void SetDefaults() 10 | //{ 11 | // FileStore = @"c:\temp\Store"; 12 | //} 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem/MigrationTools.Clients.FileSystem.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;net8.0 5 | MigrationTools.Sinks.FileSystem 6 | MigrationTools 7 | 8 | 9 | 10 | ..\..\docs\Reference\Generated\MigrationTools.Clients.FileSystem.xml 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem/MigrationTools.Sources.FileSystem.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | MigrationTools.Sinks.FileSystem 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.FileSystem/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using MigrationTools.Endpoints; 5 | 6 | namespace MigrationTools 7 | { 8 | public static partial class ServiceCollectionExtensions 9 | { 10 | public static void AddMigrationToolServicesForClientFileSystem(this IServiceCollection context, IConfiguration configuration) 11 | { 12 | context.AddConfiguredEndpoints(configuration); 13 | context.AddTransient(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel.Tests/Processors/Infra/FakeMigrationClientConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.Endpoints; 4 | using MigrationTools.Endpoints.Infrastructure; 5 | 6 | namespace _VstsSyncMigrator.Engine.Tests 7 | { 8 | [Obsolete] 9 | public class FakeMigrationClientConfig : EndpointOptions 10 | { 11 | public IEndpointOptions PopulateWithDefault() 12 | { 13 | return this; 14 | } 15 | 16 | public override string ToString() 17 | { 18 | return "FakeMigration"; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Clients/TfsTestPlanMigrationClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Extensions.Options; 4 | using MigrationTools._EngineV1.Configuration; 5 | using MigrationTools._EngineV1.DataContracts; 6 | using MigrationTools.Endpoints; 7 | using MigrationTools.Endpoints.Infrastructure; 8 | using MigrationTools.Options; 9 | 10 | namespace MigrationTools.Clients 11 | { 12 | public class TfsTestPlanMigrationClient : ITestPlanMigrationClient 13 | { 14 | 15 | 16 | public TfsTestPlanMigrationClient(IOptions options) 17 | { 18 | Options = options.Value; 19 | } 20 | 21 | public IEndpointOptions Options { get; set ; } 22 | 23 | public TestPlanData CreateTestPlan() 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | 28 | public List GetTestPlans() 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/EndPoints/TfsTeamProjectEndPointOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.Services.Client; 3 | using MigrationTools.Endpoints; 4 | using MigrationTools.Endpoints.Infrastructure; 5 | using MigrationTools.Options; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Converters; 8 | using TfsUrlParser; 9 | 10 | namespace MigrationTools.Endpoints 11 | { 12 | public class TfsTeamProjectEndpointOptions : TfsEndpointOptions 13 | { 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Endpoints/TfsLanguageMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.Extensions.Options; 4 | using Serilog; 5 | 6 | namespace MigrationTools.Endpoints 7 | { 8 | public class TfsLanguageMapOptions : IValidateOptions 9 | { 10 | public string AreaPath { get; set; } 11 | public string IterationPath { get; set; } 12 | 13 | public ValidateOptionsResult Validate(string name, TfsLanguageMapOptions options) 14 | { 15 | var errors = new List(); 16 | 17 | if (string.IsNullOrWhiteSpace(options.AreaPath)) 18 | { 19 | errors.Add("The AreaPath property must not be null or empty."); 20 | } 21 | if (string.IsNullOrWhiteSpace(options.IterationPath)) 22 | { 23 | errors.Add("The IterationPath property must not be null or empty."); 24 | } 25 | if (errors.Any()) 26 | { 27 | Log.Debug("TfsLanguageMapOptions::Validate::Fail"); 28 | ValidateOptionsResult.Fail(errors); 29 | } 30 | Log.Debug("TfsLanguageMapOptions::Validate::Success"); 31 | return ValidateOptionsResult.Success; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Endpoints/TfsTeamSettingsEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using Microsoft.TeamFoundation.Client; 5 | using Microsoft.TeamFoundation.ProcessConfiguration.Client; 6 | using Microsoft.TeamFoundation.Work.WebApi; 7 | using MigrationTools.EndpointEnrichers; 8 | 9 | namespace MigrationTools.Endpoints 10 | { 11 | public class TfsTeamSettingsEndpoint : GenericTfsEndpoint, ISourceEndPoint, ITargetEndPoint 12 | { 13 | public TfsTeamSettingsEndpoint(IOptions options, EndpointEnricherContainer endpointEnrichers, IServiceProvider serviceProvider, ITelemetryLogger telemetry, ILogger> logger) : base(options, endpointEnrichers, serviceProvider, telemetry, logger) 14 | { 15 | } 16 | 17 | public TfsTeamService TfsTeamService { get { return TfsCollection.GetService(); } } 18 | 19 | public TeamSettingsConfigurationService TfsTeamSettingsService { get { return TfsCollection.GetService(); } } 20 | 21 | public WorkHttpClient WorkHttpClient { get { return TfsCollection.GetClient(); } } 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Endpoints/TfsTeamSettingsEndpointOptions.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Endpoints 2 | { 3 | public class TfsTeamSettingsEndpointOptions : TfsEndpointOptions 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Endpoints/TfsWorkItemEndpointOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Options; 2 | 3 | namespace MigrationTools.Endpoints 4 | { 5 | public class TfsWorkItemEndpointOptions : TfsEndpointOptions 6 | { 7 | public QueryOptions Query { get; set; } 8 | 9 | //public override void SetDefaults() 10 | //{ 11 | // base.SetDefaults(); 12 | // Query = new Options.QueryOptions() 13 | // { 14 | // Query = "SELECT [System.Id], [System.Tags] " + 15 | // "FROM WorkItems " + 16 | // "WHERE [System.TeamProject] = @TeamProject " + 17 | // "AND [System.WorkItemType] NOT IN ('Test Suite', 'Test Plan') " + 18 | // "ORDER BY [System.ChangedDate] desc", 19 | // Paramiters = new Dictionary() { { "TeamProject", "migrationSource1" } } 20 | // }; 21 | //} 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/Infra/ConfigException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace MigrationTools.Processors.Infrastructure 5 | { 6 | [Serializable] 7 | internal class ConfigException : Exception 8 | { 9 | public ConfigException() 10 | { 11 | } 12 | 13 | public ConfigException(string message) : base(message) 14 | { 15 | } 16 | 17 | public ConfigException(string message, Exception innerException) : base(message, innerException) 18 | { 19 | } 20 | 21 | protected ConfigException(SerializationInfo info, StreamingContext context) : base(info, context) 22 | { 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsEmptyProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MigrationTools.Processors.Infrastructure; 7 | 8 | namespace MigrationTools.Processors 9 | { 10 | public class TfsEmptyProcessorOptions : ProcessorOptions 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportProfilePictureFromADProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | public class TfsExportProfilePictureFromADProcessorOptions : ProcessorOptions 9 | { 10 | 11 | 12 | /// 13 | /// The source domain where the pictures should be exported. 14 | /// 15 | /// String.Empty 16 | public string Domain { get; set; } 17 | 18 | /// 19 | /// The user name of the user that is used to export the pictures. 20 | /// 21 | /// String.Empty 22 | public string Username { get; set; } 23 | 24 | /// 25 | /// The password of the user that is used to export the pictures. 26 | /// 27 | /// String.Empty 28 | public string Password { get; set; } 29 | 30 | /// 31 | /// TODO: You wpuld need to customise this for your system. Clone repo and run in Debug 32 | /// 33 | /// String.Empty 34 | public string PictureEmpIDFormat { get; set; } 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Processors.Infrastructure; 2 | 3 | namespace MigrationTools.Processors 4 | { 5 | public class TfsExportUsersForMappingProcessorOptions : ProcessorOptions 6 | { 7 | 8 | public string WIQLQuery { get; set; } 9 | 10 | /// 11 | /// `OnlyListUsersInWorkItems` 12 | /// 13 | /// true 14 | public bool OnlyListUsersInWorkItems { get; set; } = true; 15 | 16 | /// 17 | /// Set to , if you want to export all users in source and target server. 18 | /// The lists of user can be useful, if you need tu manually edit mapping file. 19 | /// Users will be exported to file set in . 20 | /// 21 | public bool ExportAllUsers { get; set; } 22 | 23 | /// 24 | /// Path to export file where all source and target servers' users will be exported. 25 | /// Users are exported only if is set to . 26 | /// 27 | public string UserExportFile { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsImportProfilePictureProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | public class TfsImportProfilePictureProcessorOptions : ProcessorOptions 9 | { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsSharedQueryProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Endpoints; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | /// 9 | /// The `TfsSharedQueryProcessor` enabled you to migrate queries from one location to another. 10 | /// 11 | public class TfsSharedQueryProcessorOptions : ProcessorOptions 12 | { 13 | /// 14 | /// Do we add the source project name into the folder path 15 | /// 16 | /// false 17 | public bool PrefixProjectToNodes { get; set; } 18 | 19 | /// 20 | /// The name of the shared folder, made a parameter incase it every needs to be edited 21 | /// 22 | /// Shared Queries 23 | public string SharedFolderName { get; set; } = "Shared Queries"; 24 | 25 | /// 26 | /// Mapping of the source to the target 27 | /// 28 | public Dictionary SourceToTargetFieldMappings { get; set; } 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsTestConfigurationsMigrationProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Processors.Infrastructure; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | public class TfsTestConfigurationsMigrationProcessorOptions : ProcessorOptions 9 | { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsTestVariablesMigrationProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | public class TfsTestVariablesMigrationProcessorOptions : ProcessorOptions 9 | { 10 | /// 11 | public string Processor 12 | { 13 | get { return "TestVariablesMigrationContext"; } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemDeleteProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Processors; 4 | using MigrationTools._EngineV1.Configuration; 5 | using MigrationTools.Processors.Infrastructure; 6 | 7 | namespace MigrationTools.Processors 8 | { 9 | public class TfsWorkItemDeleteProcessorOptions : ProcessorOptions, IWorkItemProcessorConfig 10 | { 11 | 12 | 13 | public TfsWorkItemDeleteProcessorOptions() 14 | { 15 | Enabled = false; 16 | WIQLQuery = @"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @TeamProject AND [System.WorkItemType] NOT IN ('Test Suite', 'Test Plan','Shared Steps','Shared Parameter','Feedback Request') ORDER BY [System.ChangedDate] desc"; 17 | } 18 | 19 | public string WIQLQuery { get; set; } 20 | public IList WorkItemIDs { get; set; } 21 | public bool FilterWorkItemsThatAlreadyExistInTarget { get; set; } 22 | public bool PauseAfterEachWorkItem { get; set; } 23 | public int WorkItemCreateRetryLimit { get; set; } 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemOverwriteAreasAsTagsProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Processors.Infrastructure; 2 | 3 | namespace MigrationTools.Processors 4 | { 5 | public class TfsWorkItemOverwriteAreasAsTagsProcessorOptions : ProcessorOptions 6 | { 7 | /// 8 | /// This is a required parameter. That define the root path of the iteration. To get the full path use `\` 9 | /// 10 | /// \ 11 | public string AreaIterationPath { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/FieldMappingTool/FieldMaps/FieldLiteralMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.TeamFoundation.WorkItemTracking.Client; 4 | using MigrationTools._EngineV1.Configuration; 5 | using MigrationTools.Tools; 6 | using MigrationTools.Tools.Infrastructure; 7 | 8 | namespace MigrationTools.FieldMaps.AzureDevops.ObjectModel 9 | { 10 | public class FieldLiteralMap : FieldMapBase 11 | { 12 | public FieldLiteralMap(ILogger logger, ITelemetryLogger telemetryLogger) : base(logger, telemetryLogger) 13 | { 14 | } 15 | 16 | private FieldLiteralMapOptions Config { get { return (FieldLiteralMapOptions)_Config; } } 17 | 18 | public override void Configure(IFieldMapOptions config) 19 | { 20 | base.Configure(config); 21 | 22 | if (Config.targetField == null) 23 | { 24 | throw new ArgumentNullException($"The target field `{Config.targetField}` must be specified. Please use diferent fields."); 25 | } 26 | } 27 | 28 | public override string MappingDisplayName => $"{Config.value} -> {Config.targetField}"; 29 | 30 | internal override void InternalExecute(WorkItem source, WorkItem target) 31 | { 32 | target.Fields[Config.targetField].Value = Config.value; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/FieldMappingTool/FieldMaps/NodePathNotAnchoredException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MigrationTools.FieldMaps 8 | { 9 | public class NodePathNotAnchoredException: Exception 10 | { 11 | public NodePathNotAnchoredException() { } 12 | 13 | public NodePathNotAnchoredException(string message) : base(message) 14 | { 15 | 16 | } 17 | 18 | public NodePathNotAnchoredException(string message, Exception innerException) : base(message, innerException) { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsAttachmentToolOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Tools.Infrastructure; 2 | 3 | namespace MigrationTools.Tools 4 | { 5 | public class TfsAttachmentToolOptions : ToolOptions, ITfsAttachmentToolOptions 6 | { 7 | /// 8 | /// `AttachmentMigration` is set to true then you need to specify a working path for attachments to be saved locally. 9 | /// 10 | /// C:\temp\Migration\ 11 | public string ExportBasePath { get; set; } 12 | 13 | /// 14 | /// `AttachmentMigration` is set to true then you need to specify a max file size for upload in bites. 15 | /// For Azure DevOps Services the default is 480,000,000 bites (60mb), for TFS its 32,000,000 bites (4mb). 16 | /// 17 | /// 480000000 18 | public int MaxAttachmentSize { get; set; } 19 | } 20 | 21 | public interface ITfsAttachmentToolOptions 22 | { 23 | public string ExportBasePath { get; set; } 24 | public int MaxAttachmentSize { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsChangeSetMappingToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Tools.Infrastructure; 4 | 5 | namespace MigrationTools.Tools 6 | { 7 | public class TfsChangeSetMappingToolOptions : ToolOptions 8 | { 9 | 10 | public string ChangeSetMappingFile { get; set; } 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsEmbededImagesToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.TeamFoundation.Build.Client; 4 | using MigrationTools.Enrichers; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools 8 | { 9 | public class TfsEmbededImagesToolOptions : ToolOptions 10 | { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsGitRepositoryToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNet.Globbing; 4 | using Microsoft.Extensions.Options; 5 | using System.Text.RegularExpressions; 6 | using Microsoft.TeamFoundation.Build.Client; 7 | using MigrationTools.Enrichers; 8 | using MigrationTools.Tools.Infrastructure; 9 | 10 | namespace MigrationTools.Tools 11 | { 12 | public class TfsGitRepositoryToolOptions : ToolOptions 13 | { 14 | /// 15 | /// When set to True the changedset links will be dropped during the migration 16 | /// 17 | public bool ShouldDropChangedSetLinks { get; set; } 18 | 19 | /// 20 | /// List of work item mappings. 21 | /// 22 | /// {} 23 | public Dictionary Mappings { get; set; } = new Dictionary(); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsGitRepositoryToolOptionsValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Options; 7 | using Serilog; 8 | 9 | namespace MigrationTools.Tools 10 | { 11 | internal class TfsGitRepositoryToolOptionsValidator : IValidateOptions 12 | { 13 | public ValidateOptionsResult Validate(string name, TfsGitRepositoryToolOptions options) 14 | { 15 | if (options.Mappings == null) 16 | { 17 | Log.Debug("TfsGitRepositoryToolOptionsValidator::Validate::Fail"); 18 | return ValidateOptionsResult.Fail("Mappings must be set to at least an empty array"); 19 | } 20 | Log.Debug("TfsGitRepositoryToolOptionsValidator::Validate::Success"); 21 | return ValidateOptionsResult.Success; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsRevisionManagerToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Tools.Infrastructure; 4 | 5 | namespace MigrationTools.Tools 6 | { 7 | public class TfsRevisionManagerToolOptions : ToolOptions 8 | { 9 | 10 | /// 11 | /// You can choose to migrate the tip only (a single write) or all of the revisions (many writes). 12 | /// If you are setting this to `false` to migrate only the tip then you should set `BuildFieldTable` to `true`. 13 | /// 14 | /// true 15 | public bool ReplayRevisions { get; set; } 16 | 17 | /// 18 | /// Sets the maximum number of revisions that will be migrated. "First + Last N = Max". 19 | /// If this was set to 5 and there were 10 revisions you would get the first 1 (creation) and the latest 4 migrated. 20 | /// 21 | /// 0 22 | public int MaxRevisions { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsValidateRequiredFieldToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Tools.Infrastructure; 4 | 5 | namespace MigrationTools.Tools 6 | { 7 | public class TfsValidateRequiredFieldToolOptions : ToolOptions 8 | { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsWorkItemEmbededLinkToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.TeamFoundation.Build.Client; 4 | using MigrationTools.Enrichers; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools 8 | { 9 | public class TfsWorkItemEmbededLinkToolOptions : ToolOptions 10 | { 11 | 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools.Clients.TfsObjectModel/Tools/TfsWorkItemLinkToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.TeamFoundation.Build.Client; 4 | using MigrationTools.Enrichers; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools 8 | { 9 | public class TfsWorkItemLinkToolOptions : ToolOptions, ITfsWorkItemLinkToolOptions 10 | { 11 | 12 | /// 13 | /// Skip validating links if the number of links in the source and the target matches! 14 | /// 15 | public bool FilterIfLinkCountMatches { get; set; } 16 | 17 | 18 | /// 19 | /// Save the work item after each link is added. This will slow the migration as it will cause many saves to the TFS database. 20 | /// 21 | /// false 22 | public bool SaveAfterEachLinkIsAdded { get; set; } 23 | } 24 | 25 | public interface ITfsWorkItemLinkToolOptions 26 | { 27 | public bool FilterIfLinkCountMatches { get; set; } 28 | public bool SaveAfterEachLinkIsAdded { get; set; } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools.ConsoleCore/MigrationTools.ConsoleCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | Azure DevOps Migration Tools [REST API] 7 | devopsmigration 8 | 9 | 10 | 11 | 12 | Always 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/MigrationTools.ConsoleCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Hosting; 3 | using MigrationTools.Host; 4 | 5 | namespace MigrationTools.ConsoleCore 6 | { 7 | internal class Program 8 | { 9 | public static async Task Main(string[] args) 10 | { 11 | var hostBuilder = MigrationToolHost.CreateDefaultBuilder(args); 12 | if (hostBuilder is null) 13 | { 14 | return; 15 | } 16 | 17 | hostBuilder 18 | .ConfigureServices((context, services) => 19 | { 20 | // Field Mapps 21 | 22 | 23 | // Processors 24 | 25 | // Core 26 | // services.AddTransient(); 27 | }); 28 | await hostBuilder.RunConsoleAsync(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools.ConsoleCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "empty": { 4 | "commandName": "Project" 5 | }, 6 | "execute ": { 7 | "commandName": "Project", 8 | "commandLineArgs": "execute --config \"configuration.json\"" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/MigrationTools.ConsoleDataGenerator/CodeFileFinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MigrationTools.ConsoleDataGenerator 9 | { 10 | 11 | public class CodeFileFinder 12 | { 13 | private string codePath = ""; 14 | 15 | public CodeFileFinder(string path) 16 | { 17 | codePath = path; 18 | } 19 | 20 | public string FindCodeFile(Type typeToFind) 21 | { 22 | string assemblyName = typeToFind.Assembly.GetName().Name; 23 | string codePathToSearch = Path.Combine(codePath, assemblyName); 24 | List files = Directory.GetFiles(codePathToSearch, $"*{typeToFind.Name}*.cs", SearchOption.AllDirectories).ToList(); 25 | if (files.Count > 0) 26 | { 27 | var fileInfo = new FileInfo(files[0]); 28 | 29 | return files[0].Replace("../../../../..", "").Replace("\\", "/"); 30 | } 31 | return ""; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/MigrationTools.ConsoleFull/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "empty": { 4 | "commandName": "Project" 5 | }, 6 | "Execute -noconfig": { 7 | "commandName": "Project", 8 | "commandLineArgs": "execute" 9 | }, 10 | "execute": { 11 | "commandName": "Project", 12 | "commandLineArgs": "execute -c configuration.json --disableTelemetry" 13 | }, 14 | "execute --help": { 15 | "commandName": "Project", 16 | "commandLineArgs": "execute --help" 17 | }, 18 | "init Options-Basic": { 19 | "commandName": "Project", 20 | "commandLineArgs": "init --options Basic --overwrite -c configuration-basic.json " 21 | }, 22 | "init Options-Reference": { 23 | "commandName": "Project", 24 | "commandLineArgs": "init --options Reference -c configuration-ref.json --overwrite" 25 | }, 26 | "Upgrade": { 27 | "commandName": "Project", 28 | "commandLineArgs": "upgrade -c \"C:\\Users\\MartinHinshelwoodNKD\\source\\Danlewis3.json\" --debugTrace" 29 | }, 30 | "Execute Classic": { 31 | "commandName": "Project", 32 | "commandLineArgs": "execute -c \"configuration-classic.json\"" 33 | }, 34 | "Builder with Config": { 35 | "commandName": "Project", 36 | "commandLineArgs": "builder -c \"configuration.json\"" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/MigrationTools.Extension/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 naked Agility Limited - Martin Hinshelwood 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/MigrationTools.Extension/images/azure-devops-migration-tools-naked-agility-martin-hinshelwood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/src/MigrationTools.Extension/images/azure-devops-migration-tools-naked-agility-martin-hinshelwood.png -------------------------------------------------------------------------------- /src/MigrationTools.Extension/images/extension-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/src/MigrationTools.Extension/images/extension-icon.png -------------------------------------------------------------------------------- /src/MigrationTools.Extension/images/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-migration-tools/f69105ce6d3d9c78d1c7e95b972e66f06b6f457b/src/MigrationTools.Extension/images/screenshot-01.png -------------------------------------------------------------------------------- /src/MigrationTools.Helpers.Tests/MigrationTools.Helpers.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/MigrationTools.Host.Tests/MigrationHostTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace MigrationTools.Host.Tests 6 | { 7 | [TestClass()] 8 | public class MigrationHostTests 9 | { 10 | private IHost host; 11 | 12 | [TestInitialize] 13 | public void Setup() 14 | { 15 | host = MigrationToolHost.CreateDefaultBuilder(new string[] { "execute", "-c", "configuration.json" }).Build(); 16 | } 17 | 18 | [TestMethod, TestCategory("L2")] 19 | [Ignore("need to ignore for now, missing a good config file for non-objectmodel")] 20 | public void MigrationHostTest() 21 | { 22 | IMigrationEngine mh = host.Services.GetRequiredService(); 23 | } 24 | 25 | [TestMethod, TestCategory("L1")] 26 | [Ignore("need to ignore for now, untill we get some generic field maps")] 27 | public void TestEngineExecuteEmptyProcessors() 28 | { 29 | 30 | 31 | IMigrationEngine me = host.Services.GetRequiredService(); 32 | me.Run(); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/MigrationTools.Host.Tests/MigrationTools.Host.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | Always 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/MigrationTools.Host.Tests/Services/DetectOnlineServiceTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using MigrationTools.Services; 4 | using Serilog; 5 | using Serilog.Events; 6 | 7 | namespace MigrationTools.Host.Services.Tests 8 | { 9 | [TestClass] 10 | public class DetectOnlineServiceTests 11 | { 12 | [TestInitialize] 13 | public void Setup() 14 | { 15 | var loggers = new LoggerConfiguration().MinimumLevel.Verbose().Enrich.FromLogContext(); 16 | loggers.WriteTo.Logger(logger => logger 17 | .WriteTo.Debug(restrictedToMinimumLevel: LogEventLevel.Verbose)); 18 | Log.Logger = loggers.CreateLogger(); 19 | Log.Logger.Information("Logger is initialized"); 20 | } 21 | 22 | [TestMethod, TestCategory("L3")] 23 | public void DetectOnlineServiceTest() 24 | { 25 | var loggerFactory = new LoggerFactory().AddSerilog(); 26 | var dos = new DetectOnlineService(new TelemetryLoggerMock(), new Logger(loggerFactory)); 27 | var result = dos.IsOnline(); 28 | //Assert.IsTrue(result); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools.Host.Tests/Services/DetectVersionService2Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using MigrationTools.Services; 4 | using MigrationTools.Services.Shadows; 5 | using Serilog; 6 | using Serilog.Events; 7 | 8 | namespace MigrationTools.Host.Services.Tests 9 | { 10 | [TestClass] 11 | public class DetectVersionService2Tests 12 | { 13 | 14 | [TestInitialize] 15 | public void Setup() 16 | { 17 | var loggers = new LoggerConfiguration().MinimumLevel.Verbose().Enrich.FromLogContext(); 18 | loggers.WriteTo.Logger(logger => logger 19 | .WriteTo.Debug(restrictedToMinimumLevel: LogEventLevel.Verbose)); 20 | Log.Logger = loggers.CreateLogger(); 21 | Log.Logger.Information("Logger is initialized"); 22 | } 23 | 24 | 25 | [TestMethod, TestCategory("L3")] 26 | public void DetectVersionServiceTest_Initialise() 27 | { 28 | var loggerFactory = new LoggerFactory().AddSerilog(); 29 | IDetectVersionService2 dos = new DetectVersionService2(new TelemetryLoggerMock(), new Logger(loggerFactory), new FakeMigrationToolVersion()); 30 | Assert.IsNotNull(dos); 31 | 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/MigrationTools.Host.Tests/Services/DetectVersionServiceTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace MigrationTools.Host.Services.Tests 4 | { 5 | [TestClass] 6 | public class DetectVersionServiceTests 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/MigrationTools.Host/Commands/ConfigurationBuilderCommandSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Spectre.Console.Cli; 3 | 4 | namespace MigrationTools.Host.Commands 5 | { 6 | internal class ConfigurationBuilderCommandSettings : CommandSettingsBase 7 | { 8 | 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /src/MigrationTools.Host/Commands/ExecuteMigrationCommandSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.VisualStudio.Services.Common.CommandLine; 3 | using Spectre.Console.Cli; 4 | 5 | namespace MigrationTools.Host.Commands 6 | { 7 | internal class ExecuteMigrationCommandSettings : CommandSettingsBase 8 | { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /src/MigrationTools.Host/Commands/InitMigrationCommandSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using MigrationTools.Options; 3 | using Spectre.Console.Cli; 4 | 5 | namespace MigrationTools.Host.Commands 6 | { 7 | internal class InitMigrationCommandSettings : CommandSettingsBase 8 | { 9 | [Description("What type of config do you want to output? WorkItemTracking is the default.")] 10 | [CommandOption("--template|-t|--outputMode|--options")] 11 | [DefaultValue(OptionsConfigurationTemplate.WorkItemTracking)] 12 | public OptionsConfigurationTemplate Template { get; set; } 13 | 14 | [Description("Add to overwrite the existing file.")] 15 | [CommandOption("--overwrite|-o")] 16 | [DefaultValue(false)] 17 | public bool Overwrite { get; set; } 18 | 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/MigrationTools.Host/Commands/UpgradeConfigCommandSettings.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Spectre.Console.Cli; 3 | 4 | namespace MigrationTools.Host.Commands 5 | { 6 | internal class UpgradeConfigCommandSettings : CommandSettingsBase 7 | { 8 | 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /src/MigrationTools.Host/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using MigrationTools.Options; 4 | 5 | namespace MigrationTools 6 | { 7 | public static class ServiceCollectionExtensions 8 | { 9 | public static IServiceCollection AddConfiguredService(this IServiceCollection collection, IConfiguration config) 10 | { 11 | //if (collection == null) throw new ArgumentNullException(nameof(collection)); 12 | //if (config == null) throw new ArgumentNullException(nameof(config)); 13 | //collection.Configure 14 | //collection.Configure(config); 15 | //return collection.AddTransient(); 16 | 17 | return collection; 18 | } 19 | } 20 | } 21 | 22 | //https://www.youtube.com/watch?v=kLl2Mt3eYxU 23 | //https://csharp.christiannagel.com/2016/08/16/diwithconfiguration/ -------------------------------------------------------------------------------- /src/MigrationTools.Host/Services/IDetectOnlineService.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Host.Services 2 | { 3 | public interface IDetectOnlineService 4 | { 5 | bool IsOnline(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/MigrationTools.Host/Services/IDetectVersionService2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.Host.Services 4 | { 5 | public interface IDetectVersionService2 6 | { 7 | public Version AvailableVersion { get; } 8 | 9 | public Version InstalledVersion { get; } 10 | 11 | public Version RunningVersion { get; } 12 | 13 | public bool IsPackageManagerInstalled { get; } 14 | 15 | public bool IsPackageInstalled { get; } 16 | string PackageId { get; } 17 | 18 | bool IsUpdateAvailable { get; } 19 | bool IsRunningInDebug { get; } 20 | bool IsNewLocalVersionAvailable { get; } 21 | 22 | // void UpdateFromSource(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools.Samples/demo-migration-reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "TelemetryEnableTrace": true, 3 | "Target": { 4 | "Collection": "https://tfs.test.company.com/tfs/Coll2/", 5 | "Name": "ProjectName" 6 | }, 7 | "ReflectedWorkItemIdField": "TfsMigrationTool.ReflectedWorkItemId", 8 | "WorkItemTypeDefinition": { 9 | "Bug": "Bug", 10 | "User Story": "User Story", 11 | "Requirement": "Requirement", 12 | "Task": "Task", 13 | "Test Case": "Test Case", 14 | "Shared Steps": "Shared Steps", 15 | "Shared Parameter": "Shared Parameter" 16 | }, 17 | "FieldMaps": [{ 18 | "ObjectType": "VstsSyncMigrator.Engine.Configuration.FieldMap.FieldSkipMapOptions", 19 | "WorkItemTypeName": "*", 20 | "targetField": "TfsMigrationTool.ReflectedWorkItemId" 21 | }], 22 | "Processors": [{ 23 | "ObjectType": "WorkItemUpdateConfig", 24 | "WhatIf": false, 25 | "Enabled": true, 26 | "Query": "AND [TfsMigrationTool.ReflectedWorkItemId] <> '' AND [System.WorkItemType] IN ('Shared Steps', 'Shared Parameter', 'Test Case', 'Requirement', 'Task', 'User Story', 'Bug')" 27 | }] 28 | } -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Clients/WorkItemQueryBuilderFactoryFake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MigrationTools.Clients; 7 | 8 | namespace MigrationTools.Clients.Shadows 9 | { 10 | public class WorkItemQueryBuilderFactoryFake : IWorkItemQueryBuilderFactory 11 | { 12 | public IWorkItemQueryBuilder Create() 13 | { 14 | throw new NotImplementedException(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Endpoints/FakeEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Logging; 7 | using Microsoft.Extensions.Options; 8 | using MigrationTools.EndpointEnrichers; 9 | using MigrationTools.Endpoints; 10 | using MigrationTools.Endpoints.Infrastructure; 11 | 12 | namespace MigrationTools.Endpoints.Shadows 13 | { 14 | 15 | public class FakeEndpoint : Endpoint 16 | { 17 | new public FakeEndpointOptions Options => (FakeEndpointOptions)base.Options; 18 | 19 | public FakeEndpoint(IOptions options, EndpointEnricherContainer endpointEnrichers, IServiceProvider serviceProvider, ITelemetryLogger telemetry, ILogger logger) : base(options, endpointEnrichers, serviceProvider, telemetry, logger) 20 | { 21 | } 22 | 23 | [Obsolete("Dont know what this is for")] 24 | public override int Count => 0; 25 | } 26 | 27 | public class FakeEndpointOptions : EndpointOptions 28 | { 29 | public string Token { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/MigrationTools.Shadows.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net472;net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Processors/Infrastructure/MockComplexProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Logging; 7 | using Microsoft.Extensions.Options; 8 | using MigrationTools.Enrichers; 9 | using MigrationTools.Processors.Infrastructure; 10 | using MigrationTools.Tools; 11 | 12 | namespace MigrationTools.Processors.Infrastructure.Shadows 13 | { 14 | public class MockComplexProcessor : Processor 15 | { 16 | public MockComplexProcessor(IOptions options, CommonTools commonTools, ProcessorEnricherContainer processorEnrichers, IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(options, commonTools, processorEnrichers, services, telemetry, logger) 17 | { 18 | } 19 | 20 | protected override void InternalExecute() 21 | { 22 | // Do Nothing! 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Processors/Infrastructure/MockComplexProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MigrationTools.Processors.Infrastructure; 7 | 8 | namespace MigrationTool.Processors.Infrastructure.Shadows 9 | { 10 | public class MockComplexProcessorOptions : ProcessorOptions 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Processors/Infrastructure/MockSimpleProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors.Infrastructure.Shadows 7 | { 8 | public class MockSimpleProcessorOptions : ProcessorOptions 9 | { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Services/FakeMigrationToolVersion.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Services; 2 | 3 | namespace MigrationTools.Services.Shadows 4 | { 5 | public class FakeMigrationToolVersion : IMigrationToolVersion 6 | { 7 | public (Version version, string PreReleaseLabel, string versionString) GetRunningVersion() 8 | { 9 | return (new System.Version("0.0.0"), "test", "0.0.0-test"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Services/FakeMigrationToolVersionInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using MigrationTools.Services; 9 | 10 | namespace MigrationTools.Services.Shadows 11 | { 12 | public class FakeMigrationToolVersionInfo : IMigrationToolVersionInfo 13 | { 14 | public FakeMigrationToolVersionInfo() 15 | { 16 | ProductVersion = "0.0.0-test+7acec2e6266f5f05b2807264ee8f1db7b94b1949"; 17 | FileVersion = "0.0.0.0"; 18 | GitTag = "v0.0.0-test.0-0-g7acec2e"; 19 | } 20 | public FakeMigrationToolVersionInfo(string productVersion, string fileVersion, string gitTag) 21 | { 22 | ProductVersion = productVersion; 23 | FileVersion = fileVersion; 24 | GitTag = gitTag; 25 | } 26 | 27 | public string ProductVersion { get; set; } 28 | public string FileVersion { get; set; } 29 | public string GitTag { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Services/MeterFactoryFake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Metrics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MigrationTools.Services.Shadows 9 | { 10 | public class MeterFactoryFake : IMeterFactory 11 | { 12 | public Meter Create(MeterOptions options) 13 | { 14 | return new Meter(options); 15 | } 16 | 17 | public void Dispose() 18 | { 19 | // do nothing 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Services/TelemetryLoggerFake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.Services.Shadows 6 | { 7 | public class TelemetryLoggerFake : ITelemetryLogger 8 | { 9 | public string SessionId { get { return new Guid().ToString(); } } 10 | 11 | public void TrackException(Exception ex, IDictionary properties = null) 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | 16 | public void TrackException(Exception ex, IEnumerable> properties = null) 17 | { 18 | 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Tools/MockFieldMappingTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MigrationTools.DataContracts; 7 | using MigrationTools.Tools.Infrastructure; 8 | using MigrationTools.Tools.Interfaces; 9 | 10 | namespace MigrationTools.Tools.Shadows 11 | { 12 | public class MockFieldMappingTool : IFieldMappingTool 13 | { 14 | public Dictionary> Items => throw new NotImplementedException(); 15 | 16 | public void AddFieldMap(string workItemTypeName, IFieldMap fieldToTagFieldMap) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | public void ApplyFieldMappings(WorkItemData source, WorkItemData target) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | public void ApplyFieldMappings(WorkItemData target) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Tools/MockSimpleFieldMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools._EngineV1.Containers; 4 | using MigrationTools.DataContracts; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools.Shadows 8 | { 9 | public class MockSimpleFieldMap : IFieldMap 10 | { 11 | protected IFieldMapOptions _Config; 12 | 13 | public virtual void Configure(IFieldMapOptions config) 14 | { 15 | _Config = config; 16 | } 17 | 18 | public string Name 19 | { 20 | get 21 | { 22 | return this.GetType().Name; 23 | } 24 | } 25 | 26 | public string MappingDisplayName => "MockSimpleFieldMap"; 27 | 28 | public void Execute(WorkItemData source, WorkItemData target) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Tools/MockStringManipulatorTool.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Tools.Interfaces; 2 | 3 | namespace MigrationTools.Tools.Shadows 4 | { 5 | public class MockStringManipulatorTool : IStringManipulatorTool 6 | { 7 | public string? ProcessString(string? value) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Tools/MockWorkItemTypeMappingTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using MigrationTools.Tools.Interfaces; 7 | 8 | namespace MigrationTools.Tools.Shadows 9 | { 10 | public class MockWorkItemTypeMappingTool : IWorkItemTypeMappingTool 11 | { 12 | public Dictionary Mappings => throw new NotImplementedException(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/MigrationTools.Shadows/Tools/SimpleFieldMapConfigMock.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools._EngineV1.Configuration; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools.Shadows 5 | { 6 | public class MockSimpleFieldMapOptions : FieldMapOptions 7 | { 8 | public void SetExampleConfigDefaults() 9 | { 10 | throw new System.NotImplementedException(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.Functions.Worker; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | var host = new HostBuilder() 6 | .ConfigureFunctionsWebApplication() 7 | .ConfigureServices(services => 8 | { 9 | services.AddApplicationInsightsTelemetryWorkerService(); 10 | services.ConfigureFunctionsApplicationInsights(); 11 | }) 12 | .Build(); 13 | 14 | host.Run(); 15 | -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/PublishProfiles/MigrationToolsTelemetery - Web Deploy.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | MSDeploy 8 | AzureWebSite 9 | Release 10 | Any CPU 11 | https://migrationtoolstelemetery.azurewebsites.net 12 | false 13 | /subscriptions/c2d1c3f0-0945-44b4-a0ba-67c45e9d16ac/resourceGroups/MigrationTools/providers/Microsoft.Web/sites/MigrationToolsTelemetery 14 | win-x64 15 | false 16 | migrationtoolstelemetery.scm.azurewebsites.net:443 17 | WMSVC 18 | false 19 | true 20 | true 21 | MigrationToolsTelemetery 22 | 23 | -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "MigrationTools.Telemetery": { 4 | "commandName": "Project", 5 | "commandLineArgs": "--port 7008 --csharp" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery - Web Deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "storage1": { 4 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/migrationtoolstorewe", 5 | "type": "storage.azure", 6 | "connectionId": "AzureWebJobsStorage" 7 | }, 8 | "appInsights1": { 9 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/MigrationToolAI", 10 | "type": "appInsights.azure", 11 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/MigrationToolAI", 5 | "type": "appInsights.azure", 6 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" 7 | }, 8 | "storage1": { 9 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/migrationtoolstorewe", 10 | "type": "storage.azure", 11 | "connectionId": "AzureWebJobsStorage" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "storage1": { 4 | "type": "storage", 5 | "connectionId": "AzureWebJobsStorage" 6 | }, 7 | "appInsights1": { 8 | "type": "appInsights", 9 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights.sdk" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/MigrationTools.Telemetery/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | }, 9 | "enableLiveMetricsFilters": true 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools.Tests/Core/Configuration/FakeMigrationClientConfig.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools._EngineV1.Configuration; 2 | using MigrationTools.Endpoints; 3 | using MigrationTools.Endpoints.Infrastructure; 4 | 5 | namespace MigrationTools.Tests 6 | { 7 | public class FakeMigrationClientConfig : EndpointOptions 8 | { 9 | public IEndpointOptions PopulateWithDefault() 10 | { 11 | return this; 12 | } 13 | 14 | public override string ToString() 15 | { 16 | return "FakeMigration"; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/MigrationTools.Tests/MigrationTools.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/MigrationTools.Tests/Services/TelemetryClientAdapterTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights; 2 | using Microsoft.ApplicationInsights.Extensibility; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using MigrationTools; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace MigrationTools.Tests 12 | { 13 | [TestClass()] 14 | public class TelemetryClientAdapterTests 15 | { 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /src/MigrationTools.Tests/Services/TelemetryLoggerMock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.ApplicationInsights.DataContracts; 4 | 5 | namespace MigrationTools.Services 6 | { 7 | public class TelemetryLoggerMock : ITelemetryLogger 8 | { 9 | public bool EnableTrace { get; set; } 10 | 11 | public string SessionId => throw new NotImplementedException(); 12 | 13 | public void TrackException(Exception ex, IDictionary properties = null) 14 | { 15 | throw new NotImplementedException(); 16 | } 17 | 18 | public void TrackException(Exception ex, IEnumerable> properties = null) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools.WinGet/nkdAgility.AzureDevOpsMigrationTools.installer.yaml: -------------------------------------------------------------------------------- 1 | # Created using wingetcreate 1.6.1.0 2 | # yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json 3 | 4 | PackageIdentifier: nkdAgility.AzureDevOpsMigrationTools 5 | PackageVersion: 1.0.0.0 6 | InstallerType: zip 7 | NestedInstallerType: portable 8 | NestedInstallerFiles: 9 | - RelativeFilePath: devopsmigration.exe 10 | PortableCommandAlias: devopsmigration 11 | Installers: 12 | - InstallerUrl: https://github.com/nkdAgility/azure-devops-migration-tools/releases/download/v15.1.3-Preview.2/MigrationTools-15.1.3-Preview.2.zip 13 | Architecture: x64 14 | InstallerSha256: C112C8D1717EDF9632F69BBA408F2F45A5FF5B4F4AA22ED43433CB02ED187DE9 15 | ManifestType: installer 16 | ManifestVersion: 1.6.0 17 | -------------------------------------------------------------------------------- /src/MigrationTools.WinGet/nkdAgility.AzureDevOpsMigrationTools.locale.en-US.yaml: -------------------------------------------------------------------------------- 1 | # Created using wingetcreate 1.6.1.0 2 | # yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json 3 | 4 | PackageIdentifier: nkdAgility.AzureDevOpsMigrationTools 5 | PackageVersion: 13.0.4 6 | PackageLocale: en-US 7 | Publisher: naked Agility with Martin Hinshelwood & Co. 8 | PackageName: Azure DevOps Migration Tools 9 | License: MIT Licence 10 | ShortDescription: Azure DevOps Migration Tools allow you to migrate Teams, Backlogs, Tasks, Test Cases, and Plans & Suits from one Project to another in Azure DevOps / TFS both within the same Organisation, and between Organisations. 11 | ManifestType: defaultLocale 12 | ManifestVersion: 1.6.0 13 | -------------------------------------------------------------------------------- /src/MigrationTools.WinGet/nkdAgility.AzureDevOpsMigrationTools.yaml: -------------------------------------------------------------------------------- 1 | # Created using wingetcreate 1.6.1.0 2 | # yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json 3 | 4 | PackageIdentifier: nkdAgility.AzureDevOpsMigrationTools 5 | PackageVersion: 13.0.4 6 | DefaultLocale: en-US 7 | ManifestType: version 8 | ManifestVersion: 1.6.0 9 | -------------------------------------------------------------------------------- /src/MigrationTools/AppDomainExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MigrationTools 7 | { 8 | public static partial class AppDomainExtensions 9 | { 10 | public static IEnumerable GetMigrationToolsTypes(this AppDomain appDomain) 11 | { 12 | var assemblies = appDomain.GetAssemblies().Where(ass => (ass.FullName.StartsWith("MigrationTools") || ass.FullName.StartsWith("VstsSyncMigrator"))); 13 | return assemblies 14 | .SelectMany(assembly => assembly.GetTypes()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools/ConfigException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace MigrationTools 5 | { 6 | [Serializable] 7 | internal class ConfigException : Exception 8 | { 9 | public ConfigException() 10 | { 11 | } 12 | 13 | public ConfigException(string message) : base(message) 14 | { 15 | } 16 | 17 | public ConfigException(string message, Exception innerException) : base(message, innerException) 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/MigrationTools/Configuration/MigrationToolsConfiguration.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Collections.Generic; 3 | //using System.Text; 4 | //using MigrationTools._EngineV1.Configuration; 5 | //using MigrationTools.Processors; 6 | 7 | //namespace MigrationTools.Configuration 8 | //{ 9 | // public class MigrationToolsConfigurationOptions 10 | // { 11 | // public const string ConfigurationSectionName = "MigrationTools"; 12 | 13 | // public IMigrationClientConfig Source { get; set; } 14 | // public IMigrationClientConfig Target { get; set; } 15 | // public string Version { get; set; } 16 | 17 | // public ProcessorContainerOptions Processors { get; set; } 18 | 19 | // } 20 | //} 21 | -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/EnricherData.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.DataContracts 2 | { 3 | public abstract class EnricherData 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/FieldItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace MigrationTools.DataContracts 4 | { 5 | public class FieldItem 6 | { 7 | [JsonIgnore] 8 | public object internalObject { get; set; } 9 | 10 | public string ReferenceName { get; set; } 11 | public string Name { get; set; } 12 | public object Value { get; set; } 13 | public string FieldType { get; set; } 14 | public bool IsIdentity { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/IdentityItemData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace MigrationTools.DataContracts 4 | { 5 | public class IdentityItemData 6 | { 7 | public string Sid { get; set; } 8 | public string DisplayName { get; set; } 9 | public string Domain { get; set; } 10 | public string AccountName { get; set; } 11 | public string MailAddress { get; set; } 12 | } 13 | 14 | public class IdentityMapData 15 | { 16 | public IdentityItemData Source { get; set; } 17 | public IdentityItemData Target { get; set; } 18 | } 19 | 20 | public class IdentityMapResult 21 | { 22 | public List IdentityMap { get; set; } = []; 23 | public List SourceUsers { get; set; } = []; 24 | public List TargetUsers { get; set; } = []; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/LinkItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace MigrationTools.DataContracts 4 | { 5 | public class LinkItem 6 | { 7 | public LinkItemType LinkType { get; set; } 8 | public string LinkUri { get; set; } 9 | public string Comment { get; set; } 10 | public string ArtifactLinkType { get; set; } 11 | public int RelatedWorkItem { get; set; } 12 | public string LinkTypeEndImmutableName { get; set; } 13 | public string LinkTypeEndName { get; set; } 14 | 15 | [JsonIgnore] 16 | public object internalObject { get; set; } 17 | } 18 | 19 | public enum LinkItemType 20 | { 21 | Hyperlink, 22 | ExternalLink, 23 | RelatedLink 24 | } 25 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/Mapping.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.DataContracts 2 | { 3 | public class Mapping 4 | { 5 | public string SourceId { get; set; } 6 | public string TargetId { get; set; } 7 | public string Name { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/NodeStructureMissingItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MigrationTools.DataContracts 5 | { 6 | public class NodeStructureItem 7 | { 8 | public bool anchored { get; set; } = true; 9 | 10 | public string sourcePath { get; set; } 11 | public string sourceSystemPath { get; set; } 12 | public string targetPath { get; set; } 13 | public string targetSystemPath { get; set; } 14 | public string nodeType { get; set; } 15 | 16 | public DateTime? startDate { get; set; } 17 | public DateTime? finishDate { get; set; } 18 | 19 | public List workItems { get; set; } 20 | public bool sourcePathExists { get; set; } 21 | 22 | public override bool Equals(object obj) 23 | { 24 | var item = obj as NodeStructureItem; 25 | 26 | if (item == null) 27 | { 28 | return false; 29 | } 30 | 31 | return this.sourcePath.Equals(item.sourcePath); 32 | } 33 | 34 | public override int GetHashCode() 35 | { 36 | return this.sourcePath.GetHashCode(); 37 | } 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/Pipelines/DeploymentGroup.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.DataContracts.Pipelines 2 | { 3 | [ApiPath("distributedtask/deploymentgroups")] 4 | [ApiName("Deployment Groups")] 5 | public class DeploymentGroup : RestApiDefinition 6 | { 7 | public override bool HasTaskGroups() 8 | { 9 | return false; 10 | } 11 | 12 | public override bool HasVariableGroups() 13 | { 14 | return false; 15 | } 16 | 17 | public override void ResetObject() 18 | { 19 | //We are not migrating this, right now only using the names for mapping it over to target 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/Pipelines/GitRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.DataContracts.Pipelines 4 | { 5 | [ApiPath("git/repositories")] 6 | [ApiName("Git Repository")] 7 | public class GitRepository : RestApiDefinition 8 | { 9 | public Properties Properties { get; set; } 10 | 11 | public string Type { get; set; } 12 | 13 | public Uri Url { get; set; } 14 | 15 | public string DefaultBranch { get; set; } 16 | 17 | public bool Clean { get; set; } 18 | 19 | public bool CheckoutSubmodules { get; set; } 20 | 21 | public override bool HasTaskGroups() 22 | { 23 | return false; 24 | } 25 | 26 | public override bool HasVariableGroups() 27 | { 28 | return false; 29 | } 30 | 31 | public override void ResetObject() 32 | { 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/Pipelines/TaskAgentPool.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.DataContracts.Pipelines 2 | { 3 | [ApiPath("distributedtask/queues")] 4 | [ApiName("Agent Pools")] 5 | public class TaskAgentPool : RestApiDefinition 6 | { 7 | public override bool HasTaskGroups() 8 | { 9 | return false; 10 | } 11 | 12 | public override bool HasVariableGroups() 13 | { 14 | return false; 15 | } 16 | 17 | public override void ResetObject() 18 | { 19 | //We are not migrating this, right now only using the names for mapping it over to target 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/Pipelines/Tasks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.DataContracts.Pipelines 6 | { 7 | [ApiPath("distributedtask/tasks", false)] 8 | [ApiName("Tasks")] 9 | public class TaskDefinition : RestApiDefinition 10 | { 11 | public override bool HasTaskGroups() => false; 12 | 13 | public override bool HasVariableGroups() => false; 14 | 15 | public override void ResetObject() {} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools/DataContracts/RevisionItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MigrationTools.DataContracts 5 | { 6 | public class RevisionItem 7 | { 8 | public int WorkItemId { get; set; } 9 | public int Index { get; set; } 10 | public int Number { get; set; } 11 | public DateTime ChangedDate { get; set; } 12 | 13 | public DateTime OriginalChangedDate { get; set; } 14 | public string Type { get; set; } 15 | public Dictionary Fields { get; set; } 16 | public Dictionary EnricherData { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/MigrationTools/DisposableStopwatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace MigrationTools 5 | { 6 | public class DisposableStopwatch : IDisposable 7 | { 8 | private readonly Stopwatch sw; 9 | private readonly Action f; 10 | 11 | public DisposableStopwatch(Action f) 12 | { 13 | this.f = f; 14 | sw = Stopwatch.StartNew(); 15 | } 16 | 17 | public void Dispose() 18 | { 19 | sw.Stop(); 20 | f(sw.Elapsed); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/EndpointEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.Options; 3 | using Newtonsoft.Json; 4 | 5 | namespace MigrationTools.EndpointEnrichers 6 | { 7 | public abstract class EndpointEnricherOptions : IEndpointEnricherOptions 8 | { 9 | [JsonIgnore] 10 | public string OptionFor => $"{GetType().Name.Replace("Options", "")}"; 11 | 12 | [JsonIgnore] 13 | public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata 14 | { 15 | IsCollection = true, 16 | PathToInstance = null, 17 | ObjectName = $"ProcessorType", 18 | OptionFor = OptionFor, 19 | PathToDefault = $"MigrationTools:Endpoints:EnricherDefaults:{OptionFor}", 20 | PathToSample = $"MigrationTools:Endpoints:EnricherSamples:{OptionFor}" 21 | }; 22 | 23 | public bool Enabled { get; set; } 24 | 25 | public abstract Type ToConfigure { get; } 26 | public string RefName { get; set; } 27 | 28 | 29 | 30 | public abstract void SetDefaults(); 31 | } 32 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/IEndpointEnricher.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.DataContracts; 2 | using MigrationTools.Enrichers; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public interface IEndpointEnricher : IEnricher 7 | { 8 | void Configure(IEndpointEnricherOptions options); 9 | } 10 | 11 | public interface IEndpointSourceEnricher : IEndpointEnricher 12 | { 13 | } 14 | 15 | public interface IWorkItemEndpointSourceEnricher : IEndpointSourceEnricher 16 | { 17 | void EnrichWorkItemData(Endpoints.IEndpoint endpoint, object dataSource, RevisionItem dataTarget); 18 | } 19 | 20 | public interface IEndpointTargetEnricher : IEndpointEnricher 21 | { 22 | } 23 | 24 | public interface IWorkItemEndpointTargetEnricher : IEndpointTargetEnricher 25 | { 26 | } 27 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/IEndpointEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Enrichers; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | //[JsonConverter(typeof(OptionsJsonConvertor))] 6 | public interface IEndpointEnricherOptions : IEnricherOptions 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/IWorkItemEndpointEnricher.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.EndpointEnrichers 2 | { 3 | public interface IWorkItemEndpointEnricher : IEndpointEnricher 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemAttachmentEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public abstract class WorkItemAttachmentEnricher : WorkItemEndpointEnricher 7 | { 8 | private WorkItemAttachmentEnricherOptions _Options; 9 | 10 | public WorkItemAttachmentEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(services, telemetry, logger) 11 | { 12 | } 13 | 14 | public WorkItemAttachmentEnricherOptions Options 15 | { 16 | get { return _Options; } 17 | } 18 | 19 | public override void Configure(IEndpointEnricherOptions options) 20 | { 21 | _Options = (WorkItemAttachmentEnricherOptions)options; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemAttachmentEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | public class WorkItemAttachmentEnricherOptions : EndpointEnricherOptions 6 | { 7 | public string WorkingPath { get; set; } 8 | public int MaxSize { get; set; } 9 | 10 | public override Type ToConfigure => typeof(WorkItemAttachmentEnricher); 11 | 12 | public override void SetDefaults() 13 | { 14 | Enabled = true; 15 | WorkingPath = "c:\\temp\\WorkItemAttachmentWorkingFolder\\"; 16 | MaxSize = 480000000; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemCreatedEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public abstract class WorkItemCreatedEnricher : WorkItemEndpointEnricher 7 | { 8 | private WorkItemCreatedEnricherOptions _Options; 9 | 10 | public WorkItemCreatedEnricherOptions Options 11 | { 12 | get { return _Options; } 13 | } 14 | 15 | public WorkItemCreatedEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(services, telemetry, logger) 16 | { 17 | } 18 | 19 | public override void Configure(IEndpointEnricherOptions options) 20 | { 21 | _Options = (WorkItemCreatedEnricherOptions)options; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemCreatedEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | public class WorkItemCreatedEnricherOptions : EndpointEnricherOptions 6 | { 7 | public bool UpdateCreatedDate { get; set; } 8 | public bool UpdateCreatedBy { get; set; } 9 | 10 | public override Type ToConfigure => typeof(WorkItemCreatedEnricher); 11 | 12 | public override void SetDefaults() 13 | { 14 | Enabled = true; 15 | UpdateCreatedDate = true; 16 | UpdateCreatedBy = true; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemEmbedEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public abstract class WorkItemEmbedEnricher : WorkItemEndpointEnricher 7 | { 8 | private WorkItemEmbedEnricherOptions _Options; 9 | 10 | public WorkItemEmbedEnricherOptions Options 11 | { 12 | get { return _Options; } 13 | } 14 | 15 | public WorkItemEmbedEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(services, telemetry, logger) 16 | { 17 | } 18 | 19 | public override void Configure(IEndpointEnricherOptions options) 20 | { 21 | _Options = (WorkItemEmbedEnricherOptions)options; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemEmbedEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | public class WorkItemEmbedEnricherOptions : EndpointEnricherOptions 6 | { 7 | public string WorkingPath { get; set; } 8 | 9 | public override Type ToConfigure => typeof(WorkItemEmbedEnricher); 10 | 11 | public override void SetDefaults() 12 | { 13 | Enabled = true; 14 | WorkingPath = "c:\\temp\\WorkItemAttachmentWorkingFolder\\"; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemEndpointEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using MigrationTools.DataContracts; 4 | using MigrationTools.Endpoints; 5 | 6 | namespace MigrationTools.EndpointEnrichers 7 | { 8 | public abstract class WorkItemEndpointEnricher : IWorkItemEndpointSourceEnricher, IWorkItemEndpointTargetEnricher 9 | { 10 | public WorkItemEndpointEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) 11 | { 12 | Services = services; 13 | Telemetry = telemetry; 14 | Log = logger; 15 | } 16 | 17 | public IServiceProvider Services { get; } 18 | public ITelemetryLogger Telemetry { get; } 19 | public ILogger Log { get; } 20 | 21 | public abstract void Configure(IEndpointEnricherOptions options); 22 | 23 | public abstract void EnrichWorkItemData(IEndpoint endpoint, object dataSource, RevisionItem dataTarget); 24 | } 25 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemFieldTableEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public abstract class WorkItemFieldTableEnricher : WorkItemEndpointEnricher 7 | { 8 | private WorkItemFieldTableEnricherOptions _Options; 9 | 10 | public WorkItemFieldTableEnricherOptions Options 11 | { 12 | get { return _Options; } 13 | } 14 | 15 | public WorkItemFieldTableEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(services, telemetry, logger) 16 | { 17 | } 18 | 19 | public override void Configure(IEndpointEnricherOptions options) 20 | { 21 | _Options = (WorkItemFieldTableEnricherOptions)options; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemFieldTableEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | public class WorkItemFieldTableEnricherOptions : EndpointEnricherOptions 6 | { 7 | public override Type ToConfigure => typeof(WorkItemFieldTableEnricher); 8 | 9 | public override void SetDefaults() 10 | { 11 | Enabled = true; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemLinkEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace MigrationTools.EndpointEnrichers 5 | { 6 | public abstract class WorkItemLinkEnricher : WorkItemEndpointEnricher 7 | { 8 | private WorkItemLinkEnricherOptions _Options; 9 | 10 | public WorkItemLinkEnricherOptions Options 11 | { 12 | get { return _Options; } 13 | } 14 | 15 | public WorkItemLinkEnricher(IServiceProvider services, ITelemetryLogger telemetry, ILogger logger) : base(services, telemetry, logger) 16 | { 17 | } 18 | 19 | public override void Configure(IEndpointEnricherOptions options) 20 | { 21 | _Options = (WorkItemLinkEnricherOptions)options; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/EndpointEnrichers/WorkItemEndpointEnrichers/WorkItemLinkEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.EndpointEnrichers 4 | { 5 | public class WorkItemLinkEnricherOptions : EndpointEnricherOptions 6 | { 7 | public bool SaveEachAsAdded { get; set; } 8 | 9 | public override Type ToConfigure => typeof(WorkItemLinkEnricher); 10 | 11 | public override void SetDefaults() 12 | { 13 | Enabled = true; 14 | SaveEachAsAdded = false; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/AuthenticationMode.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Endpoints 2 | { 3 | public enum AuthenticationMode 4 | { 5 | AccessToken = 0, 6 | Windows = 1, 7 | Prompt = 2 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/IWorkItemQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Clients; 3 | using MigrationTools.DataContracts; 4 | 5 | namespace MigrationTools.Endpoints 6 | { 7 | public interface IWorkItemQuery 8 | { 9 | string Query { get; } 10 | 11 | void Configure(IMigrationClient migrationClient, string query, Dictionary parameters); 12 | 13 | List GetWorkItems(); 14 | 15 | List GetWorkItemIds(); 16 | } 17 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/Infrastructure/EndpointOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.EndpointEnrichers; 3 | using MigrationTools.Options; 4 | using Newtonsoft.Json; 5 | 6 | namespace MigrationTools.Endpoints.Infrastructure 7 | { 8 | public abstract class EndpointOptions : IEndpointOptions 9 | { 10 | [JsonIgnore] 11 | public string OptionFor => $"{GetType().Name.Replace("Options", "")}"; 12 | 13 | [JsonIgnore] 14 | public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata 15 | { 16 | IsCollection = false, 17 | IsKeyed = true, 18 | PathToInstance = $"MigrationTools:Endpoints:#KEY#:{OptionFor}", 19 | ObjectName = $"EndpointType", 20 | OptionFor = OptionFor, 21 | PathToDefault = $"MigrationTools:EndpointDefaults:{OptionFor}", 22 | PathToSample = $"MigrationTools:EndpointSamples:{OptionFor}" 23 | }; 24 | 25 | [JsonIgnore] 26 | public string Name { get; set; } 27 | 28 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 29 | public List EndpointEnrichers { get; set; } 30 | 31 | [JsonIgnore] 32 | public bool Enabled { get; set; } 33 | 34 | //public virtual void SetDefaults() 35 | //{ 36 | //} 37 | } 38 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/Infrastructure/IEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.EndpointEnrichers; 3 | using MigrationTools.Endpoints.Infrastructure; 4 | 5 | namespace MigrationTools.Endpoints 6 | { 7 | public interface IEndpoint 8 | { 9 | //void Configure(IEndpointOptions options); 10 | 11 | EndpointEnricherContainer EndpointEnrichers { get; } 12 | } 13 | 14 | public interface ISourceEndPoint : IEndpoint 15 | { 16 | int Count { get; } 17 | IEnumerable SourceEnrichers { get; } 18 | } 19 | 20 | public interface ITargetEndPoint : IEndpoint 21 | { 22 | IEnumerable TargetEnrichers { get; } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/Infrastructure/IEndpointOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.EndpointEnrichers; 3 | using MigrationTools.Options; 4 | 5 | namespace MigrationTools.Endpoints.Infrastructure 6 | { 7 | public interface IEndpointOptions : IOptions 8 | { 9 | //void SetDefaults(); 10 | string Name { get; set; } 11 | public List EndpointEnrichers { get; set; } 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /src/MigrationTools/Endpoints/Infrastructure/IWorkItemEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.DataContracts; 3 | using MigrationTools.Options; 4 | 5 | namespace MigrationTools.Endpoints 6 | { 7 | public interface IWorkItemSourceEndpoint : ISourceEndPoint, IWorkItemEndpoint 8 | { 9 | void Filter(IEnumerable targetWorkItems); 10 | 11 | IEnumerable GetWorkItems(); 12 | 13 | IEnumerable GetWorkItems(QueryOptions query); 14 | } 15 | 16 | public interface IWorkItemTargetEndpoint : ITargetEndPoint, IWorkItemEndpoint 17 | { 18 | void PersistWorkItem(WorkItemData sourceWorkItem); 19 | } 20 | 21 | public interface IWorkItemEndpoint : IEndpoint 22 | { 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/Enrichers/IEnricher.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Enrichers 2 | { 3 | public interface IEnricher 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/MigrationTools/Enrichers/IEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.Options; 2 | using Newtonsoft.Json; 3 | 4 | namespace MigrationTools.Enrichers 5 | { 6 | public interface IEnricherOptions : IOptions 7 | { 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /src/MigrationTools/Exceptions/MigrationToolsException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Elmah.Io.Client; 5 | using static MigrationTools.Exceptions.MigrationToolsException; 6 | 7 | namespace MigrationTools.Exceptions 8 | { 9 | 10 | public static class MigrationToolsExceptionExtensions 11 | { 12 | public static MigrationToolsException AsMigrationToolsException(this Exception ex, ExceptionSource errorSource) 13 | { 14 | return new MigrationToolsException(ex, errorSource); 15 | } 16 | } 17 | 18 | public class MigrationToolsException : Exception 19 | { 20 | public MigrationToolsException(Exception ex, ExceptionSource errorSource) : base(ex.Message) 21 | { 22 | this.ErrorSource = errorSource; 23 | } 24 | 25 | public ExceptionSource ErrorSource { get; } 26 | 27 | public enum ExceptionSource 28 | { 29 | Configuration, 30 | Internal 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/MigrationTools/Exceptions/UnknownLinkTypeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.Exceptions 4 | { 5 | public class UnknownLinkTypeException : Exception 6 | { 7 | public UnknownLinkTypeException(string message) : base(message) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/MigrationTools/IMigrationEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.Clients; 3 | using MigrationTools._EngineV1.Containers; 4 | using MigrationTools.Endpoints; 5 | using MigrationTools.Processors; 6 | using MigrationTools.Processors.Infrastructure; 7 | 8 | namespace MigrationTools 9 | { 10 | public interface IMigrationEngine 11 | { 12 | ProcessingStatus Run(); 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /src/MigrationTools/Options/ConfigurationMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.Options 6 | { 7 | public class ConfigurationMetadata 8 | { 9 | public string OptionFor { get; set; } 10 | public string PathToInstance { get; set; } 11 | public bool IsCollection { get; set; } = false; 12 | public string PathToDefault { get; set; } 13 | public string PathToSample { get; set; } 14 | public string ObjectName { get; set; } 15 | public bool IsKeyed { get; set; } = false; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools/Options/IOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Options; 6 | using Newtonsoft.Json; 7 | 8 | namespace MigrationTools.Options 9 | { 10 | 11 | public interface IOptions 12 | { 13 | [JsonIgnore] 14 | public ConfigurationMetadata ConfigurationMetadata { get; } 15 | 16 | /// 17 | /// Will be used if enabled 18 | /// 19 | [JsonProperty(Order = -200)] 20 | bool Enabled { get; set; } 21 | 22 | //public void SetExampleConfigSimple(); 23 | //public void SetExampleConfigFull(); 24 | 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/MigrationTools/Options/Infrastructure/DefaultOnlyConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace MigrationTools.Options.Infrastructure 5 | { 6 | 7 | 8 | public class DefaultOnlyConverter : JsonConverter 9 | { 10 | private readonly T _defaultValue; 11 | 12 | public DefaultOnlyConverter(T defaultValue) 13 | { 14 | _defaultValue = defaultValue; 15 | } 16 | 17 | public override bool CanConvert(Type objectType) 18 | { 19 | return true; 20 | } 21 | 22 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 23 | { 24 | // Always write the default value, no matter what the actual value is 25 | writer.WriteValue(_defaultValue); 26 | } 27 | 28 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 29 | { 30 | // Allow deserialization to work as normal 31 | return serializer.Deserialize(reader, objectType); 32 | } 33 | } 34 | 35 | 36 | } -------------------------------------------------------------------------------- /src/MigrationTools/Options/OptionsSerializationBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Newtonsoft.Json.Serialization; 4 | using Serilog; 5 | 6 | namespace MigrationTools.Options 7 | { 8 | public class OptionsSerializationBinder : ISerializationBinder 9 | { 10 | public void BindToName(Type serializedType, out string assemblyName, out string typeName) 11 | { 12 | assemblyName = null; 13 | typeName = serializedType.Name; 14 | } 15 | 16 | public Type BindToType(string assemblyName, string typeName) 17 | { 18 | Type type = AppDomain.CurrentDomain.GetAssemblies() 19 | .Where(a => !a.IsDynamic) 20 | .SelectMany(a => a.GetTypes()) 21 | .FirstOrDefault(t => t.Name.Equals(typeName) || t.FullName.Equals(typeName)); 22 | if (type is null || type.IsAbstract || type.IsInterface) 23 | { 24 | Log.Warning("Unable to load Processor: {typename}", typeName); 25 | throw new InvalidOperationException(); 26 | } 27 | return type; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools/Options/OptionsSerializeContractResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace MigrationTools.Options 6 | { 7 | public class OptionsSerializeContractResolver : DefaultContractResolver 8 | { 9 | protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 10 | { 11 | JsonProperty property = base.CreateProperty(member, memberSerialization); 12 | if (property.PropertyName == "RefName") 13 | { 14 | property.ShouldSerialize = instance => !string.IsNullOrEmpty((instance?.GetType().GetProperty(property.PropertyName).GetValue(instance)?.ToString())); 15 | } 16 | return property; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/MigrationTools/Options/QueryOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace MigrationTools.Options 5 | { 6 | public class QueryOptions 7 | { 8 | [Required] 9 | public string Query { get; set; } 10 | 11 | public Dictionary Parameters { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/IProcessorEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.DataContracts; 4 | using MigrationTools.Processors; 5 | using MigrationTools.Processors.Infrastructure; 6 | 7 | namespace MigrationTools.Enrichers 8 | { 9 | public interface IProcessorEnricher : IEnricher 10 | { 11 | void ProcessorExecutionBegin(IProcessor processor); 12 | 13 | void ProcessorExecutionEnd(IProcessor processor); 14 | 15 | void ProcessorExecutionAfterSource(IProcessor processor, List workItems); 16 | 17 | void ProcessorExecutionAfterProcessWorkItem(IProcessor processor, WorkItemData workitem); 18 | 19 | void ProcessorExecutionBeforeProcessWorkItem(IProcessor processor, WorkItemData workitem); 20 | 21 | void ProcessorExecutionWithFieldItem(IProcessor processor, FieldItem fieldItem); 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/IProcessorEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Enrichers 2 | { 3 | //[JsonConverter(typeof(OptionsJsonConvertor))] 4 | public interface IProcessorEnricherOptions : IEnricherOptions 5 | { 6 | } 7 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/PauseAfterEachItemOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools.Enrichers 4 | { 5 | public class PauseAfterEachItemOptions : ProcessorEnricherOptions 6 | { 7 | 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/ProcessorEnricherOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | using MigrationTools.Options; 4 | 5 | namespace MigrationTools.Enrichers 6 | { 7 | public abstract class ProcessorEnricherOptions : IProcessorEnricherOptions 8 | { 9 | [JsonIgnore] 10 | public string OptionFor => $"{GetType().Name.Replace("Options", "")}"; 11 | 12 | [JsonIgnore] 13 | public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata 14 | { 15 | IsCollection = true, 16 | PathToInstance = $"DemoProcessor:Enrichers", 17 | ObjectName = $"ProcessorEnricherType", 18 | OptionFor = OptionFor, 19 | PathToDefault = $"MigrationTools:ProcessorEnricherDefaults:{OptionFor}", 20 | PathToSample = $"MigrationTools:ProcessorEnricherSamples:{OptionFor}" 21 | }; 22 | 23 | /// 24 | /// If enabled this will run this migrator 25 | /// 26 | /// true 27 | public bool Enabled { get; set; } 28 | 29 | /// 30 | /// For internal use 31 | /// 32 | public string RefName { get; set; } 33 | 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/WorkItemProcessorEnrichers/IWorkItemProcessorEnricher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.DataContracts; 3 | 4 | namespace MigrationTools.Enrichers 5 | { 6 | public interface IWorkItemProcessorEnricher : IProcessorEnricher 7 | { 8 | 9 | [Obsolete("We are migrating to a new model. This is the old one.")] 10 | int Enrich(WorkItemData sourceWorkItem, WorkItemData targetWorkItem); 11 | } 12 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/WorkItemProcessorEnrichers/IWorkItemProcessorSourceEnricher.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.DataContracts; 2 | 3 | namespace MigrationTools.Enrichers 4 | { 5 | public interface IWorkItemProcessorSourceEnricher : IWorkItemProcessorEnricher 6 | { 7 | int EnrichToWorkItem(WorkItemData workItem); 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Enrichers/WorkItemProcessorEnrichers/IWorkItemProcessorTargetEnricher.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools.DataContracts; 2 | 3 | namespace MigrationTools.Enrichers 4 | { 5 | public interface IWorkItemProcessorTargetEnricher : IWorkItemProcessorEnricher 6 | { 7 | int PersistFromWorkItem(WorkItemData workItem); 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/IProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using MigrationTools._EngineV1.Configuration; 4 | using MigrationTools.Processors; 5 | 6 | namespace MigrationTools.Processors.Infrastructure 7 | { 8 | public interface IOldProcessor 9 | { 10 | string Name { get; } 11 | ProcessingStatus Status { get; } 12 | ProcessorType Type { get; } 13 | 14 | void Execute(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/IProcessor2.cs: -------------------------------------------------------------------------------- 1 | using MigrationTools._EngineV1.Containers; 2 | using MigrationTools.Endpoints; 3 | using MigrationTools.Enrichers; 4 | 5 | namespace MigrationTools.Processors.Infrastructure 6 | { 7 | public interface IProcessor : IOldProcessor 8 | { 9 | IEndpoint Source { get; } 10 | IEndpoint Target { get; } 11 | bool SupportsProcessorEnrichers { get; } 12 | ProcessorEnricherContainer ProcessorEnrichers { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/IProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using MigrationTools._EngineV1.Configuration; 4 | using MigrationTools.Enrichers; 5 | using MigrationTools.Options; 6 | 7 | namespace MigrationTools.Processors.Infrastructure 8 | { 9 | public interface IProcessorOptions : IProcessorConfig 10 | { 11 | /// 12 | /// This is the `IEndpoint` that will be used as the source of the Migration. Can be null for a write only processor. 13 | /// 14 | [Required] 15 | public string SourceName { get; } 16 | 17 | /// 18 | /// This is the `IEndpoint` that will be used as the Target of the Migration. Can be null for a read only processor. 19 | /// 20 | [Required] 21 | public string TargetName { get; } 22 | 23 | /// 24 | /// List of Enrichers that can be used to add more features to this processor. Only works with Native Processors and not legacy Processors. 25 | /// 26 | List Enrichers { get; set; } 27 | 28 | IProcessorOptions GetSample(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/InvalidProcessorException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.Processors.Infrastructure 6 | { 7 | public class InvalidProcessorException : Exception 8 | { 9 | 10 | public InvalidProcessorException() : base() 11 | { 12 | } 13 | public InvalidProcessorException(string message) : base(message) 14 | { 15 | } 16 | public InvalidProcessorException(string message, Exception innerException) : base(message, innerException) 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/ProcessorStatus.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Processors.Infrastructure 2 | { 3 | public enum ProcessingStatus { Running, Failed, Complete, None }; 4 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/Infrastructure/ProcessorType.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Processors.Infrastructure 2 | { 3 | public enum ProcessorType 4 | { 5 | Legacy = 0, 6 | AddHock = 1, 7 | Integrated = 3 8 | } 9 | } -------------------------------------------------------------------------------- /src/MigrationTools/Processors/WorkItemTrackingProcessorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Processors.Infrastructure; 5 | 6 | namespace MigrationTools.Processors 7 | { 8 | public class WorkItemTrackingProcessorOptions : ProcessorOptions 9 | { 10 | public bool ReplayRevisions { get; set; } 11 | public bool CollapseRevisions { get; set; } 12 | public int WorkItemCreateRetryLimit { get; set; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/MigrationTools/Services/ITelemetryLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MigrationTools 5 | { 6 | public interface ITelemetryLogger 7 | { 8 | string SessionId { get; } 9 | 10 | void TrackException(Exception ex, IDictionary properties = null); 11 | void TrackException(Exception ex, IEnumerable> properties = null); 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools/Services/LogLocationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace MigrationTools.Services 8 | { 9 | public class LogLocationService 10 | { 11 | private static string logDate = DateTime.Now.ToString("yyyyMMddHHmmss"); 12 | 13 | 14 | private static string _logsPath = CreateLogsPath(); 15 | 16 | public static string GetLogPath() 17 | { 18 | // Check if the string has been generated. 19 | if (_logsPath == null) 20 | { 21 | // Generate the string at runtime (e.g., any custom logic). 22 | _logsPath = CreateLogsPath(); 23 | } 24 | 25 | // Return the _logsPath string. 26 | return _logsPath; 27 | } 28 | 29 | private static string CreateLogsPath() 30 | { 31 | string exportPath; 32 | string assPath = Assembly.GetEntryAssembly().Location; 33 | exportPath = Path.Combine(Path.GetDirectoryName(assPath), "logs", logDate); 34 | if (!Directory.Exists(exportPath)) 35 | { 36 | Directory.CreateDirectory(exportPath); 37 | } 38 | 39 | return exportPath; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/MigrationTools/Services/ProcessorMetrics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Metrics; 4 | using System.Text; 5 | 6 | namespace MigrationTools.Services 7 | { 8 | public class ProcessorMetrics 9 | { 10 | public static readonly string meterName = "MigrationTools.Processors"; 11 | 12 | private readonly Meter WorkItemMeter; 13 | 14 | public Histogram Duration { get; private set; } 15 | public UpDownCounter QueueSize { get; private set; } 16 | 17 | public ProcessorMetrics(IMeterFactory meterFactory) 18 | { 19 | WorkItemMeter = meterFactory.Create(meterName); 20 | Duration = WorkItemMeter.CreateHistogram("processor_duration"); 21 | QueueSize = WorkItemMeter.CreateUpDownCounter("processor_queue_size"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/MigrationTools/Services/WorkItemMetrics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Metrics; 4 | using System.Text; 5 | using Microsoft.Extensions.Configuration; 6 | 7 | namespace MigrationTools.Services 8 | { 9 | public class WorkItemMetrics 10 | { 11 | public static readonly string meterName = "MigrationTools.WorkItems"; 12 | 13 | private readonly Meter WorkItemMeter; 14 | public Counter WorkItemsProcessedCount { get; private set ; } 15 | public Counter RevisionsProcessedCount { get; private set; } 16 | public Histogram ProcessingDuration { get; private set; } 17 | 18 | public Histogram RevisionsPerWorkItem { get; private set; } 19 | 20 | public WorkItemMetrics(IMeterFactory meterFactory) 21 | { 22 | WorkItemMeter = meterFactory.Create(meterName); 23 | WorkItemsProcessedCount = WorkItemMeter.CreateCounter("work_items_processed_total"); 24 | ProcessingDuration = WorkItemMeter.CreateHistogram("work_item_processing_duration"); 25 | RevisionsPerWorkItem = WorkItemMeter.CreateHistogram("work_item_revisions"); 26 | RevisionsProcessedCount = WorkItemMeter.CreateCounter("work_item_revisions_total"); 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/MigrationTools/StaticVariables.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /src/MigrationTools/Tests/TestHelpers.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Tests 2 | { 3 | public static class TestHelpers 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tests/TestingConstants.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Tests 2 | { 3 | public static class TestingConstants 4 | { 5 | public static string AccessToken { get { return AccessTokenRaw.Replace(@"fake", ""); } } 6 | public static readonly string AccessTokenRaw = "44exes7dbqq6vrpu4vfyaqmmjy6fake7xnqvulzgvzp2xmscuygc76fa"; 7 | } 8 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldClearMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Allows you to set an already populated field to Null. This will only work with fields that support null. 8 | /// 9 | /// ready 10 | /// Work Item 11 | public class FieldClearMapOptions : FieldMapOptions 12 | { 13 | public string targetField { get; set; } 14 | 15 | public void SetExampleConfigDefaults() 16 | { 17 | ApplyTo = new List() { "*" }; 18 | targetField = "System.Description"; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldLiteralMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Sets a field on the `target` to b a specific value. 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class FieldLiteralMapOptions : FieldMapOptions 12 | { 13 | 14 | public string targetField { get; set; } 15 | 16 | public string value { get; set; } 17 | 18 | public void SetExampleConfigDefaults() 19 | { 20 | ApplyTo = new List() { "*" }; 21 | targetField = "System.Status"; 22 | value = "New"; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldMergeMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Ever wanted to merge two or three fields? This mapping will let you do just that. 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class FieldMergeMapOptions : FieldMapOptions 12 | { 13 | public List sourceFields { get; set; } 14 | public string targetField { get; set; } 15 | public string formatExpression { get; set; } 16 | 17 | public void SetExampleConfigDefaults() 18 | { 19 | ApplyTo = new List { "System.Title" }; 20 | sourceFields = new List 21 | { 22 | "System.Description", 23 | "System.Status" 24 | }; 25 | targetField = "System.Description"; 26 | formatExpression = "{0} \n {1}"; 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldSkipMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Allows you to skip populating an existing field. Value in target with be reset to its OriginalValue. 8 | /// 9 | /// ready 10 | /// Work Item 11 | public class FieldSkipMapOptions : FieldMapOptions 12 | { 13 | public string targetField { get; set; } 14 | 15 | 16 | public void SetExampleConfigDefaults() 17 | { 18 | ApplyTo = new List() { "*" }; 19 | targetField = "System.Description"; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldValueMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Need to map not just the field but also values? This is the default value mapper. 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class FieldValueMapOptions : FieldMapOptions 12 | { 13 | public string sourceField { get; set; } 14 | public string targetField { get; set; } 15 | public string defaultValue { get; set; } 16 | public Dictionary valueMapping { get; set; } 17 | 18 | public void SetExampleConfigDefaults() 19 | { 20 | ApplyTo = new List() { "*" }; 21 | sourceField = "System.Status"; 22 | targetField = "System.Status"; 23 | defaultValue = "New"; 24 | valueMapping = new Dictionary 25 | { 26 | { "New", "New" }, 27 | { "Active", "Committed" }, 28 | { "Resolved", "Committed" }, 29 | { "Closed", "Done" } 30 | }; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldValuetoTagMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | namespace MigrationTools.Tools 4 | { 5 | /// 6 | /// Need to create a Tag based on a field value? Just create a regex match and choose how to populate the target. 7 | /// 8 | /// ready 9 | /// Work Item Field 10 | public class FieldValueToTagMapOptions : FieldMapOptions 11 | { 12 | public string sourceField { get; set; } 13 | public string pattern { get; set; } 14 | public string formatExpression { get; set; } 15 | 16 | public void SetExampleConfigDefaults() 17 | { 18 | ApplyTo = new List() { "*" }; 19 | sourceField = "System.Status"; 20 | pattern = "(Active|Resolved)"; 21 | formatExpression = "Status: {0}"; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldtoFieldMapOptions.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Collections.Generic; 3 | using MigrationTools.Tools.Infrastructure; 4 | 5 | namespace MigrationTools.Tools 6 | { 7 | /// 8 | /// Just want to map one field to another? This is the one for you. 9 | /// 10 | /// ready 11 | /// Work Item Field 12 | public class FieldToFieldMapOptions : FieldMapOptions 13 | { 14 | public string sourceField { get; set; } 15 | public string targetField { get; set; } 16 | public string defaultValue { get; set; } 17 | 18 | public void SetExampleConfigDefaults() 19 | { 20 | ApplyTo = new List() { "*" }; 21 | sourceField = "System.StackRank"; 22 | targetField = "System.Rank"; 23 | defaultValue = "1000"; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldtoFieldMultiMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Want to setup a bunch of field maps in a single go. Use this shortcut! 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class FieldToFieldMultiMapOptions : FieldMapOptions 12 | { 13 | public Dictionary SourceToTargetMappings { get; set; } 14 | 15 | public void SetExampleConfigDefaults() 16 | { 17 | ApplyTo = new List() { "*" }; 18 | SourceToTargetMappings = new Dictionary 19 | { 20 | { "Custom.Field1", "Custom.Field4" }, 21 | { "Custom.Field2", "Custom.Field5" }, 22 | { "Custom.Field3", "Custom.Field6" } 23 | }; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/FieldtoTagMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Options; 4 | using MigrationTools.Tools.Infrastructure; 5 | 6 | namespace MigrationTools.Tools 7 | { 8 | /// 9 | /// Want to take a field and convert its value to a tag? Done... 10 | /// 11 | /// ready 12 | /// Work Item Field 13 | public class FieldToTagFieldMapOptions : FieldMapOptions 14 | { 15 | public string sourceField { get; set; } 16 | public string formatExpression { get; set; } 17 | 18 | 19 | public void SetExampleConfigDefaults() 20 | { 21 | ApplyTo = new List() { "*" }; 22 | sourceField = "Custom.ProjectName"; 23 | formatExpression = "Project: {0}"; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/MultiValueConditionalMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// ??? If you know how to use this please send a PR :) 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class MultiValueConditionalMapOptions : FieldMapOptions 12 | { 13 | public Dictionary sourceFieldsAndValues { get; set; } 14 | public Dictionary targetFieldsAndValues { get; set; } 15 | 16 | public void SetExampleConfigDefaults() 17 | { 18 | ApplyTo = new List() { "*" }; 19 | sourceFieldsAndValues = new Dictionary 20 | { 21 | { "Something", "SomethingElse" } 22 | }; 23 | targetFieldsAndValues = new Dictionary 24 | { 25 | { "Something", "SomethingElse" } 26 | }; 27 | 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/RegexFieldMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | namespace MigrationTools.Tools 4 | { 5 | /// 6 | /// I just need that bit of a field... need to send "2016.2" to two fields, one for year and one for release? Done. 7 | /// 8 | /// ready 9 | /// Work Item Field 10 | public class RegexFieldMapOptions : FieldMapOptions 11 | { 12 | public string sourceField { get; set; } 13 | public string targetField { get; set; } 14 | public string pattern { get; set; } 15 | public string replacement { get; set; } 16 | 17 | public void SetExampleConfigDefaults() 18 | { 19 | ApplyTo = new List() { "*" }; 20 | sourceField = "Custom.MyVersion"; 21 | targetField = "Custom.MyVersionYearOnly"; 22 | pattern = "([0-9]{4})"; 23 | replacement = "$1"; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/FieldMaps/TreeToTagFieldMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Tools.Infrastructure; 3 | 4 | namespace MigrationTools.Tools 5 | { 6 | /// 7 | /// Need to clear out those nasty Area tree hierarchies? This creates Tags for each node in the Area Path... 8 | /// 9 | /// ready 10 | /// Work Item Field 11 | public class TreeToTagFieldMapOptions : FieldMapOptions 12 | { 13 | public int toSkip { get; set; } 14 | public int timeTravel { get; set; } 15 | 16 | public void SetExampleConfigDefaults() 17 | { 18 | ApplyTo = new List() { "*" }; 19 | toSkip = 2; 20 | timeTravel = 0; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingTool/Infrastructure/IFieldMapOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Options; 3 | using Newtonsoft.Json; 4 | 5 | namespace MigrationTools.Tools.Infrastructure 6 | { 7 | public interface IFieldMapOptions : IOptions 8 | { 9 | /// 10 | /// A list of Work Item Types that this Field Map will apply to. If the list is empty it will apply to all Work Item Types. You can use "*" to apply to all Work Item Types. 11 | /// 12 | [JsonProperty(Order = -1)] 13 | List ApplyTo { get; set; } 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/FieldMappingToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Options; 4 | using MigrationTools.Tools.Infrastructure; 5 | 6 | namespace MigrationTools.Tools 7 | { 8 | public class FieldMappingToolOptions : ToolOptions 9 | { 10 | public List FieldMaps { get; set; } = new List(); 11 | 12 | 13 | public class ConfigureOptions : IConfigureOptions 14 | { 15 | private readonly IConfiguration _configuration; 16 | 17 | public ConfigureOptions(IConfiguration configuration) 18 | { 19 | _configuration = configuration; 20 | } 21 | 22 | public void Configure(FieldMappingToolOptions options) 23 | { 24 | IConfigurationSection cfg = _configuration.GetSection(options.ConfigurationMetadata.PathToInstance); 25 | options.Enabled = cfg.GetValue(nameof(Enabled), defaultValue: false); 26 | options.FieldMaps = _configuration.GetSection(options.ConfigurationMetadata.PathToInstance + ":FieldMaps") 27 | ?.ToMigrationToolsList(child => child.GetMigrationToolsOption("FieldMapType")); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Infrastructure/ITool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.Tools.Infrastructure 6 | { 7 | public class ITool 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Infrastructure/IToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using MigrationTools.Options; 5 | using Newtonsoft.Json; 6 | 7 | namespace MigrationTools.Tools.Infrastructure 8 | { 9 | public interface IToolOptions : IOptions 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Infrastructure/Tool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Eventing.Reader; 4 | using System.Text; 5 | using Microsoft.Extensions.Logging; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace MigrationTools.Tools.Infrastructure 9 | { 10 | public abstract class Tool : ITool where TToolOptions : class, IToolOptions, new() 11 | { 12 | protected ITelemetryLogger Telemetry { get; } 13 | protected IServiceProvider Services { get; } 14 | protected ILogger Log { get; } 15 | protected Serilog.ILogger ContextLog {get;} 16 | 17 | protected TToolOptions Options { get; } 18 | 19 | public bool Enabled => Options.Enabled; 20 | 21 | public Tool(IOptions options, IServiceProvider services, ILogger logger, ITelemetryLogger telemetry) 22 | { 23 | if (options is null) 24 | { 25 | throw new ArgumentNullException(nameof(options)); 26 | } 27 | Options = options.Value; 28 | Services = services; 29 | Log = logger; 30 | ContextLog = Serilog.Log.ForContext>(); 31 | Telemetry = telemetry; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Infrastructure/ToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using MigrationTools.Options; 5 | using Newtonsoft.Json; 6 | 7 | namespace MigrationTools.Tools.Infrastructure 8 | { 9 | public abstract class ToolOptions : IToolOptions 10 | { 11 | [JsonIgnore] 12 | private string OptionFor => $"{GetType().Name.Replace("Options", "")}"; 13 | 14 | [JsonIgnore] 15 | public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata 16 | { 17 | PathToInstance = $"MigrationTools:CommonTools:{OptionFor}", 18 | ObjectName = $"ToolType", 19 | OptionFor = OptionFor, 20 | PathToDefault = $"MigrationTools:CommonTools:{OptionFor}", 21 | PathToSample = $"MigrationTools:CommonToolSamples:{OptionFor}" 22 | }; 23 | 24 | /// 25 | /// If set to `true` then the tool will run. Set to `false` and the processor will not run. 26 | /// 27 | 28 | public bool Enabled { get; set; } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Interfaces/IFieldMappingTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using MigrationTools.DataContracts; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools.Interfaces 8 | { 9 | public interface IFieldMappingTool 10 | { 11 | Dictionary> Items { get; } 12 | 13 | void AddFieldMap(string workItemTypeName, IFieldMap fieldToTagFieldMap); 14 | void ApplyFieldMappings(WorkItemData source, WorkItemData target); 15 | void ApplyFieldMappings(WorkItemData target); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Interfaces/IStringManipulatorTool.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Tools.Interfaces 2 | { 3 | public interface IStringManipulatorTool 4 | { 5 | string? ProcessString(string? value); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/Interfaces/IWorkItemTypeMappingTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MigrationTools.Tools.Interfaces 6 | { 7 | public interface IWorkItemTypeMappingTool 8 | { 9 | Dictionary Mappings { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/StaticTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using MigrationTools.Tools.Interfaces; 5 | 6 | namespace MigrationTools.Tools 7 | { 8 | public class CommonTools 9 | { 10 | public IStringManipulatorTool StringManipulator { get; private set; } 11 | public IWorkItemTypeMappingTool WorkItemTypeMapping { get; private set; } 12 | 13 | public IFieldMappingTool FieldMappingTool { get; private set; } 14 | public CommonTools(IStringManipulatorTool StringManipulatorTool, IWorkItemTypeMappingTool workItemTypeMapping, IFieldMappingTool fieldMappingTool) 15 | { 16 | StringManipulator = StringManipulatorTool; 17 | WorkItemTypeMapping = workItemTypeMapping; 18 | FieldMappingTool = fieldMappingTool; 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/StringManipulatorToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Options; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools 8 | { 9 | public class StringManipulatorToolOptions : ToolOptions 10 | { 11 | 12 | /// 13 | /// Max number of chars in a string. Applied last, and set to 1000000 by default. 14 | /// 15 | /// 1000000 16 | public int MaxStringLength { get; set; } 17 | 18 | /// 19 | /// List of regex based string manipulations to apply to all string fields. Each regex replacement is applied in order and can be enabled or disabled. 20 | /// 21 | /// {} 22 | public List Manipulators { get; set; } 23 | } 24 | 25 | public class RegexStringManipulator 26 | { 27 | public bool Enabled { get; set; } 28 | public string Pattern { get; set; } 29 | public string Replacement { get; set; } 30 | public string Description { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /src/MigrationTools/Tools/WorkItemTypeMappingTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | using Microsoft.Extensions.Logging; 6 | using Microsoft.Extensions.Options; 7 | using MigrationTools.DataContracts; 8 | using MigrationTools.Enrichers; 9 | using MigrationTools.Processors; 10 | using MigrationTools.Tools.Infrastructure; 11 | using MigrationTools.Tools.Interfaces; 12 | using static Microsoft.VisualStudio.Services.Graph.GraphResourceIds.Users; 13 | 14 | namespace MigrationTools.Tools 15 | { 16 | /// 17 | /// Used to process the String fields of a work item. This is useful for cleaning up data. It will limit fields to a max length and apply regex replacements based on what is configured. Each regex replacement is applied in order and can be enabled or disabled. 18 | /// 19 | public class WorkItemTypeMappingTool : Tool, IWorkItemTypeMappingTool 20 | { 21 | public Dictionary Mappings { get; private set; } 22 | 23 | public WorkItemTypeMappingTool(IOptions options, IServiceProvider services, ILogger logger, ITelemetryLogger telemetryLogger) 24 | : base(options, services, logger, telemetryLogger) 25 | { 26 | Mappings = Options.Mappings; 27 | } 28 | 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/MigrationTools/Tools/WorkItemTypeMappingToolOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MigrationTools.Enrichers; 4 | using MigrationTools.Options; 5 | using MigrationTools.Tools.Infrastructure; 6 | 7 | namespace MigrationTools.Tools 8 | { 9 | public class WorkItemTypeMappingToolOptions : ToolOptions 10 | { 11 | 12 | /// 13 | /// List of work item mappings. 14 | /// 15 | /// {} 16 | public Dictionary Mappings { get; set; } 17 | 18 | } 19 | 20 | public class RegexWorkItemTypeMapping 21 | { 22 | public bool Enabled { get; set; } 23 | public string Pattern { get; set; } 24 | public string Replacement { get; set; } 25 | public string Description { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/IMigrationClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Microsoft.VisualStudio.Services.Common; 3 | using Microsoft.VisualStudio.Services.WebApi; 4 | using MigrationTools._EngineV1.Configuration; 5 | using MigrationTools.Endpoints; 6 | using MigrationTools.Endpoints.Infrastructure; 7 | 8 | namespace MigrationTools.Clients 9 | { 10 | // TODO: Rename IMigrationClient to ITfsTeamProjectEndpoint 11 | public interface IMigrationClient 12 | { 13 | 14 | IWorkItemMigrationClient WorkItems { get; } 15 | ITestPlanMigrationClient TestPlans { get; } 16 | 17 | T GetService(); 18 | T GetClient() where T : IVssHttpClient; 19 | 20 | object InternalCollection { get; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/ITestPlanMigrationClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools._EngineV1.DataContracts; 4 | using MigrationTools.Endpoints; 5 | using MigrationTools.Endpoints.Infrastructure; 6 | 7 | namespace MigrationTools.Clients 8 | { 9 | public interface ITestPlanMigrationClient 10 | { 11 | IEndpointOptions Options { get; set; } 12 | 13 | 14 | List GetTestPlans(); 15 | 16 | TestPlanData CreateTestPlan(); 17 | } 18 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/IWorkItemQueryBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Endpoints; 3 | 4 | namespace MigrationTools.Clients 5 | { 6 | public interface IWorkItemQueryBuilder 7 | { 8 | string Query { get; set; } 9 | 10 | void AddParameter(string name, string value); 11 | 12 | IWorkItemQuery BuildWIQLQuery(IMigrationClient migrationClient); 13 | } 14 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/IWorkItemQueryBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools.Clients 2 | { 3 | public interface IWorkItemQueryBuilderFactory 4 | { 5 | IWorkItemQueryBuilder Create(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/ReflectedWorkItemId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools.DataContracts; 3 | 4 | namespace MigrationTools.Clients 5 | { 6 | public abstract class ReflectedWorkItemId 7 | { 8 | public ReflectedWorkItemId(WorkItemData workItem) 9 | { 10 | if (workItem is null) 11 | { 12 | throw new ArgumentNullException(nameof(workItem)); 13 | } 14 | 15 | WorkItemId = workItem.Id; 16 | } 17 | 18 | public ReflectedWorkItemId(string ReflectedWorkItemId) 19 | { 20 | if (ReflectedWorkItemId is null) 21 | { 22 | throw new ArgumentNullException(nameof(ReflectedWorkItemId)); 23 | } 24 | WorkItemId = ReflectedWorkItemId; 25 | } 26 | 27 | public ReflectedWorkItemId(int ReflectedWorkItemId) 28 | { 29 | if (ReflectedWorkItemId == 0) 30 | { 31 | throw new ArgumentNullException(nameof(ReflectedWorkItemId)); 32 | } 33 | WorkItemId = ReflectedWorkItemId.ToString(); 34 | } 35 | 36 | public override string ToString() 37 | { 38 | return WorkItemId; 39 | } 40 | 41 | public string WorkItemId 42 | { 43 | get; private set; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Clients/WorkItemQueryBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace MigrationTools.Clients 5 | { 6 | public class WorkItemQueryBuilderFactory : IWorkItemQueryBuilderFactory 7 | { 8 | private readonly IServiceProvider _serviceProvider; 9 | 10 | public WorkItemQueryBuilderFactory(IServiceProvider serviceProvider) 11 | { 12 | _serviceProvider = serviceProvider; 13 | } 14 | public IWorkItemQueryBuilder Create() 15 | { 16 | return _serviceProvider.GetService(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Configuration/IProcessorConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using MigrationTools.Enrichers; 3 | using MigrationTools.Options; 4 | using Newtonsoft.Json; 5 | 6 | namespace MigrationTools._EngineV1.Configuration 7 | { 8 | public interface IProcessorConfig : IOptions 9 | { 10 | /// 11 | /// Indicates, if this processor can be added to the list of current processors or not. 12 | /// Some processors are not compatible with each other. 13 | /// 14 | /// List of already configured processors. 15 | bool IsProcessorCompatible(IReadOnlyList otherProcessors); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Configuration/IWorkItemProcessorConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace MigrationTools._EngineV1.Configuration 4 | { 5 | public interface IWorkItemProcessorConfig : IProcessorConfig 6 | { 7 | public string WIQLQuery { get; set; } 8 | 9 | 10 | public IList WorkItemIDs { get; set; } 11 | public bool FilterWorkItemsThatAlreadyExistInTarget { get; set; } 12 | public bool PauseAfterEachWorkItem { get; set; } 13 | public int WorkItemCreateRetryLimit { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Containers/EngineContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Options; 3 | using MigrationTools._EngineV1.Configuration; 4 | 5 | namespace MigrationTools._EngineV1.Containers 6 | { 7 | public abstract class EngineContainer 8 | { 9 | private readonly IServiceProvider _services; 10 | private bool _configured = false; 11 | 12 | public abstract TItemType Items 13 | { get; } 14 | 15 | public static implicit operator TItemType(EngineContainer ecType) 16 | { 17 | return ecType.Items; 18 | } 19 | 20 | protected IServiceProvider Services 21 | { 22 | get { return _services; } 23 | } 24 | 25 | 26 | protected EngineContainer(IServiceProvider services) 27 | { 28 | _services = services; 29 | } 30 | 31 | protected abstract void Configure(); 32 | 33 | public void EnsureConfigured() 34 | { 35 | if (!_configured) 36 | { 37 | Configure(); 38 | _configured = true; 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/Containers/IFieldMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MigrationTools._EngineV1.Configuration; 3 | using MigrationTools.DataContracts; 4 | using MigrationTools.Tools.Infrastructure; 5 | 6 | namespace MigrationTools.Tools.Infrastructure 7 | { 8 | public interface IFieldMap 9 | { 10 | string Name { get; } 11 | string MappingDisplayName { get; } 12 | 13 | [Obsolete] 14 | void Configure(IFieldMapOptions config); 15 | 16 | void Execute(WorkItemData source, WorkItemData target); 17 | } 18 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/DataContracts/ProjectData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MigrationTools._EngineV1.DataContracts 4 | { 5 | public class ProjectData 6 | { 7 | public string Id { get; set; } 8 | public string Name { get; set; } 9 | public object internalObject { get; set; } 10 | public string Url { get; set; } 11 | public Guid Guid { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/MigrationTools/_EngineV1/DataContracts/TestPlanData.cs: -------------------------------------------------------------------------------- 1 | namespace MigrationTools._EngineV1.DataContracts 2 | { 3 | public class TestPlanData 4 | { 5 | public string Id { get; set; } 6 | 7 | public object internalObject { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /triggertest.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - main 8 | tags: 9 | - '*' 10 | - '!v*-*' 11 | pull_request: 12 | branches: 13 | - main 14 | workflow_dispatch: 15 | 16 | jobs: 17 | Test: 18 | name: "Test " 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: "Test" 22 | shell: pwsh 23 | id: nkdagility 24 | run: | 25 | Write-Output "Hello World" -------------------------------------------------------------------------------- /wordlist.txt: -------------------------------------------------------------------------------- 1 | DoD 2 | Cynefin 3 | SDK 4 | Cogan 5 | Burndown 6 | Walkthrough 7 | https 8 | timeboxes 9 | timebox 10 | timeboxed 11 | PBI 12 | PBI's 13 | EBM 14 | Kanban 15 | UX 16 | UI 17 | TOC 18 | toc 19 | NORTHWIND 20 | CONTOSO 21 | DEV 22 | FABRIKAM 23 | DevOps 24 | SonarQube 25 | uptime 26 | Bitbucket 27 | Jira 28 | Repos 29 | nkdagility 30 | Hinshelwood 31 | PMI 32 | mins 33 | SLE 34 | DoR 35 | accountabilities 36 | PBIs 37 | codebase 38 | WIP 39 | toolset 40 | Scrum's 41 | counterintuitive 42 | inspectable 43 | impactful 44 | http 45 | liberatingstructures 46 | pre 47 | hoc 48 | scrumguides 49 | url 50 | kickstart 51 | DIB 52 | pageType 53 | pageStatus 54 | discussionId 55 | sellable --------------------------------------------------------------------------------