【问题标题】:How to retrieve and update a file > 1MB from/to master GitHub using Octokit.Net Git Data API within c#如何在 c# 中使用 Octokit.Net Git Data API 从/向主 GitHub 检索和更新大于 1MB 的文件
【发布时间】:2020-11-08 17:14:04
【问题描述】:

我正在尝试使用 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 来读取这个大文件的内容,以及如何将这个文件上的更改更新回同一个存储库?

【问题讨论】:

    标签: c# .net-core octokit github-api-v3


    【解决方案1】:

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

    我试图读取/更新的文件是 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 thread

    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));
        }
    

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

    干杯 约翰

    【讨论】:

      猜你喜欢
      • 2019-08-28
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2014-03-04
      • 1970-01-01
      • 1970-01-01
      • 2020-10-23
      • 2012-04-02
      相关资源
      最近更新 更多