Merge pull request #46 from microsoft/users/annautiy/PreDownloadV2

Added support for PreDownload
This commit is contained in:
Annautiy 2024-06-10 23:45:15 +05:30 коммит произвёл GitHub
Родитель 8e346c5f48 984ac4a679
Коммит 9faf3df638
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
18 изменённых файлов: 207 добавлений и 79 удалений

Просмотреть файл

@ -92,6 +92,9 @@
- **availabilityDate**: optional - if informed it will configure custom availability date for your XVC/MSIXVC packages [Learn more](http://go.microsoft.com/fwlink/?LinkId=825239)
- **isEnabled**: optional (default false) - it will enable/disable custom availability date
- **effectiveDate**: optional - if informed it will set the package availability date (date format example: "2021-10-24T21:00:00.000Z")
- **preDownloadDate**: optional (default is equivalent to availabilityDate) - it will configure when package will be available for download for your XVC/MSIXVC packages
- **isEnabled**: optional (default false) - it will enable/disable custom pre-download date
- **effectiveDate**: optional - if informed it will set the package pre-download date (date format example: "2021-10-24T21:00:00.000Z")
- **uploadConfig**: optional - httpClient configuration to be used to upload the files
- **httpTimeoutMs**: (default and recommended: 5000)
- **httpUploadTimeoutMs**: (default and recommended: 300000)
@ -143,6 +146,9 @@
- **mandatoryDate**: optional - if informed it will configure custom mandatory date for your UWP market groups in the destination branch/flight [Learn more](https://docs.microsoft.com/en-gb/windows/uwp/publish/upload-app-packages#mandatory-update)
- **isEnabled**: optional (default false) - it will enable/disable custom mandatory date
- **effectiveDate**: optional - if informed it will set the mandatory date (date format example: "2021-10-24T21:00:00.000Z")
- **preDownloadDate**: optional (default is equivalent to availabilityDate) - it will configure when package will be available for download for your XVC/MSIXVC packages
- **isEnabled**: optional (default false) - it will enable/disable custom pre-download date
- **effectiveDate**: optional - if informed it will set the package pre-download date (date format example: "2021-10-24T21:00:00.000Z")
- **gradualRollout**: optional - if informed it will configure gradual rollout for your UWP packages in the destination branch/flight [Learn more](https://docs.microsoft.com/en-gb/windows/uwp/publish/upload-app-packages#gradual-package-rollout)
- **isEnabled**: optional (default false) - it will enable/disable gradual rollout
- **percentage**: optional - rollout to start with

Просмотреть файл

@ -18,9 +18,9 @@ internal class ImportPackagesOperationConfig : PackageBranchOperationConfig, IGa
public string DestinationFlightName { get; set; }
public GamePackageDate AvailabilityDate { get; set; }
public GamePackageDate PreDownloadDate { get; set; }
public GamePackageDate MandatoryDate { get; set; }
public GameGradualRolloutInfo GradualRollout { get; set; }
public bool Overwrite { get; set; }
protected override void Validate(IList<ValidationResult> validationResults)
@ -35,5 +35,15 @@ internal class ImportPackagesOperationConfig : PackageBranchOperationConfig, IGa
{
validationResults.Add(new ValidationResult($"Only one {nameof(DestinationBranchFriendlyName)} or {nameof(DestinationFlightName)} field is allowed.", new[] { nameof(DestinationBranchFriendlyName), nameof(DestinationFlightName) }));
}
}
if (PreDownloadDate?.IsEnabled == true && (AvailabilityDate?.IsEnabled != true))
{
validationResults.Add(new ValidationResult($"{nameof(PreDownloadDate)} needs {nameof(AvailabilityDate)}.", new[] { nameof(PreDownloadDate), nameof(AvailabilityDate) }));
}
if (PreDownloadDate?.IsEnabled == true && AvailabilityDate?.IsEnabled == true && PreDownloadDate.EffectiveDate > AvailabilityDate.EffectiveDate)
{
validationResults.Add(new ValidationResult($"{nameof(PreDownloadDate)} needs to be before {nameof(AvailabilityDate)}.", new[] { nameof(PreDownloadDate), nameof(AvailabilityDate) }));
}
}
}

