Skip to content

Commit 587b9dc

Browse files
authored
Release 4.3.1 (#37)
1 parent ca234f6 commit 587b9dc

15 files changed

+343
-189
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ launchSettings.json
177177
UpgradeLog.htm
178178
*.*.ini
179179
*.*.json
180+
src/Documentation/python
180181

181182
# Public repo ignores
182183
.github/pull_request_template.md

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Nullable>enable</Nullable>
55
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
66
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
7-
<Version>4.3.0</Version>
7+
<Version>4.3.1</Version>
88
<Authors>Salesforce, Inc.</Authors>
99
<Company>Salesforce, Inc.</Company>
1010
<Copyright>Copyright (c) 2024, Salesforce, Inc. and its licensors</Copyright>

src/Tableau.Migration/Api/IContentReferenceFinderFactoryExtensions.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
using Tableau.Migration.Api.Rest;
2424
using Tableau.Migration.Api.Rest.Models;
2525
using Tableau.Migration.Content;
26-
using Tableau.Migration.Content.Schedules;
2726
using Tableau.Migration.Content.Search;
2827
using Tableau.Migration.Resources;
2928

@@ -126,19 +125,6 @@ internal static class IContentReferenceFinderFactoryExtensions
126125
cancel)
127126
.ConfigureAwait(false);
128127

