Esempio n. 1
0
 public void AssertCleanWorkspace(string repodir)
 {
     var repo = new LibGit2Sharp.Repository(Path.Combine(Workdir, repodir));
     var status = repo.Index.RetrieveStatus();
     var statusString = String.Join("\n", status.Select(statusEntry => "" + statusEntry.State + ": " + statusEntry.FilePath).ToArray());
     Assert.AreEqual("", statusString, "repo status");
 }
        public IActionResult Branches(string repositoryId)
        {
            var operation = TableOperation.Retrieve<TableStorage.Entities.Repository>("1", repositoryId);
            var result = _storage.Repositories.Execute(operation);

            var repositoryEntity = result.Result as TableStorage.Entities.Repository;
            if (repositoryEntity == null)
            {
                return new ObjectResult(_errorFactory.RepositoryNotFound());
            }

            var branches = new List<Branch>();
            using (var repo = new LibGit2Sharp.Repository(repositoryEntity.Path))
            {
                foreach (var branch in repo.Branches)
                {
                    branches.Add(new Branch
                    {
                        Name = branch.Name,
                        CanonicalName = branch.CanonicalName

                    });
                }

                return new ObjectResult(branches);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Loads branches and commits.
        /// </summary>
        /// <param name="repo"></param>
        private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo = null)
        {
            var dispose = false;
            if (repo == null)
            {
                repo = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boosts.
            Commits.DisableNotifications();
            Branches.DisableNotifications();

            // Create commits.
            Commits.Clear();
            var commitList = new List<Commit>();
            foreach (var commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage))
            {
                commitList.Add(Commit.Create(repo, commit, Tags));
            }
            Commits.AddRange(commitList);

            // Create branches.
            Branches.Clear();
            foreach (var branch in repo.Branches)
            {
                var b = Branch.Create(this, repo, branch);
                Branches.Add(b);
            }

            // Post-process branches (tips and tracking branches).
            foreach (var branch in Branches)
            {
                // Set the HEAD property if it matches.
                if (repo.Head.Name == branch.Name)
                {
                    Head = branch;
                    branch.Tip.IsHead = true;
                }

                branch.PostProcess(Branches, Commits);
            }

            // Post-process commits (commit parents).
            foreach (var commit in Commits)
            {
                // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null.
                if (Head == null && repo.Head.Tip.Sha == commit.Hash)
                {
                    Head = new DetachedHead
                    {
                        Tip = commit
                    };

                    commit.IsHead = true;
                }

                commit.PostProcess(Commits, Branches);
            }

            // Calculate commit visual positions for each branch tree.
            foreach (var branch in Branches)
            {
                RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip);
            }

            // Fire notifications for the collections on the UI thread.
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Normal,
                (Action) (() =>
                {
                    Commits.EnableNotifications(true);
                    Branches.EnableNotifications(true);

                    var tabControl = UIHelper.FindChild<TabControl>(Application.Current.MainWindow, "RepositoryTabs");
                    var changesetHistory = UIHelper.FindChild<ChangesetHistory>(tabControl);

                    if (changesetHistory != null)
                        changesetHistory.RedrawGraph();
                })
            );

            if (dispose)
                repo.Dispose();
        }
Esempio n. 4
0
        /// <summary>
        /// Resets (reset --soft) the repository to the given changeset.
        /// </summary>
        /// <param name="action"></param>
        public void ResetSoft(object action)
        {
            var commit = action as Commit;

            if (commit == null)
                return;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    repo.Reset(LibGit2Sharp.ResetOptions.Mixed, commit.Hash);
                    LoadEntireRepository();
                }
            });
        }
Esempio n. 5
0
        /// <summary>
        /// Loads the repository status (modified, added, removed).
        /// </summary>
        private void LoadRepositoryStatus(LibGit2Sharp.Repository repo = null)
        {
            var dispose = false;

            if (repo == null)
            {
                repo    = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // A small performance boost.
            StatusItemsStaged.DisableNotifications();
            StatusItemsUnstaged.DisableNotifications();

            StatusItemsStaged.Clear();
            StatusItemsUnstaged.Clear();

            // Load status items.
            var itemList = new List <StatusItem>();

            var status = repo.Index.RetrieveStatus();

            foreach (var fileStatus in status)
            {
                foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus)))
                {
                    var isSet = fileStatus.State.HasFlag(value);

                    if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored")
                    {
                        continue;
                    }

                    // TODO: would it be better without full repo path?
                    var fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath;

                    // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered).
                    var item = new StatusItem
                    {
                        Filename = fileStatus.FilePath,
                        Status   = value,
                        Size     = FileUtil.GetFormattedFileSize(fileFullPath), // TODO: Should these two file IO be done lazily?
                        IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-"
                    };

                    itemList.Add(item);
                }
            }

            StatusItemsStaged.AddRange(itemList.Where(s => s.IsStaged));
            StatusItemsUnstaged.AddRange(itemList.Where(s => !s.IsStaged));

            if (dispose)
            {
                repo.Dispose();
            }

            // Fire notifications for the collection on the UI thread.
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Normal,
                (Action)(
                    () =>
            {
                StatusItemsStaged.EnableNotifications(true);
                StatusItemsUnstaged.EnableNotifications(true);
            }
                    )
                );
        }
        /// <summary>
        /// Stages or unstages the selected item.
        /// </summary>
        /// <param name="action"></param>
        private void StageUnstage(object action)
        {
            var collection = (IList) action;
            var items = collection.Cast<StatusItem>();

            var repo = new LibGit2Sharp.Repository(RepositoryFullPath);

            foreach (StatusItem item in items)
            {
                if (item.GenericStatus == "Staged")
                    repo.Index.Unstage(RepositoryFullPath + "/" + item.Filename);
                else
                    repo.Index.Stage(RepositoryFullPath + "/" + item.Filename);
            }

            repo.Dispose();
        }
        /// <summary>
        /// Deletes a file or many.
        /// </summary>
        /// <param name="action"></param>
        private void DeleteFile(object action)
        {
            var dialog = new ConfirmDialog
            {
                Title = "Delete file(s)",
                Message = "Are you sure you want to delete the selected file(s)?\r\n\r\nYou may lose your changes!",
                ButtonSet = ConfirmDialog.ButtonsSet.OK_CANCEL
            };

            dialog.ShowDialog();

            var pressedButton = (Button) dialog.PressedButton;
            if (pressedButton != null && ((string) pressedButton.Content) == "OK")
            {
                var collection = (IList) action;
                var items = collection.Cast<StatusItem>();
                LibGit2Sharp.Repository repo = null;

                // Loop through all selected status items and remove the files physically (and in some cases also from the repository).
                foreach (StatusItem item in items)
                {
                    // TODO: --cached ?

                    File.Delete(RepositoryFullPath + "/" + item.Filename);

                    if (!item.Status.HasFlag(LibGit2Sharp.FileStatus.Untracked))
                    {
                        if (!(repo is LibGit2Sharp.Repository))
                            repo = new LibGit2Sharp.Repository(RepositoryFullPath);

                        repo.Index.Unstage(RepositoryFullPath + "/" + item.Filename);
                    }
                }

                if (repo is LibGit2Sharp.Repository)
                    repo.Dispose();
            }
        }
        /// <summary>
        /// Loads and constructs the entire repository.
        /// 
        /// This will limit the amount of changesets to CommitsPerPage.
        /// </summary>
        public void LoadEntireRepository()
        {
            using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                LoadTags(repo);
                LoadBranchesAndCommits(repo);
                LoadRepositoryStatus();
                LoadRecentCommitMessages();

                ListenToDirectoryChanges();
            }
        }
        /// <summary>
        /// Copies the given changeset as a patch to clipboard.
        /// </summary>
        /// <param name="action"></param>
        public void CopyPatch(object action)
        {
            Commit commit = action as Commit;

            using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                Clipboard.SetText(RepoUtil.GetTreeChangesForCommit(repo, commit).Patch);
            }
        }
Esempio n. 10
0
        public static bool GetHeadSha(
            Build build,
            string repositoryDirectory,
            Action <string> log)
        {
            if (build == null)
            {
                throw new ArgumentNullException("build");
            }
            if (String.IsNullOrEmpty(repositoryDirectory))
            {
                throw new ArgumentNullException("repositoryDirectory");
            }
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }

            log("STEP: Getting HEAD's SHA.");

            return(RunStep(() =>
            {
                if (!string.IsNullOrEmpty(build.Revision))
                {
                    log(String.Format("Build #{0} already has a SHA. Skipping.", build.Id));
                    return true;
                }

                var repo = (LibGit2Sharp.Repository)null;
                try
                {
                    repo = new LibGit2Sharp.Repository(repositoryDirectory);
                }
                catch (Exception ex)
                {
                    log(String.Format("ERROR: Could not get repository at {0} via LibGit2Sharp. Exception: ", repositoryDirectory));
                    log(ex.ToString());
                    return false;
                }

                var head = (LibGit2Sharp.Reference)null;
                try
                {
                    string @ref;
                    if (build.Ref.StartsWith("refs/heads/", StringComparison.OrdinalIgnoreCase))
                    {
                        var branch = build.Ref.Substring(11);
                        @ref = String.Format("refs/remotes/origin/{0}", branch);
                    }

                    else if (build.Ref.StartsWith("refs/pull", StringComparison.OrdinalIgnoreCase))
                    {
                        var slashafterPrNumberIndex = build.Ref.IndexOf("/", 10, StringComparison.InvariantCultureIgnoreCase);
                        var prNumber = build.Ref.Substring(10, slashafterPrNumberIndex - 10);
                        @ref = String.Concat("refs/remotes/origin/pr/", prNumber);
                    }
                    else
                    {
                        throw new InvalidOperationException(String.Format("Unexpected type of ref: {0}.", build.Ref));
                    }

                    head = repo.Refs[@ref];

                    if (head == null)
                    {
                        throw new InvalidOperationException(String.Format("The specified ref, '{0}', does not exist.", @ref));
                    }
                }
                catch (Exception ex)
                {
                    log(String.Format("ERROR: Could not get HEAD for ref {0}. Exception: ", build.Ref));
                    log(ex.ToString());
                    return false;
                }

                log(String.Format("Setting SHA to {0}.", head.TargetIdentifier));
                SetBuildRevision(build, head.TargetIdentifier);

                return true;
            }, log));
        }
