public async Task <SyncContext> CalculateSyncContext(RepositoryInfo targetRepository) { var syncContext = new SyncContext(targetRepository); using (var syncer = new Syncer(targetRepository.Credentials, null, log)) { var diffs = new List <Mapper>(); var includedPaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase); var descriptionBuilder = new StringBuilder(); descriptionBuilder.AppendLine("This is an automated synchronization PR."); descriptionBuilder.AppendLine(); descriptionBuilder.AppendLine("The following source template repositories were used:"); // Note: iterate backwards, later registered sources should override earlier registrations for (var i = sources.Count - 1; i >= 0; i--) { var sourceRepository = sources[i]; var sourceRepositoryDisplayName = $"{sourceRepository.Owner}/{sourceRepository.Repository}"; var itemsToSync = new List <SyncItem>(); foreach (var item in await OctokitEx.GetRecursive(sourceRepository.Credentials, sourceRepository.Owner, sourceRepository.Repository)) { if (includedPaths.Contains(item)) { continue; } includedPaths.Add(item); if (manualSyncItems.Any(x => item.StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) { switch (syncMode) { case SyncMode.IncludeAllByDefault: // Continue break; case SyncMode.ExcludeAllByDefault: // Ignore this file continue; default: throw new ArgumentOutOfRangeException(nameof(syncMode), $"Sync mode '{syncMode}' is not supported"); } } itemsToSync.Add(new SyncItem { Parts = new Parts($"{sourceRepository.Owner}/{sourceRepository.Repository}", TreeEntryTargetType.Blob, sourceRepository.Branch, item), ToBeAdded = true, Target = null }); } var targetRepositoryToSync = new RepoToSync { Owner = targetRepository.Owner, Repo = targetRepository.Repository, TargetBranch = targetRepository.Branch }; var sourceMapper = targetRepositoryToSync.GetMapper(itemsToSync); var diff = await syncer.Diff(sourceMapper); if (diff.ToBeAddedOrUpdatedEntries.Count() > 0 || diff.ToBeRemovedEntries.Count() > 0) { diffs.Add(diff); descriptionBuilder.AppendLine($"* {sourceRepositoryDisplayName}"); } } var finalDiff = new Mapper(); foreach (var diff in diffs) { foreach (var item in diff.ToBeAddedOrUpdatedEntries) { foreach (var value in item.Value) { log($"Mapping '{item.Key.Url}' => '{value.Url}'"); finalDiff.Add(item.Key, value); } } // Note: how to deal with items to be removed } syncContext.Diff = finalDiff; syncContext.Description = descriptionBuilder.ToString(); } return(syncContext); }