129-
public static async Task<IContentReference> FindExtractRefreshContentAsync(
130-
this IContentReferenceFinderFactory finderFactory,
131-
ExtractRefreshContentType contentType,
132-
Guid contentId,
133-
CancellationToken cancel)
134-
{
135-
var finder = finderFactory.ForExtractRefreshContent(contentType);
136-
137-
var content = await finder.FindByIdAsync(contentId, cancel).ConfigureAwait(false);
138-
139-
return Guard.AgainstNull(content, nameof(content));
140-
}
141-
142128
private static async Task<IContentReference?> FindAsync<TResponse, TContent>(
143129
this IContentReferenceFinderFactory finderFactory,
144130
[NotNull] TResponse? response,

src/Tableau.Migration/Api/TasksApiClient.cs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
using Tableau.Migration.Net.Rest;
3333
using Tableau.Migration.Paging;
3434
using Tableau.Migration.Resources;
35+
3536
using CloudResponses = Tableau.Migration.Api.Rest.Models.Responses.Cloud;
3637
using ServerResponses = Tableau.Migration.Api.Rest.Models.Responses.Server;
3738

@@ -70,17 +71,11 @@ public TasksApiClient(
7071

7172
/// <inheritdoc />
7273
public IServerTasksApiClient ForServer()
73-
=> ExecuteForInstanceType(
74-
TableauInstanceType.Server,
75-
_sessionProvider.InstanceType,
76-
() => this);
74+
=> ExecuteForInstanceType(TableauInstanceType.Server, _sessionProvider.InstanceType, () => this);
7775

7876
/// <inheritdoc />
7977
public ICloudTasksApiClient ForCloud()
80-
=> ExecuteForInstanceType(
81-
TableauInstanceType.Cloud,
82-
_sessionProvider.InstanceType,
83-
() => this);
78+
=> ExecuteForInstanceType(TableauInstanceType.Cloud, _sessionProvider.InstanceType, () => this);
8479

8580
#endregion
8681

@@ -105,10 +100,7 @@ public async Task<IResult> DeleteExtractRefreshTaskAsync(
105100
async Task<IResult<IImmutableList<ICloudExtractRefreshTask>>> ICloudTasksApiClient.GetAllExtractRefreshTasksAsync(
106101
CancellationToken cancel)
107102
=> await GetAllExtractRefreshTasksAsync<CloudResponses.ExtractRefreshTasksResponse, ICloudExtractRefreshTask, ICloudSchedule>(
108-
(r, c) => CloudExtractRefreshTask.CreateManyAsync(
109-
r,
110-
ContentFinderFactory,
111-
c),
103+
(r, c) => CloudExtractRefreshTask.CreateManyAsync(r, ContentFinderFactory, Logger, SharedResourcesLocalizer, c),
112104
cancel)
113105
.ConfigureAwait(false);
114106

@@ -122,14 +114,18 @@ async Task<IResult<ICloudExtractRefreshTask>> ICloudTasksApiClient.CreateExtract
122114
.ForPostRequest()
123115
.WithXmlContent(new CreateExtractRefreshTaskRequest(options))
124116
.SendAsync<CloudResponses.CreateExtractRefreshTaskResponse>(cancel)
125-
.ToResultAsync((r, c) =>
126-
CloudExtractRefreshTask.CreateAsync(
127-
r.Item,
128-
r.Schedule,
129-
ContentFinderFactory,
130-
c),
131-
SharedResourcesLocalizer,
132-
cancel)
117+
.ToResultAsync(async (r, c) =>
118+
{
119+
var task = Guard.AgainstNull(r.Item, () => r.Item);
120+
var finder = ContentFinderFactory.ForExtractRefreshContent(task.GetContentType());
121+
122+
var contentReference = await finder.FindByIdAsync(task.GetContentId(), cancel).ConfigureAwait(false);
123+
124+
// Since we published with a content reference, we expect the reference returned is valid/knowable.
125+
Guard.AgainstNull(contentReference, () => contentReference);
126+
127+
return CloudExtractRefreshTask.Create(task, r.Schedule, contentReference);
128+
}, SharedResourcesLocalizer, cancel)
133129
.ConfigureAwait(false);
134130

135131
return result;
@@ -158,11 +154,7 @@ public async Task<IResult<ICloudExtractRefreshTask>> PublishAsync(
158154
/// <inheritdoc />
159155
async Task<IResult<IImmutableList<IServerExtractRefreshTask>>> IServerTasksApiClient.GetAllExtractRefreshTasksAsync(CancellationToken cancel)
160156
=> await GetAllExtractRefreshTasksAsync<ServerResponses.ExtractRefreshTasksResponse, IServerExtractRefreshTask, IServerSchedule>(
161-
(r, c) => ServerExtractRefreshTask.CreateManyAsync(
162-
r,
163-
ContentFinderFactory,
164-
_contentCacheFactory,
165-
c),
157+
(r, c) => ServerExtractRefreshTask.CreateManyAsync(r, ContentFinderFactory, _contentCacheFactory, Logger, SharedResourcesLocalizer, c),
166158
cancel)
167159
.ConfigureAwait(false);
168160

src/Tableau.Migration/Content/Schedules/Cloud/CloudExtractRefreshTask.cs

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
using System.Collections.Immutable;
2020
using System.Threading;
2121
using System.Threading.Tasks;
22+
using Microsoft.Extensions.Logging;
2223
using Tableau.Migration.Api.Rest.Models.Responses;
2324
using Tableau.Migration.Api.Rest.Models.Responses.Cloud;
2425
using Tableau.Migration.Content.Search;
26+
using Tableau.Migration.Resources;
2527

2628
namespace Tableau.Migration.Content.Schedules.Cloud
2729
{
@@ -34,54 +36,33 @@ internal CloudExtractRefreshTask(
3436
ExtractRefreshContentType contentType,
3537
IContentReference contentReference,
3638
ICloudSchedule schedule)
37-
: base(
38-
extractRefreshId,
39-
type,
40-
contentType,
41-
contentReference,
42-
schedule)
39+
: base(extractRefreshId, type, contentType, contentReference, schedule)
4340
{ }
4441

4542
public static async Task<IImmutableList<ICloudExtractRefreshTask>> CreateManyAsync(
46-
ExtractRefreshTasksResponse? response,
43+
ExtractRefreshTasksResponse response,
4744
IContentReferenceFinderFactory finderFactory,
45+
ILogger logger, ISharedResourcesLocalizer localizer,
4846
CancellationToken cancel)
4947
=> await CreateManyAsync(
5048
response,
5149
response => response.Items.ExceptNulls(i => i.ExtractRefresh),
5250
(r, c, cnl) => Task.FromResult(Create(r, r.Schedule, c)),
53-
finderFactory,
51+
finderFactory, logger, localizer,
5452
cancel)
5553
.ConfigureAwait(false);
5654

57-
public static async Task<ICloudExtractRefreshTask> CreateAsync(
58-
ICloudExtractRefreshType? response,
59-
ICloudScheduleType? schedule,
60-
IContentReferenceFinderFactory finderFactory,
61-
CancellationToken cancel)
62-
=> await CreateAsync(
63-
response,
64-
finderFactory,
65-
(r, c, cnl) => Task.FromResult(Create(r, schedule, c)),
66-
cancel)
67-
.ConfigureAwait(false);
68-
69-
private static ICloudExtractRefreshTask Create(
70-
IExtractRefreshType? response,
71-
ICloudScheduleType? schedule,
55+
public static ICloudExtractRefreshTask Create(
56+
IExtractRefreshType response,
57+
ICloudScheduleType schedule,
7258
IContentReference content)
7359
{
74-
Guard.AgainstNull(response, nameof(response));
75-
7660
return new CloudExtractRefreshTask(
7761
response.Id,
7862
response.Type!,
7963
response.GetContentType(),
8064
content,
81-
new CloudSchedule(
82-
Guard.AgainstNull(
83-
schedule,
84-
() => schedule)));
65+
new CloudSchedule(schedule));
8566
}
8667
}
8768
}

src/Tableau.Migration/Content/Schedules/ExtractRefreshTaskBase.cs

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
using System.Collections.Immutable;
2121
using System.Threading;
2222
using System.Threading.Tasks;
23-
using Tableau.Migration.Api;
23+
using Microsoft.Extensions.Logging;
2424
using Tableau.Migration.Api.Rest.Models;
2525
using Tableau.Migration.Api.Rest.Models.Responses;
2626
using Tableau.Migration.Content.Search;
27+
using Tableau.Migration.Resources;
2728

2829
namespace Tableau.Migration.Content.Schedules
2930
{
@@ -32,8 +33,11 @@ internal abstract class ExtractRefreshTaskBase<TSchedule> :
3233
where TSchedule : ISchedule
3334
{
3435
public string Type { get; set; }
36+
3537
public ExtractRefreshContentType ContentType { get; set; }
38+
3639
public IContentReference Content { get; set; }
40+
3741
public TSchedule Schedule { get; }
3842

3943
protected ExtractRefreshTaskBase(
@@ -54,57 +58,43 @@ protected ExtractRefreshTaskBase(
5458
Schedule = schedule;
5559
}
5660

57-
protected static async Task<TExtractRefreshTask> CreateAsync<TExtractRefreshType, TExtractRefreshTask>(
58-
TExtractRefreshType? response,
59-
IContentReferenceFinderFactory finderFactory,
60-
Func<TExtractRefreshType, IContentReference, CancellationToken, Task<TExtractRefreshTask>> modelFactory,
61-
CancellationToken cancel)
62-
where TExtractRefreshType : class, IExtractRefreshType
63-
where TExtractRefreshTask: IExtractRefreshTask<TSchedule>
64-
{
65-
Guard.AgainstNull(response, nameof(response));
66-
67-
var contentReference = await finderFactory
68-
.FindExtractRefreshContentAsync(
69-
response.GetContentType(),
70-
response.GetContentId(),
71-
cancel)
72-
.ConfigureAwait(false);
73-
74-
var model = await modelFactory(
75-
response,
76-
contentReference,
77-
cancel)
78-
.ConfigureAwait(false);
79-
80-
return model;
81-
}
82-
83-
protected static async Task<IImmutableList<TExtractRefreshTask>> CreateManyAsync<TResponse,TExtractRefreshType, TExtractRefreshTask>(
84-
TResponse? response,
61+
protected static async Task<IImmutableList<TExtractRefreshTask>> CreateManyAsync<TResponse, TExtractRefreshType, TExtractRefreshTask>(
62+
TResponse response,
8563
Func<TResponse, IEnumerable<TExtractRefreshType?>> responseItemFactory,
8664
Func<TExtractRefreshType, IContentReference, CancellationToken, Task<TExtractRefreshTask>> modelFactory,
8765
IContentReferenceFinderFactory finderFactory,
66+
ILogger logger, ISharedResourcesLocalizer localizer,
8867
CancellationToken cancel)
8968
where TResponse : ITableauServerResponse
9069
where TExtractRefreshType : class, IExtractRefreshType
9170
where TExtractRefreshTask: IExtractRefreshTask<TSchedule>
9271
{
93-
Guard.AgainstNull(response, nameof(response));
94-
95-
var tasks = ImmutableArray.CreateBuilder<TExtractRefreshTask>();
96-
97-
var items = responseItemFactory(response).ExceptNulls();
72+
var items = responseItemFactory(response).ExceptNulls().ToImmutableArray();
73+
var tasks = ImmutableArray.CreateBuilder<TExtractRefreshTask>(items.Length);
9874

9975
foreach (var item in items)
10076
{
101-
tasks.Add(
102-
await CreateAsync(
103-
item,
104-
finderFactory,
105-
modelFactory,
106-
cancel)
107-
.ConfigureAwait(false));
77+
var contentType = item.GetContentType();
78+
79+
if(contentType is ExtractRefreshContentType.Unknown)
80+
{
81+
logger.LogWarning(localizer[SharedResourceKeys.UnknownExtractRefreshContentTypeWarning], item.Id);
82+
continue;
83+
}
84+
85+
var finder = finderFactory.ForExtractRefreshContent(contentType);
86+
var contentReference = await finder.FindByIdAsync(item.GetContentId(), cancel).ConfigureAwait(false);
87+
88+
/*
89+
* Content reference is null when the referenced content item (e.g. workbook/data source)
90+
* is in a private space or other "pre-manifest" filter.
91+
*
92+
* We similarly filter out those extract refresh tasks.
93+
*/
94+
if(contentReference is not null)
95+
{
96+
tasks.Add(await modelFactory(item, contentReference, cancel).ConfigureAwait(false));
97+
}
10898
}
10999

110100
return tasks.ToImmutable();

src/Tableau.Migration/Content/Schedules/Server/ServerExtractRefreshTask.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
using System.Linq;
2121
using System.Threading;
2222
using System.Threading.Tasks;
23+
using Microsoft.Extensions.Logging;
2324
using Tableau.Migration.Api.Rest.Models.Responses;
2425
using Tableau.Migration.Api.Rest.Models.Responses.Server;
2526
using Tableau.Migration.Content.Search;
27+
using Tableau.Migration.Resources;
2628

2729
namespace Tableau.Migration.Content.Schedules.Server
2830
{
@@ -47,26 +49,25 @@ internal ServerExtractRefreshTask(
4749
{ }
4850

4951
public static async Task<IImmutableList<IServerExtractRefreshTask>> CreateManyAsync(
50-
ExtractRefreshTasksResponse? response,
52+
ExtractRefreshTasksResponse response,
5153
IContentReferenceFinderFactory finderFactory,
5254
IContentCacheFactory contentCacheFactory,
55+
ILogger logger, ISharedResourcesLocalizer localizer,
5356
CancellationToken cancel)
5457
=> await CreateManyAsync(
5558
response,
5659
response => response.Items.ExceptNulls(i => i.ExtractRefresh),
5760
async (r, c, cnl) => await CreateAsync(r, c, contentCacheFactory, cnl).ConfigureAwait(false),
58-
finderFactory,
61+
finderFactory, logger, localizer,
5962
cancel)
6063
.ConfigureAwait(false);
6164

6265
private static async Task<IServerExtractRefreshTask> CreateAsync(
63-
IServerExtractRefreshType? response,
66+
IServerExtractRefreshType response,
6467
IContentReference content,
6568
IContentCacheFactory contentCacheFactory,
6669
CancellationToken cancel)
6770
{
68-
Guard.AgainstNull(response, nameof(response));
69-
7071
var scheduleCache = contentCacheFactory.ForContentType<IServerSchedule>(true);
7172

7273
var schedule = await scheduleCache.ForIdAsync(response.Schedule.Id, cancel).ConfigureAwait(false);

src/Tableau.Migration/Resources/SharedResourceKeys.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,7 @@ internal static class SharedResourceKeys
142142
public const string UserWithCustomViewDefaultSkippedMissingReferenceWarning = "UserWithCustomViewDefaultSkippedMissingReferenceWarning";
143143

144144
public const string DuplicateContentTypeConfigurationMessage = "DuplicateContentTypeConfigurationMessage";
145+
146+
public const string UnknownExtractRefreshContentTypeWarning = "UnknownExtractRefreshContentTypeWarning";
145147
}
146148
}

src/Tableau.Migration/Resources/SharedResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,7 @@ Owner with ID {OwnerID}: {owner}</value>
315315
<data name="DuplicateContentTypeConfigurationMessage" xml:space="preserve">
316316
<value>Duplicate content type configuration found for content type {0}.</value>
317317
</data>
318+
<data name="UnknownExtractRefreshContentTypeWarning" xml:space="preserve">
319+
<value>The extract refresh task with ID {TaskId} references an unknown content type. The task will be ignored.</value>
320+
</data>
318321
</root>

0 commit comments

Comments
 (0)