使用octokit.net库更新github中的子模块commit sha

时间:2017-06-26 05:17:53

标签: c# git github octokit.net

我正在尝试在另一个项目更改某些文件时自动更新子模块的提交ID。我有一个.net webhook,我正在使用octokit.net库。

我可以在github文档(https://developer.github.com/v3/git/trees/#create-a-tree)中看到,在创建允许添加提交和路径的新树时,有一个子模块选项,但我无法使其工作。 Octokit还有NewTreeItem / TreeItem对象的子模块类型,但没有示例或文档。

我当前的代码在这里 - 目前我将提交sha作为sha参数传递,但我可以看到这是错误的,我需要在该repo上创建一个提交并使用该sha,我只是不在创建树之前知道如何做到这一点,而且我找不到任何文档:

    public static async Task UpdateSubmoduleInBranch(string repo, string branchName, string submodulePath, string sha, string commitComment, GitHubClient github = null)
    {
        //hoping this will update the sha of a submodule

        // url encode branch name for github operations
        branchName = HttpUtility.UrlEncode(branchName);

        if (github == null) github = GetClient();

        var repoId = (await github.Repository.Get(Settings.GitHub.OrgName, repo)).Id;

        RepositoriesClient rClient = new RepositoriesClient(new ApiConnection(github.Connection));

        var branch = await rClient.Branch.Get(repoId, branchName);

        var tree = await github.Git.Tree.Get(repoId, branchName);

        var newTree = new NewTree { BaseTree = tree.Sha };
        newTree.Tree.Add(new NewTreeItem
        {
            Mode = Octokit.FileMode.Submodule,
            Path = submodulePath,
            Type = TreeType.Commit,
            Sha = sha
        });

        var createdTree = await github.Git.Tree.Create(repoId, newTree);

        var newCommit = new NewCommit(commitComment, createdTree.Sha, new[] { branch.Commit.Sha });
        newCommit.Committer = Settings.GitHub.Committer;

        var createdCommit = await github.Git.Commit.Create(Settings.GitHub.OrgName, Settings.GitHub.AppName, newCommit);

        var updateRef = new ReferenceUpdate(createdCommit.Sha, false);
        await github.Git.Reference.Update(repoId, "heads/" + branchName, updateRef);
    }

修改

如果其他人正在寻找这个,我解决了这个问题 - octokit api 支持这个动作,即使它看起来像。

除了在PATCH Async requests with Windows.Web.Http.HttpClient class找到的PatchAsync方法外,以下代码对我有用:

    public static async Task UpdateSubmoduleInBranch(string repo, string branchName, string submodulePath, string sha, string commitComment)
    {
        using (var client = new HttpClient())
        {
            try
            {
                //these headers authenticate with github, useragent is required.
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Settings.GitHub.AuthToken);
                client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("mathspathway-environment-manager", "v1.0"));

                var committer = Settings.GitHub.Committer;

                //get the branch, and collect the sha of the current commit
                var branchResponse = await client.GetAsync($"{Settings.GitHub.ApiUrl}/repos/{Settings.GitHub.OrgName}/{repo}/branches/{branchName}");
                JToken branchResult = JToken.Parse(await branchResponse.Content.ReadAsStringAsync());
                var currentCommitSha = branchResult["commit"].Value<string>("sha");

                //create the new tree, with the mode of 160000 (submodule mode) and type of commit, and the sha of the other 
                //repository's commit that you want to update the submodule to, and the base tree of the current commit on this repo
                var newTreeObj = new
                {
                    base_tree = currentCommitSha,
                    tree = new List<Object> { new { path = submodulePath, mode= "160000", type = "commit", sha = sha}
            }
                };

                HttpContent treeHttpContent = new StringContent(JsonConvert.SerializeObject(newTreeObj));
                var treeResponse = await client.PostAsync($"{Settings.GitHub.ApiUrl}/repos/{Settings.GitHub.OrgName}/{repo}/git/trees", treeHttpContent);
                var treeResponseContent = JToken.Parse(await treeResponse.Content.ReadAsStringAsync());
                var treeSha = treeResponseContent.Value<string>("sha");


                //Create a new commit based on the tree we just created, with the parent of the current commit on the branch
                var newCommitObj = new
                {
                    message = commitComment,
                    author = new { name = committer.Name, email = committer.Email, date = committer.Date },
                    parents = new[] { currentCommitSha },
                    tree = treeSha
                };
                HttpContent newCommitContent = new StringContent(JsonConvert.SerializeObject(newCommitObj));
                var commitResponse = await client.PostAsync($"{Settings.GitHub.ApiUrl}/repos/{Settings.GitHub.OrgName}/{repo}/git/commits", newCommitContent);
                var commitResponseContent = JToken.Parse(await commitResponse.Content.ReadAsStringAsync());
                var commitSha = commitResponseContent.Value<string>("sha");



                //create an update reference object, and update the branch's head commit reference to the new commit
                var updateRefObject = new { sha = commitSha, force = false };
                HttpContent updateRefContent = new StringContent(JsonConvert.SerializeObject(updateRefObject));
                var updateRefResponse = await client.PatchAsync($"{Settings.GitHub.ApiUrl}/repos/{Settings.GitHub.OrgName}/{repo}/git/refs/heads/{branchName}", updateRefContent);

            } catch (Exception ex)
            {
                Debug.WriteLine($"Error occurred updating submodule: {ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}");
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

在尝试完成大致相同的目标时,但是通过单独的用户提交拉取请求,我给您的原始代码注射了一些小的更改。结果是它与Octokit.net完美配合。

提取的示例代码

var submoduleRepoId = (await gitHubClient.Repository.Get(submoduleRepoOwnerName, submoduleRepoName)).Id;
var submoduleRepoBranchLatestSha = (await gitHubClient.Git.Tree.Get(submoduleRepoId, submoduleRepoBranchName)).Sha;
…
var updateParentTree = new NewTree { BaseTree = parentRepoBranchLatestSha };
updateParentTree.Tree.Add(new NewTreeItem
{
    Mode = FileMode.Submodule,
    Sha = submoduleRepoBranchLatestSha,
    Path = pathToSubmoduleInParentRepo,
    Type = TreeType.Commit,
});
var newParentTree = await gitHubClient.Git.Tree.Create(pullRequestOwnerForkRepoId, updateParentTree);
var commitMessage = $"Bump to {submoduleOwnerName}/{submoduleRepoName}@{submoduleCommitHash}";
var newCommit = new NewCommit(commitMessage, newParentTree.Sha, parentBranchLatestSha);
var pullRequestBranchRef = $"heads/{pullRequestBranchName}";
var commit = await gitHubClient.Git.Commit.Create(pullRequestOwnerName, parentRepoName, newCommit);
var await gitHubClient.Git.Reference.Update(pullRequestOwnerForkRepoId, pullRequestBranchRef, new ReferenceUpdate(commit.Sha));

Full sample code

此时,我只能看到一些潜在的差异。

  • 我绝对不会HttpUtility.UrlEncode我的分支名称(Octokit必须为我做任何所需的编码)
  • 我在自己的分支上承诺使用单独的用户分支

可能是那些差异已经足够,或者当你尝试同样的事情时,可能已经解决了这个问题。