Esempio n. 11
0
        protected override async Task OnExecute(CommandLineApplication app)
        {
            var gitDirectory = LibGit2Sharp.Repository.Discover(".");

            using (var repository = new LibGit2Sharp.Repository(gitDirectory))
            {
                var head          = repository.Head;
                var trackedBranch = head.TrackedBranch;
                if (trackedBranch is null)
                {
                    Console.WriteLine($"Current branch '{head.FriendlyName}' isn't tracking a remote.");
                    return;
                }

                var upstreamBranchCanonicalName = trackedBranch.UpstreamBranchCanonicalName;
                var branchName = ToBranchName(upstreamBranchCanonicalName);
                var remoteUrl  = new UriString(repository.Network.Remotes[trackedBranch.RemoteName].Url);

                var pullRequestStates = new[] { PullRequestState.Open, PullRequestState.Closed, PullRequestState.Merged };
                var query             = new Query()
                                        .Repository(owner: remoteUrl.Owner, name: remoteUrl.RepositoryName)
                                        .Ref(upstreamBranchCanonicalName)
                                        .Select(r => new
                {
                    Repository = r.Repository.NameWithOwner,
                    ForkedFrom = r.Repository.Parent != null ? r.Repository.Parent.NameWithOwner : null,
                    r.Target.Oid,
                    PullRequests = r.AssociatedPullRequests(100, null, null, null, null, branchName, null, null, pullRequestStates).Nodes.Select(pr => new
                    {
                        Repository = pr.Repository.NameWithOwner,
                        pr.Number,
                        pr.Title,
                        pr.Url,
                        Author = pr.Author != null ? pr.Author.Login : null,
                        pr.CreatedAt,
                        pr.AuthorAssociation,
                        pr.State,
                        pr.HeadRefName,
                        HeadRepository = pr.HeadRepository.NameWithOwner,
                        pr.BaseRefName,
                        BaseRepository = pr.BaseRef != null ? pr.BaseRef.Repository.NameWithOwner : null,
                        pr.HeadRefOid
                    }).ToList()
                }).Compile();

                var connection = CreateConnection(remoteUrl);
                var result     = await connection.Run(query);

                Console.WriteLine(result.ForkedFrom is null ? result.Repository : $"{result.Repository} forked from {result.ForkedFrom}");
                Console.WriteLine(result.Oid == trackedBranch.Tip.Sha ? "No new commits" : "There are new commits!");
                var prs = result.PullRequests
                          .Where(pr => pr.HeadRepository == pr.Repository); // Only show incoming pull requests
                if (prs.Count() == 0)
                {
                    Console.WriteLine("No associated pull requests");
                }
                else
                {
                    Console.WriteLine(@"
Associated pull requests:");
                    foreach (var pr in prs)
                    {
                        Console.WriteLine(
                            @$ "{pr.Repository} - {pr.Title} [{pr.State}]
#{pr.Number} opened on {pr.CreatedAt:D} by {pr.Author} ({pr.AuthorAssociation})");
                    }
                    Console.WriteLine();
                }
            }
        }
Esempio n. 12
0
        /// <summary>
        /// We used to group commits in a tree object so there would be only one commit per
        /// change but this doesn't work for trees that end up being too big (around 20K files).
        /// By using LibGit2Sharp we still group changes in one and we don't need to create a new
        /// tree. Everything happens locally in the host executing the push.
        /// </summary>
        /// <param name="filesToCommit">Collection of files to update.</param>
        /// <param name="repoUri">The repository to push the files to.</param>
        /// <param name="branch">The branch to push the files to.</param>
        /// <param name="commitMessage">The commmit message.</param>
        /// <returns></returns>
        protected async Task CommitFilesAsync(
            List <GitFile> filesToCommit,
            string repoUri,
            string branch,
            string commitMessage,
            ILogger _logger,
            string pat)
        {
            string dotnetMaestro = "dotnet-maestro";

            using (_logger.BeginScope("Pushing files to {branch}", branch))
            {
                string tempRepoFolder = Path.Combine(TemporaryRepositoryPath, Path.GetRandomFileName());

                try
                {
                    string repoPath = LibGit2Sharp.Repository.Clone(
                        repoUri,
                        tempRepoFolder,
                        new LibGit2Sharp.CloneOptions
                    {
                        BranchName          = branch,
                        Checkout            = true,
                        CredentialsProvider = (url, user, cred) =>
                                              new LibGit2Sharp.UsernamePasswordCredentials
                        {
                            // The PAT is actually the only thing that matters here, the username
                            // will be ignored.
                            Username = dotnetMaestro,
                            Password = pat
                        }
                    });

                    using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoPath))
                    {
                        foreach (GitFile file in filesToCommit)
                        {
                            string filePath = Path.Combine(tempRepoFolder, file.FilePath);

                            if (file.Operation == GitFileOperation.Add)
                            {
                                if (!File.Exists(filePath))
                                {
                                    string parentFolder = Directory.GetParent(filePath).FullName;

                                    Directory.CreateDirectory(parentFolder);
                                }

                                using (FileStream stream = File.Create(filePath))
                                {
                                    byte[] contentBytes = GetUtf8ContentBytes(file.Content, file.ContentEncoding);
                                    await stream.WriteAsync(contentBytes, 0, contentBytes.Length);
                                }
                            }
                            else
                            {
                                File.Delete(Path.Combine(tempRepoFolder, file.FilePath));
                            }
                        }

                        LibGit2Sharp.Commands.Stage(localRepo, "*");

                        LibGit2Sharp.Signature author   = new LibGit2Sharp.Signature(dotnetMaestro, $"@{dotnetMaestro}", DateTime.Now);
                        LibGit2Sharp.Signature commiter = author;
                        localRepo.Commit(commitMessage, author, commiter, new LibGit2Sharp.CommitOptions
                        {
                            AllowEmptyCommit = false,
                            PrettifyMessage  = true
                        });

                        localRepo.Network.Push(localRepo.Branches[branch], new LibGit2Sharp.PushOptions
                        {
                            CredentialsProvider = (url, user, cred) =>
                                                  new LibGit2Sharp.UsernamePasswordCredentials
                            {
                                // The PAT is actually the only thing that matters here, the username
                                // will be ignored.
                                Username = dotnetMaestro,
                                Password = pat
                            }
                        });
                    }
                }
                catch (LibGit2Sharp.EmptyCommitException)
                {
                    _logger.LogInformation("There was nothing to commit...");
                }
                catch (Exception exc)
                {
                    // This was originally a DarcException. Making it an actual Exception so we get to see in AppInsights if something failed while
                    // commiting the changes
                    throw new Exception($"Something went wrong when pushing the files to repo {repoUri} in branch {branch}", exc);
                }
                finally
                {
                    try
                    {
                        // Libgit2Sharp behaves similarly to git and marks files under the .git/objects hierarchy as read-only,
                        // thus if the read-only attribute is not unset an UnauthorizedAccessException is thrown.
                        GitFileManager.NormalizeAttributes(tempRepoFolder);

                        Directory.Delete(tempRepoFolder, true);
                    }
                    catch (DirectoryNotFoundException)
                    {
                        // If the directory wasn't found, that means that the clone operation above failed
                        // but this error isn't interesting at all.
                    }
                }
            }
        }
Esempio n. 13
0
 public static bool IsGitHubRepository(this LibGit2Sharp.Repository repository)
 => repository?.Network.Remotes
 .Where(x => x.Name == "origin")
 .Select(x => x.Url.Contains("github.com"))
 .FirstOrDefault() ?? false;
