private void UpdateSubmodules(GitCommit buildRepoCommit, GitTree buildRepoTree, bool rewriteGitModules) { // copy most items from the existing commit tree const string gitModulesPath = ".gitmodules"; List<GitTreeItem> treeItems = buildRepoTree.Items .Where(x => (x.Type != "commit" && x.Type != "blob") || (x.Type == "blob" && (!rewriteGitModules || x.Path != gitModulesPath))).ToList(); // add all the submodules treeItems.AddRange(m_submodules.Select(x => new GitTreeItem { Mode = "160000", Path = x.Key, Sha = x.Value.LatestCommitId, Type = "commit", })); if (rewriteGitModules) { // create the contents of the .gitmodules file string gitModules; using (StringWriter sw = new StringWriter { NewLine = "\n" }) { foreach (var pair in m_submodules.OrderBy(x => x.Key, StringComparer.Ordinal)) { sw.WriteLine("[submodule \"{0}\"]", pair.Key); sw.WriteLine("\tpath = {0}", pair.Key); sw.WriteLine("\turl = {0}", pair.Value.Url); } gitModules = sw.ToString(); } // create the blob GitBlob gitModulesBlob = CreateBlob(gitModules); treeItems.Add(new GitTreeItem { Mode = "100644", Path = gitModulesPath, Sha = gitModulesBlob.Sha, Type = "blob", }); } const string commitMessage = "Update submodules to match Leeroy configuration."; GitCommit newCommit = CreateNewCommit(buildRepoCommit, null, treeItems, commitMessage); Log.Info("Created new commit for synced submodules: {0}; moving branch.", newCommit.Sha); // advance the branch pointer to the new commit if (TryAdvanceBranch(newCommit.Sha)) { Log.Info("Build repo updated successfully to commit {0}.", newCommit.Sha); m_lastBuildCommitId = newCommit.Sha; } }
private string ReadGitModulesBlob(GitTree tree) { GitTreeItem gitModulesItem = tree.Items.FirstOrDefault(x => x.Type == "blob" && x.Path == ".gitmodules"); if (gitModulesItem == null) return null; GitBlob gitModulesBlob = m_gitHubClient.GetBlob(gitModulesItem); return gitModulesBlob.GetContent(); }
// Loads the desired list of submodules from the configuration file. private void SyncSubmodules(GitCommit buildRepoCommit, GitTree buildRepoTree) { ReadSubmodulesFromConfig(); // find submodules that should be present in the build repo, but aren't bool updateSubmodules = false; foreach (KeyValuePair<string, Submodule> pair in m_submodules) { string path = pair.Key; Submodule submodule = pair.Value; GitTreeItem submoduleItem = buildRepoTree.Items.FirstOrDefault(x => x.Type == "commit" && x.Mode == "160000" && x.Path == path); if (submoduleItem != null) { submodule.LatestCommitId = submoduleItem.Sha; } else { submodule.LatestCommitId = m_gitHubClient.GetLatestCommitId(submodule.User, submodule.Repo, submodule.Branch); if (submodule.LatestCommitId == null) throw new WatcherException("Submodule '{0}' doesn't have a latest commit for branch '{1}'; will stop monitoring project.".FormatInvariant(pair.Key, submodule.Branch)); Log.Info("Submodule at path '{0}' is missing; it will be added.", pair.Key); updateSubmodules = true; } } // find extra submodules that aren't in the configuration file List<string> extraSubmodulePaths = buildRepoTree.Items .Where(x => x.Type == "commit" && x.Mode == "160000" && !m_submodules.ContainsKey(x.Path)) .Select(x => x.Path) .ToList(); if (extraSubmodulePaths.Count != 0) { Log.Info("Extra submodule paths: {0}".FormatInvariant(string.Join(", ", extraSubmodulePaths))); updateSubmodules = true; } // determine if .gitmodules needs to be updated bool rewriteGitModules = false; string gitModulesBlob = ReadGitModulesBlob(buildRepoTree); using (StringReader reader = new StringReader(gitModulesBlob ?? "")) { var existingGitModules = ParseConfigFile(reader) .Where(x => x.Key.StartsWith("submodule ", StringComparison.Ordinal)) .Select(x => new { Path = x.Value["path"], Url = x.Value["url"] }) .OrderBy(x => x.Path, StringComparer.Ordinal) .ToList(); var desiredGitModules = m_submodules.Select(x => new { Path = x.Key, x.Value.Url }).OrderBy(x => x.Path, StringComparer.Ordinal).ToList(); if (!existingGitModules.SequenceEqual(desiredGitModules)) { Log.Info(".gitmodules needs to be updated."); rewriteGitModules = true; } } if (updateSubmodules || rewriteGitModules) UpdateSubmodules(buildRepoCommit, buildRepoTree, rewriteGitModules); }
private void LoadSubmodules(GitTree buildRepoTree) { string gitModulesBlob = ReadGitModulesBlob(buildRepoTree); if (gitModulesBlob == null) { Log.Error("Tree {0} doesn't contain a .gitmodules file.", buildRepoTree.Sha); return; } using (StringReader reader = new StringReader(gitModulesBlob)) { foreach (var submodule in ParseConfigFile(reader).Where(x => x.Key.StartsWith("submodule ", StringComparison.Ordinal))) { // get submodule details string path = submodule.Value["path"]; string url = submodule.Value["url"]; string server, user, repo; if (!SplitRepoUrl(url, out server, out user, out repo)) { Log.Error("{0} is not a valid Git URL".FormatInvariant(url)); continue; } // find submodule in repo, and add it to list of tracked submodules GitTreeItem submoduleItem = buildRepoTree.Items.FirstOrDefault(x => x.Type == "commit" && x.Mode == "160000" && x.Path == path); if (submoduleItem == null) { Log.Warn(".gitmodules contains [{0}] but there is no submodule at path '{1}'.", submodule.Key, path); } else { // use specified branch; else default to tracking the build repo's branch string branch; if (m_project.SubmoduleBranches == null || !m_project.SubmoduleBranches.TryGetValue(path, out branch)) branch = m_branch; Log.Info("Adding new submodule: '{0}' = '{1}'.", path, url); m_submodules.Add(path, new Submodule { Url = url, User = user, Repo = repo, Branch = branch, LatestCommitId = submoduleItem.Sha }); } } } }