Просмотреть файл

@ -6,7 +6,7 @@ using PackageUploader.ClientApi.Models;
namespace PackageUploader.Application.Config;
internal class UploadUwpPackageOperationConfig : UploadPackageOperationConfig, IGameConfiguration
internal class UploadUwpPackageOperationConfig : UploadPackageOperationConfig, IUwpGameConfiguration
{
internal override string GetOperationName() => "UploadUwpPackage";

Просмотреть файл

@ -1,12 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using PackageUploader.ClientApi.Models;
namespace PackageUploader.Application.Config;
internal class UploadXvcPackageOperationConfig : UploadPackageOperationConfig
internal class UploadXvcPackageOperationConfig : UploadPackageOperationConfig, IXvcGameConfiguration
{
internal override string GetOperationName() => "UploadXvcPackage";
@ -14,4 +15,21 @@ internal class UploadXvcPackageOperationConfig : UploadPackageOperationConfig
public GameAssets GameAssets { get; set; }
public bool DeltaUpload { get; set; } = false;
public GamePackageDate PreDownloadDate { get; set; }
protected override void Validate(IList<ValidationResult> validationResults)
{
base.Validate(validationResults);
if (PreDownloadDate?.IsEnabled == true && (AvailabilityDate?.IsEnabled != true))
{
validationResults.Add(new ValidationResult($"{nameof(PreDownloadDate)} needs {nameof(AvailabilityDate)}.", new[] { nameof(PreDownloadDate), nameof(AvailabilityDate) }));
}
if (PreDownloadDate?.IsEnabled == true && AvailabilityDate?.IsEnabled == true && PreDownloadDate.EffectiveDate > AvailabilityDate.EffectiveDate)
{
validationResults.Add(new ValidationResult($"{nameof(PreDownloadDate)} needs to be before {nameof(AvailabilityDate)}.", new[] { nameof(PreDownloadDate), nameof(AvailabilityDate) }));
}
}
}

Просмотреть файл

@ -36,10 +36,10 @@ internal class UploadXvcPackageOperation : Operation
var gamePackage = await _storeBrokerService.UploadGamePackageAsync(product, packageBranch, marketGroupPackage, _config.PackageFilePath, _config.GameAssets, _config.MinutesToWaitForProcessing, _config.DeltaUpload, isXvc: true, ct).ConfigureAwait(false);
_logger.LogInformation("Uploaded package with id: {gamePackageId}", gamePackage.Id);
if (_config.AvailabilityDate is not null)
if (_config.AvailabilityDate is not null || _config.PreDownloadDate is not null)
{
await _storeBrokerService.SetXvcAvailabilityDateAsync(product, packageBranch, gamePackage, _config.MarketGroupName, _config.AvailabilityDate, ct).ConfigureAwait(false);
_logger.LogInformation("Availability date set");
await _storeBrokerService.SetXvcConfigurationAsync(product, packageBranch, gamePackage, _config.MarketGroupName, _config, ct).ConfigureAwait(false);
_logger.LogInformation("Configuration set for Xvc packages");
}
}
}

Просмотреть файл

