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 で、このファイルを (SevenZip を使用して) 512K まで圧縮できたので、レポで読み取り/更新できるようになりましたが、1Mb を超えるファイルを読み取り/更新したかったのです。

これを実現するには、GitHub の GraphQL API を使用する必要がありました。読み取り/更新に関心のある特定のファイルの SHA1 を取得するために必要でした。

Git API や GraphQL を使ったことがないので、GraphQL クライアント (GraphQL.Client と GraphQL.Client.Serializer.Newtonsoft) を利用することにしました。

GraphQL を使用すると、GitHub リポジトリにある既存のファイル/ブロブの SHA-1 ID を取得できました。BLOB の SHA-1 を取得したら、GIT Data API を介して問題のファイルを簡単に取得できました。

その後、コンテンツを変更し、変更を Octokit.Net 経由で GitHub にプッシュすることができました。

これは決して洗練されたものではありませんが、これをやろうとしている他の人のために何かでこれを締めくくりたいと思いました.

次のスタックオーバー フロー スレッドの功績によるものです。

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 に答える