Esempio n. 14
0
        /// <summary>
        ///     Clone a remote git repo.
        /// </summary>
        /// <param name="repoUri">Repository uri to clone</param>
        /// <param name="commit">Branch, commit, or tag to checkout</param>
        /// <param name="targetDirectory">Target directory to clone to</param>
        /// <param name="gitDirectory">Location for the .git directory, or null for default</param>
        /// <returns></returns>
        protected void Clone(string repoUri, string commit, string targetDirectory, ILogger _logger, string pat, string gitDirectory)
        {
            string dotnetMaestro = "dotnet-maestro";

            LibGit2Sharp.CloneOptions cloneOptions = new LibGit2Sharp.CloneOptions
            {
                Checkout            = false,
                CredentialsProvider = (url, user, cred) =>
                                      new LibGit2Sharp.UsernamePasswordCredentials
                {
                    // The PAT is actually the only thing that matters here, the username
                    // will be ignored.
                    Username = dotnetMaestro,
                    Password = pat
                },
            };
            using (_logger.BeginScope("Cloning {repoUri} to {targetDirectory}", repoUri, targetDirectory))
            {
                try
                {
                    _logger.LogDebug($"Cloning {repoUri} to {targetDirectory}");
                    string repoPath = LibGit2Sharp.Repository.Clone(
                        repoUri,
                        targetDirectory,
                        cloneOptions);

                    LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions
                    {
                        CheckoutModifiers = LibGit2Sharp.CheckoutModifiers.Force,
                    };

                    _logger.LogDebug($"Reading local repo from {repoPath}");
                    using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoPath))
                    {
                        if (commit == null)
                        {
                            commit = localRepo.Head.Reference.TargetIdentifier;
                            _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} has no commit to clone at, assuming it's {commit}");
                        }
                        try
                        {
                            _logger.LogDebug($"Attempting to checkout {commit} as commit in {localRepo.Info.WorkingDirectory}");
                            LibGit2Sharp.Commands.Checkout(localRepo, commit, checkoutOptions);
                        }
                        catch
                        {
                            _logger.LogDebug($"Failed to checkout {commit} as commit, trying to resolve");
                            string resolvedReference = ParseReference(localRepo, commit, _logger);
                            _logger.LogDebug($"Resolved {commit} to {resolvedReference ?? "<invalid>"} in {localRepo.Info.WorkingDirectory}, attempting checkout");
                            LibGit2Sharp.Commands.Checkout(localRepo, resolvedReference, checkoutOptions);
                        }
                    }
                    // LibGit2Sharp doesn't support a --git-dir equivalent yet (https://github.com/libgit2/libgit2sharp/issues/1467), so we do this manually
                    if (gitDirectory != null)
                    {
                        Directory.Move(repoPath, gitDirectory);
                        File.WriteAllText(repoPath.TrimEnd('\\', '/'), $"gitdir: {gitDirectory}");
                    }
                    using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(targetDirectory))
                    {
                        CheckoutSubmodules(localRepo, cloneOptions, gitDirectory, _logger);
                    }
                }
                catch (Exception exc)
                {
                    throw new Exception($"Something went wrong when cloning repo {repoUri} at {commit ?? "<default branch>"} into {targetDirectory}", exc);
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Loads the tags.
        /// </summary>
        private void LoadTags(LibGit2Sharp.Repository repo = null)
        {
            var dispose = false;
            if (repo == null)
            {
                repo = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boost.
            Tags.DisableNotifications();

            Tags.Clear();

            // Add new tags.
            foreach (var tag in repo.Tags)
            {
                var t = Tag.Create(repo, tag);

                if (t.HasCommitAsTarget)
                    Tags.Add(t);
            }

            // Fire notifications for the Tags collection on the UI thread.
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Normal,
                (Action) (() => Tags.EnableNotifications(true))
            );

            if (dispose)
                repo.Dispose();
        }
Esempio n. 16
0
        internal async Task <IEnumerable <ReleaseInfo> > GetReleaseInfoAsync()
        {
            var    repository = new LibGit2Sharp.Repository(_configuration.RepositoryPath);
            string origin     = repository.Network.Remotes.First(r => r.Name == "origin").Url;
            string url        = !origin.EndsWith(".git") ? $"{origin}.git" : origin;

            Console.WriteLine($"Analyzing Git Repository at '{new FileInfo(_configuration.RepositoryPath).FullName}'");
            var orderedReleaseInfos = GetOrderedReleaseInfos(repository);

            Console.WriteLine($"Getting Issues and Pull Requests from '{url}'");
            var result = await GetAllIssuesAndPullRequestsAsync(url).ConfigureAwait(false);

            bool IssueTimeIsLessThenReleaseTime(DateTimeOffset releaseTime, DateTimeOffset?issueClosedTime)
            => issueClosedTime < releaseTime.AddSeconds(DeltaSeconds);

            bool IssueTimeIsGreaterThenPreviousReleaseTime(int idx, DateTimeOffset?issueClosedTime) =>
            idx <= 0 || issueClosedTime > orderedReleaseInfos[idx - 1].When.AddSeconds(DeltaSeconds);

            bool IssueLinkedToRelease(int idx, ReleaseInfo releaseInfo, DateTimeOffset?issueClosedAtTime) =>
            IssueTimeIsLessThenReleaseTime(releaseInfo.When, issueClosedAtTime) && IssueTimeIsGreaterThenPreviousReleaseTime(idx, issueClosedAtTime);

            // Loop all orderedReleaseInfos and add the correct Pull Requests and Issues
            foreach (var x in orderedReleaseInfos.Select((releaseInfo, index) => new { index, releaseInfo }))
            {
                // Process only Issues
                var issuesForThisTag = result.Issues.Where(issue => issue.PullRequest == null && IssueLinkedToRelease(x.index, x.releaseInfo, issue.ClosedAt));
                var issueInfos       = issuesForThisTag.Select(issue => new IssueInfo
                {
                    Number       = issue.Number,
                    IsPulRequest = false,
                    IssueUrl     = issue.HtmlUrl,
                    Title        = issue.Title,
                    User         = issue.User.Login,
                    UserUrl      = issue.User.HtmlUrl,
                    Labels       = issue.Labels.Select(label => label.Name).ToArray()
                });

                // Process PullRequests
                var pullsForThisTag = result.PullRequests.Where(pullRequest => IssueLinkedToRelease(x.index, x.releaseInfo, pullRequest.ClosedAt));
                var pullInfos       = pullsForThisTag.Select(pull => new IssueInfo
                {
                    Number       = pull.Number,
                    IsPulRequest = true,
                    IssueUrl     = pull.HtmlUrl,
                    Title        = pull.Title,
                    User         = pull.User.Login,
                    UserUrl      = pull.User.HtmlUrl,
                    Labels       = result.Issues
                                   .First(issue => issue.Number == pull.Number).Labels // Get the labels from the Issues (because this is not present in the 'PullRequest')
                                   .Select(label => label.Name)
                                   .ToArray()
                });

                bool ExcludeIssue(string[] labels) => _configuration.ExcludeLabels != null &&
                _configuration.ExcludeLabels.Any(s => labels.Contains(s, StringComparer.OrdinalIgnoreCase));

                var allIssues = issueInfos.Union(pullInfos)
                                .Distinct()
                                .Where(issueInfo => !ExcludeIssue(issueInfo.Labels));

                x.releaseInfo.IssueInfos = allIssues.OrderByDescending(issue => issue.IsPulRequest).ThenBy(issue => issue.Number).ToList();
            }

            if (_configuration.SkipEmptyReleases)
            {
                orderedReleaseInfos = orderedReleaseInfos.Where(r => r.IssueInfos.Count > 0).ToList();
            }

            return(orderedReleaseInfos.OrderByDescending(r => r.Version));
        }
Esempio n. 17
0
        /// <summary>
        /// This methods draws the graph for the changeset history grid.
        /// </summary>
        public void Draw(ItemCollection commitList)
        {
            if (graph == null)
                return;

            Console.WriteLine("Drawing graph.");

            var repo = new LibGit2Sharp.Repository(repositoryViewModel.RepositoryFullPath);
            commitDotPositions.Clear();
            SetBranchColors(repo.Branches);

            // Loop through all commits and draw the graph, in reverse order.
            commitList.MoveCurrentToLast();

            // Clear the existing graph.
            graph.Children.Clear();

            TotalHeight = 0;

            while (true)
            {
                Commit commit = commitList.CurrentItem as Commit;
                int rowNumber = commitList.CurrentPosition;

                if (commit == null)
                    break;

                // Get a list of branches around this commit.
                List<Branch> branchesAroundCommit = commit.BranchesAround;

                // Sort the lists alphabetically.
                branchesAroundCommit.OrderBy(o => o.Name.ToString());

                // Retrieve the index of this commit's branch on the list. This index determines the horizontal positions of dots (commit dots).
                int indexOfCurrentBranch;
                if (commit.Branches.Count > 0)
                    indexOfCurrentBranch = branchesAroundCommit.IndexOf(commit.Branches.ElementAt(0));
                else
                    indexOfCurrentBranch = 0;

                int horizontalIndex = indexOfCurrentBranch + commit.VisualPosition;
                for (var i = indexOfCurrentBranch - 1; i >= 0; i--)
                    horizontalIndex += ((Branch) branchesAroundCommit.ElementAt(i)).RightMostVisualPosition;

                // Draw the dot/ellipse based on the index of the current branch.
                byte dotSize = 10;
                byte horizontalDotSpacing = 12;

                int dotX = horizontalDotSpacing + dotSize * horizontalIndex + horizontalDotSpacing * horizontalIndex;
                int dotY = cellHeight * rowNumber + cellHeight / 2 - dotSize / 2;

                if (TotalHeight == 0)
                    TotalHeight = cellHeight * (rowNumber + 1);

                // Store the dot position on the dictionary.
                commitDotPositions.Add(commit.Hash, new int[2] { dotX, dotY });

                Ellipse dot = new Ellipse
                {
                    Fill = Brushes.Black,
                    StrokeThickness = 0,
                    Width = dotSize + 2,
                    Height = dotSize + 2
                };

                Canvas.SetLeft(dot, dotX - 1);
                Canvas.SetTop(dot, dotY - 1);
                Canvas.SetZIndex(dot, 1);

                graph.Children.Add(dot);

                // ToolTip for commits.
                var commitTooltip = new TextBlock
                {
                    MaxWidth = 320,
                    TextWrapping = TextWrapping.Wrap
                };

                // ToolTip for paths.
                var pathTooltip = new TextBlock
                {
                    MaxWidth = 320,
                    TextWrapping = TextWrapping.Wrap
                };

                if (commit.Branches.Count == 1)
                {
                    pathTooltip.Text = commit.Branches.ElementAt(0).Name;
                }
                else
                {
                    int i = 0, count = commit.Branches.Count;

                    commit.Branches.ForEach(b =>
                    {
                        i++;
                        pathTooltip.Inlines.AddRange(new Inline[]
                        {
                            new Run(b.Name + (i < count ? ", " : "")),
                        });
                    });
                }

                // Regular commits have a white circle inside.
                if (commit.IsMergeCommit() == false && commit.ParentCount < 2)
                {
                    Ellipse dotInner = new Ellipse
                    {
                        Fill = Brushes.White,
                        StrokeThickness = 0,
                        Width = dotSize,
                        Height = dotSize
                    };

                    Canvas.SetLeft(dotInner, dotX);
                    Canvas.SetTop(dotInner, dotY);
                    Canvas.SetZIndex(dotInner, 2);

                    graph.Children.Add(dotInner);

                    // ToolTip.
                    commitTooltip.Inlines.AddRange(new Inline[]
                    {
                        new Run("Commit: ")  {FontWeight = FontWeights.Bold},
                        new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold},
                        new LineBreak(),
                        new Run("Author: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.AuthorName) ,
                        new LineBreak(),
                        new Run("Date: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.FormattedDate),
                        new LineBreak(),
                        new LineBreak(),
                        new Run(commit.Description.TrimEnd())
                    });

                    dotInner.ToolTip = commitTooltip;
                    ToolTipService.SetShowDuration(dotInner, 60000);
                    ToolTipService.SetInitialShowDelay(dotInner, 1);
                }
                else
                {
                    // Tooltip.
                    commitTooltip.Inlines.AddRange(new Inline[]
                    {
                        new Run("Merge commit: ")  {FontWeight = FontWeights.Bold},
                        new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold},
                        new LineBreak(),
                        new Run("Author: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.AuthorName) ,
                        new LineBreak(),
                        new Run("Date: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.FormattedDate),
                        new LineBreak(),
                        new LineBreak(),
                        new Run(commit.Description.TrimEnd())
                    });

                    dot.ToolTip = commitTooltip;
                    ToolTipService.SetShowDuration(dot, 60000);
                    ToolTipService.SetInitialShowDelay(dot, 1);
                }

                if (commit.Branches.Count > 0)
                {
                    // Draw the line to the parent dot(s)/commit(s).
                    foreach (string hash in commit.ParentHashes)
                    {
                        // Retrieve the parent commit dot position.
                        var positions = commitDotPositions.Where(o => o.Key == hash);

                        if (positions.Count() > 0)
                        {
                            int[] parentPosition = commitDotPositions.Where(o => o.Key == hash).First().Value;

                            Brush lineColor = BranchColors[commit.Branches.ElementAt(0).Name];

                            // Calculate line positions.
                            float startLineX1 = dotX + dotSize / 2;
                            float startLineY1 = dotY + dotSize / 2;
                            float endLineX2 = parentPosition[0] + dotSize / 2;
                            float endLineY2 = parentPosition[1] + dotSize / 2;
                            float startLineX2;
                            float startLineY2;
                            float endLineX1;
                            float endLineY1;

                            if (commit.IsMergeCommit())
                            {
                                startLineX2 = endLineX2;
                                startLineY2 = startLineY1;

                                endLineX1 = endLineX2;
                                endLineY1 = startLineY1;
                            }
                            else
                            {
                                startLineX2 = startLineX1;
                                startLineY2 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 6;

                                endLineX1 = startLineX1;
                                endLineY1 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 12;
                            }

                            // Construct and draw the line path.
                            Path path = new Path
                            {
                                Stroke = lineColor,
                                StrokeThickness = 4,
                                Data = new PathGeometry
                                {
                                    Figures = new PathFigureCollection
                                    {
                                        new PathFigure
                                        {
                                            StartPoint = new Point(startLineX1, startLineY1),
                                            Segments = new PathSegmentCollection
                                            {
                                                new PolyBezierSegment
                                                {
                                                    Points = new PointCollection
                                                    {
                                                        new Point(startLineX2, startLineY2),
                                                        new Point(endLineX1, endLineY1),
                                                        new Point(endLineX2, endLineY2)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            graph.Children.Add(path);

                            path.ToolTip = pathTooltip;
                            ToolTipService.SetShowDuration(path, 60000);
                            ToolTipService.SetInitialShowDelay(path, 1);
                        }
                    }
                }

                commitList.MoveCurrentToPrevious();
                if (commitList.IsCurrentBeforeFirst)
                {
                    break;
                }
            }

            repo.Dispose();
        }
Esempio n. 18
0
        /// <summary>
        ///     Updates local copies of the files.
        /// </summary>
        /// <param name="filesToCommit">Files to update locally</param>
        /// <param name="repoUri">Base path of the repo</param>
        /// <param name="branch">Unused</param>
        /// <param name="commitMessage">Unused</param>
        /// <returns></returns>
        public async Task CommitFilesAsync(List <GitFile> filesToCommit, string repoUri, string branch, string commitMessage)
        {
            string repoDir = LocalHelpers.GetRootDir(_gitExecutable, _logger);

            try
            {
                using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir))
                {
                    foreach (GitFile file in filesToCommit)
                    {
                        Debug.Assert(file != null, "Passed in a null GitFile in filesToCommit");
                        switch (file.Operation)
                        {
                        case GitFileOperation.Add:
                            string parentDirectory = Directory.GetParent(file.FilePath).FullName;

                            if (!Directory.Exists(parentDirectory))
                            {
                                Directory.CreateDirectory(parentDirectory);
                            }

                            string fullPath = Path.Combine(repoUri, file.FilePath);
                            using (var streamWriter = new StreamWriter(fullPath))
                            {
                                string finalContent;
                                switch (file.ContentEncoding)
                                {
                                case ContentEncoding.Utf8:
                                    finalContent = file.Content;
                                    break;

                                case ContentEncoding.Base64:
                                    byte[] bytes = Convert.FromBase64String(file.Content);
                                    finalContent = Encoding.UTF8.GetString(bytes);
                                    break;

                                default:
                                    throw new DarcException($"Unknown file content encoding {file.ContentEncoding}");
                                }
                                finalContent = NormalizeLineEndings(fullPath, finalContent);
                                await streamWriter.WriteAsync(finalContent);

                                LibGit2SharpHelpers.AddFileToIndex(localRepo, file, fullPath, _logger);
                            }
                            break;

                        case GitFileOperation.Delete:
                            if (File.Exists(file.FilePath))
                            {
                                File.Delete(file.FilePath);
                            }
                            break;
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                throw new DarcException($"Something went wrong when checking out {repoUri} in {repoDir}", exc);
            }
        }
        /// <summary>
        /// Creates a tag.
        /// </summary>
        /// <param name="action"></param>
        public void CreateTag(object action)
        {
            var dialog = new PromptDialog();
            dialog.Title = "Create a new tag";
            dialog.Message = "Enter the name for the tag:";

            dialog.ShowDialog();

            if (dialog.DialogResult == true)
            {
                Commit commit = action as Commit;

                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    repo.Tags.Create(dialog.ResponseText, commit.Hash);
                    LoadEntireRepository();
                }
            }
        }
Esempio n. 20
0
        public static void PullFromRemote(string url, string path, Credentials credentials)
        {
            logger.InfoFormat("Start repository sync: {0}", path);
            if (!Directory.Exists(path))
            {
                logger.Info("Repository does not exist");
                logger.InfoFormat("Clone from {0}", url);
                var cloneOptions = new LibGit2Sharp.CloneOptions();
                if (credentials != null)
                {
                    cloneOptions.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.UsernamePasswordCredentials
                    {
                        Username = credentials.Username,
                        Password = credentials.Password
                    };
                }
                LibGit2Sharp.Repository.Clone(url, path, cloneOptions);
            }
            else
            {
                logger.Info("Repository exists");
                var fetchOptions = new LibGit2Sharp.FetchOptions();
                if (credentials != null)
                {
                    fetchOptions.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.UsernamePasswordCredentials
                    {
                        Username = credentials.Username,
                        Password = credentials.Password
                    };
                }
                using (var repository = new LibGit2Sharp.Repository(path))
                {
                    foreach (var remote in repository.Network.Remotes)
                    {
                        IEnumerable <string> refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);
                        logger.InfoFormat("Fetch repository from {0}: {1}", remote.Name, remote.Url);
                        LibGit2Sharp.Commands.Fetch(repository, remote.Name, refSpecs, fetchOptions, "");
                    }

                    var branchesUpdated = 0;
                    var branchesCreated = 0;
                    foreach (var branch in repository.Branches.Where(b => b.IsRemote))
                    {
                        var localBranchName = branch.FriendlyName.Replace(branch.RemoteName + "/", "");
                        if (repository.Branches[localBranchName] == null)
                        {
                            logger.InfoFormat("Branch does not exist: {0}", localBranchName);
                            logger.InfoFormat("Create branch from {0}: {1}", branch.FriendlyName, branch.Tip.Sha.Substring(0, 7));
                            repository.Branches.Update(
                                repository.Branches.Add(localBranchName, branch.Tip),
                                b => b.TrackedBranch = branch.CanonicalName);
                            branchesCreated++;
                        }

                        var localBranch = repository.Branches[localBranchName];
                        if (localBranch.Tip.Sha != branch.Tip.Sha)
                        {
                            //check out branch and reset
                            logger.InfoFormat("Branch {0} is behind: {1}", localBranchName, localBranch.Tip.Sha.Substring(0, 7));
                            logger.InfoFormat("Fast-forward to {0}", branch.Tip.Sha.Substring(0, 7));
                            LibGit2Sharp.Commands.Checkout(repository, localBranchName);
                            repository.Reset(LibGit2Sharp.ResetMode.Hard, branch.Tip);
                            branchesUpdated++;
                        }
                        else
                        {
                            logger.InfoFormat("Branch {0} is in sync: {1}", localBranch.FriendlyName, localBranch.Tip.Sha.Substring(0, 7));
                        }
                    }
                    logger.InfoFormat("Created branches: {0}", branchesCreated);
                    logger.InfoFormat("Updated branches: {0}", branchesUpdated);
                    logger.InfoFormat("Repository sync ready: {0}", path);
                }
            }
        }
        /// <summary>
        /// Updates the diff panel text.
        /// </summary>
        /// <param name="items"></param>
        public void UpdateStatusItemDiff(IList collection)
        {
            if (NotOpened == true)
                return;

            var diff = "";
            var items = collection.Cast<StatusItem>();

            using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                foreach (StatusItem item in items)
                {

                }

                diff += repo.Diff.Compare(repo.Head.Tip.Tree, LibGit2Sharp.DiffTarget.Index).Patch;
            }

            StatusItemDiff = diff;
        }
 public static void InitializeRepository(string repoUri, string repoDirectory)
 {
     LibGit2Sharp.Repository.Init(repoDirectory);
     using (var repo = new LibGit2Sharp.Repository(repoDirectory)) repo.Network.Remotes.Add(origin, repoUri);
 }
        /// <summary>
        /// Loads the repository status (modified, added, removed).
        /// </summary>
        private void LoadRepositoryStatus()
        {
            var repo = new LibGit2Sharp.Repository(RepositoryFullPath);

            StatusItems.Clear();

            // Load status items.
            List<StatusItem> itemList = new List<StatusItem>();

            LibGit2Sharp.RepositoryStatus status = repo.Index.RetrieveStatus();
            foreach (LibGit2Sharp.StatusEntry fileStatus in status)
            {
                foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus)))
                {
                    bool isSet = fileStatus.State.HasFlag(value);

                    if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored")
                        continue;

                    string fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath;

                    // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered).
                    StatusItem item = new StatusItem
                    {
                        Filename = fileStatus.FilePath,
                        Status = value,
                        Size = FileUtil.GetFormattedFileSize(fileFullPath),
                        IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-"
                    };

                    itemList.Add(item);
                }
            }

            StatusItems.AddRange(itemList);

            repo.Dispose();
        }
Esempio n. 24
0
 /// <summary>
 /// Initializes a new instance of the <see cref="VersionOracle"/> class.
 /// </summary>
 public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, ICloudBuild cloudBuild, int?overrideBuildNumberOffset = null, string projectPathRelativeToGitRepoRoot = null)
     : this(projectDirectory, repo, null, cloudBuild, overrideBuildNumberOffset, projectPathRelativeToGitRepoRoot)
 {
 }
Esempio n. 25
0
 private void OnContentRendered(object sender, EventArgs e)
 {
     _repo = OpenPasswordRepository();
     FillTreeView();
 }
Esempio n. 26
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VersionOracle"/> class.
        /// </summary>
        public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, LibGit2Sharp.Commit head, ICloudBuild cloudBuild, int?overrideVersionHeightOffset = null, string projectPathRelativeToGitRepoRoot = null)
        {
            var repoRoot = repo?.Info?.WorkingDirectory?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
            var relativeRepoProjectDirectory = !string.IsNullOrWhiteSpace(repoRoot)
                ? (!string.IsNullOrEmpty(projectPathRelativeToGitRepoRoot)
                    ? projectPathRelativeToGitRepoRoot
                    : projectDirectory.Substring(repoRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
                : null;

            var commit = head ?? repo?.Head.Commits.FirstOrDefault();

            var committedVersion = VersionFile.GetVersion(commit, relativeRepoProjectDirectory);

            var workingVersion = head != null?VersionFile.GetVersion(head, relativeRepoProjectDirectory) : VersionFile.GetVersion(projectDirectory);

            if (overrideVersionHeightOffset.HasValue)
            {
                if (committedVersion != null)
                {
                    committedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value;
                }

                if (workingVersion != null)
                {
                    workingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value;
                }
            }

            this.VersionOptions = committedVersion ?? workingVersion;

            this.GitCommitId   = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null;
            this.GitCommitDate = commit?.Author.When;
            this.VersionHeight = CalculateVersionHeight(relativeRepoProjectDirectory, commit, committedVersion, workingVersion);
            this.BuildingRef   = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName;

            // Override the typedVersion with the special build number and revision components, when available.
            if (repo != null)
            {
                this.Version = GetIdAsVersion(commit, committedVersion, workingVersion, this.VersionHeight);
            }
            else
            {
                this.Version = this.VersionOptions?.Version.Version ?? Version0;
            }

            // get the commit id abbreviation only if the commit id is set
            if (!string.IsNullOrEmpty(this.GitCommitId))
            {
                var gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength;
                var gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0;
                // get it from the git repository if there is a repository present and it is enabled
                if (repo != null && gitCommitIdShortAutoMinimum > 0)
                {
                    this.GitCommitIdShort = repo.ObjectDatabase.ShortenObjectId(commit, gitCommitIdShortAutoMinimum);
                }
                else
                {
                    this.GitCommitIdShort = this.GitCommitId.Substring(0, gitCommitIdShortFixedLength);
                }
            }

            this.VersionHeightOffset = this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0;

            this.PrereleaseVersion = this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty);

            this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance;

            if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Length > 0)
            {
                this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any(
                    expr => Regex.IsMatch(this.BuildingRef, expr));
            }
        }
Esempio n. 27
0
        /// <summary>
        /// Exports the given changeset as a patch to a file.
        /// </summary>
        /// <param name="action"></param>
        public void ExportPatch(object action)
        {
            var commit = action as Commit;

            if (commit == null)
                return;

            var dialog = new SaveFileDialog
            {
                FileName = commit.Description.Right(72),
                DefaultExt = ".patch",
                Filter = "Patch files|*.patch"
            };

            if (dialog.ShowDialog() == false)
                return;

            var filename = dialog.FileName;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    File.WriteAllText(filename, RepoUtil.GetTreeChangesForCommit(repo, commit).Patch);
                }
            });
        }
        /// <summary>
        ///     Checkout the repo to the specified state.
        /// </summary>
        /// <param name="commit">Tag, branch, or commit to checkout.</param>
        public void Checkout(string repoDir, string commit, bool force = false)
        {
            _logger.LogDebug($"Checking out {commit}", commit ?? "default commit");
            LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions
            {
                CheckoutModifiers = force ? LibGit2Sharp.CheckoutModifiers.Force : LibGit2Sharp.CheckoutModifiers.None,
            };
            try
            {
                _logger.LogDebug($"Reading local repo from {repoDir}");
                using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir))
                {
                    if (commit == null)
                    {
                        commit = localRepo.Head.Reference.TargetIdentifier;
                        _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} default commit to checkout is {commit}");
                    }
                    try
                    {
                        _logger.LogDebug($"Attempting to check out {commit} in {repoDir}");
                        LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger);
                        if (force)
                        {
                            CleanRepoAndSubmodules(localRepo, _logger);
                        }
                    }
                    catch (LibGit2Sharp.NotFoundException)
                    {
                        _logger.LogWarning($"Couldn't find commit {commit} in {repoDir} locally.  Attempting fetch.");
                        try
                        {
                            foreach (LibGit2Sharp.Remote r in localRepo.Network.Remotes)
                            {
                                IEnumerable <string> refSpecs = r.FetchRefSpecs.Select(x => x.Specification);
                                _logger.LogDebug($"Fetching {string.Join(";", refSpecs)} from {r.Url} in {repoDir}");
                                try
                                {
                                    LibGit2Sharp.Commands.Fetch(localRepo, r.Name, refSpecs, new LibGit2Sharp.FetchOptions(), $"Fetching from {r.Url}");
                                }
                                catch
                                {
                                    _logger.LogWarning($"Fetching failed, are you offline or missing a remote?");
                                }
                            }
                            _logger.LogDebug($"After fetch, attempting to checkout {commit} in {repoDir}");
                            LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger);

                            if (force)
                            {
                                CleanRepoAndSubmodules(localRepo, _logger);
                            }
                        }
                        catch   // Most likely network exception, could also be no remotes.  We can't do anything about any error here.
                        {
                            _logger.LogError($"After fetch, still couldn't find commit or treeish {commit} in {repoDir}.  Are you offline or missing a remote?");
                            throw;
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                throw new Exception($"Something went wrong when checking out {commit} in {repoDir}", exc);
            }
        }