@ -168,6 +168,7 @@ internal static class IngestionMapper
MandatoryUpdateInfo = ingestionMarketGroupPackage.MandatoryUpdateInfo.Map(),
AvailabilityDate = ingestionMarketGroupPackage.AvailabilityDate,
PackageAvailabilityDates = ingestionMarketGroupPackage.PackageAvailabilityDates,
PackageIdToMetadataMap = ingestionMarketGroupPackage.PackageIdToMetadataMap?.ToDictionary(a => a.Key, a => a.Value?.Map()),
};
private static GameMandatoryUpdateInfo Map(this IngestionMandatoryUpdateInfo ingestionMandatoryUpdateInfo) =>
@ -209,6 +210,7 @@ internal static class IngestionMapper
Markets = gameMarketGroupPackage.Markets,
Name = gameMarketGroupPackage.Name,
PackageAvailabilityDates = gameMarketGroupPackage.PackageAvailabilityDates?.ToDictionary(a => a.Key, a => a.Value?.ToUniversalTime()),
PackageIdToMetadataMap = gameMarketGroupPackage.PackageIdToMetadataMap?.ToDictionary(a => a.Key, a => a.Value?.Map()),
PackageIds = gameMarketGroupPackage.PackageIds,
};
@ -258,4 +260,16 @@ internal static class IngestionMapper
Name = ingestionFlight.Name,
CurrentDraftInstanceId = gamePackageBranch.CurrentDraftInstanceId,
};
private static GameMarketGroupPackageMetadata Map(this IngestionMarketGroupPackageMetadata ingestionMarketGroupPackageMetadata) =>
ingestionMarketGroupPackageMetadata is null ? null : new()
{
PreDownloadDate = ingestionMarketGroupPackageMetadata.PreDownloadDate,
};
private static IngestionMarketGroupPackageMetadata Map(this GameMarketGroupPackageMetadata marketGroupPackageMetadata) =>
marketGroupPackageMetadata is null ? null : new()
{
PreDownloadDate = marketGroupPackageMetadata.PreDownloadDate,
};
}

Просмотреть файл

@ -42,4 +42,9 @@ public sealed class GameMarketGroupPackage
/// Dictionary of per region, per package scheduled release dates for XVC and MSIXVC packages
/// </summary>
public Dictionary<string, DateTime?> PackageAvailabilityDates { get; set; }
/// <summary>
/// Dictionary of per package metadata (e.g. predownload date) for XVC and MSIXVC packages
/// </summary>
public Dictionary<string, GameMarketGroupPackageMetadata> PackageIdToMetadataMap { get; set; }
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
namespace PackageUploader.ClientApi.Client.Ingestion.Models;
public class GameMarketGroupPackageMetadata
{
public DateTime? PreDownloadDate { get; set; }
}

Просмотреть файл

@ -29,12 +29,12 @@ internal class IngestionMarketGroupPackage
public List<string> PackageIds { get; set; }
/// <summary>
/// Mandatory update
/// Mandatory update for UWP packages
/// </summary>
public IngestionMandatoryUpdateInfo MandatoryUpdateInfo { get; set; }
/// <summary>
/// Schedule release date per region
/// Schedule release date per region for UWP packages
/// </summary>
public DateTime? AvailabilityDate { get; set; }
@ -42,4 +42,9 @@ internal class IngestionMarketGroupPackage
/// Dictionary of per region, per package scheduled release dates for XVC and MSIXVC packages
/// </summary>
public Dictionary<string, DateTime?> PackageAvailabilityDates { get; set; }
/// <summary>
/// Dictionary of per package metadata (e.g. predownload date) for XVC and MSIXVC packages
/// </summary>
public Dictionary<string, IngestionMarketGroupPackageMetadata> PackageIdToMetadataMap { get; set; }
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
namespace PackageUploader.ClientApi.Client.Ingestion.Models.Internal;
internal class IngestionMarketGroupPackageMetadata
{
public DateTime? PreDownloadDate { get; set; }
}

Просмотреть файл

