Esempio n. 1
0
    internal async Task <IReadOnlyList <UpdateResult> > Sync(
        Mapper diff,
        SyncOutput expectedOutput,
        IEnumerable <string> labelsToApplyOnPullRequests = null,
        string description = null)
    {
        Guard.AgainstNull(diff, nameof(diff));
        Guard.AgainstNull(expectedOutput, nameof(expectedOutput));
        var labels = labelsToApplyOnPullRequests?.ToArray() ?? new string[] { };

        if (labels.Any() && expectedOutput != SyncOutput.CreatePullRequest)
        {
            throw new Exception($"Labels can only be applied in '{SyncOutput.CreatePullRequest}' mode.");
        }

        var t = diff.Transpose();

        var results = new List <UpdateResult>();

        foreach (var updatesPerOwnerRepositoryBranch in t.Values)
        {
            var updates = await ProcessUpdates(expectedOutput, updatesPerOwnerRepositoryBranch, labels, description);

            results.Add(updates);
        }

        return(results);
    }
 private void WriteSyncOutput(SyncOutput output)
 {
     if (output != null)
     {
         if (output.Error)
         {
             Host.UI.RawUI.ForegroundColor = ConsoleColor.Red;
         }
         WriteObject(output);
         if (output.Error)
         {
             Host.UI.RawUI.ForegroundColor = hostColor;
         }
     }
 }
Esempio n. 3
0
    internal async Task <bool> CanSynchronize(RepositoryInfo targetRepository, SyncOutput expectedOutput)
    {
        if (expectedOutput == SyncOutput.CreatePullRequest ||
            expectedOutput == SyncOutput.MergePullRequest)
        {
            var hasOpenPullRequests = await gateway.HasOpenPullRequests(targetRepository.Owner, targetRepository.Repository, PullRequestTitle);

            if (hasOpenPullRequests)
            {
                log("Cannot create pull request, there is an existing open pull request, close or merge that first");
                return(false);
            }
        }

        return(true);
    }
Esempio n. 4
0
        public async Task <IReadOnlyList <UpdateResult> > Sync(SyncOutput syncOutput = SyncOutput.CreatePullRequest)
        {
            var list = new List <UpdateResult>();

            foreach (var targetRepository in targets)
            {
                var targetRepositoryDisplayName = $"{targetRepository.Owner}/{targetRepository.Repository}";

                using var syncer = new Syncer(targetRepository.Credentials, null, log);
                if (!await syncer.CanSynchronize(targetRepository, syncOutput, targetRepository.Branch))
                {
                    continue;
                }

                var syncContext = await CalculateSyncContext(targetRepository);

                if (!syncContext.Diff.ToBeAddedOrUpdatedEntries.Any())
                {
                    log($"Repo {targetRepositoryDisplayName} is in sync");
                    continue;
                }

                var sync = await syncer.Sync(syncContext.Diff, syncOutput, labelsToApplyOnPullRequests, syncContext.Description);

                var createdSyncBranch = sync.FirstOrDefault();

                if (createdSyncBranch == null)
                {
                    log($"Repo {targetRepositoryDisplayName} is in sync");
                }
                else
                {
                    log($"Pull created for {targetRepositoryDisplayName}, click here to review and pull: {createdSyncBranch}");
                }
                list.Add(createdSyncBranch);
            }

            return(list);
        }