Esempio n. 29
0
        /// <summary>
        /// Commits the currently staged files.
        /// </summary>
        /// <param name="action"></param>
        private void CommitChanges(object action)
        {
            var commitMessage = ((TextBox) action).Text;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    LibGit2Sharp.RepositoryExtensions.Commit(repo, commitMessage, false);

                    // Reconstruct the repository.
                    LoadEntireRepository();

                    // Clear the commit message box.
                    Application.Current.Dispatcher.BeginInvoke(
                        (Action)(() => UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "CommitMessageTextBox").Clear())
                    );
                }
            });
        }
        private static void CleanRepoAndSubmodules(LibGit2Sharp.Repository repo, ILogger log)
        {
            using (log.BeginScope($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules"))
            {
                log.LogDebug($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules");
                LibGit2Sharp.StatusOptions options = new LibGit2Sharp.StatusOptions
                {
                    IncludeUntracked     = true,
                    RecurseUntrackedDirs = true,
                };
                int count = 0;
                foreach (LibGit2Sharp.StatusEntry item in repo.RetrieveStatus(options))
                {
                    if (item.State == LibGit2Sharp.FileStatus.NewInWorkdir)
                    {
                        File.Delete(Path.Combine(repo.Info.WorkingDirectory, item.FilePath));
                        ++count;
                    }
                }
                log.LogDebug($"Deleted {count} untracked files");

                foreach (LibGit2Sharp.Submodule sub in repo.Submodules)
                {
                    string normalizedSubPath  = sub.Path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
                    string subRepoPath        = Path.Combine(repo.Info.WorkingDirectory, normalizedSubPath);
                    string subRepoGitFilePath = Path.Combine(subRepoPath, ".git");
                    if (!File.Exists(subRepoGitFilePath))
                    {
                        log.LogDebug($"Submodule {sub.Name} in {subRepoPath} does not appear to be initialized (no file at {subRepoGitFilePath}), attempting to initialize now.");
                        // hasn't been initialized yet, can happen when different hashes have new or moved submodules
                        try
                        {
                            repo.Submodules.Update(sub.Name, new LibGit2Sharp.SubmoduleUpdateOptions {
                                Init = true
                            });
                        }
                        catch
                        {
                            log.LogDebug($"Submodule {sub.Name} in {subRepoPath} is already initialized, trying to adopt from super-repo {repo.Info.Path}");

                            // superrepo thinks it is initialized, but it's orphaned.  Go back to the master repo to find out where this is supposed to point.
                            using (LibGit2Sharp.Repository masterRepo = new LibGit2Sharp.Repository(repo.Info.WorkingDirectory))
                            {
                                LibGit2Sharp.Submodule masterSubModule = masterRepo.Submodules.Single(s => s.Name == sub.Name);
                                string masterSubPath = Path.Combine(repo.Info.Path, "modules", masterSubModule.Path);
                                log.LogDebug($"Writing .gitdir redirect {masterSubPath} to {subRepoGitFilePath}");
                                Directory.CreateDirectory(Path.GetDirectoryName(subRepoGitFilePath));
                                File.WriteAllText(subRepoGitFilePath, $"gitdir: {masterSubPath}");
                            }
                        }
                    }

                    using (log.BeginScope($"Beginning clean of submodule {sub.Name}"))
                    {
                        log.LogDebug($"Beginning clean of submodule {sub.Name} in {subRepoPath}");

                        // The worktree is stored in the .gitdir/config file, so we have to change it
                        // to get it to check out to the correct place.
                        LibGit2Sharp.ConfigurationEntry <string> oldWorkTree = null;
                        using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                        {
                            oldWorkTree = subRepo.Config.Get <string>("core.worktree");
                            if (oldWorkTree != null)
                            {
                                log.LogDebug($"{subRepoPath} old worktree is {oldWorkTree.Value}, setting to {subRepoPath}");
                                subRepo.Config.Set("core.worktree", subRepoPath);
                            }
                            // This branch really shouldn't happen but just in case.
                            else
                            {
                                log.LogDebug($"{subRepoPath} has default worktree, leaving unchanged");
                            }
                        }

                        using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                        {
                            log.LogDebug($"Resetting {sub.Name} to {sub.HeadCommitId.Sha}");
                            subRepo.Reset(LibGit2Sharp.ResetMode.Hard, subRepo.Commits.QueryBy(new LibGit2Sharp.CommitFilter {
                                IncludeReachableFrom = subRepo.Refs
                            }).Single(c => c.Sha == sub.HeadCommitId.Sha));
                            // Now we reset the worktree back so that when we can initialize a Repository
                            // from it, instead of having to figure out which hash of the repo was most recently checked out.
                            if (oldWorkTree != null)
                            {
                                log.LogDebug($"resetting {subRepoPath} worktree to {oldWorkTree.Value}");
                                subRepo.Config.Set("core.worktree", oldWorkTree.Value);
                            }
                            else
                            {
                                log.LogDebug($"leaving {subRepoPath} worktree as default");
                            }
                            log.LogDebug($"Done resetting {subRepoPath}, checking submodules");
                            CleanRepoAndSubmodules(subRepo, log);
                        }
                    }

                    if (File.Exists(subRepoGitFilePath))
                    {
                        log.LogDebug($"Deleting {subRepoGitFilePath} to orphan submodule {sub.Name}");
                        File.Delete(subRepoGitFilePath);
                    }
                    else
                    {
                        log.LogDebug($"{sub.Name} doesn't have a .gitdir redirect at {subRepoGitFilePath}, skipping delete");
                    }
                }
            }
        }
Esempio n. 31
0
        /// <summary>
        /// Loads the repository status (modified, added, removed).
        /// </summary>
        private void LoadRepositoryStatus(LibGit2Sharp.Repository repo = null)
        {
            var dispose = false;
            if (repo == null)
            {
                repo = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // A small performance boost.
            StatusItemsStaged.DisableNotifications();
            StatusItemsUnstaged.DisableNotifications();

            StatusItemsStaged.Clear();
            StatusItemsUnstaged.Clear();

            // Load status items.
            var itemList = new List<StatusItem>();

            var status = repo.Index.RetrieveStatus();
            foreach (var fileStatus in status)
            {
                foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus)))
                {
                    var isSet = fileStatus.State.HasFlag(value);

                    if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored")
                        continue;

                    // TODO: would it be better without full repo path?
                    var fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath;

                    // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered).
                    var item = new StatusItem
                    {
                        Filename = fileStatus.FilePath,
                        Status = value,
                        Size = FileUtil.GetFormattedFileSize(fileFullPath), // TODO: Should these two file IO be done lazily?
                        IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-"
                    };

                    itemList.Add(item);
                }
            }

            StatusItemsStaged.AddRange(itemList.Where(s => s.IsStaged));
            StatusItemsUnstaged.AddRange(itemList.Where(s => !s.IsStaged));

            if (dispose)
                repo.Dispose();

            // Fire notifications for the collection on the UI thread.
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Normal,
                (Action)(
                    () =>
                    {
                        StatusItemsStaged.EnableNotifications(true);
                        StatusItemsUnstaged.EnableNotifications(true);
                    }
                )
            );
        }
