Skip to content

Commit 353414e

Browse files
authored
Merge pull request #23 from tableau/release/4.0.0
Release 4.0.0
2 parents 197e2cd + cdfd627 commit 353414e

File tree

298 files changed

+13191
-4302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

298 files changed

+13191
-4302
lines changed

.github/workflows/python-test.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ jobs:
4444
- name: Test with pytest
4545
run: |
4646
python -m hatch --data-dir=.hatch --cache-dir=.hatch_cache run test:testcov
47-
python -m hatch --data-dir=.hatch --cache-dir=.hatch_cache run test:pytest tests/test_migrations_engine_hooks_lifetime.py
48-
python -m hatch --data-dir=.hatch --cache-dir=.hatch_cache run test:pytest tests/test_migrations_engine_hooks_filters_lifetime.py
49-
python -m hatch --data-dir=.hatch --cache-dir=.hatch_cache run test:pytest tests/test_migrations_engine_hooks_mappings_lifetime.py
50-
python -m hatch --data-dir=.hatch --cache-dir=.hatch_cache run test:pytest tests/test_migrations_engine_hooks_transformers_lifetime.py
5147
5248
- name: Test TestApplication with pytest
5349
run: |

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ appsettings.Development.json
176176
clean-server-settings.dev.json
177177
launchSettings.json
178178
UpgradeLog.htm
179-
*.DEV.ini
180-
*.DEV.json
179+
*.*.ini
180+
*.*.json
181181
/src/Python/Documentation/_build
182182
/src/Python/Documentation/_static
183183
/src/Python/Python.pyproj.user

Directory.Build.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
<Nullable>enable</Nullable>
55
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
66
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
7-
<Version>3.0.1</Version>
7+
<Version>4.0.0</Version>
88
<Authors>Salesforce, Inc.</Authors>
99
<Company>Salesforce, Inc.</Company>
1010
<Copyright>Copyright (c) 2024, Salesforce, Inc. and its licensors</Copyright>
11+
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
1112
</PropertyGroup>
1213
</Project>

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Apache License Version 2.0
22

3-
Copyright (c) 2023 Salesforce, Inc.
3+
Copyright (c) 2024 Salesforce, Inc.
44
All rights reserved.
55

66
Apache License

