octokit.net icon indicating copy to clipboard operation
octokit.net copied to clipboard

Calculate Sha locally without Client.Git.Blob.Create()

Open krulci opened this issue 2 years ago • 11 comments

I am currently looping my local directory to compare with remote repository. What I do not get is that everytime creating a NewBlob, Sha is generated through the Create methods (which uses Rates). Is it possible to calculate Sha locally?

krulci avatar Jul 18 '22 11:07 krulci

Hi there! Can you tell me a bit more about what you’re trying to achieve?

timrogers avatar Jul 18 '22 11:07 timrogers

public class GitCommit
    {
        public void CommitToRepo(string ProductRoot, string DataRoot)
        {
            var Client = new GitHubClient(new Octokit.ProductHeaderValue("my-cool-app"));
            var Owner = "krulci";
            var RepositoryName = "dmm_gameplayer_filelist_diff";
            Client.Credentials = new Credentials(File.ReadAllText("Data\\Personal_Access_Token.txt"));
            try
            {
                // 1. Get the SHA of the latest commit of the master branch.
                var headMasterRef = "heads/main";
                var masterReference = Client.Git.Reference.Get(Owner, RepositoryName, headMasterRef).Result; // Get reference of master branch
                var latestCommit = Client.Git.Commit.Get(Owner, RepositoryName, masterReference.Object.Sha).Result; // Get the laster commit of this branch
                var currentTree = Client.Git.Tree.GetRecursive(Owner, RepositoryName, latestCommit.Tree.Sha).Result; // Get the tree of the latest commit

                System.IO.DirectoryInfo ProductsRoot = new System.IO.DirectoryInfo(ProductRoot);
                foreach (string subdirectory in Directory.GetDirectories(ProductRoot))
                {
                    Console.WriteLine(subdirectory);
                    Models.GameLists.Products Json = JsonSerializer.Deserialize<Models.GameLists.Products>(File.ReadAllText(DataRoot + $"ProductDictionary.json"));
                    foreach (string files in Directory.GetFiles(subdirectory))
                    {
                        try
                        {
                            var nt = new NewTree { BaseTree = latestCommit.Tree.Sha };
                            Console.WriteLine(files);
                            Json.ProductName.TryGetValue(subdirectory.Replace($"Products\\", ""), out var productName);
                            productName.TryGetValue(files.Remove(files.Length - 5).Replace(subdirectory + "\\", ""), out var fileList);
                            // 2. Create the blob(s) corresponding to your file(s)
                            var textBlob = new NewBlob { Encoding = EncodingType.Utf8, Content = File.ReadAllText(files) };
                            var textBlobRef = Client.Git.Blob.Create(Owner, RepositoryName, textBlob);
                            // 3. Create a new tree with:
                            var newTreeItem = new NewTreeItem { Path = files.Replace("\\", "/"), Mode = "100644", Type = TreeType.Blob, Sha = textBlobRef.Result.Sha };
                            // 4. Add if currentTree does not contain the NewTreeItem
                            if (!currentTree.Tree.Any(x => x.Sha == newTreeItem.Sha && x.Path == newTreeItem.Path))
                            {
                                nt.Tree.Add(newTreeItem);
                                var newTree = Client.Git.Tree.Create(Owner, RepositoryName, nt).Result;
                                var newCommit = new NewCommit(subdirectory.Replace($"Products\\", "") + "::" + files.Remove(files.Length - 5).Replace(subdirectory + "\\", "") + "::" + fileList.Replace(Json.URI, ""), newTree.Sha, masterReference.Object.Sha);
                                var commit = Client.Git.Commit.Create(Owner, RepositoryName, newCommit).Result;
                                var update = Client.Git.Reference.Update(Owner, RepositoryName, headMasterRef, new ReferenceUpdate(commit.Sha)).Result;
                                masterReference = update;
                                latestCommit = commit;
                                currentTree = newTree;
                            }
                        }
                        catch (AggregateException e)
                        {
                            AggregateExceptionHandler(e);
                        }
                    }
                }
            }
            catch (AggregateException e)
            {
                AggregateExceptionHandler(e);
            }
        }

        public void AggregateExceptionHandler (AggregateException e)
        {
            Console.WriteLine($"An exception is detected in the commit step. {e.Message}");
            if (e.InnerException.Message == "You have exceeded a secondary rate limit. Please wait a few minutes before you try again.")
            {
                Console.WriteLine($"Sleep {1000 * 60} milliseconds");
                Thread.Sleep(1000 * 60);
            }
            else if (e.InnerException.Message.Contains("API rate limit exceeded for user ID"))
            {
                Console.WriteLine($"Sleep {1000 * 60 * 30} milliseconds");
                Thread.Sleep(1000 * 60 * 30);
            }
        }
    }
    ```
I am committing to my repo.
What happen is that everytime I create a NewBlob to compare the Sha of local file with Remote file, the Create method uses the rate.

krulci avatar Jul 18 '22 11:07 krulci

Can you tell me a bit more about why you are trying to do that comparison? I’d like to understand your goal so I might be able to suggest a different approach.

timrogers avatar Jul 18 '22 11:07 timrogers

The project's ultimate goal is to commit these files separately so that each files has specific comment. Due to this reason, I chose to commit each file separately instead of commit as a single tree.

krulci avatar Jul 18 '22 11:07 krulci

If you're creating commits using the GitHub REST API, then you will need to make an API call for each commit. An alternative approach would be to use Git locally to build the commits and push them.

timrogers avatar Jul 18 '22 12:07 timrogers

I was looking for this feature earlier. The only thinging I was able to figure was that update method. I don't see something that could push multiple commits with octokit

krulci avatar Jul 18 '22 12:07 krulci

If you wanted to do that, then you would just stop using Octokit and instead you'd use a Git library or the Git binary on your machine.

timrogers avatar Jul 18 '22 12:07 timrogers

I use Octokit because I needed a solution to programatically do commit since this project's is also a scheduled crawler which I do plan on converting to a background app in the future.

krulci avatar Jul 18 '22 12:07 krulci

You can still do it programatically with a Git SDK, for example https://github.com/libgit2/libgit2sharp.

timrogers avatar Jul 18 '22 12:07 timrogers

Thanks for your suggestion I was able to get commit and push. I understand this might be better to post as an issue in libgit2sharp. However, does this library you suggested allow Parralel.ForEach loop when staging files?

krulci avatar Jul 19 '22 09:07 krulci

I don't know I'm afraid - sorry!

timrogers avatar Jul 19 '22 11:07 timrogers

Response given

JonruAlveus avatar Aug 21 '22 16:08 JonruAlveus