Esempio n. 32
0
        /// <summary>
        /// Loads branches and commits.
        /// </summary>
        /// <param name="repo"></param>
        private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo)
        {
            var dispose = false;

            if (repo == null)
            {
                repo    = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boosts.
            Commits.DisableNotifications();
            Branches.DisableNotifications();

            // Create commits.
            Commits.Clear();
            List <Commit> commitList = new List <Commit>();

            foreach (LibGit2Sharp.Commit commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter {
                Since = repo.Branches
            }).Take(CommitsPerPage))
            {
                commitList.Add(Commit.Create(repo, commit, Tags));
            }
            Commits.AddRange(commitList);

            // Create branches.
            Branches.Clear();
            foreach (LibGit2Sharp.Branch branch in repo.Branches)
            {
                Branch b = Branch.Create(this, repo, branch);
                Branches.Add(b);
            }

            // Post-process branches (tips and tracking branches).
            foreach (Branch branch in Branches)
            {
                // Set the HEAD property if it matches.
                if (repo.Head.Name == branch.Name)
                {
                    Head = branch;
                    branch.Tip.IsHead = true;
                }

                branch.PostProcess(Branches, Commits);
            }

            // Post-process commits (commit parents).
            foreach (Commit commit in Commits)
            {
                // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null.
                if (Head == null && repo.Head.Tip.Sha == commit.Hash)
                {
                    Head = new DetachedHead
                    {
                        Tip = commit
                    };

                    commit.IsHead = true;
                }

                commit.PostProcess(Commits, Branches);
            }

            // Calculate commit visual positions for each branch tree.
            foreach (Branch branch in Branches)
            {
                RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip);
            }

            Commits.EnableNotifications();
            Branches.EnableNotifications();

            if (dispose)
            {
                repo.Dispose();
            }
        }
