From 92915eaefaf4ff68c68d5de25cf0ba804631785b Mon Sep 17 00:00:00 2001 From: Steffen Froehlich Date: Fri, 10 May 2024 16:03:59 -0700 Subject: [PATCH] Release 3.0.0 --- .editorconfig | 2 +- .gitignore | 4 -- CODEOWNERS | 5 +- Directory.Build.props | 8 +-- .../Csharp.ExampleApplication.csproj | 2 +- ...endencyInjection.ExampleApplication.csproj | 2 +- scripts/generate-docs.ps1 | 31 +++++++----- scripts/generate-license-header-python.ps1 | 4 +- src/Documentation/api/index.md | 41 +++++++++++++++- src/Documentation/articles/configuration.md | 24 ++++----- src/Documentation/articles/intro.md | 2 +- src/Documentation/articles/toc.yml | 32 +++++------- src/Documentation/index.md | 2 +- src/Documentation/python_wrapper/.gitignore | 4 +- src/Documentation/samples/intro.md | 7 +-- src/Documentation/samples/toc.yml | 12 ++--- .../templates/tableau/styles/main.css | 12 ++++- src/Documentation/toc.yml | 7 ++- src/Python/pyproject.toml | 2 +- src/Python/scripts/build-package.ps1 | 2 +- src/Python/scripts/build_binaries.py | 2 +- src/Python/scripts/build_tests.py | 2 +- .../Api/IHttpResponseMessageExtensions.cs | 12 +++-- .../Api/IServiceCollectionExtensions.cs | 13 +++-- src/Tableau.Migration/Api/ISitesApiClient.cs | 12 +++-- .../Rest/Models/Responses/FlowsResponse.cs | 49 ++++++++++++++++--- .../Api/Rest/RestException.cs | 20 ++++++-- .../Api/Rest/RestUrlPrefixes.cs | 25 +++++----- src/Tableau.Migration/Api/SitesApiClient.cs | 19 ++++--- .../Files/ContentTypeFilePathResolver.cs | 11 +++-- .../Resources/SharedResources.resx | 8 +-- .../Tableau.Migration.csproj | 4 +- tests/Python.TestApplication/build.py | 6 +-- tests/Python.TestApplication/pyproject.toml | 2 +- .../Tableau.Migration.TestApplication.csproj | 2 +- ...leau.Migration.TestComponents.Tests.csproj | 2 +- .../Tableau.Migration.TestComponents.csproj | 2 +- .../Tableau.Migration.Tests.csproj | 2 +- .../Unit/Api/DataSourcesApiClientTests.cs | 8 +-- .../Api/IServiceCollectionExtensionsTests.cs | 8 +-- .../Unit/Api/Rest/RestExceptionTests.cs | 9 ++-- .../Files/ContentTypeFilePathResolverTests.cs | 9 ++-- 42 files changed, 275 insertions(+), 157 deletions(-) diff --git a/.editorconfig b/.editorconfig index fcdafe09..cdeaa198 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ [*.{cs,vb}] # File header -file_header_template = Copyright (c) 2023, 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 +file_header_template = \n Copyright (c) 2024, 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 #### Naming styles #### diff --git a/.gitignore b/.gitignore index 3e6a4924..93a79bba 100644 --- a/.gitignore +++ b/.gitignore @@ -184,8 +184,4 @@ UpgradeLog.htm /src/Documentation/_python /src/Python/Documentation/generated /tests/Python.TestApplication/manifest.json -/.git2gus -/src/Python/scripts/publish-package.ps1 -# Public repo ignores -.github/pull_request_template.md \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index c044e596..0c41fc3f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,3 @@ -# Comment line immediately above ownership line is reserved for related other information. Please be careful while editing. -#ECCN:Open Source 5D002 +#GUSINFO: gus_team_id,product_tag_id +#GUSINFO: a00EE00000glzJCYAY,a1aEE000000JtTpYAK +* @tableau/migration diff --git a/Directory.Build.props b/Directory.Build.props index 68edf209..941f3299 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,9 +4,9 @@ enable true true - 2.1.1 - Tableau Software, LLC - Tableau Software, LLC - Copyright (c) 2024, Tableau Software, LLC and its licensors + 3.0.0 + Salesforce, Inc. + Salesforce, Inc. + Copyright (c) 2024, Salesforce, Inc. and its licensors \ No newline at end of file diff --git a/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj b/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj index 13715dda..bb42f3e7 100644 --- a/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj +++ b/examples/Csharp.ExampleApplication/Csharp.ExampleApplication.csproj @@ -1,7 +1,7 @@  Exe - net6.0;net7.0;net8.0 + net6.0;net8.0 CA2007,IDE0073 7d7631f1-dc4a-49de-89d5-a194544705c1 diff --git a/examples/DependencyInjection.ExampleApplication/DependencyInjection.ExampleApplication.csproj b/examples/DependencyInjection.ExampleApplication/DependencyInjection.ExampleApplication.csproj index 1ecd9a56..0ce37473 100644 --- a/examples/DependencyInjection.ExampleApplication/DependencyInjection.ExampleApplication.csproj +++ b/examples/DependencyInjection.ExampleApplication/DependencyInjection.ExampleApplication.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net7.0;net8.0 + net6.0;net8.0 CA2007,IDE0073 diff --git a/scripts/generate-docs.ps1 b/scripts/generate-docs.ps1 index a6362859..81bfa82d 100644 --- a/scripts/generate-docs.ps1 +++ b/scripts/generate-docs.ps1 @@ -1,15 +1,15 @@ <# -Copyright (c) 2023, Salesforce, Inc. +Copyright (c) 2024, Salesforce, Inc. SPDX-License-Identifier: Apache-2 -Licensed under the Apache License, Version 2.0 (the ""License"") +Licensed under the Apache License, Version 2.0 (the "License") you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an ""AS IS"" BASIS, +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. @@ -43,6 +43,14 @@ $main_docs_dir = Join-Path $root_dir "src/Documentation" # Directory that sphinx generates automatic documentation to. $sphinx_output_dir = Join-Path $python_dir "Documentation/generated" +# Directory for Python wrapper files. Includes an index file and a directory for autogenerated files. +$python_wrapper_dir = Join-Path $main_docs_dir "python_wrapper"; + +$python_reference_dir_name = "reference"; + +# Directory where DocFX looks for markdown files to render into our 'Python Wrapper' section. +$python_md_destination = Join-Path $python_wrapper_dir $python_reference_dir_name; + function Run-Command { param([string]$Cmd) Write-Host "Executing command"; @@ -149,10 +157,7 @@ function Copy-Python-Docs { #> # Directory to which sphinx write generated markdown files. $sphinx_generated_files_dir = Join-Path $sphinx_output_dir "markdown/generated/*"; - - # Directory where DocFX looks for markdown files to render into our 'Python Wrapper' section. - $python_md_destination = Join-Path $main_docs_dir "python_wrapper"; - + Write-Host-With-Timestamp "Copying python docs to final destination."; Run-Command ("Clear-Directory -Path $python_md_destination"); Run-Command ("Copy-Item -Force -Recurse $sphinx_generated_files_dir -Destination $python_md_destination"); @@ -166,7 +171,6 @@ function Write-Python-Docs-Toc { .SYNOPSIS Generate a toc.yml file (table of contents for DocFX) from the python doc markdown files. #> - $python_md_destination = Join-Path $main_docs_dir "python_wrapper"; Write-Host-With-Timestamp "Generating toc.yml for Python auto-generated doc files ($python_md_destination)."; class DocFileInfo { @@ -212,6 +216,7 @@ function Write-Python-Docs-Toc { # Build the yaml file from DocFileInfo list $fileContent = New-Object Collections.Generic.List[string]; + $fileContent.Add("### YamlMime:TableOfContent"); $fileContent.Add("items:"); $packages = $docFiles | Where-Object { $_.Category -eq "Package" } if ($packages.Length -eq 0) { @@ -219,7 +224,7 @@ function Write-Python-Docs-Toc { } foreach ($package in $packages) { $fileContent.Add("- name: $($package.Package)"); - $fileContent.Add(" href: $($package.FileName)"); + $fileContent.Add(" href: $($python_reference_dir_name)/$($package.FileName)"); $moduleGroups = $docFiles | Where-Object { $_.Category -ne "Package" -and $_.Package -eq $package.Package } | Group-Object -Property Package, Module; if ($moduleGroups.Length -eq 0) { continue; @@ -229,7 +234,7 @@ function Write-Python-Docs-Toc { foreach ($moduleGroup in $moduleGroups) { $module = $moduleGroup.Group | Where-Object { $_.Category -eq "Module" }; $fileContent.Add(" - name: $($module.Module)"); - $fileContent.Add(" href: $($module.FileName)"); + $fileContent.Add(" href: $($python_reference_dir_name)/$($module.FileName)"); $members = $moduleGroup.Group | Where-Object { $_.Category -eq "Member" }; if ($members.Length -eq 0) { @@ -242,17 +247,17 @@ function Write-Python-Docs-Toc { foreach ($member in $functions) { $fileContent.Add(" - name: $($member.Member)"); - $fileContent.Add(" href: $($member.FileName)"); + $fileContent.Add(" href: $($python_reference_dir_name)/$($member.FileName)"); } foreach ($member in $classes) { $fileContent.Add(" - name: $($member.Member)"); - $fileContent.Add(" href: $($member.FileName)"); + $fileContent.Add(" href: $($python_reference_dir_name)/$($member.FileName)"); } } } - $tocPath = Join-Path -Path $python_md_destination -ChildPath toc.yml; + $tocPath = Join-Path -Path $python_wrapper_dir -ChildPath toc.yml; Run-Command ("Out-File -FilePath '$tocPath' -InputObject '$($fileContent | Out-String)'"); diff --git a/scripts/generate-license-header-python.ps1 b/scripts/generate-license-header-python.ps1 index d8b51de9..aa480465 100644 --- a/scripts/generate-license-header-python.ps1 +++ b/scripts/generate-license-header-python.ps1 @@ -1,5 +1,5 @@ <# -Copyright (c) 2023, Salesforce, Inc. +Copyright (c) 2024, Salesforce, Inc. SPDX-License-Identifier: Apache-2 Licensed under the Apache License, Version 2.0 (the ""License"") @@ -23,7 +23,7 @@ limitations under the License. #> param([string[]]$Target) -$license_header_python = "# Copyright (c) 2023, Salesforce, Inc. +$license_header_python = "# Copyright (c) 2024, Salesforce, Inc. # SPDX-License-Identifier: Apache-2 # # Licensed under the Apache License, Version 2.0 (the ""License""); diff --git a/src/Documentation/api/index.md b/src/Documentation/api/index.md index 060b96fc..14861723 100644 --- a/src/Documentation/api/index.md +++ b/src/Documentation/api/index.md @@ -1,6 +1,45 @@ # Introduction -This is the API Reference for the Migration SDK. +Welcome to the C# API Reference for the Migration SDK. + +## Examples to get started + +The following code samples are for writing a simple migration app using the Migration SDK. For details on configuring and customizing the Migration SDK to your specific needs, see [Articles](~/articles/intro.md) and [Code Samples](~/samples/intro.md). + +### [Program.cs](#tab/program-cs) + +[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Program.cs#namespace)] + +### [Startup code](#tab/startup-cde) + +[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/MyMigrationApplication.cs#namespace)] + +### [Config classes](#tab/config-classes) + +[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Config/MyMigrationApplicationOptions.cs#namespace)] + +[!code-csharp[CS](../../../examples/Csharp.ExampleApplication/Config/EndpointOptions.cs#namespace)] + +### [Config file](#tab/appsettings) + +```json +{ + "source": { + "serverUrl": "http://server", + "siteContentUrl": "", + "accessTokenName": "my server token name", + "accessToken": "my-secret-server-pat" + }, + "destination": { + "serverUrl": "https://pod.online.tableau.com", + "siteContentUrl": "site-name", + "accessTokenName": "my cloud token name", + "accessToken": "my-secret-cloud-pat" + } +} +``` + +--- ## Suggested Reading diff --git a/src/Documentation/articles/configuration.md b/src/Documentation/articles/configuration.md index 1c8f8efa..2e5315f1 100644 --- a/src/Documentation/articles/configuration.md +++ b/src/Documentation/articles/configuration.md @@ -53,7 +53,7 @@ The [`IMigrationPlan`](xref:Tableau.Migration.IMigrationPlan) interface defines *Optional/Required:* **Optional**. -*Description:* The Plan Builder exposes the properties [`MigrationPlanBuilder.Hooks`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Hooks), [`MigrationPlanBuilder.Filters`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Filters), [`MigrationPlanBuilder.Mappings`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Mappings), and [`MigrationPlanBuilder.Transformers`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Transformers). With these properties, it is possible to adjust a given migration plan for specific scenarios. For more details, check the [Custom Hooks article](advanced_config/hooks/custom_hooks.md). +*Description:* The Plan Builder exposes the properties [`MigrationPlanBuilder.Hooks`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Hooks), [`MigrationPlanBuilder.Filters`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Filters), [`MigrationPlanBuilder.Mappings`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Mappings), and [`MigrationPlanBuilder.Transformers`](xref:Tableau.Migration.Engine.MigrationPlanBuilder#Tableau_Migration_Engine_MigrationPlanBuilder_Transformers). With these properties, it is possible to adjust a given migration plan for specific scenarios. For more details, see the [Custom Hooks article](hooks/custom_hooks.md). ### Build @@ -65,7 +65,7 @@ The [`IMigrationPlan`](xref:Tableau.Migration.IMigrationPlan) interface defines [`MigrationSdkOptions`](xref:Tableau.Migration.Config.MigrationSdkOptions) is the configuration class the Migration SDK uses internally to process a migration. It contains adjustable properties that change some engine behaviors. These properties are useful tools to troubleshoot and tune a migration process. Start with this class and others in the [Config](xref:Tableau.Migration.Config) section for more details. -When writing a C# application, it is recommended that a [.NET Generic Host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host?tabs=appbuilder) is used to initialize the application. This will enable setting configuration values via `appsettings.json` which can be passed into `userOptions` in [`.AddTableauMigrationSdk`](xref:Tableau.Migration.IServiceCollectionExtensions#Tableau_Migration_IServiceCollectionExtensions_AddTableauMigrationSdk_Microsoft_Extensions_DependencyInjection_IServiceCollection_Microsoft_Extensions_Configuration_IConfiguration_). See [.NET getting started examples](~/samples/csharp.md) for more info. +When writing a C# application, we recommend using a [.NET Generic Host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host?tabs=appbuilder) to initialize the application. This will enable setting configuration values via `appsettings.json` which can be passed into `userOptions` in [`.AddTableauMigrationSdk`](xref:Tableau.Migration.IServiceCollectionExtensions#Tableau_Migration_IServiceCollectionExtensions_AddTableauMigrationSdk_Microsoft_Extensions_DependencyInjection_IServiceCollection_Microsoft_Extensions_Configuration_IConfiguration_). See [.NET getting started examples](~/api/index.md) for more info. When writing a python application, configuration values are set via environment variables. The `:` delimiter doesn't work with environment variable hierarchical keys on all platforms. For example, the `:` delimiter is not supported by Bash. The double underscore (`__`), which is supported on all platforms, automatically replaces any `:` delimiters in environment variables. All configuration environment variables start with `MigrationSDK__`. @@ -133,7 +133,7 @@ The following sections describe each setting. They should always be set per cont *Reload on Edit?:* **Yes**. The update will apply next time the Migration SDK requests a list of objects. -*Description:* The Migration SDK uses the **BatchSize** property to define the page size of each List Request. For more details, check the [Tableau REST API Paginating Results documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_paging.htm). +*Description:* The Migration SDK uses the **BatchSize** property to define the page size of each List Request. For more details, see the [Tableau REST API Paginating Results documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_paging.htm). #### ContentTypes.BatchPublishingEnabled @@ -158,7 +158,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK publishes a new batch. -*Description:* The Migration SDK uses [two methods](advanced_config/hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **individual process**. The SDK uses the **MigrationParallelism** property to define the number of parallel tasks migrating the same type of content simultaneously. It is possible to tune the Migration SDK processing time with this configuration. +*Description:* The Migration SDK uses [two methods](hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **individual process**. The SDK uses the **MigrationParallelism** property to define the number of parallel tasks migrating the same type of content simultaneously. It is possible to tune the Migration SDK processing time with this configuration. > [!WARNING] > There are [concurrency limits in REST APIs on Tableau Cloud](https://kb.tableau.com/articles/issue/concurrency-limits-in-rest-apis-on-tableau-cloud). The current default configuration is the balance between performance without blocking too many resources to the migration process. @@ -198,7 +198,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK publishes a new file. -*Description:* As part of the migration process, the Migration SDK has to publish file-based content types like Workbooks and Data Sources. Some of these files are very large. The Migration SDK uses the **FileChunkSizeKB** property to split these files into smaller pieces, making the publishing process more reliable. For more details, check the [Tableau REST API Publishing Resources documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm). +*Description:* As part of the migration process, the Migration SDK has to publish file-based content types like Workbooks and Data Sources. Some of these files are very large. The Migration SDK uses the **FileChunkSizeKB** property to split these files into smaller pieces, making the publishing process more reliable. For more details, see the [Tableau REST API Publishing Resources documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_publish.htm). ### Network.HeadersLoggingEnabled @@ -210,7 +210,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK logs a new HTTP request. -*Description:* Check the [logging article](logging.md) for more details. +*Description:* See the [logging article](logging.md) for more details. ### Network.ContentLoggingEnabled @@ -222,7 +222,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK logs a new HTTP request. -*Description:* Check the [logging article](logging.md) for more details. +*Description:* See the [logging article](logging.md) for more details. ### Network.BinaryContentLoggingEnabled @@ -234,7 +234,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK logs a new HTTP request. -*Description:* Check the [logging article](logging.md) for more details. +*Description:* See the [logging article](logging.md) for more details. ### Network.ExceptionsLoggingEnabled @@ -246,7 +246,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK logs a new HTTP request. -*Description:* Check the [logging article](logging.md) for more details. +*Description:* See the [logging article](logging.md) for more details. ### Network.Resilience.RetryEnabled @@ -450,7 +450,7 @@ Supported Content Types: *Reload on Edit?:* **No**. Any changes to this configuration will reflect on the next time the application starts. -*Description:* The SDK uses the **UrlSegments** property as a list of types of default permissions of given project. For more details, check the [Query Default Permissions documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#query_default_permissions). +*Description:* The SDK uses the **UrlSegments** property as a list of types of default permissions of given project. For more details, see the [Query Default Permissions documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#query_default_permissions). ### Jobs.JobPollRate @@ -462,7 +462,7 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK delays the processing status recheck. -*Description:* The Migration SDK uses [two methods](advanced_config/hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **bulk process**. After publishing a batch, the API will return a Job ID. With it, the SDK can call another API to check the job processing status. The SDK uses the **JobPollRate** property to define the interval it will wait to recheck processing status. For more details, check the [Tableau REST API Query Job documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job). +*Description:* The Migration SDK uses [two methods](hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **bulk process**. After publishing a batch, the API will return a Job ID. With it, the SDK can call another API to see the job processing status. The SDK uses the **JobPollRate** property to define the interval it will wait to recheck processing status. For more details, see the [Tableau REST API Query Job documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job). > [!WARNING] > There is [a limit for querying job status on Tableau Cloud](https://help.tableau.com/current/online/en-us/to_site_capacity.htm#jobs-initiated-by-command-line-and-api-calls). The current default configuration is the balance between performance without blocking too many resources to the migration process. @@ -476,4 +476,4 @@ Supported Content Types: *Reload on Edit?:* **Yes**. The update will apply the next time the Migration SDK validates the total time it has waited for the job to complete. -*Description:* The Migration SDK uses [two methods](advanced_config/hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **bulk process**. The SDK uses the **JobTimeout** property to define the maximum interval it will wait for a job to complete. For more details, check the [Tableau REST API Query Job documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job). +*Description:* The Migration SDK uses [two methods](hooks/index.md#hook-execution-flow) to publish the content to a destination server: the **bulk process**, where a single call to the API will push multiple items to the server, and the **individual process**, where it publishes a single item with a single call to the API. This configuration only applies to the **bulk process**. The SDK uses the **JobTimeout** property to define the maximum interval it will wait for a job to complete. For more details, see the [Tableau REST API Query Job documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job). diff --git a/src/Documentation/articles/intro.md b/src/Documentation/articles/intro.md index 5500acc9..2235bf0d 100644 --- a/src/Documentation/articles/intro.md +++ b/src/Documentation/articles/intro.md @@ -1,5 +1,5 @@ # Introduction -The Migration SDK is primarily written in C# using the [.NET](https://dotnet.microsoft.com/en-us/learn/dotnet/what-is-dotnet-framework) Framework. To enable interoperability with Python, it also includes a [Python Wrapper](python_wrapper.md). The articles in this section delve into useful information to help you design and write your migration application. +The Migration SDK is primarily written in C# using the [.NET](https://dotnet.microsoft.com/en-us/learn/dotnet/what-is-dotnet-framework) Framework. To enable interoperability with Python, it also includes a [Python Wrapper](~/python_wrapper/index.md). The articles in this section delve into useful information to help you design and write your migration application. This documentation also contains [Code Samples](~/samples/intro.md) to give you a head start. diff --git a/src/Documentation/articles/toc.yml b/src/Documentation/articles/toc.yml index 03210422..6d901f09 100644 --- a/src/Documentation/articles/toc.yml +++ b/src/Documentation/articles/toc.yml @@ -4,29 +4,19 @@ href: configuration.md - name: Plan Validation href: plan_validation.md -- name: Advanced Configuration - items: - - name: Hooks - href: advanced_config/hooks/index.md - items: - - name: Custom Hooks - href: advanced_config/hooks/custom_hooks.md - - name: Hooks in Python - href: advanced_config/hooks/python_hooks.md - - name: Example Hook Use Cases - href: advanced_config/hooks/example_hook_use_cases.md - - name: User Authentication - href: advanced_config/user_authentication.md - name: Logging - href: logging.md + href: logging.md +- name: Hooks + href: hooks/index.md + items: + - name: Custom Hooks + href: hooks/custom_hooks.md + - name: Example Hook Use Cases + href: hooks/example_hook_use_cases.md +- name: User Authentication + href: user_authentication.md - name: Dependency Injection href: dependency_injection.md -- name: Python Wrapper - href: python_wrapper.md - name: Troubleshooting - items: - - name: Troubleshooting - href: troubleshooting/troubleshooting.md - - name: Errors and Warning - href: troubleshooting/errors.md + href: troubleshooting.md diff --git a/src/Documentation/index.md b/src/Documentation/index.md index 3f694389..1cae2c3e 100644 --- a/src/Documentation/index.md +++ b/src/Documentation/index.md @@ -4,7 +4,7 @@ The full C# API Reference. -## [Python Wrapper](~/python_wrapper/tableau_migration.md) +## [Python Wrapper](~/python_wrapper/index.md) The Python Wrapper Reference. diff --git a/src/Documentation/python_wrapper/.gitignore b/src/Documentation/python_wrapper/.gitignore index c96a04f0..cd777832 100644 --- a/src/Documentation/python_wrapper/.gitignore +++ b/src/Documentation/python_wrapper/.gitignore @@ -1,2 +1,2 @@ -* -!.gitignore \ No newline at end of file +reference +/toc.yml \ No newline at end of file diff --git a/src/Documentation/samples/intro.md b/src/Documentation/samples/intro.md index e2f1e2b5..75af3c96 100644 --- a/src/Documentation/samples/intro.md +++ b/src/Documentation/samples/intro.md @@ -1,8 +1,3 @@ # Code Samples -To get you started with developing the Migration SDK, here is some example code. - -* [.NET getting started examples](csharp.md) -* [Python getting started examples](python.md) - -There are some more examples in this section to help you get started with advanced configuration via hooks. +After you have started building your migration using the example code in [C#](~/api/index.md) or [Python](~/python_wrapper/index.md), you may want to further customize your migration using hooks. This section contains some code samples to help. diff --git a/src/Documentation/samples/toc.yml b/src/Documentation/samples/toc.yml index d0b7c34c..45b83136 100644 --- a/src/Documentation/samples/toc.yml +++ b/src/Documentation/samples/toc.yml @@ -1,10 +1,6 @@ - name: Introduction href: intro.md -- name: Getting Started (.NET) - href: csharp.md -- name: Getting Started (Python) - href: python.md -- name: Samples - items: - - name: Hooks - href: hooks/toc.yml +- name: Hooks + href: hooks/toc.yml +- name: Hooks in Python + href: python_hooks.md diff --git a/src/Documentation/templates/tableau/styles/main.css b/src/Documentation/templates/tableau/styles/main.css index 30e6aa9b..aeb2f1b2 100644 --- a/src/Documentation/templates/tableau/styles/main.css +++ b/src/Documentation/templates/tableau/styles/main.css @@ -2,6 +2,7 @@ body { font-family: "Open Sans", Helvetica, Arial, sans-serif; + color: #555; } .toc .nav>li>a { @@ -11,6 +12,10 @@ body { padding: 0; } +.toc .nav>li.active>a { + font-weight: bold; +} + /* Table of Contents*/ .sidetoc { background-color: #ffffff; @@ -47,8 +52,8 @@ body .toc { } .toc .level1>li { - font-weight: bold; font-size: 14px; + font-weight: normal; } .toc .level2 { @@ -57,6 +62,11 @@ body .toc { .expand-stub::before { color: #337ab7; + font-weight: normal; +} + +.expand-stub+a { + font-weight: normal; } /*Navbar*/ diff --git a/src/Documentation/toc.yml b/src/Documentation/toc.yml index 1bae974a..136cb8b6 100644 --- a/src/Documentation/toc.yml +++ b/src/Documentation/toc.yml @@ -2,8 +2,11 @@ href: api/ homepage: api/index.md - name: Python Wrapper - href: python_wrapper/tableau_migration.md + href: python_wrapper/ + homepage: python_wrapper/index.md - name: Code Samples href: samples/ + homepage: samples/intro.md - name: Articles - href: articles/ \ No newline at end of file + href: articles/ + homepage: articles/intro.md \ No newline at end of file diff --git a/src/Python/pyproject.toml b/src/Python/pyproject.toml index 4468ecce..f1801815 100644 --- a/src/Python/pyproject.toml +++ b/src/Python/pyproject.toml @@ -7,7 +7,7 @@ name = "tableau_migration" dynamic = ["version"] authors = [ - { name="Tableau a Salesforce Product" }, + { name="Salesforce, Inc." }, ] description = "Tableau Migration SDK" readme = "README.md" diff --git a/src/Python/scripts/build-package.ps1 b/src/Python/scripts/build-package.ps1 index 7106703b..60b0bc07 100644 --- a/src/Python/scripts/build-package.ps1 +++ b/src/Python/scripts/build-package.ps1 @@ -38,7 +38,7 @@ try { Remove-Item -Recurse -ErrorAction SilentlyContinue dist/* - dotnet publish /p:DebugType=None /p:DebugSymbols=false $projectToBuild -c $Configuration -o .\src\tableau_migration\bin -f net7.0 + dotnet publish /p:DebugType=None /p:DebugSymbols=false $projectToBuild -c $Configuration -o .\src\tableau_migration\bin -f net6.0 } finally { diff --git a/src/Python/scripts/build_binaries.py b/src/Python/scripts/build_binaries.py index 3d63a66a..0609bbcb 100644 --- a/src/Python/scripts/build_binaries.py +++ b/src/Python/scripts/build_binaries.py @@ -14,4 +14,4 @@ sys.path.append(bin_path) shutil.rmtree(bin_path, True) -subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net7.0"]) +subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net6.0"]) diff --git a/src/Python/scripts/build_tests.py b/src/Python/scripts/build_tests.py index 103dfabd..a48c793d 100644 --- a/src/Python/scripts/build_tests.py +++ b/src/Python/scripts/build_tests.py @@ -6,4 +6,4 @@ testcomponent_project = abspath("../../tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj") -subprocess.run(["dotnet", "publish", testcomponent_project, "-o", build_binaries.bin_path, "-f", "net7.0"]) \ No newline at end of file +subprocess.run(["dotnet", "publish", testcomponent_project, "-o", build_binaries.bin_path, "-f", "net6.0"]) \ No newline at end of file diff --git a/src/Tableau.Migration/Api/IHttpResponseMessageExtensions.cs b/src/Tableau.Migration/Api/IHttpResponseMessageExtensions.cs index 3df8d0f1..2d6203e6 100644 --- a/src/Tableau.Migration/Api/IHttpResponseMessageExtensions.cs +++ b/src/Tableau.Migration/Api/IHttpResponseMessageExtensions.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -58,6 +59,7 @@ public static async Task ToResultAsync(this IHttpResponseMessage respon if (tsError is not null) { throw new RestException( + response.RequestMessage?.Method, response.RequestMessage?.RequestUri, tsError, sharedResourcesLocalizer); @@ -117,6 +119,7 @@ public static IResult ToResult(this IHttpResponseMess if (restError is not null) { throw new RestException( + response.RequestMessage?.Method, response.RequestMessage?.RequestUri, restError, sharedResourcesLocalizer); @@ -147,6 +150,7 @@ public static async Task> ToResultAsync(this if (restError is not null) { throw new RestException( + response.RequestMessage?.Method, response.RequestMessage?.RequestUri, restError, sharedResourcesLocalizer); @@ -193,6 +197,7 @@ public static IPagedResult ToPagedResult(this IHttpRe if (restError is not null) { throw new RestException( + response.RequestMessage?.Method, response.RequestMessage?.RequestUri, restError, sharedResourcesLocalizer); @@ -241,6 +246,7 @@ public static async Task> ToPagedResultAsync(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); - services.AddScoped(); services.AddScoped(); + services.AddScoped(); //API Simulator. services.AddSingleton(); @@ -77,6 +79,7 @@ internal static IServiceCollection AddMigrationApiClient(this IServiceCollection //Publishing services. services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(typeof(ILabelsApiClient<>), typeof(LabelsApiClient<>)); diff --git a/src/Tableau.Migration/Api/ISitesApiClient.cs b/src/Tableau.Migration/Api/ISitesApiClient.cs index f618a6a1..33b1b50c 100644 --- a/src/Tableau.Migration/Api/ISitesApiClient.cs +++ b/src/Tableau.Migration/Api/ISitesApiClient.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -63,6 +64,11 @@ public interface ISitesApiClient : IAsyncDisposable, IContentApiClient /// IViewsApiClient Views { get; } + /// + /// Gets the API client for prep flow operations. + /// + IFlowsApiClient Flows { get; } + /// /// Gets the site with the specified ID. /// diff --git a/src/Tableau.Migration/Api/Rest/Models/Responses/FlowsResponse.cs b/src/Tableau.Migration/Api/Rest/Models/Responses/FlowsResponse.cs index 42a6066b..5f01a399 100644 --- a/src/Tableau.Migration/Api/Rest/Models/Responses/FlowsResponse.cs +++ b/src/Tableau.Migration/Api/Rest/Models/Responses/FlowsResponse.cs @@ -1,20 +1,22 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; +using System.Linq; using System.Xml.Serialization; namespace Tableau.Migration.Api.Rest.Models.Responses @@ -37,7 +39,7 @@ public class FlowsResponse : PagedTableauServerResponse /// /// Class representing a site response. /// - public class FlowType + public class FlowType : IFlowType { /// /// Gets or sets the ID for the response. @@ -63,6 +65,12 @@ public class FlowType [XmlAttribute("webpageUrl")] public string? WebpageUrl { get; set; } + /// + /// Gets or sets the file type for the response. + /// + [XmlAttribute("fileType")] + public string? FileType { get; set; } + /// /// Gets or sets the created timestamp for the response. /// @@ -81,11 +89,15 @@ public class FlowType [XmlElement("project")] public ProjectType? Project { get; set; } + IProjectReferenceType? IWithProjectType.Project => Project; + /// /// Gets or sets the owner for the response. /// [XmlElement("owner")] - public UserType? Owner { get; set; } + public OwnerType? Owner { get; set; } + + IOwnerType? IWithOwnerType.Owner => Owner; /// /// Gets or sets the tags for the response. @@ -94,10 +106,16 @@ public class FlowType [XmlArrayItem("tag")] public TagType[] Tags { get; set; } = Array.Empty(); + ITagType[] IWithTagTypes.Tags + { + get => Tags; + set => Tags = value.Select(t => new TagType(t)).ToArray(); + } + /// /// Class representing a REST API project response. /// - public class ProjectType + public class ProjectType : IProjectReferenceType { /// /// Gets or sets the ID for the response. @@ -115,7 +133,7 @@ public class ProjectType /// /// Class representing a REST API user response. /// - public class UserType + public class OwnerType : IOwnerType { /// /// Gets or sets the ID for the response. @@ -133,13 +151,28 @@ public class UserType /// /// Class representing a REST API tag response. /// - public class TagType + public class TagType : ITagType { /// /// Gets or sets the label for the response. /// [XmlAttribute("label")] public string? Label { get; set; } + + /// + /// The default parameterless constructor. + /// + public TagType() + { } + + /// + /// Constructor to build from + /// + /// The object. + public TagType(ITagType tag) + { + Label = tag.Label; + } } } } diff --git a/src/Tableau.Migration/Api/Rest/RestException.cs b/src/Tableau.Migration/Api/Rest/RestException.cs index 1ab220ea..06e3c388 100644 --- a/src/Tableau.Migration/Api/Rest/RestException.cs +++ b/src/Tableau.Migration/Api/Rest/RestException.cs @@ -1,20 +1,22 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; +using System.Net.Http; using Tableau.Migration.Api.Rest.Models; using Tableau.Migration.Resources; @@ -25,6 +27,11 @@ namespace Tableau.Migration.Api.Rest /// public class RestException : Exception { + /// + /// Gets the request URI from Tableau API. + /// + public readonly HttpMethod? HttpMethod; + /// /// Gets the request URI from Tableau API. /// @@ -48,15 +55,18 @@ public class RestException : Exception /// /// Creates a new instance. /// + /// The http method that generated the current error. /// The request URI that generated the current error. /// The returned from the Tableau API. /// A string localizer. public RestException( + HttpMethod? httpMethod, Uri? requestUri, Error error, ISharedResourcesLocalizer sharedResourcesLocalizer) - : base(FormatError(requestUri, error, sharedResourcesLocalizer)) + : base(FormatError(httpMethod, requestUri, error, sharedResourcesLocalizer)) { + HttpMethod = httpMethod; RequestUri = requestUri; Code = error.Code; Detail = error.Detail; @@ -64,6 +74,7 @@ public RestException( } private static string FormatError( + HttpMethod? httpMethod, Uri? requestUri, Error error, ISharedResourcesLocalizer sharedResourcesLocalizer) @@ -72,6 +83,7 @@ private static string FormatError( return string.Format( sharedResourcesLocalizer[SharedResourceKeys.RestExceptionContent], + httpMethod, requestUri, error.Code ?? nullValue, error.Summary ?? nullValue, diff --git a/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs b/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs index 4566984d..2b485379 100644 --- a/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs +++ b/src/Tableau.Migration/Api/Rest/RestUrlPrefixes.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -25,26 +26,28 @@ internal static class RestUrlPrefixes private static readonly IImmutableDictionary _urlPrefixesByType = new Dictionary(InheritedTypeComparer.Instance) { [typeof(IDataSourcesApiClient)] = DataSources, + [typeof(IFlowsApiClient)] = Flows, [typeof(IGroupsApiClient)] = Groups, [typeof(IJobsApiClient)] = Jobs, [typeof(IProjectsApiClient)] = Projects, [typeof(ISitesApiClient)] = Sites, [typeof(IUsersApiClient)] = Users, - [typeof(IWorkbooksApiClient)] = Workbooks, [typeof(IViewsApiClient)] = Views, + [typeof(IWorkbooksApiClient)] = Workbooks, } .ToImmutableDictionary(InheritedTypeComparer.Instance); - public const string Sites = "sites"; - public const string Projects = "projects"; - public const string Users = "users"; - public const string Groups = "groups"; + public const string Content = "content"; public const string DataSources = "datasources"; - public const string Workbooks = "workbooks"; + public const string FileUploads = "fileUploads"; + public const string Flows = "flows"; + public const string Groups = "groups"; public const string Jobs = "jobs"; + public const string Projects = "projects"; + public const string Sites = "sites"; + public const string Users = "users"; public const string Views = "views"; - public const string FileUploads = "fileUploads"; - public const string Content = "content"; + public const string Workbooks = "workbooks"; public static string GetUrlPrefix() where TApiClient : IContentApiClient diff --git a/src/Tableau.Migration/Api/SitesApiClient.cs b/src/Tableau.Migration/Api/SitesApiClient.cs index be435276..786f39d4 100644 --- a/src/Tableau.Migration/Api/SitesApiClient.cs +++ b/src/Tableau.Migration/Api/SitesApiClient.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -52,7 +53,8 @@ public SitesApiClient( IUsersApiClient usersApiClient, IDataSourcesApiClient dataSourcesApiClient, IWorkbooksApiClient workbooksApiClient, - IViewsApiClient viewssApiClient, + IViewsApiClient viewsApiClient, + IFlowsApiClient flowsApiClient, ISharedResourcesLocalizer sharedResourcesLocalizer) : base(restRequestBuilderFactory, finderFactory, loggerFactory, sharedResourcesLocalizer) { @@ -65,7 +67,8 @@ public SitesApiClient( Users = usersApiClient; DataSources = dataSourcesApiClient; Workbooks = workbooksApiClient; - Views = viewssApiClient; + Views = viewsApiClient; + Flows = flowsApiClient; } private static readonly ImmutableDictionary> _contentTypeAccessors = new Dictionary>(InheritedTypeComparer.Instance) @@ -75,7 +78,8 @@ public SitesApiClient( { typeof(IProject), client => client.Projects }, { typeof(IDataSource), client => client.DataSources }, { typeof(IWorkbook), client => client.Workbooks }, - { typeof(IView), client => client.Views } + { typeof(IView), client => client.Views }, + { typeof(IFlow), client => client.Flows } } .ToImmutableDictionary(InheritedTypeComparer.Instance); @@ -109,6 +113,9 @@ public SitesApiClient( /// public IViewsApiClient Views { get; } + /// + public IFlowsApiClient Flows { get; } + /// public IReadApiClient? GetReadApiClient() where TContent : class diff --git a/src/Tableau.Migration/Content/Files/ContentTypeFilePathResolver.cs b/src/Tableau.Migration/Content/Files/ContentTypeFilePathResolver.cs index ac096423..efa14c36 100644 --- a/src/Tableau.Migration/Content/Files/ContentTypeFilePathResolver.cs +++ b/src/Tableau.Migration/Content/Files/ContentTypeFilePathResolver.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -33,6 +34,10 @@ public string ResolveRelativePath(TContent contentItem, string origina { return Path.Combine("data-sources", $"data-source-{ds.Id:N}{extension}"); } + else if(contentItem is IFlow f) + { + return Path.Combine("flows", $"flow-{f.Id:N}{extension}"); + } else if (contentItem is IWorkbook wb) { return Path.Combine("workbooks", $"workbook-{wb.Id:N}{extension}"); diff --git a/src/Tableau.Migration/Resources/SharedResources.resx b/src/Tableau.Migration/Resources/SharedResources.resx index 73029620..bc462a34 100644 --- a/src/Tableau.Migration/Resources/SharedResources.resx +++ b/src/Tableau.Migration/Resources/SharedResources.resx @@ -188,10 +188,10 @@ An error was returned from the Tableau API: -URL: {0} -Code: {1} -Summary: {2} -Detail: {3} +URL: {0} {1} +Code: {2} +Summary: {3} +Detail: {4} # Exception diff --git a/src/Tableau.Migration/Tableau.Migration.csproj b/src/Tableau.Migration/Tableau.Migration.csproj index 9e052f41..6e9fcbfc 100644 --- a/src/Tableau.Migration/Tableau.Migration.csproj +++ b/src/Tableau.Migration/Tableau.Migration.csproj @@ -2,7 +2,7 @@ Tableau Migration SDK https://github.com/tableau/tableau-migration-sdk - net6.0;net7.0;net8.0 + net6.0;net8.0 Tableau.Migration True @@ -41,7 +41,7 @@ Note: This SDK is specific for migrating from Tableau Server to Tableau Cloud. I - + diff --git a/tests/Python.TestApplication/build.py b/tests/Python.TestApplication/build.py index eb41699f..0154cd6e 100644 --- a/tests/Python.TestApplication/build.py +++ b/tests/Python.TestApplication/build.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, Salesforce, Inc. +# Copyright (c) 2024, Salesforce, Inc. # SPDX-License-Identifier: Apache-2 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,7 +34,7 @@ def build(): migration_project = abspath("../../tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj") test_component_project = abspath("../../tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj") shutil.rmtree(bin_path, True) - subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net7.0"]) - subprocess.run(["dotnet", "publish", test_component_project, "-o", bin_path, "-f", "net7.0"]) + subprocess.run(["dotnet", "publish", migration_project, "-o", bin_path, "-f", "net6.0"]) + subprocess.run(["dotnet", "publish", test_component_project, "-o", bin_path, "-f", "net6.0"]) sys.path.append(bin_path) diff --git a/tests/Python.TestApplication/pyproject.toml b/tests/Python.TestApplication/pyproject.toml index bdb46cb5..2a266ed4 100644 --- a/tests/Python.TestApplication/pyproject.toml +++ b/tests/Python.TestApplication/pyproject.toml @@ -3,7 +3,7 @@ name = "tableau_migration_testapplication" dynamic = ["version"] authors = [ - { name="Tableau a Salesforce Product" }, + { name="Salesforce, Inc." }, ] description = "Tableau Migration SDK - Test Application" # https://devguide.python.org/versions/ diff --git a/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj b/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj index c5d175f1..39ed68e1 100644 --- a/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj +++ b/tests/Tableau.Migration.TestApplication/Tableau.Migration.TestApplication.csproj @@ -1,7 +1,7 @@  Exe - net6.0;net7.0;net8.0 + net6.0;net8.0 CA2007 7d7631f1-dc4a-49de-89d5-a194544705c1 diff --git a/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj b/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj index 6aecc9f4..4cb6f478 100644 --- a/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj +++ b/tests/Tableau.Migration.TestComponents.Tests/Tableau.Migration.TestComponents.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net8.0 enable enable diff --git a/tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj b/tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj index 35b09c01..b56b7df8 100644 --- a/tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj +++ b/tests/Tableau.Migration.TestComponents/Tableau.Migration.TestComponents.csproj @@ -1,7 +1,7 @@ - net6.0;net7.0;net8.0 + net6.0;net8.0 enable enable diff --git a/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj b/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj index 0db2537d..09f23bda 100644 --- a/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj +++ b/tests/Tableau.Migration.Tests/Tableau.Migration.Tests.csproj @@ -1,6 +1,6 @@  - net6.0;net7.0;net8.0 + net6.0;net8.0 true CA2007 diff --git a/tests/Tableau.Migration.Tests/Unit/Api/DataSourcesApiClientTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/DataSourcesApiClientTests.cs index 3bfd1728..39b9af7c 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/DataSourcesApiClientTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/DataSourcesApiClientTests.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -24,7 +25,6 @@ using Tableau.Migration.Api; using Tableau.Migration.Api.Rest.Models.Responses; using Tableau.Migration.Content; -using Tableau.Migration.Content.Files; using Tableau.Migration.Tests.Unit.Api.Permissions; using Xunit; diff --git a/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs index f4114e9e..63d4380e 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/IServiceCollectionExtensionsTests.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -104,6 +105,7 @@ public async Task RegistersScopedApiClients() AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); + AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); AssertService(scope, ServiceLifetime.Scoped); diff --git a/tests/Tableau.Migration.Tests/Unit/Api/Rest/RestExceptionTests.cs b/tests/Tableau.Migration.Tests/Unit/Api/Rest/RestExceptionTests.cs index 00eaab43..af710560 100644 --- a/tests/Tableau.Migration.Tests/Unit/Api/Rest/RestExceptionTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Api/Rest/RestExceptionTests.cs @@ -1,20 +1,22 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // using System; +using System.Net.Http; using Microsoft.Extensions.Localization; using Moq; using Tableau.Migration.Api.Rest; @@ -41,6 +43,7 @@ public void Initializes() var error = Create(); var exception = new RestException( + HttpMethod.Get, new Uri("http://localhost"), error, mockLocalizer.Object); diff --git a/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentTypeFilePathResolverTests.cs b/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentTypeFilePathResolverTests.cs index 0a2dba67..3753db9b 100644 --- a/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentTypeFilePathResolverTests.cs +++ b/tests/Tableau.Migration.Tests/Unit/Content/Files/ContentTypeFilePathResolverTests.cs @@ -1,14 +1,15 @@ -// Copyright (c) 2023, Salesforce, Inc. +// +// Copyright (c) 2024, Salesforce, Inc. // SPDX-License-Identifier: Apache-2 // -// Licensed under the Apache License, Version 2.0 (the ""License"") +// Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an ""AS IS"" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -33,6 +34,8 @@ public class ResolveRelativePath : AutoFixtureTestBase [InlineData(typeof(IDataSource), "data-sources", "orig.tds", "data-source-", "tds")] [InlineData(typeof(IWorkbook), "workbooks", "orig.twbx", "workbook-", "twbx")] [InlineData(typeof(IWorkbook), "workbooks", "orig.twb", "workbook-", "twb")] + [InlineData(typeof(IFlow), "flows", "orig.tflx", "flow-", "tflx")] + [InlineData(typeof(IFlow), "flows", "orig.tfl", "flow-", "tfl")] public void SupportedContentTypesGenerateExpectedPath(Type t, string dir, string originalFileName, string expectedPrefix, string expectedExtension) {