@ -21,8 +21,8 @@ public interface IPackageUploaderService
Task<GamePackageConfiguration> UpdatePackageConfigurationAsync(GameProduct product, GamePackageConfiguration packageConfiguration, CancellationToken ct);
Task<GamePackage> UploadGamePackageAsync(GameProduct product, IGamePackageBranch packageBranch, GameMarketGroupPackage marketGroupPackage, string packageFilePath, GameAssets gameAssets, int minutesToWaitForProcessing, bool deltaUpload, bool isXvc, CancellationToken ct);
Task<GamePackageConfiguration> RemovePackagesAsync(GameProduct product, IGamePackageBranch packageBranch, string marketGroupName, string packageFileName, CancellationToken ct);
Task<GamePackageConfiguration> SetXvcAvailabilityDateAsync(GameProduct product, IGamePackageBranch packageBranch, GamePackage gamePackage, string marketGroupName, GamePackageDate availabilityDate, CancellationToken ct);
Task<GamePackageConfiguration> SetUwpConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, string marketGroupId, IGameConfiguration gameConfiguration, CancellationToken ct);
Task<GamePackageConfiguration> SetXvcConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, GamePackage gamePackage, string marketGroupName, IXvcGameConfiguration gameConfiguration, CancellationToken ct);
Task<GamePackageConfiguration> SetUwpConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, string marketGroupId, IUwpGameConfiguration gameConfiguration, CancellationToken ct);
Task<GamePackageConfiguration> ImportPackagesAsync(GameProduct product, IGamePackageBranch originPackageBranch, IGamePackageBranch destinationPackageBranch, string marketGroupName, bool overwrite, CancellationToken ct);
Task<GamePackageConfiguration> ImportPackagesAsync(GameProduct product, IGamePackageBranch originPackageBranch, IGamePackageBranch destinationPackageBranch, string marketGroupName, bool overwrite, IGameConfiguration gameConfiguration, CancellationToken ct);
Task<GameSubmission> PublishPackagesToSandboxAsync(GameProduct product, GamePackageBranch originPackageBranch, string destinationSandboxName, int minutesToWaitForPublishing, CancellationToken ct);

Просмотреть файл

@ -1,24 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using PackageUploader.ClientApi.Client.Ingestion.Models;
namespace PackageUploader.ClientApi.Models;
public class GameConfiguration : IGameConfiguration
{
/// <summary>
/// Availability date (Uwp/Xvc packages)
/// </summary>
public GamePackageDate AvailabilityDate { get; set; }
/// <summary>
/// MandatoryDate (Uwp packages)
/// </summary>
public GamePackageDate MandatoryDate { get; set; }
/// <summary>
/// Gradual rollout information (Uwp packages)
/// </summary>
public GameGradualRolloutInfo GradualRollout { get; set; }
}

Просмотреть файл

@ -8,6 +8,7 @@ namespace PackageUploader.ClientApi.Models;
public interface IGameConfiguration
{
GamePackageDate AvailabilityDate { get; set; }
GamePackageDate PreDownloadDate { get; set; }
GamePackageDate MandatoryDate { get; set; }
GameGradualRolloutInfo GradualRollout { get; set; }
}

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using PackageUploader.ClientApi.Client.Ingestion.Models;
namespace PackageUploader.ClientApi.Models;
public interface IUwpGameConfiguration
{
GamePackageDate AvailabilityDate { get; set; }
GamePackageDate MandatoryDate { get; set; }
GameGradualRolloutInfo GradualRollout { get; set; }
}

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace PackageUploader.ClientApi.Models;
public interface IXvcGameConfiguration
{
GamePackageDate AvailabilityDate { get; set; }
GamePackageDate PreDownloadDate { get; set; }
}

Просмотреть файл