Migration SDK.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1818
CONTRIBUTING.md = CONTRIBUTING.md
1919
Directory.Build.props = Directory.Build.props
2020
global.json = global.json
21+
LICENSE.txt = LICENSE.txt
2122
README.md = README.md
2223
SECURITY.md = SECURITY.md
2324
EndProjectSection
@@ -82,6 +83,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "setup-dotnet", "setup-dotne
8283
.github\actions\setup-dotnet\action.yml = .github\actions\setup-dotnet\action.yml
8384
EndProjectSection
8485
EndProject
86+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tableau.Migration.PythonGenerator", "src\Tableau.Migration.PythonGenerator\Tableau.Migration.PythonGenerator.csproj", "{F20029C7-4514-4668-8941-B2C3BC245CCB}"
87+
EndProject
8588
Global
8689
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8790
Debug|Any CPU = Debug|Any CPU
@@ -124,6 +127,10 @@ Global
124127
{99DA12FB-BB16-4EE1-9C9C-047755210255}.Debug|Any CPU.Build.0 = Debug|Any CPU
125128
{99DA12FB-BB16-4EE1-9C9C-047755210255}.Release|Any CPU.ActiveCfg = Release|Any CPU
126129
{99DA12FB-BB16-4EE1-9C9C-047755210255}.Release|Any CPU.Build.0 = Release|Any CPU
130+
{F20029C7-4514-4668-8941-B2C3BC245CCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
131+
{F20029C7-4514-4668-8941-B2C3BC245CCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
132+
{F20029C7-4514-4668-8941-B2C3BC245CCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
133+
{F20029C7-4514-4668-8941-B2C3BC245CCB}.Release|Any CPU.Build.0 = Release|Any CPU
127134
EndGlobalSection
128135
GlobalSection(SolutionProperties) = preSolution
129136
HideSolutionNode = FALSE

examples/Csharp.ExampleApplication/Hooks/Mappings/ChangeProjectMapping.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,32 @@
55
using Tableau.Migration;
66
using Tableau.Migration.Content;
77
using Tableau.Migration.Engine.Hooks.Mappings;
8+
using Tableau.Migration.Resources;
89

910
namespace Csharp.ExampleApplication.Hooks.Mappings
1011
{
1112
#region class
12-
public class ChangeProjectMapping : IContentMapping<IDataSource>, IContentMapping<IWorkbook>
13+
public class ChangeProjectMapping<T> : ContentMappingBase<T>
14+
where T : IContentReference, IMappableContainerContent
1315
{
1416
private static readonly StringComparer StringComparer = StringComparer.OrdinalIgnoreCase;
1517

16-
private readonly ILogger<ChangeProjectMapping> _logger;
18+
private readonly ILogger<IContentMapping<T>>? _logger;
1719

18-
public ChangeProjectMapping(ILogger<ChangeProjectMapping> logger)
20+
public ChangeProjectMapping(ISharedResourcesLocalizer? localizer, ILogger<IContentMapping<T>>? logger) : base(localizer, logger)
1921
{
2022
_logger = logger;
2123
}
2224

23-
private async Task<ContentMappingContext<T>?> ExecuteAsync<T>(ContentMappingContext<T> ctx)
24-
where T : IContentReference, IMappableContainerContent
25+
public override Task<ContentMappingContext<T>?> MapAsync(ContentMappingContext<T> ctx, CancellationToken cancel)
2526
{
2627
// Get the container (project) location for the content item.
2728
var containerLocation = ctx.ContentItem.Location.Parent();
2829

2930
// We only want to map content items whose project name is "Test".
3031
if (!StringComparer.Equals("Test", containerLocation.Name))
3132
{
32-
return ctx;
33+
return ctx.ToTask();
3334
}
3435

3536
// Build the new project location.
@@ -41,20 +42,20 @@ public ChangeProjectMapping(ILogger<ChangeProjectMapping> logger)
4142
// Map the new content item location.
4243
ctx = ctx.MapTo(newLocation);
4344

44-
_logger.LogInformation(
45+
_logger?.LogInformation(
4546
"{ContentType} mapped from {OldLocation} to {NewLocation}.",
4647
typeof(T).Name,
4748
ctx.ContentItem.Location,
4849
ctx.MappedLocation);
4950

50-
return await ctx.ToTask();
51+
return ctx.ToTask();
5152
}
5253

53-
public async Task<ContentMappingContext<IDataSource>?> ExecuteAsync(ContentMappingContext<IDataSource> ctx, CancellationToken cancel)
54-
=> await ExecuteAsync(ctx);
54+
public async Task<ContentMappingContext<IDataSource>?> MapAsync(ContentMappingContext<IDataSource> ctx, CancellationToken cancel)
55+
=> await MapAsync(ctx, cancel);
5556

56-
public async Task<ContentMappingContext<IWorkbook>?> ExecuteAsync(ContentMappingContext<IWorkbook> ctx, CancellationToken cancel)
57-
=> await ExecuteAsync(ctx);
57+
public async Task<ContentMappingContext<IWorkbook>?> MapAsync(ContentMappingContext<IWorkbook> ctx, CancellationToken cancel)
58+
=> await MapAsync(ctx, cancel);
5859
}
5960
#endregion
6061
}

examples/Csharp.ExampleApplication/Hooks/Mappings/EmailDomainMapping.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ public EmailDomainMapping(
4242
public override Task<ContentMappingContext<IUser>?> MapAsync(ContentMappingContext<IUser> userMappingContext, CancellationToken cancel)
4343
{
4444
var domain = userMappingContext.MappedLocation.Parent();
45+
4546
// Re-use an existing email if it already exists.
4647
if (!string.IsNullOrEmpty(userMappingContext.ContentItem.Email))
4748
return userMappingContext.MapTo(domain.Append(userMappingContext.ContentItem.Email)).ToTask();
4849

49-
// Takes the existing username and appends the default domain to build the email
50+
// Takes the existing username and appends the domain to build the email
5051
var testEmail = $"{userMappingContext.ContentItem.Name}@{_domain}";
5152
return userMappingContext.MapTo(domain.Append(testEmail)).ToTask();
5253
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Microsoft.Extensions.Logging;
6+
using Tableau.Migration;
7+
using Tableau.Migration.Content;
8+
using Tableau.Migration.Engine.Hooks.Transformers;
9+
using Tableau.Migration.Resources;
10+
11+
namespace Csharp.ExampleApplication.Hooks.Transformers
12+
{
13+
#region class
14+
public class EncryptExtractsTransformer<T> : ContentTransformerBase<T> where T : IContentReference, IFileContent, IExtractContent
15+
{
16+
private readonly ILogger<IContentTransformer<T>>? _logger;
17+
18+
public EncryptExtractsTransformer(ISharedResourcesLocalizer? localizer, ILogger<IContentTransformer<T>>? logger) : base(localizer, logger)
19+
{
20+
_logger = logger;
21+
}
22+
23+
public override async Task<T?> TransformAsync(T itemToTransform, CancellationToken cancel)
24+
{
25+
itemToTransform.EncryptExtracts = true;
26+
27+
_logger?.LogInformation(
28+
@"Setting encrypt extract to true for {ContentType} {ContentLocation}",
29+
typeof(T).Name,
30+
itemToTransform.Location);
31+
32+
return await Task.FromResult(itemToTransform);
33+
}
34+
35+
public async Task<IPublishableWorkbook?> TransformAsync(IPublishableWorkbook ctx, CancellationToken cancel)
36+
=> await TransformAsync(ctx, cancel);
37+
38+
public async Task<IPublishableDataSource?> TransformAsync(IPublishableDataSource ctx, CancellationToken cancel)
39+
=> await TransformAsync(ctx, cancel);
40+
}
41+
#endregion
42+
}

examples/Csharp.ExampleApplication/Hooks/Transformers/MigratedTagTransformer.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,41 @@
66
using Tableau.Migration;
77
using Tableau.Migration.Content;
88
using Tableau.Migration.Engine.Hooks.Transformers;
9+
using Tableau.Migration.Resources;
910

1011
namespace Csharp.ExampleApplication.Hooks.Transformers
1112
{
1213
#region class
13-
public class MigratedTagTransformer : IContentTransformer<IPublishableWorkbook>, IContentTransformer<IPublishableDataSource>
14+
public class MigratedTagTransformer<T> : ContentTransformerBase<T> where T : IContentReference, IWithTags
1415
{
15-
private readonly ILogger<MigratedTagTransformer> _logger;
16+
private readonly ILogger<IContentTransformer<T>>? _logger;
1617

17-
public MigratedTagTransformer(ILogger<MigratedTagTransformer> logger)
18+
public MigratedTagTransformer(ISharedResourcesLocalizer? localizer, ILogger<IContentTransformer<T>>? logger) : base(localizer, logger)
1819
{
1920
_logger = logger;
2021
}
2122

22-
protected async Task<T?> ExecuteAsync<T>(T ctx)
23-
where T : IContentReference, IWithTags
23+
public override async Task<T?> TransformAsync(T itemToTransform, CancellationToken cancel)
2424
{
2525
var tag = "Migrated";
2626

2727
// Add the tag to the content item.
28-
ctx.Tags.Add(new Tag(tag));
28+
itemToTransform.Tags.Add(new Tag(tag));
2929

30-
_logger.LogInformation(
30+
_logger?.LogInformation(
3131
@"Added ""{Tag}"" tag to {ContentType} {ContentLocation}.",
3232
tag,
3333
typeof(T).Name,
34-
ctx.Location);
34+
itemToTransform.Location);
3535

36-
return await Task.FromResult(ctx);
36+
return await Task.FromResult(itemToTransform);
3737
}
3838

39-
public async Task<IPublishableWorkbook?> ExecuteAsync(IPublishableWorkbook ctx, CancellationToken cancel)
40-
=> await ExecuteAsync(ctx);
39+
public async Task<IPublishableWorkbook?> TransformAsync(IPublishableWorkbook ctx, CancellationToken cancel)
40+
=> await TransformAsync(ctx, cancel);
4141

42-
public async Task<IPublishableDataSource?> ExecuteAsync(IPublishableDataSource ctx, CancellationToken cancel)
43-
=> await ExecuteAsync(ctx);
42+
public async Task<IPublishableDataSource?> TransformAsync(IPublishableDataSource ctx, CancellationToken cancel)
43+
=> await TransformAsync(ctx, cancel);
4444
}
4545
#endregion
4646
}

examples/Csharp.ExampleApplication/MyMigrationApplication.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ public async Task StartAsync(CancellationToken cancel)
8686
#endregion
8787

8888
#region ChangeProjectMapping-Registration
89-
_planBuilder.Mappings.Add<ChangeProjectMapping, IDataSource>();
90-
_planBuilder.Mappings.Add<ChangeProjectMapping, IWorkbook>();
89+
_planBuilder.Mappings.Add<ChangeProjectMapping<IDataSource>, IDataSource>();
90+
_planBuilder.Mappings.Add<ChangeProjectMapping<IWorkbook>, IWorkbook>();
9191
#endregion
9292

9393
// Add filters
@@ -111,8 +111,13 @@ public async Task StartAsync(CancellationToken cancel)
111111

112112
// Add transformers
113113
#region MigratedTagTransformer-Registration
114-
_planBuilder.Transformers.Add<MigratedTagTransformer, IPublishableDataSource>();
115-
_planBuilder.Transformers.Add<MigratedTagTransformer, IPublishableWorkbook>();
114+
_planBuilder.Transformers.Add<MigratedTagTransformer<IPublishableDataSource>, IPublishableDataSource>();
115+
_planBuilder.Transformers.Add<MigratedTagTransformer<IPublishableWorkbook>, IPublishableWorkbook>();
116+
#endregion
117+
118+
#region EncryptExtractTransformer-Registration
119+
_planBuilder.Transformers.Add<EncryptExtractsTransformer<IPublishableDataSource>, IPublishableDataSource>();
120+
_planBuilder.Transformers.Add<EncryptExtractsTransformer<IPublishableWorkbook>, IPublishableWorkbook>();
116121
#endregion
117122

118123
// Add migration action completed hooks

examples/Csharp.ExampleApplication/Program.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.Extensions.DependencyInjection;
1010
using Microsoft.Extensions.Hosting;
1111
using Tableau.Migration;
12+
using Tableau.Migration.Content;
1213

1314
#region namespace
1415
namespace Csharp.ExampleApplication
@@ -56,7 +57,8 @@ public static IServiceCollection AddCustomizations(this IServiceCollection servi
5657
#endregion
5758

5859
#region ChangeProjectMapping-DI
59-
services.AddScoped<ChangeProjectMapping>();
60+
services.AddScoped<ChangeProjectMapping<IWorkbook>>();
61+
services.AddScoped<ChangeProjectMapping<IDataSource>>();
6062
#endregion
6163

6264
#region DefaultProjectsFilter-DI
@@ -76,7 +78,13 @@ public static IServiceCollection AddCustomizations(this IServiceCollection servi
7678
#endregion
7779

7880
#region MigratedTagTransformer-DI
79-
services.AddScoped<MigratedTagTransformer>();
81+
services.AddScoped<MigratedTagTransformer<IPublishableDataSource>>();
82+
services.AddScoped<MigratedTagTransformer<IPublishableWorkbook>>();
83+
#endregion
84+
85+
#region EncryptExtractTransformer-DI
86+
services.AddScoped<EncryptExtractsTransformer<IPublishableDataSource>>();
87+
services.AddScoped<EncryptExtractsTransformer<IPublishableWorkbook>>();
8088
#endregion
8189

8290
#region LogMigrationActionsHook-DI
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from tableau_migration import (
2+
IProject,
3+
ContentMigrationItem,
4+
ContentFilterBase)
5+
6+
7+
class DefaultProjectFilter(ContentFilterBase[IProject]):
8+
def should_migrate(self, item: ContentMigrationItem[IProject]) -> bool:
9+
if item.source_item.name.casefold() == 'Default'.casefold():
10+
return False
11+
return True
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from tableau_migration import (
2+
IUser,
3+
ContentMigrationItem,
4+
ContentFilterBase,
5+
SiteRoles)
6+
7+
8+
class UnlicensedUserFilter(ContentFilterBase[IUser]):
9+
def should_migrate(self, item: ContentMigrationItem[IUser]) -> bool:
10+
if item.source_item.license_level.casefold() == SiteRoles.UNLICENSED.casefold():
11+
return False
12+
return True
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import logging
2+
from typing import TypeVar
3+
from tableau_migration import(
4+
ContentBatchMigrationCompletedHookBase,
5+
IContentBatchMigrationResult,
6+
IUser
7+
)
8+
9+
T = TypeVar("T")
10+
11+
class LogMigrationBatchesHook(ContentBatchMigrationCompletedHookBase[T]):
12+
def __init__(self) -> None:
13+
super().__init__()
14+
self._logger = logging.getLogger(__name__)
15+
16+
def execute(self, ctx: IContentBatchMigrationResult[T]) -> IContentBatchMigrationResult[T]:
17+
18+
item_status = ""
19+
for item in ctx.item_results:
20+
item_status += "%s: %s".format(item.manifest_entry.source.location, item.manifest_entry.status)
21+
22+
self._logger.info("%s batch of %d item(s) completed:\n%s", ctx._content_type, ctx.item_results.count, item_status)
23+
24+
pass
25+
26+
class LogMigrationBatchesHookForUsers(ContentBatchMigrationCompletedHookBase[IUser]):
27+
def __init__(self) -> None:
28+
super().__init__()
29+
self._content_type = "User";
30+
31+
class LogMigrationBatchesHookForGoups(ContentBatchMigrationCompletedHookBase[IUser]):
32+
def __init__(self) -> None:
33+
super().__init__()
34+
self._content_type = "Group";

0 commit comments

Comments
 (0)