Esempio n. 33
0
        static int Main(string[] args)
        {
            var modelBindingDefinition = Args.Configuration.Configure<GitReleaseNotesArguments>();

            if (args.Any(a => a == "/?"))
            {
                var help = new HelpProvider().GenerateModelHelp(modelBindingDefinition);
                var f = new ConsoleHelpFormatter();
                f.WriteHelp(help, Console.Out);

                return 0;
            }

            var arguments = modelBindingDefinition.CreateAndBind(args);

            if (arguments.IssueTracker == null)
            {
                Console.WriteLine("The IssueTracker argument must be provided, see help (/?) for possible options");
                return 1;
            }
            if (string.IsNullOrEmpty(arguments.OutputFile) || !arguments.OutputFile.EndsWith(".md"))
            {
                Console.WriteLine("Specify an output file (*.md)");
                return 1;
            }

            CreateIssueTrackers(arguments);
            var issueTracker = IssueTrackers[arguments.IssueTracker.Value];
            if (!issueTracker.VerifyArgumentsAndWriteErrorsToConsole(arguments))
                return 1;

            var workingDirectory = arguments.WorkingDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            var gitDirectory = GitDirFinder.TreeWalkForGitDir(workingDirectory);
            if (string.IsNullOrEmpty(gitDirectory))
            {
                throw new Exception("Failed to find .git directory.");
            }

            Console.WriteLine("Git directory found at {0}", gitDirectory);

            var repositoryRoot = Directory.GetParent(gitDirectory).FullName;

            var gitHelper = new GitHelper();
            var gitRepo = new Repository(gitDirectory);
            var taggedCommitFinder = new TaggedCommitFinder(gitRepo, gitHelper);
            var tagToStartFrom = string.IsNullOrEmpty(arguments.FromTag) ?
                taggedCommitFinder.GetLastTaggedCommit() :
                taggedCommitFinder.GetTag(arguments.FromTag);
            var commitsToScan = gitRepo.Commits.TakeWhile(c => c != tagToStartFrom.Commit).ToArray();

            if (arguments.Verbose)
            {
                Console.WriteLine("Scanning the following commits for issue numbers");
                foreach (var commit in commitsToScan)
                {
                    Console.WriteLine(commit.Message);
                }
            }

            var releaseNotes = issueTracker.ScanCommitMessagesForReleaseNotes(arguments, commitsToScan);

            new ReleaseNotesWriter(new FileSystem(), repositoryRoot).WriteReleaseNotes(arguments, releaseNotes);
            return 0;
        }
Esempio n. 34
0
        /// <summary>
        /// A helper method for listing branches that contain the given commit.
        /// </summary>
        /// <param name="repo"></param>
        /// <param name="commitSha"></param>
        /// <returns></returns>
        public static IEnumerable <LibGit2Sharp.Branch> GetBranchesContaininingCommit(LibGit2Sharp.Repository repo, string commitSha)
        {
            bool directBranchHasBeenFound = false;

            foreach (var branch in repo.Branches)
            {
                if (branch.Tip.Sha != commitSha)
                {
                    continue;
                }

                directBranchHasBeenFound = true;
                yield return(branch);
            }

            if (directBranchHasBeenFound)
            {
                yield break;
            }

            foreach (var branch in repo.Branches)
            {
                var commits = repo.Commits.QueryBy(new LibGit2Sharp.Filter {
                    Since = branch
                }).Where(c => c.Sha == commitSha);

                if (commits.Count() == 0)
                {
                    continue;
                }

                yield return(branch);
            }
        }
        /// <summary>
        /// Adds a new note for the given commit.
        /// </summary>
        /// <param name="action"></param>
        public void AddNote(object action)
        {
            var dialog = new PromptDialog();
            dialog.Title = "Add a note";
            dialog.Message = "Enter the note to add for the commit:";

            dialog.ShowDialog();

            if (dialog.DialogResult == true)
            {
                Commit commit = action as Commit;

                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    //repo.Notes.Create(commit.Hash, dialog.ResponseText);
                    LoadEntireRepository();
                }
            }
        }
Esempio n. 36
0
        /// <summary>
        ///     Inits the repo, gpg etc
        /// </summary>
        public FrmMain(FileSystemInterface fileSystemInterface, KeySelect keySelect, ConfigHandling config)
        {
            log.Debug(() => "Init variables");
            fsi        = fileSystemInterface;
            _keySelect = keySelect;
            _config    = config;
            InitializeComponent();
            toolStripStatusLabel1.Text = "";

            this.enableTray = false;
            // Getting actual version
            log.Debug(() => "Getting program version");
            var assembly = Assembly.GetExecutingAssembly();
            var fvi      = FileVersionInfo.GetVersionInfo(assembly.Location);
            var version  = fvi.FileVersion;

            _config["version"] = version.Remove(5);
            Text = @"Pass4Win " + Strings.Version + @" " + _config["version"];
            // check config input
            log.Debug(() => "Checking config validity");
            try
            {
                bool ChkBool = Directory.Exists(_config["PassDirectory"]);
                if (!ChkBool)
                {
                    throw new Exception("Pass directory fail");
                }
                ChkBool = File.Exists(_config["GPGEXE"]);
                if (!ChkBool)
                {
                    throw new Exception("GPG location fail");
                }
                if (_config["UseGitRemote"] || _config["ExternalGit"])
                {
                    // nobody cares, we want the exception and it's auto generated due to a null value or not a boolean
                }
            }
            catch
            {
                // no matter if it's a first run or a corrupt entry, let them fix it.
                log.Debug(() => "Config corrupt or first run");
                _config["FirstRun"] = true;
                Program.Scope.Resolve <FrmConfig>().ShowDialog();
            }

            // checking for update in the background
            log.Debug(() => "Checking online for latest release");

            // making new git object
            if (_config["ExternalGit"] && !Program.NoGit)
            {
                log.Debug(() => "Using an external git executable");
                GitRepo = new GitHandling(_config["PassDirectory"], _config["GitRemote"], _config["ExternalGitLocation"]);
            }
            else if (!Program.NoGit)
            {
                log.Debug(() => "Using the internal git executable");
                GitRepo = new GitHandling(_config["PassDirectory"], _config["GitRemote"]);
            }

            //checking git status
            if (_config["UseGitRemote"] == true || _config["ExternalGit"])
            {
                if (!Program.NoGit)
                {
                    if (GitRepo.ConnectToRepo() || (_config["ExternalGit"]))
                    {
                        log.Debug(() => "Remote Git is valid and active");
                        this.gitRepoOffline      = false;
                        toolStripOffline.Visible = false;
                        if (!GitRepo.Fetch(_config["GitUser"], DecryptConfig(_config["GitPass"], "pass4win")))
                        {
                            // Something failed which shouldn't fail, rechecking online status
                            CheckOnline(false);
                        }
                    }
                    // checking if we can clone, otherwise make a new one
                    else if (!GitRepo.GitClone(_config["GitUser"], DecryptConfig(_config["GitPass"], "pass4win")))
                    {
                        log.Debug(() => "Making a new git repo");
                        Repository.Init(_config["PassDirectory"], false);
                        GitRepo.ConnectToRepo();
                        toolStripOffline.Visible = true;
                    }
                    // no connection, no repo. So make a new one
                    else if (!GitHandling.IsValid(_config["PassDirectory"]))
                    {
                        log.Debug(() => "Making a new git repo");
                        Repository.Init(_config["PassDirectory"], false);
                        GitRepo.ConnectToRepo();
                        toolStripOffline.Visible = true;
                    }
                }
            }

            // Init GPG if needed
            string gpgfile = _config["PassDirectory"];

            gpgfile += "\\.gpg-id";
            // Check if we need to init the directory
            if (!File.Exists(gpgfile) || (new FileInfo(gpgfile).Length == 0))
            {
                log.Debug(() => "Creating .gpg-id");
                // ReSharper disable once AssignNullToNotNullAttribute
                Directory.CreateDirectory(Path.GetDirectoryName(gpgfile));
                if (_keySelect.ShowDialog() == DialogResult.OK)
                {
                    using (var w = new StreamWriter(gpgfile))
                    {
                        w.Write(_keySelect.Gpgkey);
                    }

                    if (!Program.NoGit)
                    {
                        if (!GitRepo.Commit(gpgfile))
                        {
                            MessageBox.Show(
                                Strings.FrmMain_EncryptCallback_Commit_failed_,
                                Strings.Error,
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                            return;
                        }
                    }
                }
                else
                {
                    _keySelect.Close();
                    MessageBox.Show(Strings.Error_nokey, Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(1);
                }
            }
            // Setting the exe location for the GPG Dll
            GpgInterface.ExePath = _config["GPGEXE"];

            // Fill tree
            CreateNodes();

            this.enableTray = true;
        }
        /// <summary>
        /// Creates a branch.
        /// </summary>
        /// <param name="action"></param>
        public void CreateBranch(object action)
        {
            var dialog = new PromptDialog
            {
                Title = "Creating a new branch",
                Message = "Please give a name for your new branch:"
            };

            dialog.ShowDialog();

            if (dialog.DialogResult == true)
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    var sha = repo.Head.Tip.Sha.ToString();
                    repo.Branches.Create(dialog.ResponseText, repo.Head.Tip.Sha.ToString());
                }

                LoadEntireRepository();
            }
        }