Esempio n. 5
0
        public async Task Sync(SyncOutput syncOutput = SyncOutput.CreatePullRequest)
        {
            foreach (var targetRepository in targets)
            {
                var targetRepositoryDisplayName = $"{targetRepository.Owner}/{targetRepository.Repository}";

                using (var syncer = new Syncer(targetRepository.Credentials, null, log))
                {
                    if (!await syncer.CanSynchronize(targetRepository, syncOutput))
                    {
                        continue;
                    }

                    var syncContext = await CalculateSyncContext(targetRepository);

                    if (syncContext.Diff.ToBeAddedOrUpdatedEntries.Count() == 0)
                    {
                        log($"Repo {targetRepositoryDisplayName} is in sync");
                        continue;
                    }

                    var sync = await syncer.Sync(syncContext.Diff, syncOutput, labelsToApplyOnPullRequests, syncContext.Description);

                    var createdSyncBranch = sync.FirstOrDefault();

                    if (string.IsNullOrEmpty(createdSyncBranch))
                    {
                        log($"Repo {targetRepositoryDisplayName} is in sync");
                    }
                    else
                    {
                        log($"Pull created for {targetRepositoryDisplayName}, click here to review and pull: {createdSyncBranch}");
                    }
                }
            }
        }
Esempio n. 6
0
        public IEnumerable<string> Sync(Diff diff, SyncOutput expectedOutput, IEnumerable<string> labelsToApplyOnPullRequests = null)
        {
            var labels = labelsToApplyOnPullRequests == null ? new string[]{ } : labelsToApplyOnPullRequests.ToArray();

            if (labels.Any() && expectedOutput != SyncOutput.CreatePullRequest)
            {
                throw new InvalidOperationException(string.Format("Labels can only be applied in '{0}' mode.", SyncOutput.CreatePullRequest));
            }

            var t = diff.Transpose();
            var branchName = "SyncOMatic-" + DateTimeOffset.UtcNow.ToString("yyyyMMdd-HHmmss");

            foreach (var updatesPerOwnerRepositoryBranch in t.Values)
            {
                var root = updatesPerOwnerRepositoryBranch.First().Item1.RootTreePart;
                var tt = new TargetTree(root);

                foreach (var change in updatesPerOwnerRepositoryBranch)
                {
                    var source = change.Item2;
                    var destination = change.Item1;

                    tt.Add(destination, source);
                }

                var btt = BuildTargetTree(tt);

                var parentCommit = gw.RootCommitFrom(root);

                var c = gw.CreateCommit(btt, root.Owner, root.Repository, parentCommit.Sha);

                switch (expectedOutput)
                {
                    case SyncOutput.CreateCommit:
                        yield return "https://github.com/" + root.Owner + "/" + root.Repository + "/commit/" + c;
                        break;

                    case SyncOutput.CreateBranch:
                        branchName = gw.CreateBranch(root.Owner, root.Repository, branchName, c);
                        yield return "https://github.com/" + root.Owner + "/" + root.Repository + "/compare/" + UrlSanitize(root.Branch) + "..." + UrlSanitize(branchName);
                        break;

                    case SyncOutput.CreatePullRequest:
                        branchName = gw.CreateBranch(root.Owner, root.Repository, branchName, c);
                        var prNumber = gw.CreatePullRequest(root.Owner, root.Repository, branchName, root.Branch);
                        gw.ApplyLabels(root.Owner, root.Repository, prNumber, labels);
                        yield return "https://github.com/" + root.Owner + "/" + root.Repository + "/pull/" + prNumber;
                        break;

                    default:
                        throw new NotSupportedException();
                }
            }
        }
        /// <summary>
        /// Processes the record.
        /// </summary>
        /// <exception cref="PSInvalidCastException">Incorrect object found.</exception>
        protected override async Task ProcessRecordAsync()
        {
            foreach (string input in Input)
            {
                var member = new Member(Prefix, input, true);
                var output = new SyncOutput(member.Name);

                if (_currentMembers.ContainsKey(member.Name.ToLower()))
                {
                    // No changes just add to _postMembers so we don't remove it
                    _postMembers.Add(member.Name.ToLower());
                }
                else
                {
                    var obj = await FindObjectByName(member);

                    string oldName = null;
                    if (obj == null && Rename.IsPresent)
                    {
                        obj = await FindObjectByIP(member);

                        if (obj != null)
                        {
                            oldName         = obj.Name;
                            output.Actions  = Actions.Rename;
                            output.Comments = $"Renamed {obj.Name}";
                            try
                            {
                                if (obj is Network n)
                                {
                                    n.Name = member.Name;
                                    await n.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                                }
                                else if (obj is Host h)
                                {
                                    h.Name = member.Name;
                                    await h.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                                }
                            }
                            catch (Koopman.CheckPoint.Exceptions.GenericException e)
                            {
                                output.Error = true;
                                WriteError(new ErrorRecord(e, "Rename", ErrorCategory.WriteError, null));
                            }
                        }
                    }

                    if (obj == null)
                    {
                        output.Actions = Actions.Create;
                        try
                        {
                            if (member.IsHost())
                            {
                                var host = new Host(Session)
                                {
                                    Name     = member.Name,
                                    Color    = Color,
                                    Comments = Comments
                                };

                                if (member.IsIPv4())
                                {
                                    host.IPv4Address = member.IPAddress;
                                }
                                else
                                {
                                    host.IPv6Address = member.IPAddress;
                                }

                                host.Groups.Add(GroupName);
                                foreach (string t in Tags ?? Enumerable.Empty <string>())
                                {
                                    host.Tags.Add(t);
                                }

                                await host.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                            }
                            else
                            {
                                var network = new Network(Session)
                                {
                                    Name     = member.Name,
                                    Color    = Color,
                                    Comments = Comments
                                };

                                if (member.IsIPv4())
                                {
                                    network.Subnet4     = member.IPAddress;
                                    network.MaskLength4 = member.CIDR;
                                }
                                else
                                {
                                    network.Subnet6     = member.IPAddress;
                                    network.MaskLength6 = member.CIDR;
                                }

                                network.Groups.Add(GroupName);
                                foreach (string t in Tags ?? Enumerable.Empty <string>())
                                {
                                    network.Tags.Add(t);
                                }

                                await network.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                            }
                        }
                        catch (Koopman.CheckPoint.Exceptions.GenericException e)
                        {
                            output.Error = true;
                            WriteError(new ErrorRecord(e, "Create", ErrorCategory.WriteError, null));
                        }
                    }
                    else if (!_currentMembers.ContainsKey(obj.Name.ToLower()))
                    {
                        output.Actions |= Actions.Add;
                        group.Members.Add(obj.Name);
                        try
                        {
                            await group.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                        }
                        catch (Koopman.CheckPoint.Exceptions.GenericException e)
                        {
                            output.Error = true;
                            WriteError(new ErrorRecord(e, "AddToGroup", ErrorCategory.WriteError, null));
                        }
                    }

                    // As _postMembers used to work out which entries to remove from the group If
                    // object was renamed enter old name as it could of already been a member Of the
                    // group under the old name
                    _postMembers.Add(((output.Actions.HasFlag(Actions.Rename)) ? oldName : member.Name).ToLower());
                }

                WriteSyncOutput(output);
            }
        }
        /// <inheritdoc />
        protected override async Task EndProcessingAsync()
        {
            string[] deleteKeys = _currentMembers.Keys.Except(_postMembers).ToArray();
            bool     removed    = true;

            if (deleteKeys.Length > 0)
            {
                WriteVerbose("Performing bulk remove from group");
                foreach (string n in deleteKeys)
                {
                    group.Members.Remove(n);
                }
                try
                {
                    await group.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                }
                catch (Koopman.CheckPoint.Exceptions.GenericException e)
                {
                    removed = false;
                    WriteError(new ErrorRecord(e, "RemoveFromGroup", ErrorCategory.WriteError, null));
                }
            }

            foreach (string key in deleteKeys)
            {
                var obj    = _currentMembers[key];
                var output = new SyncOutput(obj.Name)
                {
                    Actions = Actions.Remove,
                    Error   = !removed
                };

                var used = await Session.FindWhereUsed(identifier : obj.Name, detailLevel : DetailLevels.UID, cancellationToken : CancelProcessToken);

                if (used.UsedDirectly.Total == 0)
                {
                    output.Actions |= Actions.Delete;
                    try
                    {
                        if (obj is Host h)
                        {
                            await h.Delete(cancellationToken : CancelProcessToken);
                        }
                        else if (obj is Network n)
                        {
                            await n.Delete(cancellationToken : CancelProcessToken);
                        }
                    }
                    catch (Koopman.CheckPoint.Exceptions.GenericException e)
                    {
                        output.Error = true;
                        WriteError(new ErrorRecord(e, "Delete", ErrorCategory.WriteError, null));
                    }
                }
                else
                {
                    try
                    {
                        if (obj is Host h)
                        {
                            foreach (string t in Tags)
                            {
                                h.Tags.Remove(t);
                            }
                            await h.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                        }
                        else if (obj is Network n)
                        {
                            foreach (string t in Tags)
                            {
                                n.Tags.Remove(t);
                            }
                            await n.AcceptChanges(Ignore, cancellationToken : CancelProcessToken);
                        }
                    }
                    catch (Koopman.CheckPoint.Exceptions.GenericException e)
                    {
                        output.Error = true;
                        WriteError(new ErrorRecord(e, "RemoveTags", ErrorCategory.WriteError, null));
                    }
                }

                WriteSyncOutput(output);
            }
        }