@ -95,6 +95,7 @@ public class PackageUploaderService : IPackageUploaderService
PackageIds = new List<string>(),
AvailabilityDate = null,
PackageAvailabilityDates = new Dictionary<string, DateTime?>(),
PackageIdToMetadataMap = new Dictionary<string, GameMarketGroupPackageMetadata>(),
MandatoryUpdateInfo = null,
},
};
@ -222,6 +223,7 @@ public class PackageUploaderService : IPackageUploaderService
packagesRemoved += marketGroupPackage.PackageIds.Count;
marketGroupPackage.PackageIds = new List<string>();
marketGroupPackage.PackageAvailabilityDates = new Dictionary<string, DateTime?>();
marketGroupPackage.PackageIdToMetadataMap = new Dictionary<string, GameMarketGroupPackageMetadata>();
}
else
{
@ -246,6 +248,7 @@ public class PackageUploaderService : IPackageUploaderService
packagesRemoved++;
marketGroupPackage.PackageIds.Remove(packageId);
marketGroupPackage.PackageAvailabilityDates.Remove(packageId);
marketGroupPackage.PackageIdToMetadataMap?.Remove(packageId);
}
}
}
@ -264,18 +267,16 @@ public class PackageUploaderService : IPackageUploaderService
return packageConfiguration;
}
public async Task<GamePackageConfiguration> SetXvcAvailabilityDateAsync(GameProduct product, IGamePackageBranch packageBranch, GamePackage gamePackage, string marketGroupName, GamePackageDate availabilityDate, CancellationToken ct)
public async Task<GamePackageConfiguration> SetXvcConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, GamePackage gamePackage, string marketGroupName, IXvcGameConfiguration gameConfiguration, CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(product);
ArgumentNullException.ThrowIfNull(packageBranch);
ArgumentNullException.ThrowIfNull(gamePackage);
ArgumentNullException.ThrowIfNull(availabilityDate);
ArgumentNullException.ThrowIfNull(gameConfiguration);
_logger.LogDebug("Setting the availability date to package with id '{gamePackageId}' in '{productId}' and draft id '{currentDraftInstanceID}'.", gamePackage.Id, product.ProductId, packageBranch.CurrentDraftInstanceId);
_logger.LogDebug("Setting the dates to package with id '{gamePackageId}' in '{productId}' and draft id '{currentDraftInstanceID}'.", gamePackage.Id, product.ProductId, packageBranch.CurrentDraftInstanceId);
var packageConfiguration = await _ingestionHttpClient.GetPackageConfigurationAsync(product.ProductId, packageBranch.CurrentDraftInstanceId, ct).ConfigureAwait(false);
// Setting the availability date
if (packageConfiguration.MarketGroupPackages is not null && packageConfiguration.MarketGroupPackages.Any())
{
if (!string.IsNullOrWhiteSpace(marketGroupName) && !packageConfiguration.MarketGroupPackages.Any(x => x.Name.Equals(marketGroupName)))
@ -284,35 +285,34 @@ public class PackageUploaderService : IPackageUploaderService
}
else
{
foreach (var marketGroupPackage in packageConfiguration.MarketGroupPackages)
foreach (var marketGroupPackage in packageConfiguration.MarketGroupPackages
.Where(marketGroupPackage => marketGroupPackage.PackageIds.Contains(gamePackage.Id))
.Where(marketGroupPackage => string.IsNullOrWhiteSpace(marketGroupName) || marketGroupName.Equals(marketGroupPackage.Name)))
{
if (marketGroupPackage.PackageIds.Contains(gamePackage.Id))
// Availability Date
if (gameConfiguration.AvailabilityDate.IsEnabled)
{
if (string.IsNullOrWhiteSpace(marketGroupName) || marketGroupName.Equals(marketGroupPackage.Name))
{
if (availabilityDate.IsEnabled)
{
if (marketGroupPackage.PackageAvailabilityDates is null)
{
marketGroupPackage.PackageAvailabilityDates = new Dictionary<string, DateTime?>();
}
marketGroupPackage.PackageAvailabilityDates[gamePackage.Id] = availabilityDate.EffectiveDate;
}
else if (marketGroupPackage.PackageAvailabilityDates is not null)
{
marketGroupPackage.PackageAvailabilityDates[gamePackage.Id] = null;
}
}
marketGroupPackage.PackageAvailabilityDates ??= new Dictionary<string, DateTime?>();
marketGroupPackage.PackageAvailabilityDates[gamePackage.Id] = gameConfiguration.AvailabilityDate.EffectiveDate;
}
else if (marketGroupPackage.PackageAvailabilityDates is not null)
{
marketGroupPackage.PackageAvailabilityDates[gamePackage.Id] = null;
}
// PreDownload Date
marketGroupPackage.PackageIdToMetadataMap ??= new Dictionary<string, GameMarketGroupPackageMetadata>();
marketGroupPackage.PackageIdToMetadataMap[gamePackage.Id] = CalculatePackageMetadata(gameConfiguration.PreDownloadDate);
}
}
}
}
var result = await _ingestionHttpClient.UpdatePackageConfigurationAsync(product.ProductId, packageConfiguration, ct).ConfigureAwait(false);
return result;
}
public async Task<GamePackageConfiguration> SetUwpConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, string marketGroupName, IGameConfiguration gameConfiguration, CancellationToken ct)
public async Task<GamePackageConfiguration> SetUwpConfigurationAsync(GameProduct product, IGamePackageBranch packageBranch, string marketGroupName, IUwpGameConfiguration gameConfiguration, CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(product);
ArgumentNullException.ThrowIfNull(packageBranch);
@ -330,27 +330,25 @@ public class PackageUploaderService : IPackageUploaderService
}
else
{
foreach (var marketGroupPackage in packageConfiguration.MarketGroupPackages)
foreach (var marketGroupPackage in packageConfiguration.MarketGroupPackages
.Where(marketGroupPackage => string.IsNullOrWhiteSpace(marketGroupName) || marketGroupName.Equals(marketGroupPackage.Name)))
{
if (string.IsNullOrWhiteSpace(marketGroupName) || marketGroupName.Equals(marketGroupPackage.Name))
// Setting the availability date
if (gameConfiguration.AvailabilityDate is not null)
{
// Setting the availability date
if (gameConfiguration.AvailabilityDate is not null)
{
marketGroupPackage.AvailabilityDate = gameConfiguration.AvailabilityDate.IsEnabled
? gameConfiguration.AvailabilityDate.EffectiveDate
: null;
}
marketGroupPackage.AvailabilityDate = gameConfiguration.AvailabilityDate.IsEnabled
? gameConfiguration.AvailabilityDate.EffectiveDate
: null;
}
// Setting the mandatory date
if (gameConfiguration.MandatoryDate is not null)
// Setting the mandatory date
if (gameConfiguration.MandatoryDate is not null)
{
marketGroupPackage.MandatoryUpdateInfo = new GameMandatoryUpdateInfo
{
marketGroupPackage.MandatoryUpdateInfo = new GameMandatoryUpdateInfo
{
IsEnabled = gameConfiguration.MandatoryDate.IsEnabled,
EffectiveDate = gameConfiguration.MandatoryDate.EffectiveDate,
};
}
IsEnabled = gameConfiguration.MandatoryDate.IsEnabled,
EffectiveDate = gameConfiguration.MandatoryDate.EffectiveDate,
};
}
}
}
@ -423,10 +421,10 @@ public class PackageUploaderService : IPackageUploaderService
{
foreach (var (packageId, _) in destinationMarketGroupPackage.PackageAvailabilityDates)
{
if (originalPackageAvailabilityDates.ContainsKey(packageId))
if (originalPackageAvailabilityDates.TryGetValue(packageId, out var availabilityDate))
{
// If the package was already there, we keep the availability date
destinationMarketGroupPackage.PackageAvailabilityDates[packageId] = originalPackageAvailabilityDates[packageId];
destinationMarketGroupPackage.PackageAvailabilityDates[packageId] = availabilityDate;
}
else
{
@ -444,9 +442,12 @@ public class PackageUploaderService : IPackageUploaderService
}
}
}
OverWritePackageMetadata(originMarketGroupPackage, destinationMarketGroupPackage, gameConfiguration.PreDownloadDate);
}
else
{
destinationMarketGroupPackage.PackageIds ??= new List<string>();
var packageIdsToAdd = originMarketGroupPackage.PackageIds.Where(packageId => !destinationMarketGroupPackage.PackageIds.Contains(packageId)).ToList();
if (packageIdsToAdd.Any())
{
@ -467,6 +468,11 @@ public class PackageUploaderService : IPackageUploaderService
}
}
}
if(gameConfiguration.PreDownloadDate is not null)
{
AddPackageMetadata(destinationMarketGroupPackage, packageIdsToAdd, gameConfiguration.PreDownloadDate);
}
}
}
@ -642,7 +648,39 @@ public class PackageUploaderService : IPackageUploaderService
return gameSubmission;
}
private static XvcTargetPlatform ReadXvcTargetPlatformFromMetaData(FileSystemInfo packageFile)
private static void AddPackageMetadata(GameMarketGroupPackage destinationMarketGroupPackage, List<string> packageIdsToAdd, GamePackageDate preDownloadDate)
{
destinationMarketGroupPackage.PackageIdToMetadataMap ??= new Dictionary<string, GameMarketGroupPackageMetadata>();
foreach (var packageId in packageIdsToAdd)
{
destinationMarketGroupPackage.PackageIdToMetadataMap.Add(packageId, CalculatePackageMetadata(preDownloadDate));
}
}
private static void OverWritePackageMetadata(GameMarketGroupPackage originMarketGroupPackage, GameMarketGroupPackage destinationMarketGroupPackage, GamePackageDate preDownloadDate)
{
var originalPackageIdToMetadataMap = destinationMarketGroupPackage.PackageIdToMetadataMap ?? new Dictionary<string, GameMarketGroupPackageMetadata>();
destinationMarketGroupPackage.PackageIdToMetadataMap = originMarketGroupPackage.PackageIdToMetadataMap;
if (destinationMarketGroupPackage.PackageIdToMetadataMap is not null)
{
var destinationPkgIds = destinationMarketGroupPackage.PackageIdToMetadataMap.Keys.ToList();
foreach (var packageId in destinationPkgIds)
{
destinationMarketGroupPackage.PackageIdToMetadataMap[packageId] = originalPackageIdToMetadataMap.TryGetValue(packageId, out var value) ? value : CalculatePackageMetadata(preDownloadDate);
}
}
}
private static GameMarketGroupPackageMetadata CalculatePackageMetadata(GamePackageDate preDownloadDate)
{
return new GameMarketGroupPackageMetadata
{
PreDownloadDate = preDownloadDate?.IsEnabled == true ? preDownloadDate.EffectiveDate : null,
};
}
private static XvcTargetPlatform ReadXvcTargetPlatformFromMetaData(FileSystemInfo packageFile)
{
const int headerOffsetForXvcTargetPlatform = 1137;

Просмотреть файл

@ -24,6 +24,11 @@
"effectiveDate": "{{ optional - if informed it will set the mandatory date in the destination branch for the Uwp packages (if any) }}"
},
"preDownloadDate": {
"isEnabled": false,
"effectiveDate": "{{ optional - if informed it will set the pre-download date in the destination branch for the Xvc packages (if any) }}"
},
"gradualRollout": {
"isEnabled": false,
"percentage": 33,

Просмотреть файл

@ -27,6 +27,11 @@
"effectiveDate": "{{ optional - if informed it will set the availability date in this branch/marketGroupId for this Xvc package }}"
},
"preDownloadDate": {
"isEnabled": false,
"effectiveDate": "{{ optional - if informed it will set the predownload date in this branch/marketGroupId for this Xvc package }}"
},
"aadAuthInfo": {
"clientId": "{{ required when using authentication method *AppCert* or *AppSecret* }}",
"tenantId": "{{ required when using authentication method *AppCert* or *AppSecret* }}",