Esempio n. 38
0
        // install pyRevit by cloning from git repo
        // @handled @logs
        public static void DeployFromRepo(string cloneName,
                                          string deploymentName = null,
                                          string branchName     = null,
                                          string repoUrl        = null,
                                          string destPath       = null,
                                          string username       = null,
                                          string password       = null)
        {
            string repoSourcePath = repoUrl ?? PyRevitLabsConsts.OriginalRepoGitPath;
            string repoBranch     = branchName != null ? branchName : PyRevitLabsConsts.TragetBranch;

            logger.Debug("Repo source determined as \"{0}:{1}\"", repoSourcePath, repoBranch);

            // determine destination path if not provided
            if (destPath is null)
            {
                destPath = Path.Combine(PyRevitLabsConsts.PyRevitPath, PyRevitConsts.DefaultCloneInstallName);
            }
            logger.Debug("Destination path determined as \"{0}\"", destPath);
            // make sure destPath exists
            CommonUtils.EnsurePath(destPath);

            // check existing destination path
            if (CommonUtils.VerifyPath(destPath))
            {
                logger.Debug("Destination path already exists {0}", destPath);
                destPath = Path.Combine(destPath, cloneName);
                logger.Debug("Using subpath {0}", destPath);
                if (CommonUtils.VerifyPath(destPath))
                {
                    throw new PyRevitException(string.Format("Destination path already exists \"{0}\"", destPath));
                }
            }

            // start the clone process
            LibGit2Sharp.Repository repo = null;
            if (deploymentName != null)
            {
                // TODO: Add core checkout option. Figure out how to checkout certain folders in libgit2sharp
                throw new NotImplementedException("Deployment with git clones not implemented yet.");
            }
            else
            {
                repo = GitInstaller.Clone(repoSourcePath, repoBranch, destPath, username, password);
            }

            // Check installation
            if (repo != null)
            {
                // make sure to delete the repo if error occured after cloning
                var clonedPath = repo.Info.WorkingDirectory;
                try {
                    PyRevitClone.VerifyCloneValidity(clonedPath);
                    logger.Debug("Clone successful \"{0}\"", clonedPath);
                    RegisterClone(cloneName, clonedPath);
                }
                catch (Exception ex) {
                    logger.Debug(string.Format("Exception occured after clone complete. Deleting clone \"{0}\" | {1}",
                                               clonedPath, ex.Message));
                    try {
                        CommonUtils.DeleteDirectory(clonedPath);
                    }
                    catch (Exception delEx) {
                        logger.Error(string.Format("Error post-install cleanup on \"{0}\" | {1}",
                                                   clonedPath, delEx.Message));
                    }

                    // cleanup completed, now baloon up the exception
                    throw ex;
                }
            }
            else
            {
                throw new PyRevitException(string.Format("Error installing pyRevit. Null repo error on \"{0}\"",
                                                         repoUrl));
            }
        }
        /// <summary>
        /// Exports the given changeset as a patch to a file.
        /// </summary>
        /// <param name="action"></param>
        public void ExportPatch(object action)
        {
            Commit commit = action as Commit;

            using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.FileName = commit.Description.Right(72);
                dialog.DefaultExt = ".patch";
                dialog.Filter = "Patch files|*.patch";

                if (dialog.ShowDialog() == true)
                {
                    // Save the patch to a file.
                    File.WriteAllText(dialog.FileName, RepoUtil.GetTreeChangesForCommit(repo, commit).Patch);
                }
            }
        }
Esempio n. 40
0
        public ActionResult Clone(Guid id, RepositoryDetailModel model)
        {
            if (!RepositoryPermissionService.HasCreatePermission(User.Id()))
            {
                return(RedirectToAction("Unauthorized", "Home"));
            }

            if (model != null && !String.IsNullOrEmpty(model.Name))
            {
                model.Name = Regex.Replace(model.Name, @"\s", "");
            }

            if (model != null && String.IsNullOrEmpty(model.Name))
            {
                ModelState.AddModelError("Name", Resources.Repository_Create_NameFailure);
            }
            else if (ModelState.IsValid)
            {
                var repo_model = ConvertRepositoryDetailModel(model);
                if (RepositoryRepository.Create(repo_model))
                {
                    string targetRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, model.Name);
                    if (!Directory.Exists(targetRepositoryPath))
                    {
                        var    source_repo          = RepositoryRepository.GetRepository(id);
                        string sourceRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, source_repo.Name);

                        LibGit2Sharp.CloneOptions options = new LibGit2Sharp.CloneOptions()
                        {
                            IsBare   = true,
                            Checkout = false
                        };

                        LibGit2Sharp.Repository.Clone(sourceRepositoryPath, targetRepositoryPath, options);

                        using (var repo = new LibGit2Sharp.Repository(targetRepositoryPath))
                        {
                            if (repo.Network.Remotes.Any(r => r.Name == "origin"))
                            {
                                repo.Network.Remotes.Remove("origin");
                            }
                        }

                        TempData["CloneSuccess"] = true;
                        return(RedirectToAction("Index"));
                    }
                    else
                    {
                        RepositoryRepository.Delete(model.Id);
                        ModelState.AddModelError("", Resources.Repository_Create_DirectoryExists);
                    }
                }
                else
                {
                    ModelState.AddModelError("", Resources.Repository_Create_Failure);
                }
            }

            ViewBag.ID = id;
            PopulateCheckboxListData(ref model);
            return(View(model));
        }
        /// <summary>
        /// Resets (reset --soft) the repository to the given changeset.
        /// </summary>
        /// <param name="action"></param>
        public void ResetSoft(object action)
        {
            Commit commit = action as Commit;

            using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                repo.Reset(LibGit2Sharp.ResetOptions.Mixed, commit.Hash);
                LoadEntireRepository();
            }
        }
        private static void CheckoutSubmodules(LibGit2Sharp.Repository repo, LibGit2Sharp.CloneOptions submoduleCloneOptions, string gitDirParentPath, ILogger log)
        {
            foreach (LibGit2Sharp.Submodule sub in repo.Submodules)
            {
                log.LogDebug($"Updating submodule {sub.Name} at {sub.Path} for {repo.Info.WorkingDirectory}.  GitDirParent: {gitDirParentPath}");
                repo.Submodules.Update(sub.Name, new LibGit2Sharp.SubmoduleUpdateOptions {
                    CredentialsProvider = submoduleCloneOptions.CredentialsProvider, Init = true
                });

                string normalizedSubPath  = sub.Path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
                string subRepoPath        = Path.Combine(repo.Info.WorkingDirectory, normalizedSubPath);
                string relativeGitDirPath = File.ReadAllText(Path.Combine(subRepoPath, ".git")).Substring(8);

                log.LogDebug($"Submodule {sub.Name} has .gitdir {relativeGitDirPath}");
                string absoluteGitDirPath  = Path.GetFullPath(Path.Combine(subRepoPath, relativeGitDirPath));
                string relocatedGitDirPath = absoluteGitDirPath.Replace(repo.Info.Path.TrimEnd(new[] { '/', '\\' }), gitDirParentPath.TrimEnd(new[] { '/', '\\' }));
                string subRepoGitFilePath  = Path.Combine(subRepoPath, ".git");

                log.LogDebug($"Writing new .gitdir path {relocatedGitDirPath} to submodule at {subRepoPath}");

                // File.WriteAllText gets access denied for some reason
                using (FileStream s = File.OpenWrite(subRepoGitFilePath))
                    using (StreamWriter w = new StreamWriter(s))
                    {
                        w.Write($"gitdir: {relocatedGitDirPath}");
                        w.Flush();
                        s.SetLength(s.Position);
                    }

                // The worktree is stored in the .gitdir/config file, so we have to change it
                // to get it to check out to the correct place.
                LibGit2Sharp.ConfigurationEntry <string> oldWorkTree = null;
                using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                {
                    oldWorkTree = subRepo.Config.Get <string>("core.worktree");
                    if (oldWorkTree != null)
                    {
                        log.LogDebug($"{subRepoPath} old worktree is {oldWorkTree.Value}, setting to {subRepoPath}");
                        subRepo.Config.Set("core.worktree", subRepoPath);
                    }
                    else
                    {
                        log.LogDebug($"{subRepoPath} has default worktree, leaving unchanged");
                    }
                }

                using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                {
                    log.LogDebug($"Resetting {sub.Name} to {sub.HeadCommitId.Sha}");
                    subRepo.Reset(LibGit2Sharp.ResetMode.Hard, subRepo.Commits.QueryBy(new LibGit2Sharp.CommitFilter {
                        IncludeReachableFrom = subRepo.Refs
                    }).Single(c => c.Sha == sub.HeadCommitId.Sha));

                    // Now we reset the worktree back so that when we can initialize a Repository
                    // from it, instead of having to figure out which hash of the repo was most recently checked out.
                    if (oldWorkTree != null)
                    {
                        log.LogDebug($"resetting {subRepoPath} worktree to {oldWorkTree.Value}");
                        subRepo.Config.Set("core.worktree", oldWorkTree.Value);
                    }
                    else
                    {
                        log.LogDebug($"leaving {subRepoPath} worktree as default");
                    }

                    log.LogDebug($"Done checking out {subRepoPath}, checking submodules");
                    CheckoutSubmodules(subRepo, submoduleCloneOptions, absoluteGitDirPath, log);
                }

                if (File.Exists(subRepoGitFilePath))
                {
                    log.LogDebug($"Deleting {subRepoGitFilePath} to orphan submodule {sub.Name}");
                    File.Delete(subRepoGitFilePath);
                }
                else
                {
                    log.LogDebug($"{sub.Name} doesn't have a .gitdir redirect at {subRepoGitFilePath}, skipping delete");
                }
            }
        }
        /// <summary>
        /// Commits the currently staged files.
        /// </summary>
        /// <param name="action"></param>
        private void CommitChanges(object action)
        {
            var commitMessage = (string) action;

            using (LibGit2Sharp.Repository repo = new LibGit2Sharp.Repository(RepositoryFullPath))
            {
                LibGit2Sharp.RepositoryExtensions.Commit(repo, commitMessage, false);

                // Reconstruct the repository.
                LoadEntireRepository();
                LoadRepositoryStatus();

                // Clear the commit message box.
                UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "CommitMessageTextBox").Clear();
            }
        }
