0

我正在尝试使用 Octokit.Net 读取和更新我的存储库中的单个文件。

我尝试读取/更新的特定文件大小约为 2.1MB,因此当我尝试使用以下代码读取此文件时...

var currentFileText = "";

            var contents = await client.Repository.Content.GetAllContentsByRef("jkears", "NextWare.ProductPortal", "domainModel.ddd", "master");
            var targetFile = contents[0];
            if (targetFile.EncodedContent != null)
            {
                currentFileText = Encoding.UTF8.GetString(Convert.FromBase64String(targetFile.EncodedContent));
            }
            else
            {
                currentFileText = targetFile.Content;
            }

我得到这个例外..

Octokit.ForbiddenException
  HResult=0x80131500
  Message=This API returns blobs up to 1 MB in size. The requested blob is too large to fetch via the API, but you can use the Git Data API to request blobs up to 100 MB in size.

我的问题是如何在 c# 中使用 Git Data API 来读取这个大文件的内容,以及如何将这个文件的更改更新回同一个存储库?

4

1 回答 1

0

嗯,不难,但不是那么明显。

我试图读取/更新的文件是 2.4 Mb,虽然我能够将此文件压缩到 512K(使用 SevenZip),这允许我在 repo 上读取/更新,但我想读取/更新超过 1Mb 的文件。

为此,我不得不使用 GitHub 的 GraphQL API。为了检索我有兴趣阅读/更新的特定文件的 SHA1,我要求这样做。

由于从未使用过 Git API 或 GraphQL,我选择使用 GraphQL 客户端(GraphQL.Client 和 GraphQL.Client.Serializer.Newtonsoft)。

使用 GraphQL,我能够在我的 GitHub 存储库中检索现有文件/blob 的 SHA-1 id。一旦我有了 blob 的 SHA-1,我就可以通过 GIT Data API 轻松地拉下有问题的文件。

然后我能够更改内容并通过 Octokit.Net 将更改推送回 GitHub。

虽然这并没有以任何方式完善,但我想为其他尝试这样做的人提供一些东西来结束它。

归功于以下stackover flow 线程

public async Task<string> GetSha1(string owner, string personalToken, string repositoryName,  string pathName, string branch = "master")
        {
            string basicValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{owner}:{personalToken}"));

            var graphQLClient = new GraphQLHttpClient("https://api.github.com/graphql", new NewtonsoftJsonSerializer());
            graphQLClient.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basicValue);

            var getShaRequest = new GraphQLRequest
            {
                Query = @"
                    query {
                      repository(owner: """+owner+@""", name: """+ repositoryName +@""") {
                        object(expression: """ + branch + @":" + pathName +@""") {
                                            ... on Blob {
                                            oid
                                        }
                                    }
                                }
                            }",
                    
                    Variables = new
                    {
                    }
            };

            var graphQLResponse = await graphQLClient.SendQueryAsync<ResponseType>(getShaRequest, cancellationToken: CancellationToken.None);
            return graphQLResponse.Data.Repository.Object.Oid;
        }

这是我的助手类

public class ContentResponseType
        {
            public string content { get; set; }
            public string encoding { get; set; }
            public string url { get; set; }
            public string sha { get; set; }
            public long size { get; set; }
        }

        public class DataObject
        {
            public string Oid;
        }

        public class Repository
        {
            public DataObject Object;
        }

        public class ResponseType
        {
            public Repository Repository { get; set; }
        }

这是通过上述方法提供的使用 SHA-1 检索内容的文件。

 public async Task<ContentResponseType> RetrieveFileAsync(string owner, string personalToken, string repositoryName, string pathName, string branch = "master")
        {
            var sha1 = await this.GetSha1(owner: owner, personalToken: personalToken, repositoryName: repositoryName, pathName: pathName, branch: branch);
            var url = this.GetBlobUrl(owner, repositoryName, sha1);
            var req = this.BuildRequestMessage(url, personalToken);
            using (var httpClient = new HttpClient())
            {
                var resp = await httpClient.SendAsync(req);
                if (resp.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    throw new Exception($"error happens when downloading the {req.RequestUri}, statusCode={resp.StatusCode}");
                }
                using (var ms = new MemoryStream())
                {
                    await resp.Content.CopyToAsync(ms);
                    ms.Seek(0, SeekOrigin.Begin);
                    StreamReader reader = new StreamReader(ms);
                    var jsonString =  reader.ReadToEnd();
                    return System.Text.Json.JsonSerializer.Deserialize<ContentResponseType>(jsonString);
                }
            }
        }

这是我的控制台测试应用程序...

    static async Task Main(string[] args)
    {

        // GitHub variables
        var owner = "{Put Owner Name here}";
        var personalGitHubToken = "{Put your Token here}";
        var repo = "{Put Repo Name Here}";
        var branch = "master";
        var referencePath = "{Put path and filename here}";

        // Get the existing Domain Model file
        var api = new GitHubRepoApi();
        var response = await api.RetrieveFileAsync(owner:owner, personalToken: personalGitHubToken, repositoryName: repo, pathName: referencePath, branch:branch);
        var currentFileText = Encoding.UTF8.GetString(Convert.FromBase64String(response.content));

        // Change the description of the JSON Domain Model
        currentFileText = currentFileText.Replace(@"""description"":""SubDomain", @"""description"":""Domain");
        
        // Update the changes back to GitHub repo using Octokit
        var client = new GitHubClient(new Octokit.ProductHeaderValue(repo));
        var tokenAuth = new Credentials(personalGitHubToken);
        client.Credentials = tokenAuth;
        
        // Read back the changes to confirm all works
        var updateChangeSet = await client.Repository.Content.UpdateFile(owner, repo, referencePath,
                                    new UpdateFileRequest("Domain Model was updated via automation", currentFileText, response.sha, branch));
         
        response = await api.RetrieveFileAsync(owner: owner, personalToken: personalGitHubToken, repositoryName: repo, pathName: referencePath, branch: branch);
        currentFileText = Encoding.UTF8.GetString(Convert.FromBase64String(response.content));
    }

我确信还有很多其他方法可以实现这一点,但这对我有用,我希望这有助于让别人的生活更轻松一些。

干杯约翰

于 2020-11-09T20:41:15.963 回答