Esempio n. 9
0
    async Task <string> ProcessUpdates(SyncOutput expectedOutput, IList <Tuple <Parts, IParts> > updatesPerOwnerRepositoryBranch,
                                       string[] labels, string description)
    {
        var branchName = $"GitHubSync-{DateTimeOffset.UtcNow:yyyyMMdd-HHmmss}";
        var root       = updatesPerOwnerRepositoryBranch.First().Item1.RootTreePart;

        var commitSha = string.Empty;

        var isCollaborator = await gateway.IsCollaborator(root.Owner, root.Repository);

        if (!isCollaborator)
        {
            log("User is not a collaborator, need to create a fork");

            if (expectedOutput != SyncOutput.CreatePullRequest)
            {
                throw new NotSupportedException($"User is not a collaborator, sync output '{expectedOutput}' is not supported, only creating PRs is supported");
            }

            commitSha = await ProcessUpdatesInFork(root, branchName, updatesPerOwnerRepositoryBranch);
        }
        else
        {
            commitSha = await ProcessUpdatesInTargetRepository(root, updatesPerOwnerRepositoryBranch);
        }

        if (expectedOutput == SyncOutput.CreateCommit)
        {
            return($"https://github.com/{root.Owner}/{root.Repository}/commit/{commitSha}");
        }

        if (expectedOutput == SyncOutput.CreateBranch)
        {
            branchName = await gateway.CreateBranch(root.Owner, root.Repository, branchName, commitSha);

            return($"https://github.com/{root.Owner}/{root.Repository}/compare/{UrlSanitize(root.Branch)}...{UrlSanitize(branchName)}");
        }

        if (expectedOutput == SyncOutput.CreatePullRequest || expectedOutput == SyncOutput.MergePullRequest)
        {
            var merge          = expectedOutput == SyncOutput.MergePullRequest;
            var prSourceBranch = branchName;

            if (isCollaborator)
            {
                branchName = await gateway.CreateBranch(root.Owner, root.Repository, branchName, commitSha);
            }
            else
            {
                // Never auto-merge
                merge = false;

                var forkedRepository = await gateway.Fork(root.Owner, root.Repository);

                prSourceBranch = $"{forkedRepository.Owner.Login}:{prSourceBranch}";
            }

            var prNumber = await gateway.CreatePullRequest(root.Owner, root.Repository, prSourceBranch, root.Branch, merge, description);

            if (isCollaborator)
            {
                await gateway.ApplyLabels(root.Owner, root.Repository, prNumber, labels);
            }

            return($"https://github.com/{root.Owner}/{root.Repository}/pull/{prNumber}");
        }

        throw new NotSupportedException();
    }