Esempio n. 44
0
 private static string GetRepoRelativePath(string searchPath, LibGit2Sharp.Repository repository)
 {
     return(searchPath.Substring(repository.Info.WorkingDirectory.Length));
 }
        /// <summary>
        /// Loads branches and commits.
        /// </summary>
        /// <param name="repo"></param>
        private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo)
        {
            var dispose = false;
            if (repo == null)
            {
                repo = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boosts.
            Commits.DisableNotifications();
            Branches.DisableNotifications();

            // Create commits.
            Commits.Clear();
            List<Commit> commitList = new List<Commit>();
            foreach (LibGit2Sharp.Commit commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage))
            {
                commitList.Add(Commit.Create(repo, commit, Tags));
            }
            Commits.AddRange(commitList);

            // Create branches.
            Branches.Clear();
            foreach (LibGit2Sharp.Branch branch in repo.Branches)
            {
                Branch b = Branch.Create(this, repo, branch);
                Branches.Add(b);
            }

            // Post-process branches (tips and tracking branches).
            foreach (Branch branch in Branches)
            {
                // Set the HEAD property if it matches.
                if (repo.Head.Name == branch.Name)
                {
                    Head = branch;
                    branch.Tip.IsHead = true;
                }

                branch.PostProcess(Branches, Commits);
            }

            // Post-process commits (commit parents).
            foreach (Commit commit in Commits)
            {
                // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null.
                if (Head == null && repo.Head.Tip.Sha == commit.Hash)
                {
                    Head = new DetachedHead
                    {
                        Tip = commit
                    };

                    commit.IsHead = true;
                }

                commit.PostProcess(Commits, Branches);
            }

            // Calculate commit visual positions for each branch tree.
            foreach (Branch branch in Branches)
            {
                RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip);
            }

            Commits.EnableNotifications();
            Branches.EnableNotifications();

            if (dispose)
                repo.Dispose();
        }
Esempio n. 46
0
        /// <summary>
        /// Creates a branch.
        /// </summary>
        /// <param name="action"></param>
        public void CreateBranch(object action)
        {
            var dialog = new PromptDialog
            {
                Title = "Creating a new branch",
                Message = "Please give a name for your new branch:"
            };

            dialog.ShowDialog();

            if (dialog.DialogResult != true)
                return;

            var response = dialog.ResponseText;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    repo.Branches.Create(response, repo.Head.Tip.Sha.ToString(CultureInfo.InvariantCulture));
                }

                LoadEntireRepository();
            });
        }
        /// <summary>
        /// Loads the tags.
        /// </summary>
        private void LoadTags(LibGit2Sharp.Repository repo)
        {
            var dispose = false;
            if (repo == null)
            {
                repo = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boost.
            Tags.DisableNotifications();

            Tags.Clear();

            // Add new tags.
            foreach (LibGit2Sharp.Tag tag in repo.Tags)
            {
                Tag t = Tag.Create(repo, tag);

                if (t.HasCommitAsTarget)
                    Tags.Add(t);
            }

            Tags.EnableNotifications();

            if (dispose)
                repo.Dispose();
        }
Esempio n. 48
0
        /// <summary>
        /// Creates a tag.
        /// </summary>
        /// <param name="action"></param>
        public void CreateTag(object action)
        {
            var commit = action as Commit;

            var dialog = new PromptDialog
            {
                Title = "Create a new tag",
                Message = "Enter the name for the tag:"
            };

            dialog.ShowDialog();

            if (dialog.DialogResult != true || commit == null)
                return;

            var response = dialog.ResponseText;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    repo.Tags.Create(response, commit.Hash);
                    LoadEntireRepository();
                }
            });
        }
Esempio n. 49
0
        protected LibGit2Sharp.Repository OpenPasswordRepository()
        {
            var enforceSelectionOfNewPath = false;

            while (true)
            {
                try
                {
                    var passwordStorePath = GetPasswordStorePath(enforceSelectionOfNewPath);
                    var repo = new LibGit2Sharp.Repository(passwordStorePath);

                    Properties.Settings.Default.PasswordStorePath = passwordStorePath;
                    Properties.Settings.Default.Save();

                    return repo;
                }
                catch
                {
                    enforceSelectionOfNewPath = true;
                }
            }
        }
Esempio n. 50
0
        /// <summary>
        /// Deletes a tag.
        /// </summary>
        /// <param name="action"></param>
        public void DeleteTag(object action)
        {
            var tag = (Tag) action;

            var dialog = new ConfirmDialog
            {
                Title = "Deleting a tag",
                Message = String.Format("Are you sure you want to delete this tag ({0})?", tag.Name)
            };

            dialog.ShowDialog();

            var pressedButton = dialog.PressedButton;
            if (pressedButton == null || ((string) pressedButton.Content) != "OK")
                return;

            Task.Run(() =>
            {
                using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath))
                {
                    // Remove the tag from the Git repository.
                    repo.Tags.Delete(tag.CanonicalName);

                    // Reload all tags.
                    LoadTags();

                    Application.Current.Dispatcher.BeginInvoke(
                        DispatcherPriority.Normal,
                        (Action) (() => tag.Target.Tags.Remove(tag))
                    );
                }
            });
        }
        public ActionResult Clone(string id, RepositoryDetailModel model)
        {
            if (!User.IsInRole(Definitions.Roles.Administrator) && !UserConfiguration.Current.AllowUserRepositoryCreation)
            {
                return RedirectToAction("Unauthorized", "Home");
            }

            if (model != null && !String.IsNullOrEmpty(model.Name))
            {
                model.Name = Regex.Replace(model.Name, @"\s", "");
            }

            if (String.IsNullOrEmpty(model.Name))
            {
                ModelState.AddModelError("Name", Resources.Repository_Create_NameFailure);
            }
            else if (ModelState.IsValid)
            {
                if (RepositoryRepository.Create(ConvertRepositoryDetailModel(model)))
                {
                    string targetRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, model.Name);
                    if (!Directory.Exists(targetRepositoryPath))
                    {
                        string sourceRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, id);
                        
                        LibGit2Sharp.CloneOptions options = new LibGit2Sharp.CloneOptions()
                            {
                                IsBare = true,
                                Checkout = false
                            };

                        LibGit2Sharp.Repository.Clone(sourceRepositoryPath, targetRepositoryPath, options);

                        using (var repo = new LibGit2Sharp.Repository(targetRepositoryPath))
                        {
                            if (repo.Network.Remotes.Any(r => r.Name == "origin"))
                            {
                                repo.Network.Remotes.Remove("origin");
                            }
                        }

                        TempData["CloneSuccess"] = true;
                        return RedirectToAction("Index");
                    }
                    else
                    {
                        RepositoryRepository.Delete(model.Name);
                        ModelState.AddModelError("", Resources.Repository_Create_DirectoryExists);
                    }
                }
                else
                {
                    ModelState.AddModelError("", Resources.Repository_Create_Failure);
                }
            }

            ViewBag.ID = id;
            PopulateEditData();
            return View(model);
        }
Esempio n. 52
0
        /// <summary>
        /// Loads branches and commits.
        /// </summary>
        /// <param name="repo"></param>
        private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo = null)
        {
            var dispose = false;

            if (repo == null)
            {
                repo    = new LibGit2Sharp.Repository(RepositoryFullPath);
                dispose = true;
            }

            // Small performance boosts.
            Commits.DisableNotifications();
            Branches.DisableNotifications();

            // Create commits.
            Commits.Clear();
            var commitList = new List <Commit>();

            foreach (var commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter {
                Since = repo.Branches
            }).Take(CommitsPerPage))
            {
                commitList.Add(Commit.Create(repo, commit, Tags));
            }
            Commits.AddRange(commitList);

            // Create branches.
            Branches.Clear();
            foreach (var branch in repo.Branches)
            {
                var b = Branch.Create(this, repo, branch);
                Branches.Add(b);
            }

            // Post-process branches (tips and tracking branches).
            foreach (var branch in Branches)
            {
                // Set the HEAD property if it matches.
                if (repo.Head.Name == branch.Name)
                {
                    Head = branch;
                    branch.Tip.IsHead = true;
                }

                branch.PostProcess(Branches, Commits);
            }

            // Post-process commits (commit parents).
            foreach (var commit in Commits)
            {
                // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null.
                if (Head == null && repo.Head.Tip.Sha == commit.Hash)
                {
                    Head = new DetachedHead
                    {
                        Tip = commit
                    };

                    commit.IsHead = true;
                }

                commit.PostProcess(Commits, Branches);
            }

            // Calculate commit visual positions for each branch tree.
            foreach (var branch in Branches)
            {
                RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip);
            }

            // Fire notifications for the collections on the UI thread.
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Normal,
                (Action)(() =>
            {
                Commits.EnableNotifications(true);
                Branches.EnableNotifications(true);

                var tabControl = UIHelper.FindChild <TabControl>(Application.Current.MainWindow, "RepositoryTabs");
                var changesetHistory = UIHelper.FindChild <ChangesetHistory>(tabControl);

                if (changesetHistory != null)
                {
                    changesetHistory.RedrawGraph();
                }
            })
                );

            if (dispose)
            {
                repo.Dispose();
            }
        }