From c74d11912abacf3468641fc7aa1ef7d194584b59 Mon Sep 17 00:00:00 2001 From: Derek Ng Date: Tue, 22 Jul 2025 11:21:31 -0700 Subject: [PATCH 1/2] Release 5.3.0 --- .config/dotnet-tools.json | 2 +- .editorconfig | 23 +- .github/.vars.default | 2 + .github/ISSUE_TEMPLATE/bug_report.md | 38 - .github/ISSUE_TEMPLATE/feature_request.md | 25 - .github/actions/clean-dotnet/action.yml | 50 + .github/actions/setup-dotnet/action.yml | 47 +- .github/workflows/README.md | 117 ++- .github/workflows/build-docs.yml | 13 +- .github/workflows/build-dotnet.yml | 26 +- .github/workflows/build-python-package.yml | 5 +- .github/workflows/deploy-all.yml | 5 + .github/workflows/deploy-docs.yml | 3 +- .github/workflows/deploy-dotnet.yml | 34 +- .github/workflows/sdk-workflow.yml | 29 +- .github/workflows/test-dotnet.yml | 57 +- .github/workflows/test-python.yml | 28 +- Directory.Build.props | 4 +- Migration SDK.sln | 21 +- .../Csharp.ExampleApplication.csproj | 2 +- .../SetMigrationContextHook.cs | 2 +- .../PostPublish/UpdatePermissionsHook.cs | 6 +- .../ModifyPermissionsTransformer.cs | 29 + .../MyMigrationApplication.cs | 5 + examples/Csharp.ExampleApplication/Program.cs | 4 + .../appsettings.json | 3 +- .../packages.lock.json | 994 +++++++++--------- ...endencyInjection.ExampleApplication.csproj | 2 +- .../packages.lock.json | 666 ++++++------ .../modify_permissions_transformer.py | 10 + .../Python.ExampleApplication.pyproj | 1 + .../Python.ExampleApplication/pyproject.toml | 2 +- .../requirements.txt | 2 +- src/Documentation/articles/configuration.md | 20 +- src/Documentation/articles/logging.md | 1 + .../configuration/sdk_opts_content_types.html | 16 +- .../configuration/sdk_opts_network.html | 28 +- .../post-publish/update_permissions.md | 3 +- .../samples/transformers/index.md | 3 +- .../transformers/modify_permissions.md | 44 + .../samples/transformers/toc.yml | 4 +- src/Python/Python.pyproj | 4 +- src/Python/pyproject.toml | 10 +- src/Python/pytest.ini | 3 +- src/Python/requirements.txt | 4 +- src/Python/src/tableau_migration/__init__.py | 38 +- src/Python/src/tableau_migration/migration.py | 32 +- .../tableau_migration/migration_content.py | 127 ++- .../migration_content_permissions.py | 75 +- .../migration_content_search.py | 69 ++ .../migration_engine_endpoints_search.py | 63 +- .../migration_engine_hooks.py | 2 +- .../migration_engine_hooks_filters.py | 2 +- ...ation_engine_hooks_initializemigration.py} | 4 +- .../migration_engine_hooks_interop.py | 4 +- .../migration_engine_hooks_transformers.py | 2 +- .../migration_engine_pipelines.py | 34 +- src/Python/tests/test_classes.py | 214 ++-- src/Python/tests/test_migration.py | 16 + src/Python/tests/test_migration_content.py | 109 ++ .../test_migration_content_permissions.py | 46 +- .../tests/test_migration_content_search.py | 53 + .../tests/test_migration_engine_hooks.py | 6 +- ...est_migration_engine_hooks_transformers.py | 40 +- .../tests/test_migration_engine_pipelines.py | 10 + src/Python/tests/test_other.py | 3 - .../Generators/PythonDocstringGenerator.cs | 2 +- .../Generators/PythonMemberGenerator.cs | 8 + .../Generators/PythonMethodGenerator.cs | 51 +- .../PythonGenerationList.cs | 14 + .../PythonMethod.cs | 3 +- .../PythonTestGenerationList.cs | 3 + .../PythonType.cs | 5 + .../Tableau.Migration.PythonGenerator.csproj | 2 +- .../Writers/PythonMemberWriter.cs | 26 +- .../Writers/PythonMethodWriter.cs | 52 +- .../Writers/PythonTestWriter.cs | 12 +- .../packages.lock.json | 501 ++++----- .../Api/ContentApiClientBase.cs | 10 + .../Api/CustomViewsApiClient.cs | 27 +- .../Api/DataSourcesApiClient.cs | 15 +- .../Api/FavoritesApiClient.cs | 233 ++++ .../Api/FavoritesApiListPager.cs | 69 ++ src/Tableau.Migration/Api/FlowsApiClient.cs | 13 +- .../Api/GroupSetsApiClient.cs | 286 +++++ src/Tableau.Migration/Api/GroupsApiClient.cs | 2 +- ...ContentReferenceFinderFactoryExtensions.cs | 27 + .../Api/IFavoritesApiClient.cs | 71 ++ .../Api/IGroupSetsApiClient.cs | 51 + .../Api/IServiceCollectionExtensions.cs | 2 + src/Tableau.Migration/Api/ISitesApiClient.cs | 17 + .../Api/Models/IPublishFileOptions.cs | 10 +- .../Api/Models/PublishCustomViewOptions.cs | 14 +- .../Api/Models/PublishDataSourceOptions.cs | 13 +- .../Api/Models/PublishFileOptionsBase.cs | 58 + .../Api/Models/PublishFlowOptions.cs | 14 +- .../Api/Models/PublishWorkbookOptions.cs | 14 +- .../Api/PublishContentWithFileOptions.cs | 70 -- .../Api/Publishing/FilePublisherBase.cs | 33 +- .../Api/Rest/Models/IFavoriteType.cs | 55 + .../Rest/Models/IFavoriteTypeExtensions.cs | 62 ++ .../Rest/Models/IGroupSetType.cs} | 19 +- .../Api/Rest/Models/ParentContentTypeNames.cs | 15 - .../Models/Requests/AddFavoriteRequest.cs | 286 +++++ .../Models/Requests/CreateGroupSetRequest.cs | 62 ++ .../Rest/Models/Requests/UpdateSiteRequest.cs | 36 +- .../Models/Responses/CollectionsResponse.cs | 86 ++ .../Responses/CreateGroupSetResponse.cs | 59 ++ .../Models/Responses/FavoritesResponse.cs | 264 +++++ .../Rest/Models/Responses/GroupSetResponse.cs | 83 ++ .../Models/Responses/GroupSetsResponse.cs | 60 ++ .../Api/Rest/Models/Responses/SiteResponse.cs | 16 +- .../Api/Rest/RestErrorCodes.cs | 2 + .../Api/Rest/RestUrlKeywords.cs | 3 +- .../Api/Rest/RestUrlPrefixes.cs | 32 +- .../Search/BulkApiContentReferenceCache.cs | 4 + .../Rest/Api/FavoritesRestApiSimulator.cs | 106 ++ .../Rest/Api/GroupSetsRestApiSimulator.cs | 155 +++ .../Rest/Api/ViewsRestApiSimulator.cs | 18 +- .../Rest/Net/Requests/RestUrlPatterns.cs | 3 + .../RestAddFavoriteResponseBuilder.cs | 97 ++ ...RestCommitWorkbookUploadResponseBuilder.cs | 16 + .../RestGetFavoritesForUserResponseBuilder.cs | 153 +++ .../RestGroupSetCreateResponseBuilder.cs | 78 ++ .../RestPermissionsCreateResponseBuilder.cs | 2 +- .../Api/Simulation/Rest/RestApiSimulator.cs | 14 +- .../Api/Simulation/SimulatedWorkbookData.cs | 10 +- .../Api/Simulation/TableauData.cs | 109 +- src/Tableau.Migration/Api/SitesApiClient.cs | 24 + .../Api/WorkbooksApiClient.cs | 18 +- src/Tableau.Migration/Config/CacheOptions.cs | 46 + .../Config/ContentTypesOptions.cs | 53 +- .../Config/MigrationSDKOptions.cs | 9 +- .../Config/NetworkOptions.cs | 15 + src/Tableau.Migration/Content/Favorite.cs | 73 ++ .../Content/FavoriteContentType.cs | 61 ++ .../Content/FavoriteContentTypeExtensions.cs | 65 ++ src/Tableau.Migration/Content/GroupSet.cs | 41 + src/Tableau.Migration/Content/IFavorite.cs | 45 + .../IGroupSet.cs} | 10 +- .../Content/IPublishableGroupSet.cs | 32 + src/Tableau.Migration/Content/ISite.cs | 5 + .../Content/ISiteSettingsUpdate.cs | 12 +- .../ITableauCollection.cs} | 8 +- src/Tableau.Migration/Content/IView.cs | 3 +- .../Content/MappableContainerContentBase.cs | 5 +- .../Content/MappableContentBase.cs | 39 + .../Content/Permissions/IPermissionSet.cs | 32 + .../Content/Permissions/IPermissions.cs | 17 +- .../Content/Permissions/Permissions.cs | 24 +- .../Content/PublishableGroupSet.cs | 40 + .../Search/CachedContentReferenceFinder.cs | 5 + .../Search/ContentReferenceCacheBase.cs | 68 +- .../Content/Search/IContentReferenceCache.cs | 8 + .../Content/Search/IContentReferenceFinder.cs | 8 + .../Search/IContentReferenceFinderFactory.cs | 29 +- src/Tableau.Migration/Content/Site.cs | 7 +- .../Content/SiteSettingsUpdate.cs | 13 +- src/Tableau.Migration/Content/View.cs | 4 + .../Engine/Actions/MigrateContentAction.cs | 2 +- .../Engine/Actions/PreflightAction.cs | 38 +- .../Caching/ConfigurableMigrationCacheBase.cs | 187 ++++ .../Engine/Caching/IMigrationCache.cs | 48 + .../Endpoints/Caching/IEndpointViewCache.cs | 29 + .../Caching/IEndpointWorkbookViewsCache.cs | 30 + .../Caching/TableauApiEndpointViewCache.cs | 52 + .../TableauApiEndpointWorkbookViewsCache.cs | 62 ++ .../ContentClients/ApiContentClientFactory.cs | 83 -- .../ContentClients/ContentClientBase.cs | 4 +- .../ContentClients/FavoritesContentClient.cs | 59 ++ .../ContentClients/IFavoritesContentClient.cs | 48 + .../ContentClients/ViewsContentClient.cs | 20 +- .../ContentClients/WorkbooksContentClient.cs | 23 +- .../Engine/Endpoints/IMigrationEndpoint.cs | 66 +- .../Endpoints/MigrationEndpointFactory.cs | 9 +- .../Search/DestinationViewReferenceFinder.cs | 92 ++ .../IDestinationContentReferenceFinder.cs | 13 +- ...estinationContentReferenceFinderFactory.cs | 19 + .../Search/IDestinationViewReferenceFinder.cs | 21 + ...nifestDestinationContentReferenceFinder.cs | 5 + .../ManifestSourceContentReferenceFinder.cs | 12 + .../TableauApiDestinationEndpoint.cs | 5 +- .../Endpoints/TableauApiEndpointBase.cs | 38 +- .../Endpoints/TableauApiSourceEndpoint.cs | 5 +- .../Hooks/Filters/AsyncContentFilterBase.cs | 72 ++ .../Engine/Hooks/Filters/ContentFilterBase.cs | 42 +- .../Hooks/Filters/Default/FavoriteFilter.cs | 104 ++ .../Hooks/Filters/RootContentFilterBase.cs | 62 ++ .../EmbeddedCredentialsCapabilityManager.cs | 29 +- .../EndpointSettingCapabilityManagerBase.cs | 81 ++ .../GroupSetsCapabilityManager.cs | 40 + .../IMigrationCapabilityManager.cs | 9 +- .../MigrationCapabilityManagerBase.cs | 70 ++ .../SubscriptionsCapabilityManager.cs | 43 + .../EmbeddedCredentialsPreflightCheck.cs | 50 - .../Default/InitializeCapabilitiesHook.cs | 118 +++ .../Default/SubscriptionsPreflightCheck.cs | 50 - .../EndpointPreflightContext.cs | 26 + .../IEndpointPreflightContext.cs | 43 + .../IInitializeMigrationContext.cs | 42 + .../IInitializeMigrationHook.cs | 2 +- .../IInitializeMigrationHookResult.cs | 16 +- .../InitializeMigrationCapabilityHookBase.cs | 112 -- .../InitializeMigrationHookResult.cs | 24 +- .../Hooks/Mappings/Default/FavoriteMapping.cs | 78 ++ .../Hooks/MigrationCapabilityManagerBase.cs | 48 - .../ChildItemsPermissionsPostPublishHook.cs | 34 +- .../DeleteUserFavoritesPostPublishHook.cs | 78 ++ .../Default/PermissionPostPublishHookBase.cs | 31 +- .../Default/PermissionsItemPostPublishHook.cs | 42 +- .../PopulateViewCachePostPublishHook.cs | 55 + .../Default/ProjectPostPublishHook.cs | 28 +- .../Hooks/SubscriptionsCapabilityManager.cs | 57 - .../Transformers/ContentTransformerBase.cs | 1 - .../Default/FavoriteTransformer.cs | 80 ++ .../Default/GroupSetGroupsTransformer.cs | 82 ++ .../Default/IContentReferenceExtensions.cs | 44 + .../Default/IPermissionsTransformer.cs | 3 +- .../Default/PermissionsTransformer.cs | 63 +- .../Default/SubscriptionTransformer.cs | 73 +- .../Engine/IServiceCollectionExtensions.cs | 41 +- .../MigrationManifestContentTypePartition.cs | 23 +- .../Engine/MigrationPlanBuilder.cs | 32 +- .../CloudToCloudMigrationPipeline.cs | 29 +- .../Engine/Pipelines/MigrationPipelineBase.cs | 3 + .../Pipelines/MigrationPipelineContentType.cs | 36 +- .../ServerToCloudMigrationPipeline.cs | 31 +- .../ServerToServerMigrationPipeline.cs | 29 +- .../Pipelines/TableauMigrationPipelineBase.cs | 74 ++ .../Preparation/ContentItemPreparerBase.cs | 2 +- .../IEmptyIdContentReference.cs | 34 + .../IMigrationCapabilities.cs | 5 - .../IMigrationCapabilitiesEditor.cs | 5 - src/Tableau.Migration/IResult.cs | 18 + .../Hooks/ISyncInitializeMigrationHook.cs | 2 +- .../Interop/IServiceCollectionExtensions.cs | 18 +- .../MigrationCapabilities.cs | 8 +- .../Net/Handlers/LoggingHttpHandler.cs | 30 +- .../Net/IServiceCollectionExtensions.cs | 7 +- .../Net/Logging/HttpActivityDetailsBuilder.cs | 217 ++++ .../Net/Logging/HttpActivityLogger.cs | 103 ++ .../HttpContentRedactor.cs} | 22 +- .../IHttpActivityLogger.cs} | 16 +- .../IHttpContentRedactor.cs} | 4 +- .../Net/NetworkTraceLogger.cs | 272 ----- .../CallbackPager.cs} | 25 +- src/Tableau.Migration/Paging/MemoryPager.cs | 42 +- .../Paging/MemoryPagerBase.cs | 73 ++ .../Resources/SharedResourceKeys.cs | 37 +- .../Resources/SharedResources.resx | 51 +- .../Tableau.Migration.csproj | 17 +- src/Tableau.Migration/TypeExtensions.cs | 2 +- src/Tableau.Migration/packages.lock.json | 612 ++++++----- .../pyproject.toml | 12 +- .../requirements.txt | 10 +- tests/Python.TestApplication/pyproject.toml | 6 +- tests/Python.TestApplication/requirements.txt | 2 +- .../TimeLoggerAfterActionHook.cs | 2 +- .../LogMigrationBatchSummaryHook.cs | 2 +- ...anifestAfterBatchMigrationCompletedHook.cs | 2 +- .../{ => Filters}/NonDomainUserFilter.cs | 2 +- .../SkipByParentLocationFilter.cs | 2 +- .../Hooks/{ => Filters}/SkipFilter.cs | 2 +- .../Hooks/{ => Filters}/SkipIdsFilter.cs | 2 +- .../Hooks/{ => Filters}/SpecialUserFilter.cs | 2 +- .../{ => Filters}/UnlicensedUserFilter.cs | 2 +- .../ContentWithinSkippedLocationMapping.cs | 2 +- .../{ => Mappings}/SpecialUserMapping.cs | 2 +- .../TestTableauCloudUsernameMapping.cs | 14 +- .../TestTableauCloudUsernameOptions.cs | 2 +- .../{ => Mappings}/UnlicensedUserMapping.cs | 2 +- ...ngDestinationUsersFromGroupsTransformer.cs | 2 +- .../ViewerOwnerTransformer.cs | 2 +- .../IServiceCollectionExtensions.cs | 6 +- .../LogFileHelper.cs | 9 +- .../SerilogExtensions.cs | 37 +- .../Tableau.Migration.TestApplication.csproj | 8 +- .../TestApplication.cs | 10 +- .../appsettings.json | 12 + .../packages.lock.json | 541 +++++----- .../Tableau.Migration.Tests/FixtureFactory.cs | 4 + .../Tableau.Migration.Tests/MockHttpClient.cs | 35 +- .../PageInfoSpecimenBuilder.cs | 87 ++ .../ResultExtensions.cs | 9 +- .../DataPreparation/CommonDataPreparation.cs | 174 +++ .../CustomViewsDataPreparation.cs | 126 +++ .../DataSourcesDataPreparation.cs | 80 ++ .../ExtractRefreshTasksDataPreparation.cs | 112 ++ .../FavoritesDataPreparation.cs | 77 ++ .../GroupSetsDataPreparation.cs | 102 ++ .../DataPreparation/GroupsDataPreparation.cs | 61 ++ .../ProjectsDataPreparation.cs | 133 +++ .../SchedulesDataPreparation.cs | 144 +++ .../SubscriptionsDataPreparation.cs | 82 ++ .../DataPreparation/UsersDataPreparation.cs | 95 ++ .../WorkbooksDataPreparation.cs | 113 ++ .../ServerToCloudSimulationTestBase.cs | 803 ++------------ .../Simulation/TableauDataExtensions.cs | 31 + .../Tests/Api/DataSourcesApiClientTests.cs | 8 +- .../Tests/Api/FavoritesApiClientTests.cs | 223 ++++ .../Tests/Api/GroupSetsApiClientTests.cs | 166 +++ .../PermissionsContentApiClientTestBase.cs | 2 +- .../Tests/Api/WorkbooksApiClientTests.cs | 16 +- .../Tests/CustomViewsMigrationTests.cs | 12 +- .../Tests/DataSourceMigrationTests.cs | 24 +- .../Tests/ExtractRefreshTaskMigrationTests.cs | 12 +- .../Tests/FavoritesMigrationTests.cs | 129 +++ .../Simulation/Tests/GroupMigrationTests.cs | 10 +- .../Tests/GroupSetMigrationTests.cs | 149 +++ .../Simulation/Tests/HookTests.cs | 23 +- .../Tests/IncrementalMigrationTests.cs | 30 +- .../Simulation/Tests/MigratorTests.cs | 39 +- .../Simulation/Tests/ProjectMigrationTests.cs | 12 +- .../Tests/SubscriptionMigrationTests.cs | 16 +- .../Simulation/Tests/UserMigrationTests.cs | 10 +- .../Tests/WorkbookMigrationTests.cs | 16 +- .../Tableau.Migration.Tests.csproj | 12 +- .../Unit/Api/ApiClientTestDependencies.cs | 7 +- .../Unit/Api/ApiTestBase.cs | 8 +- .../Unit/Api/CustomViewsApiClientTests.cs | 1 + .../Unit/Api/DataSourcesApiClientTests.cs | 6 +- .../Unit/Api/FavoritesApiClientTests.cs | 362 +++++++ .../Unit/Api/FavoritesApiListPagerTests.cs | 99 ++ .../Unit/Api/GroupSetsApiClientTests.cs | 572 ++++++++++ ...ntReferenceFinderFactoryExtensionsTests.cs | 96 +- .../Api/IServiceCollectionExtensionsTests.cs | 3 + .../Models/PublishCustomViewOptionsTests.cs | 10 +- .../Models/PublishDataSourceOptionsTests.cs | 10 +- .../Api/Models/PublishFlowOptionsTests.cs | 10 +- .../Api/Models/PublishWorkbookOptionsTests.cs | 9 +- .../Api/Publishing/FilePublisherBaseTests.cs | 27 +- .../Models/IFavoriteTypeExtensionsTests.cs | 98 ++ .../Rest/Models/PublishFlowOptionsTests.cs | 6 +- .../Requests/AddFavoriteRequestTests.cs | 87 ++ .../Requests/CreateGroupSetRequestTests.cs | 46 + .../Models/Requests/UpdateSiteRequestTests.cs | 90 +- .../Models/Responses/GroupSetResponseTests.cs | 75 ++ .../Responses/GroupSetsResponseTests.cs | 74 ++ .../Unit/Api/SchedulesApiClientTests.cs | 1 + .../BulkApiContentReferenceCacheTests.cs | 47 +- .../Unit/Api/SitesApiClientTests.cs | 41 + .../Unit/Api/WorkbooksApiClientTests.cs | 8 +- .../Unit/Config/ConfigReaderTests.cs | 17 +- .../Unit/Config/ConfigurationTests.cs | 33 +- .../FavoriteContentTypeExtensionsTests.cs | 62 ++ .../Unit/Content/FavoriteTests.cs | 193 ++++ .../Unit/Content/Files/MockXmlFileHandle.cs | 8 +- .../Unit/Content/GroupSetTests.cs | 85 ++ .../Unit/Content/MappableContentBaseTests.cs | 46 + .../Unit/Content/PublishableGroupSetTests.cs | 62 ++ .../CachedContentReferenceFinderTests.cs | 23 +- .../Search/ContentReferenceCacheBaseTests.cs | 73 +- .../IContentReferenceFinderFactoryTests.cs | 75 ++ .../Unit/Content/SiteSettingUpdateTests.cs | 22 + .../Unit/Content/SiteTests.cs | 7 +- .../ApiContentClientFactoryTests.cs | 87 -- .../ContentClients/ViewsContentClientTests.cs | 80 -- .../WorkbooksContentClientTests.cs | 86 -- .../Engine/Actions/PreflightActionTests.cs | 57 + .../ConfigurableMigrationCacheBaseTests.cs | 284 +++++ .../TableauApiEndpointViewCacheTests.cs | 57 + ...bleauApiEndpointWorkbookViewsCacheTests.cs | 79 ++ .../FavoritesContentClientTests.cs | 147 +++ .../ContentClients/ViewsContentClientTests.cs | 86 ++ .../WorkbooksContentClientTests.cs | 58 + .../Endpoints/IMigrationEndpointTests.cs | 99 ++ .../MigrationEndpointFactoryTests.cs | 2 - .../DestinationViewReferenceFinderTests.cs | 143 +++ ...ationContentReferenceFinderFactoryTests.cs | 69 ++ ...tDestinationContentReferenceFinderTests.cs | 30 +- ...nifestSourceContentReferenceFinderTests.cs | 38 +- .../TableauApiDestinationEndpointTests.cs | 2 - .../Endpoints/TableauApiEndpointBaseTests.cs | 91 +- .../Endpoints/TableauApiEndpointTestBase.cs | 5 + .../TableauApiSourceEndpointTests.cs | 2 - .../Filters/AsyncContentFilterBaseTests.cs | 95 ++ .../Filters/Default/FavoriteFilterTests.cs | 219 ++++ ...beddedCredentialsCapabilityManagerTests.cs | 14 +- ...dpointSettingCapabilityManagerBaseTests.cs | 115 ++ .../GroupSetsCapabilityManagerTests.cs | 98 ++ .../SubscriptionsCapabilityManagerTests.cs | 129 +++ .../EmbeddedCredentialsPreflightCheckTests.cs | 93 -- .../InitializeCapabilitiesHookTests.cs | 132 +++ ...tializeMigrationCapabilityHookBaseTests.cs | 118 --- .../SubscriptionsPreflightCheckTests.cs | 92 -- .../InitializeMigrationHookResultTests.cs | 29 +- .../Mappings/Default/FavoriteMappingTests.cs | 103 ++ ...ildItemsPermissionsPostPublishHookTests.cs | 29 +- .../PermissionPostPublishHookBaseTests.cs | 7 +- .../PermissionsItemPostPublishHookTests.cs | 30 +- .../PopulateViewCachePostPublishHookTests.cs | 88 ++ .../Default/ProjectPostPublishHookTests.cs | 22 +- .../SubscriptionsCapabilityManagerTests.cs | 93 -- .../Default/FavoriteTransformerTests.cs | 139 +++ .../Default/GroupSetGroupsTransformerTests.cs | 102 ++ .../IContentReferenceExtensionsTests.cs | 71 ++ .../Default/PermissionsTransformerTests.cs | 145 ++- .../IServiceCollectionExtensionsTests.cs | 94 +- ...rationManifestContentTypePartitionTests.cs | 76 ++ .../MigrationManifestSerializerTests.cs | 165 +++ .../Unit/Engine/MigrationPlanBuilderTests.cs | 11 +- .../ServerToCloudMigrationPipelineTests.cs | 16 +- .../Unit/IResultTests.cs | 76 ++ .../SerializedExceptionJsonConverterTests.cs | 2 +- .../Unit/MockHttpResponseMessage.cs | 4 +- .../Unit/MockHttpResponseMessageExtensions.cs | 4 +- .../Net/Handlers/LoggingHttpHandlerTests.cs | 32 +- .../Net/IServiceCollectionExtensionsTests.cs | 5 +- .../HttpActivityDetailsBuilderTests.cs | 459 ++++++++ .../Net/Logging/HttpActivityLoggerTests.cs | 267 +++++ .../HttpContentRedactorTests.cs} | 36 +- .../Unit/Net/NetworkTraceLoggerTests.cs | 677 ------------ .../Unit/Paging/CallbackPagerTests.cs | 52 + .../ISharedResourcesLocalizerTests.cs | 54 +- .../packages.lock.json | 820 ++++++++------- .../Tableau.Migration.CleanSite.csproj | 6 +- .../packages.lock.json | 381 +++---- .../Tableau.Migration.ManifestAnalyzer.csproj | 2 +- .../packages.lock.json | 501 ++++----- .../packages.lock.json | 938 +++++++++-------- .../packages.lock.json | 752 ++++++------- 421 files changed, 20045 insertions(+), 7743 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/actions/clean-dotnet/action.yml create mode 100644 examples/Csharp.ExampleApplication/Hooks/Transformers/ModifyPermissionsTransformer.cs create mode 100644 examples/Python.ExampleApplication/Hooks/transformers/modify_permissions_transformer.py create mode 100644 src/Documentation/samples/transformers/modify_permissions.md create mode 100644 src/Python/src/tableau_migration/migration_content_search.py rename src/Python/src/tableau_migration/{migration_engine_hooks_results.py => migration_engine_hooks_initializemigration.py} (91%) create mode 100644 src/Python/tests/test_migration_content_search.py create mode 100644 src/Tableau.Migration/Api/FavoritesApiClient.cs create mode 100644 src/Tableau.Migration/Api/FavoritesApiListPager.cs create mode 100644 src/Tableau.Migration/Api/GroupSetsApiClient.cs create mode 100644 src/Tableau.Migration/Api/IFavoritesApiClient.cs create mode 100644 src/Tableau.Migration/Api/IGroupSetsApiClient.cs create mode 100644 src/Tableau.Migration/Api/Models/PublishFileOptionsBase.cs delete mode 100644 src/Tableau.Migration/Api/PublishContentWithFileOptions.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/IFavoriteType.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/IFavoriteTypeExtensions.cs rename src/Tableau.Migration/{Engine/Endpoints/ContentClients/IContentClientFactory.cs => Api/Rest/Models/IGroupSetType.cs} (64%) create mode 100644 src/Tableau.Migration/Api/Rest/Models/Requests/AddFavoriteRequest.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Requests/CreateGroupSetRequest.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Responses/CollectionsResponse.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Responses/CreateGroupSetResponse.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Responses/FavoritesResponse.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Responses/GroupSetResponse.cs create mode 100644 src/Tableau.Migration/Api/Rest/Models/Responses/GroupSetsResponse.cs create mode 100644 src/Tableau.Migration/Api/Simulation/Rest/Api/FavoritesRestApiSimulator.cs create mode 100644 src/Tableau.Migration/Api/Simulation/Rest/Api/GroupSetsRestApiSimulator.cs create mode 100644 src/Tableau.Migration/Api/Simulation/Rest/Net/Responses/RestAddFavoriteResponseBuilder.cs create mode 100644 src/Tableau.Migration/Api/Simulation/Rest/Net/Responses/RestGetFavoritesForUserResponseBuilder.cs create mode 100644 src/Tableau.Migration/Api/Simulation/Rest/Net/Responses/RestGroupSetCreateResponseBuilder.cs create mode 100644 src/Tableau.Migration/Config/CacheOptions.cs create mode 100644 src/Tableau.Migration/Content/Favorite.cs create mode 100644 src/Tableau.Migration/Content/FavoriteContentType.cs create mode 100644 src/Tableau.Migration/Content/FavoriteContentTypeExtensions.cs create mode 100644 src/Tableau.Migration/Content/GroupSet.cs create mode 100644 src/Tableau.Migration/Content/IFavorite.cs rename src/Tableau.Migration/{Engine/Hooks/IEmbeddedCredentialsCapabilityManager.cs => Content/IGroupSet.cs} (78%) create mode 100644 src/Tableau.Migration/Content/IPublishableGroupSet.cs rename src/Tableau.Migration/{Engine/Hooks/ISubscriptionsCapabilityManager.cs => Content/ITableauCollection.cs} (79%) create mode 100644 src/Tableau.Migration/Content/MappableContentBase.cs create mode 100644 src/Tableau.Migration/Content/Permissions/IPermissionSet.cs create mode 100644 src/Tableau.Migration/Content/PublishableGroupSet.cs create mode 100644 src/Tableau.Migration/Engine/Caching/ConfigurableMigrationCacheBase.cs create mode 100644 src/Tableau.Migration/Engine/Caching/IMigrationCache.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Caching/IEndpointViewCache.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Caching/IEndpointWorkbookViewsCache.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Caching/TableauApiEndpointViewCache.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Caching/TableauApiEndpointWorkbookViewsCache.cs delete mode 100644 src/Tableau.Migration/Engine/Endpoints/ContentClients/ApiContentClientFactory.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/ContentClients/FavoritesContentClient.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/ContentClients/IFavoritesContentClient.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Search/DestinationViewReferenceFinder.cs create mode 100644 src/Tableau.Migration/Engine/Endpoints/Search/IDestinationViewReferenceFinder.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Filters/AsyncContentFilterBase.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Filters/Default/FavoriteFilter.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Filters/RootContentFilterBase.cs rename src/Tableau.Migration/Engine/Hooks/{ => InitializeMigration/Capabilities}/EmbeddedCredentialsCapabilityManager.cs (82%) create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Capabilities/EndpointSettingCapabilityManagerBase.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Capabilities/GroupSetsCapabilityManager.cs rename src/Tableau.Migration/Engine/Hooks/{ => InitializeMigration/Capabilities}/IMigrationCapabilityManager.cs (72%) create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Capabilities/MigrationCapabilityManagerBase.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Capabilities/SubscriptionsCapabilityManager.cs delete mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Default/EmbeddedCredentialsPreflightCheck.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Default/InitializeCapabilitiesHook.cs delete mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/Default/SubscriptionsPreflightCheck.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/EndpointPreflightContext.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/IEndpointPreflightContext.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/IInitializeMigrationContext.cs rename src/Tableau.Migration/Engine/Hooks/{ => InitializeMigration}/IInitializeMigrationHook.cs (93%) rename src/Tableau.Migration/Engine/Hooks/{ => InitializeMigration}/IInitializeMigrationHookResult.cs (72%) delete mode 100644 src/Tableau.Migration/Engine/Hooks/InitializeMigration/InitializeMigrationCapabilityHookBase.cs rename src/Tableau.Migration/Engine/Hooks/{ => InitializeMigration}/InitializeMigrationHookResult.cs (63%) create mode 100644 src/Tableau.Migration/Engine/Hooks/Mappings/Default/FavoriteMapping.cs delete mode 100644 src/Tableau.Migration/Engine/Hooks/MigrationCapabilityManagerBase.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/PostPublish/Default/DeleteUserFavoritesPostPublishHook.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/PostPublish/Default/PopulateViewCachePostPublishHook.cs delete mode 100644 src/Tableau.Migration/Engine/Hooks/SubscriptionsCapabilityManager.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Transformers/Default/FavoriteTransformer.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Transformers/Default/GroupSetGroupsTransformer.cs create mode 100644 src/Tableau.Migration/Engine/Hooks/Transformers/Default/IContentReferenceExtensions.cs create mode 100644 src/Tableau.Migration/Engine/Pipelines/TableauMigrationPipelineBase.cs create mode 100644 src/Tableau.Migration/IEmptyIdContentReference.cs create mode 100644 src/Tableau.Migration/Net/Logging/HttpActivityDetailsBuilder.cs create mode 100644 src/Tableau.Migration/Net/Logging/HttpActivityLogger.cs rename src/Tableau.Migration/Net/{NetworkTraceRedactor.cs => Logging/HttpContentRedactor.cs} (86%) rename src/Tableau.Migration/Net/{INetworkTraceLogger.cs => Logging/IHttpActivityLogger.cs} (65%) rename src/Tableau.Migration/Net/{INetworkTraceRedactor.cs => Logging/IHttpContentRedactor.cs} (90%) delete mode 100644 src/Tableau.Migration/Net/NetworkTraceLogger.cs rename src/Tableau.Migration/{Engine/Hooks/InitializeMigration/Default/PreflightCheck.cs => Paging/CallbackPager.cs} (50%) create mode 100644 src/Tableau.Migration/Paging/MemoryPagerBase.cs rename tests/Tableau.Migration.TestApplication/Hooks/{ => ActionCompleted}/TimeLoggerAfterActionHook.cs (96%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => BatchMigrationCompleted}/LogMigrationBatchSummaryHook.cs (96%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => BatchMigrationCompleted}/SaveManifestAfterBatchMigrationCompletedHook.cs (97%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/NonDomainUserFilter.cs (98%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/SkipByParentLocationFilter.cs (98%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/SkipFilter.cs (95%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/SkipIdsFilter.cs (97%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/SpecialUserFilter.cs (96%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Filters}/UnlicensedUserFilter.cs (95%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Mappings}/ContentWithinSkippedLocationMapping.cs (98%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Mappings}/SpecialUserMapping.cs (97%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Mappings}/TestTableauCloudUsernameMapping.cs (87%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Mappings}/TestTableauCloudUsernameOptions.cs (94%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Mappings}/UnlicensedUserMapping.cs (96%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Transformers}/RemoveMissingDestinationUsersFromGroupsTransformer.cs (97%) rename tests/Tableau.Migration.TestApplication/Hooks/{ => Transformers}/ViewerOwnerTransformer.cs (98%) create mode 100644 tests/Tableau.Migration.Tests/PageInfoSpecimenBuilder.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/CommonDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/CustomViewsDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/DataSourcesDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/ExtractRefreshTasksDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/FavoritesDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/GroupSetsDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/GroupsDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/ProjectsDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/SchedulesDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/SubscriptionsDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/UsersDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/DataPreparation/WorkbooksDataPreparation.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/Tests/Api/FavoritesApiClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/Tests/Api/GroupSetsApiClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/Tests/FavoritesMigrationTests.cs create mode 100644 tests/Tableau.Migration.Tests/Simulation/Tests/GroupSetMigrationTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/FavoritesApiClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/FavoritesApiListPagerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/GroupSetsApiClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/Rest/Models/IFavoriteTypeExtensionsTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/Rest/Models/Requests/AddFavoriteRequestTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/Rest/Models/Requests/CreateGroupSetRequestTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/Rest/Models/Responses/GroupSetResponseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Api/Rest/Models/Responses/GroupSetsResponseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/FavoriteContentTypeExtensionsTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/FavoriteTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/GroupSetTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/MappableContentBaseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/PublishableGroupSetTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Content/Search/IContentReferenceFinderFactoryTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/ContentClients/ApiContentClientFactoryTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/ContentClients/ViewsContentClientTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/ContentClients/WorkbooksContentClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Caching/ConfigurableMigrationCacheBaseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Caching/TableauApiEndpointViewCacheTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Caching/TableauApiEndpointWorkbookViewsCacheTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/ContentClients/FavoritesContentClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/ContentClients/ViewsContentClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/ContentClients/WorkbooksContentClientTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/IMigrationEndpointTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/DestinationViewReferenceFinderTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Endpoints/Search/IDestinationContentReferenceFinderFactoryTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Filters/AsyncContentFilterBaseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Filters/Default/FavoriteFilterTests.cs rename tests/Tableau.Migration.Tests/Unit/Engine/Hooks/{ => InitializeMigration/Capabilities}/EmbeddedCredentialsCapabilityManagerTests.cs (92%) create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Capabilities/EndpointSettingCapabilityManagerBaseTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Capabilities/GroupSetsCapabilityManagerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Capabilities/SubscriptionsCapabilityManagerTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Default/EmbeddedCredentialsPreflightCheckTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Default/InitializeCapabilitiesHookTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Default/InitializeMigrationCapabilityHookBaseTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/InitializeMigration/Default/SubscriptionsPreflightCheckTests.cs rename tests/Tableau.Migration.Tests/Unit/Engine/Hooks/{ => InitializeMigration}/InitializeMigrationHookResultTests.cs (69%) create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Mappings/Default/FavoriteMappingTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/PostPublish/Default/PopulateViewCachePostPublishHookTests.cs delete mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/SubscriptionsCapabilityManagerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Transformers/Default/FavoriteTransformerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Transformers/Default/GroupSetGroupsTransformerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Engine/Hooks/Transformers/Default/IContentReferenceExtensionsTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/IResultTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Net/Logging/HttpActivityDetailsBuilderTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Net/Logging/HttpActivityLoggerTests.cs rename tests/Tableau.Migration.Tests/Unit/Net/{NetworkTraceRedactorTests.cs => Logging/HttpContentRedactorTests.cs} (82%) delete mode 100644 tests/Tableau.Migration.Tests/Unit/Net/NetworkTraceLoggerTests.cs create mode 100644 tests/Tableau.Migration.Tests/Unit/Paging/CallbackPagerTests.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 60760273..63784e39 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -10,7 +10,7 @@ "rollForward": false }, "dotnet-reportgenerator-globaltool": { - "version": "5.4.7", + "version": "5.4.8", "commands": [ "reportgenerator" ], diff --git a/.editorconfig b/.editorconfig index 9e605ef9..8d9f7541 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,10 @@ - -[*.{cs,vb}] +[ + "*.", + { + "cs", + "vb" + } +] # File header file_header_template = \n Copyright (c) 2025, Salesforce, Inc.\n SPDX-License-Identifier: Apache-2\n \n Licensed under the Apache License, Version 2.0 (the "License") \n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n \n http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an "AS IS" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n @@ -112,4 +117,16 @@ csharp_style_prefer_primary_constructors = false:suggestion csharp_prefer_system_threading_lock = true:suggestion # Organize usings -dotnet_sort_system_directives_first = true \ No newline at end of file +dotnet_sort_system_directives_first = true + +# Enforce Async suffix for async methods +dotnet_naming_rule.async_methods_must_end_with_async.severity = error +dotnet_naming_rule.async_methods_must_end_with_async.symbols = async_methods +dotnet_naming_rule.async_methods_must_end_with_async.style = end_with_async + +dotnet_naming_symbols.async_methods.applicable_kinds = method +dotnet_naming_symbols.async_methods.applicable_accessibilities = * +dotnet_naming_symbols.async_methods.required_modifiers = async + +dotnet_naming_style.end_with_async.required_suffix = Async +dotnet_naming_style.end_with_async.capitalization = pascal_case \ No newline at end of file diff --git a/.github/.vars.default b/.github/.vars.default index 3f3eb918..c08725df 100644 --- a/.github/.vars.default +++ b/.github/.vars.default @@ -18,11 +18,13 @@ PUBLISH_PACKAGE_OS="ubuntu-latest" # Development NUGET_PACKAGE_REPOSITORY="https://artifactory.dev.tableautools.com/artifactory/api/nuget/pqt-tuk/Tableau.Migration" PYPI_PUBLISH_USER="svc_cmt" +NUGET_PUBLISH_USER="svc_cmt" PYPI_PACKAGE_REPOSITORY="https://artifactory.dev.tableautools.com/artifactory/api/pypi/tab-pypi-local-tuk/" # Staging #NUGET_PACKAGE_REPOSITORY="https://artifactory.prod.tableautools.com/artifactory/api/nuget/power-tools-nuget-local/Tableau.Migration" #PYPI_PUBLISH_USER="svc_cmt" +NUGET_PUBLISH_USER="svc_cmt" #PYPI_PACKAGE_REPOSITORY="https://artifactory.prod.tableautools.com/artifactory/api/pypi/tabpypi" # Public Test diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index b43420c5..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Language (please complete the following information):** - - Python - - C# - -**Migration Type** -- Server -> Server -- Server -> Cloud -- Cloud -> Cloud - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - - - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Error Message(s)** -Any applicable error messages or stack traces. - - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 0c0fcdcb..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Language** -Is the feature language specific? If so, please mention which one of these you are using -- Python -- C# - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/actions/clean-dotnet/action.yml b/.github/actions/clean-dotnet/action.yml new file mode 100644 index 00000000..7f624d7e --- /dev/null +++ b/.github/actions/clean-dotnet/action.yml @@ -0,0 +1,50 @@ +name: Clean .NET Installations +description: 'Remove all existing .NET installations from the system. Does not install any new versions.' + +runs: + using: "composite" + steps: + # Step 1: Clean existing .NET installations on Ubuntu/Linux + - name: Clean .NET installations (Ubuntu/Linux) + if: runner.os == 'Linux' + shell: bash + run: | + echo "Cleaning existing .NET installations on Ubuntu/Linux..." + # Remove via package manager + sudo apt-get remove -y --purge dotnet* aspnetcore* netstandard* || true + # Remove installation directories + sudo rm -rf /usr/share/dotnet || true + sudo rm -rf /etc/dotnet || true + sudo rm -rf ~/.dotnet || true + echo "✅ Cleaned .NET installations on Ubuntu/Linux" + + # Step 2: Clean existing .NET installations on macOS + - name: Clean .NET installations (macOS) + if: runner.os == 'macOS' + shell: bash + run: | + echo "Cleaning existing .NET installations on macOS..." + # Remove installation directories + sudo rm -rf /usr/local/share/dotnet || true + sudo rm -rf ~/.dotnet || true + # Remove brew installed versions if any (suppress error output to avoid annotations) + brew uninstall --ignore-dependencies dotnet 2>/dev/null || true + echo "✅ Cleaned .NET installations on macOS" + + # Step 3: Clean existing .NET installations on Windows + - name: Clean .NET installations (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + Write-Host "Cleaning existing .NET installations on Windows..." + # Remove via package manager + try { + Get-Package -Name "Microsoft .NET*" | Uninstall-Package -Force -ErrorAction SilentlyContinue + } catch { + Write-Host "No .NET packages found to uninstall" + } + # Remove installation directories + Remove-Item -Path "C:\Program Files\dotnet" -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Path "C:\Program Files (x86)\dotnet" -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Path "$env:USERPROFILE\.dotnet" -Recurse -Force -ErrorAction SilentlyContinue + Write-Host "✅ Cleaned .NET installations on Windows" \ No newline at end of file diff --git a/.github/actions/setup-dotnet/action.yml b/.github/actions/setup-dotnet/action.yml index c9008073..a3bb9211 100644 --- a/.github/actions/setup-dotnet/action.yml +++ b/.github/actions/setup-dotnet/action.yml @@ -1,24 +1,49 @@ name: Setup .NET -description: 'Setup .NET' +description: 'Setup a specific .NET SDK version and add to PATH. Ensures only the specified version is active.' + +inputs: + dotnet-version: + description: 'The .NET SDK version to install (e.g., 8.0.x, 9.0.x).' + required: true env: DOTNET_NOLOGO: 'true' + # Prevent global .NET installations from interfering. + # This tells .NET to not look for SDKs/runtimes in global locations. + DOTNET_MULTILEVEL_LOOKUP: "0" runs: using: "composite" steps: + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ inputs.dotnet-version }} + - name: nuget Cache uses: actions/cache@v4 with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + path: ~/.nuget/packages # This path is standard for NuGet cache + key: ${{ runner.os }}-nuget-${{ inputs.dotnet-version }}-${{ hashFiles('**/packages.lock.json') }} restore-keys: | + ${{ runner.os }}-nuget-${{ inputs.dotnet-version }}- ${{ runner.os }}-nuget- - - name: Setup .NET 8.0 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - name: Setup .NET 9.0 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x \ No newline at end of file + + - name: Verify .NET installation + shell: pwsh + run: | + Write-Host "Verifying .NET installation..." + Write-Host "PATH: $($env:PATH)" + Write-Host "DOTNET_ROOT: $($env:DOTNET_ROOT)" # DOTNET_ROOT is set by setup-dotnet + $dotnetExists = Get-Command dotnet -ErrorAction SilentlyContinue + if (-not $dotnetExists) { + Write-Error "dotnet command could not be found!" + exit 1 + } + Write-Host "Running dotnet --info:" + dotnet --info + Write-Host "Running dotnet --list-sdks:" + dotnet --list-sdks + Write-Host "Running dotnet --list-runtimes:" + dotnet --list-runtimes + Write-Host "Successfully set up .NET SDK ${{ inputs.dotnet-version }}" \ No newline at end of file diff --git a/.github/workflows/README.md b/.github/workflows/README.md index f3e344d8..7cf4ae72 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -30,7 +30,6 @@ When sdk-workflow is started manually: - Tests and linting are run - Packages are automatically deployed to the **staging** environment - ## Overview The workflows are organized hierarchically with a main workflow orchestrating various specialized workflows: @@ -66,6 +65,110 @@ The SDK supports the following deployment environments: - **Staging**: Manual deployment with Production release type or beta-to-production intent - **Production**: Manual deployment after approval from staging with proper release flags +## .NET Version Support and Updates + +### Current Requirements + +The Migration SDK workflows support and test multiple .NET versions: + +- **Build/Deployment**: Requires .NET 9.0.x (as specified in `global.json`) +- **Runtime Compatibility**: Supports .NET 8.0+ and .NET 9.0+ for end users +- **Testing**: Runs compatibility tests on both .NET 8.0.x and .NET 9.0.x via matrix strategy + +### GitHub Actions Configuration + +The workflows use centralized version management: + +- **Build Version**: Set via `DOTNET_BUILD_VERSION: '9.0.x'` in `sdk-workflow.yml` +- **Test Matrix**: Set via `BUILD_DOTNET_VERSIONS` variable (e.g., `['8.0.x', '9.0.x']`) used by both `test-dotnet.yml` and `test-python.yml` +- **Version Mismatch Handling**: Uses `DOTNET_ROLL_FORWARD: LatestMajor` during package restore + +### Updating for New .NET Versions + +When a new major version of .NET is released, update these workflow files: + +#### Required Updates + +1. **`global.json`** - Update the SDK version to the latest LTS or Current version +2. **`sdk-workflow.yml`** - Update `DOTNET_BUILD_VERSION` environment variable +3. **Workflow Variables** - Update `BUILD_DOTNET_VERSIONS` variable to include new version (e.g., `['8.0.x', '9.0.x', '10.0.x']`), in test-dotnet and test-python. +4. **Project files** - Add new target framework monikers where appropriate + +#### Example for .NET 10 (when released) + +```yaml +# In sdk-workflow.yml +env: + DOTNET_BUILD_VERSION: '10.0.x' # Update build version +``` + +```json +// In global.json +{ + "sdk": { + "version": "10.0.100", // Update to latest SDK + "rollForward": "latestMajor" + } +} +``` + +Workflow Variables: + +- Update `BUILD_DOTNET_VERSIONS` to `['8.0.x', '9.0.x', '10.0.x']` + +### Compatibility Testing Strategy + +The workflows use several strategies to ensure .NET version compatibility: + +- **Matrix Testing**: Tests run on multiple .NET versions simultaneously using framework targeting: + - **.NET 8 Matrix**: Installs both .NET 8 and .NET 9 SDKs, tests solution with `--framework net8.0` targeting + - **.NET 9 Matrix**: Installs .NET 9 SDK, tests solution with `--framework net9.0` targeting +- **Cross-Platform**: Tests run on Windows, macOS, and Linux runners +- **Version Rollforward**: Uses `DOTNET_ROLL_FORWARD: LatestMajor` to handle version mismatches during package restore +- **Artifact Compatibility**: Build artifacts use the build version but are tested against all matrix versions +- **Clean Environment**: Each test run starts with a completely clean .NET environment using two steps: first the `clean-dotnet` action removes all existing .NET installations, then `setup-dotnet` installs the target version. This eliminates conflicts with global.json or other version requirements across all platforms. + +#### .NET Version-Specific Testing + +**.NET 8.0.x Matrix Behavior:** + +- ✅ Clean .NET installation and install .NET 8 runtime +- ✅ Install .NET 9 SDK for build compatibility (global.json requirements) +- ✅ Restore dependencies and tools (using .NET 9 SDK) +- ✅ Test solution with `--framework net8.0` targeting (tests .NET 8 assemblies) +- ✅ Collect code coverage with XPlat Code Coverage +- ✅ Generate coverage reports with reportgenerator +- ✅ Upload test results and coverage artifacts + +**.NET 9.0.x Matrix Behavior:** + +- ✅ Clean .NET installation and install .NET 9 SDK +- ✅ Restore dependencies and tools +- ✅ Test solution with `--framework net9.0` targeting (tests .NET 9 assemblies) +- ✅ Collect code coverage with XPlat Code Coverage +- ✅ Generate coverage reports with reportgenerator +- ✅ Upload test results and coverage artifacts + +This approach ensures both versions get **full testing capabilities** while verifying true **runtime compatibility** through framework targeting. + +## Custom Actions + +The workflows use several custom actions located in `.github/actions/`: + +### setup-dotnet + +Standard .NET SDK setup with verification and caching. + +### clean-dotnet + +Removes all existing .NET installations from the system across all platforms: + +- **Linux**: Removes via `apt-get purge` and deletes installation directories (`/usr/share/dotnet`, `/etc/dotnet`, `~/.dotnet`) +- **macOS**: Removes installation directories (`/usr/local/share/dotnet`, `~/.dotnet`) and brew packages +- **Windows**: Uses PowerShell to uninstall packages and remove directories (`C:\Program Files\dotnet`, etc.) + +This action only performs cleanup and does not install any .NET versions. Use in combination with `setup-dotnet` for a clean installation environment. + ## Testing with Act [Act](https://github.com/nektos/act) allows you to run GitHub Actions workflows locally for testing. To use Act with these workflows: @@ -144,14 +247,4 @@ For a more user-friendly experience, you can use the [GitHub Local Actions VS Co 4. Configure your environment variables and secrets in the extension interface - From the steps above, after creating local .vars and .secrets file, Use "Locate Variable File" and "Locate Secret File" to find them. More details here: https://sanjulaganepola.github.io/github-local-actions-docs/usage/settings/ - Once you've added your local .vars and .secrets file, remember to CHECK THE BOX or else it won't pick it up. -5. You need to add in a artifacts-server-path field under Options (This is for the upload parts. Go to `Settings` -> `Options` -> `+` -> `artifact-server-path` and define a temp folder (D:\temp) -6. Run the workflow and view the results directly in VS Code - -### Limitations - -When testing with Act: - -1. GitHub environment variables and secrets need to be manually defined in `.vars` and `.secrets` files or via CLI arguments -2. Some GitHub-specific features like environment protection rules won't work locally -3. Act detects when it's running and uses a timestamp instead of run numbers for versioning -4. **Environment Support**: Act has limited support for GitHub's environment concept. Workflows that transition between different deployment environments (development → staging → production) are particularly challenging to test locally, as Act does not fully simulate GitHub's environment-specific variable scoping. For example, workflows that depend on different variable values in staging versus production environments may not behave as expected during local testing, since the same variables are used across all simulated environments. +5. You need to add in a artifacts-server-path field under Options (This is for the upload parts. Go to `Settings` -> `Options` -> ` \ No newline at end of file diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index b6b46df2..d819110a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -9,17 +9,23 @@ on: python-version: required: true type: string + dotnet-sdk-version: # New input for .NET SDK version + required: true + type: string jobs: build-docs: runs-on: ${{ inputs.runs-on-config }} - name: Build Docs + name: Build Docs (.NET ${{ inputs.dotnet-sdk-version }}) # Updated name steps: # Checkout the repository - uses: actions/checkout@v4 # Setup .NET environment - - uses: ./.github/actions/setup-dotnet + - name: Setup .NET ${{ inputs.dotnet-sdk-version }} + uses: ./.github/actions/setup-dotnet + with: + dotnet-version: ${{ inputs.dotnet-sdk-version }} # Pass the input here # Setup Python environment - name: Setup Python @@ -32,11 +38,10 @@ jobs: shell: pwsh run: | ./scripts/generate-docs.ps1 -SkipPreClean - Compress-Archive ./docs/* -Destination docs.zip # Upload Docs Artifact - name: Upload Docs Artifact uses: actions/upload-artifact@v4 with: name: docs - path: docs.zip + path: ./docs diff --git a/.github/workflows/build-dotnet.yml b/.github/workflows/build-dotnet.yml index 0308b588..cee9adda 100644 --- a/.github/workflows/build-dotnet.yml +++ b/.github/workflows/build-dotnet.yml @@ -10,6 +10,9 @@ on: runs-on-config: required: true type: string + dotnet-sdk-version: # Input for the .NET SDK version + required: true + type: string env: MIGRATIONSDK_BUILD_DOCS: "no" @@ -26,7 +29,8 @@ jobs: config: ${{ fromJSON(vars.BUILD_CONFIGURATIONS) }} runs-on: ${{ inputs.runs-on-config }} - name: Build .NET (${{ matrix.os }}, ${{ matrix.config }}) + # Updated job name to include the .NET version from input + name: Build .NET ${{ inputs.dotnet-sdk-version }} (${{ matrix.os }}, ${{ matrix.config }}) steps: ## SETUP @@ -34,15 +38,19 @@ jobs: - uses: actions/checkout@v4 # Setup .NET environment - - uses: ./.github/actions/setup-dotnet + - name: Setup .NET ${{ inputs.dotnet-sdk-version }} + uses: ./.github/actions/setup-dotnet + with: + dotnet-version: ${{ inputs.dotnet-sdk-version }} # Use the input for .NET version - # Cache NuGet packages based on the lock file + # Cache NuGet packages based on the lock file and .NET version - name: Cache NuGet packages uses: actions/cache@v4 with: path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + key: ${{ runner.os }}-nuget-${{ inputs.dotnet-sdk-version }}-${{ hashFiles('**/packages.lock.json') }} restore-keys: | + ${{ runner.os }}-nuget-${{ inputs.dotnet-sdk-version }}- ${{ runner.os }}-nuget- # Explicitly restore dependencies using the lock file @@ -85,7 +93,7 @@ jobs: echo "OS Comparison Result: ${{ matrix.os == vars.PUBLISH_OS }}" echo "Config Comparison Result: ${{ matrix.config == 'Release' }}" echo "SHOULD_PUBLISH=${{ matrix.os == vars.PUBLISH_OS && matrix.config == 'Release' }}" >> $GITHUB_ENV - + # Publish the .NET library - name: Publish .NET Library ${{ matrix.config }} if: ${{ env.SHOULD_PUBLISH == 'true' }} @@ -103,7 +111,7 @@ jobs: if: ${{ env.SHOULD_PUBLISH == 'true' }} uses: actions/upload-artifact@v4 with: - name: product-${{ matrix.config }} + name: product-${{ matrix.config }}-net${{ inputs.dotnet-sdk-version }} path: "./src/Python/src/tableau_migration/bin/**" retention-days: 15 # This is not required to stick around very long as it's not pushed to production. @@ -113,7 +121,7 @@ jobs: if: ${{ env.SHOULD_PUBLISH == 'true' }} uses: actions/upload-artifact@v4 with: - name: tests-${{ matrix.config }} + name: tests-${{ matrix.config }}-net${{ inputs.dotnet-sdk-version }} path: "./dist/tests/**" retention-days: 15 # This is not required to stick around very long as it's not pushed to production. @@ -122,7 +130,7 @@ jobs: if: ${{ env.SHOULD_PUBLISH == 'true' }} uses: actions/upload-artifact@v4 with: - name: nuget-package + name: nuget-package-${{ matrix.config }}-net${{ inputs.dotnet-sdk-version }} path: "./src/${{ vars.NUGET_PACKAGE_FOLDER }}/bin/${{ matrix.config }}/*.nupkg" if-no-files-found: error @@ -131,7 +139,7 @@ jobs: if: ${{ env.SHOULD_PUBLISH == 'true' }} uses: actions/upload-artifact@v4 with: - name: build-output-${{ matrix.config }} + name: build-output-${{ matrix.config }}-net${{ inputs.dotnet-sdk-version }} path: | **/bin/${{ matrix.config }}/** **/obj/${{ matrix.config }}/** diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index c3ca863a..9e8be609 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -13,6 +13,9 @@ on: beta-version: required: true type: string + dotnet-build-version: + required: true + type: string env: WORKING_DIRECTORY: ./src/Python @@ -57,7 +60,7 @@ jobs: # Download the product artifact - uses: actions/download-artifact@v4 with: - name: product-${{ inputs.build-config }} + name: product-${{ inputs.build-config }}-net${{ inputs.dotnet-build-version }} path: ./src/Python/src/tableau_migration/bin/ # Set replaced version diff --git a/.github/workflows/deploy-all.yml b/.github/workflows/deploy-all.yml index 7b5f25d2..dcdb1c18 100644 --- a/.github/workflows/deploy-all.yml +++ b/.github/workflows/deploy-all.yml @@ -37,6 +37,10 @@ on: description: 'Whether to deploy the docs.' required: true type: boolean + dotnet-build-version: + description: 'The .NET version used for building' + required: true + type: string env: DOTNET_NOLOGO: 'true' @@ -52,6 +56,7 @@ jobs: build-config: ${{ vars.PUBLISH_CONFIGURATION }} publish-environment: ${{ inputs.publish-environment }} continue-on-error: ${{ inputs.dotnet-continue-on-error }} + dotnet-build-version: ${{ inputs.dotnet-build-version }} deploy-python: name: Deploy python to ${{ inputs.publish-environment }} diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 8f7c2b39..b8e1a53f 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -35,6 +35,7 @@ jobs: uses: actions/download-artifact@v4 with: name: docs + path: ./docs # Setup GitHub Pages - name: Setup GitHub Pages @@ -44,7 +45,7 @@ jobs: - name: Upload Github Pages uses: actions/upload-pages-artifact@v3.0.1 with: - path: "." + path: "./docs" # Deploy to GitHub Pages - name: Deploy to GitHub Pages diff --git a/.github/workflows/deploy-dotnet.yml b/.github/workflows/deploy-dotnet.yml index 6e6aefed..6b5dfcd7 100644 --- a/.github/workflows/deploy-dotnet.yml +++ b/.github/workflows/deploy-dotnet.yml @@ -23,6 +23,10 @@ on: description: "Whether to continue on error for this deployment" required: true type: boolean + dotnet-build-version: + description: "The .NET version used for building" + required: true + type: string env: DOTNET_NOLOGO: "true" @@ -62,14 +66,36 @@ jobs: # Download the NuGet package artifact - uses: actions/download-artifact@v4 - with: - name: nuget-package + name: nuget-package-Release-net${{ inputs.dotnet-build-version }} # Publish the package to a NuGet Repository - name: Publish the package to a Nuget Repository shell: pwsh env: NUGET_API_KEY: ${{ secrets.NUGET_PUBLISH_API_KEY }} - # This command will fail if the package already exists in the repository. - run: dotnet nuget push Tableau.Migration.*.nupkg -k $env:NUGET_API_KEY -s ${{ env.NUGET_PACKAGE_REPOSITORY }} + run: | + $publishEnv = "${{ inputs.publish-environment }}" + + if ("${{ vars.NUGET_PUBLISH_USER }}" -ne "") { + Write-Host "Using username and API key authentication for environment: $publishEnv" + + # Remove existing source if it exists to avoid conflicts + dotnet nuget remove source $publishEnv 2>$null + + # Add the NuGet source configuration + dotnet nuget add source ${{ env.NUGET_PACKAGE_REPOSITORY }} ` + --name $publishEnv ` + --username ${{ vars.NUGET_PUBLISH_USER }} ` + --password ${{ secrets.NUGET_PUBLISH_API_KEY }} ` + --store-password-in-clear-text + + # Push the package using the configured source + dotnet nuget push Tableau.Migration.*.nupkg -s $publishEnv + } + else { + Write-Host "Using API key only authentication for environment: $publishEnv" + + # Push directly with API key + dotnet nuget push Tableau.Migration.*.nupkg -k $env:NUGET_PUBLISH_API_KEY -s ${{ env.NUGET_PACKAGE_REPOSITORY }} + } diff --git a/.github/workflows/sdk-workflow.yml b/.github/workflows/sdk-workflow.yml index edd09e0a..82695dfc 100644 --- a/.github/workflows/sdk-workflow.yml +++ b/.github/workflows/sdk-workflow.yml @@ -6,8 +6,6 @@ on: branches: - main - "release/**" - - "staging/**" - - "feature/**" paths-ignore: - README.md - "**/README.md" @@ -52,6 +50,8 @@ on: env: DOTNET_NOLOGO: "true" + # Centralized .NET version for building and deploying + DOTNET_BUILD_VERSION: '9.0.x' jobs: # Define version job @@ -61,6 +61,7 @@ jobs: outputs: beta-version: ${{ steps.get-beta-version.outputs.betaversion }} code-version: ${{ steps.get-prod-version.outputs.codeversion }} + dotnet-build-version: ${{ steps.set-versions.outputs.dotnet-build-version }} if: github.event.pull_request.draft == false steps: - uses: actions/checkout@v4 @@ -99,6 +100,14 @@ jobs: majorminorbuild=$(grep -oP '\K[^<]*' Directory.Build.props) echo "codeversion=$majorminorbuild" >> "$GITHUB_OUTPUT" + # This step makes the env variable available DOTNET_BUILD_VERSION to reusable workflows + # GitHub Actions limitation: The 'env' context is not available in the 'with' section + # when calling reusable workflows. This step converts env variables to job outputs + # so they can be used by reusable workflows while maintaining centralized management. + - name: Set dotnet Build Version Output + id: set-versions + run: echo "dotnet-build-version=${{ env.DOTNET_BUILD_VERSION }}" >> "$GITHUB_OUTPUT" + # Build .NET build-dotnet: name: Build .NET @@ -107,6 +116,7 @@ jobs: with: runs-on-config: ${{ vars.BASE_OS }} beta-version: ${{ needs.define-version.outputs.beta-version }} + dotnet-sdk-version: ${{ needs.define-version.outputs.dotnet-build-version }} # Build documentation build-docs: @@ -116,6 +126,7 @@ jobs: with: runs-on-config: ${{ vars.DOCS_OS }} python-version: ${{ vars.PYTHON_PUBLISH_DOCS_VERSION }} + dotnet-sdk-version: ${{ needs.define-version.outputs.dotnet-build-version }} build-python-package: name: Build Python @@ -125,6 +136,7 @@ jobs: beta-version: ${{ needs.define-version.outputs.beta-version }} runs-on-config: ${{ vars.BASE_OS }} build-config: ${{ vars.PUBLISH_CONFIGURATION }} + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} # Lint lint-python: @@ -144,24 +156,28 @@ jobs: # Test test-dotnet: name: Test - needs: [build-dotnet] + needs: [define-version,build-dotnet] uses: ./.github/workflows/test-dotnet.yml + with: + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} test-python: name: Test - needs: [build-dotnet] + needs: [define-version, build-dotnet] uses: ./.github/workflows/test-python.yml with: working-directory: ./src/Python test-name: "python-test" + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} test-python-examples-test: name: Test - needs: [build-dotnet] + needs: [define-version,build-dotnet] uses: ./.github/workflows/test-python.yml with: working-directory: ./tests/Python.ExampleApplication.Tests test-name: "python-example-test" + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} # Deployments deploy-to-dev: @@ -194,6 +210,7 @@ jobs: create-release: false release-version: "" deploy-docs: false + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} # Staging environment is configured in GitHub # Staging is a artifactory repository @@ -227,6 +244,7 @@ jobs: create-release: false release-version: "" deploy-docs: false + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} # Evaluate Go-To-Production Readiness evaluate-goto-production: @@ -299,3 +317,4 @@ jobs: create-release: true release-version: ${{ needs.define-version.outputs.beta-version != '' && needs.define-version.outputs.beta-version || needs.define-version.outputs.code-version }} deploy-docs: true + dotnet-build-version: ${{ needs.define-version.outputs.dotnet-build-version }} diff --git a/.github/workflows/test-dotnet.yml b/.github/workflows/test-dotnet.yml index b73a5560..e9a8c4a1 100644 --- a/.github/workflows/test-dotnet.yml +++ b/.github/workflows/test-dotnet.yml @@ -3,6 +3,10 @@ name: Test .NET Workflow on: workflow_call: + inputs: + dotnet-build-version: + required: true + type: string env: DOTNET_NOLOGO: "true" @@ -18,28 +22,45 @@ jobs: matrix: os: ${{ fromJSON(vars.BUILD_OS) }} config: ${{ fromJSON(vars.BUILD_CONFIGURATIONS) }} + dotnet-version: ['8.0.x', '9.0.x'] runs-on: ${{ matrix.os }} - name: Test .NET (${{ matrix.os }} ${{ matrix.config }}) + name: Test .NET (${{ matrix.os }}, ${{ matrix.config }}, .NET ${{ matrix.dotnet-version }}) steps: # Checkout the repository - uses: actions/checkout@v4 - # Setup .NET environment - - uses: ./.github/actions/setup-dotnet + # Clean all existing .NET installations + - name: Clean existing .NET installations + uses: ./.github/actions/clean-dotnet - # Cache NuGet packages based on the lock file + # Setup .NET SDK + - name: Setup .NET ${{ matrix.dotnet-version }} + uses: ./.github/actions/setup-dotnet + with: + dotnet-version: ${{ matrix.dotnet-version }} + + # Setup .NET 9 SDK (Needed to run dotnet test in any matrix) + - name: Setup .NET 9 SDK (for build compatibility) + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + + # Cache NuGet packages based on the lock file and .NET version - name: Cache NuGet packages uses: actions/cache@v4 with: path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} + key: ${{ runner.os }}-nuget-${{ matrix.dotnet-version }}-${{ hashFiles('**/packages.lock.json') }} restore-keys: | + ${{ runner.os }}-nuget-${{ matrix.dotnet-version }}- ${{ runner.os }}-nuget- # Restore dependencies - name: Restore Dependencies run: dotnet restore '${{ vars.BUILD_SOLUTION }}' --locked-mode + env: + DOTNET_ROLL_FORWARD: LatestMajor # Restore Tools (i.e. report generator) - name: Restore .NET Tools @@ -49,29 +70,39 @@ jobs: - name: Download Build Output uses: actions/download-artifact@v4 with: - name: build-output-${{ matrix.config }} + name: build-output-${{ matrix.config }}-net${{ inputs.dotnet-build-version }} path: ./ - # Test the solution + # Test the solution with framework targeting - name: Test Solution with ${{ matrix.config }} Configuration + shell: pwsh run: | - dotnet test '${{ vars.BUILD_SOLUTION }}' --no-build --no-restore -c ${{ matrix.config }} --verbosity normal --collect:"XPlat Code Coverage" --logger junit --results-directory "TestResults-${{ matrix.os }}-${{ matrix.config }}" -- RunConfiguration.TestSessionTimeout=${{ vars.MIGRATIONSDK_TEST_CANCELLATION_TIMEOUT_MILLISECONDS }} + $framework = if ('${{ matrix.dotnet-version }}' -eq '8.0.x') { 'net8.0' } else { 'net9.0' } + Write-Host "Testing with framework: $framework" + dotnet test '${{ vars.BUILD_SOLUTION }}' ` + --framework $framework ` + --no-build --no-restore ` + -c ${{ matrix.config }} ` + --verbosity normal ` + --collect:"XPlat Code Coverage" ` + --logger junit ` + --results-directory "TestResults-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }}" ` + -- RunConfiguration.TestSessionTimeout=${{ vars.MIGRATIONSDK_TEST_CANCELLATION_TIMEOUT_MILLISECONDS }} # Build code coverage reports - name: Build Coverage Summary - run: dotnet reportgenerator -reports:"TestResults-${{ matrix.os }}-${{ matrix.config }}/*/coverage.cobertura.xml" -targetdir:"TestResults-${{ matrix.os }}-${{ matrix.config }}/coverage-reports" -reporttypes:"Html;MarkdownSummaryGithub" + run: dotnet reportgenerator -reports:"TestResults-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }}/*/coverage.cobertura.xml" -targetdir:"TestResults-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }}/coverage-reports" -reporttypes:"Html;MarkdownSummaryGithub" # Create job summary - name: Set Job Summary - run: cat "TestResults-${{ matrix.os }}-${{ matrix.config }}/coverage-reports/SummaryGithub.md" >> $GITHUB_STEP_SUMMARY + run: cat "TestResults-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }}/coverage-reports/SummaryGithub.md" >> $GITHUB_STEP_SUMMARY shell: bash # Upload test results - name: Upload Test Results - # Use always() to always run this step to publish test results when there are test failures if: ${{ always() }} uses: actions/upload-artifact@v4 with: - name: dotnet-results-${{ matrix.os }}-${{ matrix.config }} - path: TestResults-${{ matrix.os }}-${{ matrix.config }} + name: dotnet-results-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }} + path: TestResults-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }} if-no-files-found: error diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index cf93f6f8..b519674f 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -9,6 +9,9 @@ on: test-name: required: true type: string + dotnet-build-version: + required: true + type: string env: DOTNET_NOLOGO: "true" @@ -25,18 +28,28 @@ jobs: matrix: os: ${{ fromJSON(vars.BUILD_OS) }} config: ${{ fromJSON(vars.BUILD_CONFIGURATIONS) }} + dotnet-version: ['8.0.x', '9.0.x'] runs-on: ${{ matrix.os }} - name: Test Python ${{ inputs.test-name }} (${{ matrix.os }}, ${{ matrix.config }}) + name: Test Python ${{ inputs.test-name }} (${{ matrix.os }}, ${{ matrix.config }}, .NET ${{ matrix.dotnet-version }}) steps: # Checkout the repository - uses: actions/checkout@v4 + # Clean all existing .NET installations + - name: Clean existing .NET installations + uses: ./.github/actions/clean-dotnet + # Setup .NET environment - - uses: ./.github/actions/setup-dotnet + - name: Setup .NET ${{ matrix.dotnet-version }} + uses: ./.github/actions/setup-dotnet + with: + dotnet-version: ${{ matrix.dotnet-version }} # Pass the .NET version from the matrix - # Restore Tools (i.e. report generator) + # Restore Tools (i.e. report generator) - skip for .NET 8 + # Code coverage report generation is only supported on the latest .NET version - name: Restore .NET Tools + if: ${{ !(matrix.dotnet-version == '8.0.x') }} run: dotnet tool restore # Setup Python environment @@ -69,7 +82,7 @@ jobs: # TODO: [W-18497981: CI/CD Improvements: Python tests should test final package | Work](https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00002EIUwKYAX/view) - uses: actions/download-artifact@v4 with: - name: tests-${{ matrix.config }} + name: tests-${{ matrix.config }}-net${{ inputs.dotnet-build-version }} path: ./src/Python/src/tableau_migration/bin/ # Test with pytest @@ -78,19 +91,20 @@ jobs: # Build code coverage reports - name: Build Coverage Summary + if: ${{ !(matrix.dotnet-version == '8.0.x') }} run: dotnet reportgenerator -reports:"./TestResults/coverage*.xml" -targetdir:"./TestResults/coverage-reports" -reporttypes:"Html;MarkdownSummaryGithub" # Create job summary - name: Set Job Summary + if: ${{ !(matrix.dotnet-version == '8.0.x') }} run: cat "./TestResults/coverage-reports/SummaryGithub.md" >> $GITHUB_STEP_SUMMARY shell: bash # Upload test results - name: Upload Test Results - # Use always() to always run this step to publish test results when there are test failures - if: ${{ always() }} + if: ${{ !(matrix.dotnet-version == '8.0.x') }} uses: actions/upload-artifact@v4 with: - name: ${{ inputs.test-name }}-results-${{ matrix.os }}-${{ matrix.config }} + name: ${{ inputs.test-name }}-results-${{ matrix.os }}-${{ matrix.config }}-net${{ matrix.dotnet-version }} path: ${{ inputs.working-directory }}/TestResults if-no-files-found: error diff --git a/Directory.Build.props b/Directory.Build.props index f6cdcc90..9ef89976 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,12 +4,12 @@ enable true true - 5.2.0 + 5.3.0 Salesforce, Inc. Salesforce, Inc. Copyright (c) 2025, Salesforce, Inc. and its licensors Apache-2.0 - 11.3.0 + 11.3.2