logo elektroda
logo elektroda
X
logo elektroda

How to programmatically access Github pull requests, commits and download artifacts?

p.kaczmarek2  23 2205 Cool? (+4)
📢 Listen (AI):

TL;DR

  • A C# utility accesses GitHub pull requests, commits, workflow runs, and build artifacts to automate firmware downloads for OpenBeken and similar WiFi MCU projects.
  • It uses Octokit for repository data, HttpClient for GitHub API calls, and JsonSerializer to parse workflows and artifacts into C# classes.
  • The example queries commit d763b28c9a433217f3c95ef4c9bbd6777a32486d and workflow run 12305496423 via GitHub API endpoints.
  • After iterating artifact links, the utility downloads ZIP build files to disk for later OTA processing.
  • Unauthenticated requests can hit GitHub's API rate limit, while authenticated tokens get a higher limit.
Generated by the language model.
List of completed checks in GitHub Actions
GitHub Actions workflows can be used to automatically build and test firmware on each commit. They may or may not create Github Releases, if not, build files are downloadable only via Github Action details. By default, those binaries require manual download, but here I will show you how to automate it.

The goal of the project is to create an auto-updater for WiFi MCU firmware, like for BK7231, W800/W600, or anything else supported by OpenBeken.

The basic presentation of Github Actions Binaries used in
OpenBeken was shown here, today I am going to create small C# utility to automate that. Let's start.

Used tools
For this presentation, I will use following tools:
- Visual Studio as a C# IDE and compiler
- Octokit library from NuGet for easier Github API access
- in some later parts, I will also use HTTPClient to directly access Github API, as I had some issues with Octokit. Responses will be parsed via JSONSerializer

Octokit library
First you'll need the Octokit library. Octokit provides easy access to Github API and can be downloaded within Visual Studio via "Manage NuGet Packages":
NuGet Package Manager screen in Visual Studio with the Octokit library installed.
Add it to your stock Console program and make sure you have correct usings:
Code: C#
Log in, to see the code


Initializing GitHubClient
Octokit library is using asynchronous tasks to run, so if your main function is not a task, you'll need to await for the result. Here's basic GitHubClient initialization:
Code: C#
Log in, to see the code



Github Access Token
This is not required for listing pull requests, but needed for artifacts. You will also obviously need it for the write access. Login to Github and go to Settings:
Screenshot of the user menu on the GitHub page.
then to Developer settings:
Screenshot of GitHub settings menu.
and then to Tokens. I have used "Classic" mode:
Screenshot of GitHub personal access token settings
Create a token, make sure to write it down. Choose the token scopes depending on what you are going to use to the token for. Don't give full write access to token if you don't want to use it to write to repository and use separate token for reach purpose you have.
Finally, add the authentication code to your sample:
Code: C#
Log in, to see the code



Enumerating pull requests
Now it's time to get this list:
https://github.com/openshwprojects/OpenBK7231T_App/pulls
This can be done with PullRequest object:
Code: C#
Log in, to see the code

Result:
List of pull requests in console


Enumerating commit
Once you have Pull Request, you can get the latest commit. All commits can be listed in similiar way:
Code: C#
Log in, to see the code

Result:
Screenshot of a console application showing a list of GitHub pull requests.



Accessing workflows
For workflows, you'll need a separate function that will get JSON information from Github.
The URL we want to access is the following:
https://api.github.com/repos/openshwprojects/OpenBK7231T_App/commits/d763b28c9a433217f3c95ef4c9bbd6777a32486d/check-runs
The commit Hash to be inserted there.
Returned JSON is very simple:
Code: JSON
Log in, to see the code

It's basically a JSON representation of each build here:
GitHub pull request list with highlighted test results.
We're very close!
So, let's prepare the HttpClient and do GET request.
Code: C#
Log in, to see the code

Then, let's put resulting JSON data into the classes with JsonSerializer:
Code: C#
Log in, to see the code


Iterating the runs
Once you have a list of workflows, you can iterate it:
Code: C / C++
Log in, to see the code

Result:
Screenshot of build results and statuses in a program console.


Fetching artifacts
Now we need to get links to zip files. We will need to extract a numerical ID for that. The ID can be found in workflow run data:
Code: C#
Log in, to see the code

Here is a sample run ID: 12328623947
You can now construct link like:
https://api.github.com/repos/openshwprojects/OpenBK7231T_App/actions/runs/12305496423/artifacts
Visiting this link yields following JSON:
Code: JSON
Log in, to see the code

It's time to parse it. Here is function call:
Code: C#
Log in, to see the code

And the implementation:
Code: C#
Log in, to see the code

Again, the JSON data is deserialized into classes with JsonSerializer. Used classes:
Code: C#
Log in, to see the code

Finally it's time to iterate them:
Code: C#
Log in, to see the code

Result:
Screenshot showing console output with a link to GitHub Actions artifacts.

Downloading ZIP files
Now we finally have ZIP file links, there's not much left to do:
Code: C#
Log in, to see the code

Download handler:
Code: C#
Log in, to see the code

Finally, after a few moments of downloading, we're getting OBK build files on our drive:
Files of various types in the ConsoleApp8 application folder.
Now it's time to futher process them, maybe send them to devices via OTA, but it's a task for another topic.


Warning!
Without authentication, you can easily hit API rate limit:

Error: API rate limit exceeded for 123.234.233.121. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)
Press any key to exit...


Summary
This was the first part of Github Artifacts downloading presentation. In this part we've learned how to access Github API to list pull requests, commits, workflows and artifacts. We've also managed to download built files.
In the next part I will present the tool that I based on the knowledge shown here:
Screenshot of Form1 application showing interface for updating OpenBK7231T via GitHub
This tool will be able to automatically keep OBK device updated to the latest build from given PR, thus making testing and development easier.
Stay tuned!
What would YOU have used Github API for?


Full demo code is in the description:
Attachments:
  • gitAPIdemo.zip (1.9 KB) You must be logged in to download this attachment.

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14400 posts with rating 12330 , helped 650 times. Been with us since 2014 year.

Comments

p.kaczmarek2 16 Dec 2024 22:01

Repository with a very early and dirty draft of mentioned tool: https://github.com/openshwprojects/OBKotaTool My private TODO for upcoming days: - add field for Github key and store settings in JSON -... [Read more]

DeDaMrAz 16 Dec 2024 22:03

It does start. https://obrazki.elektroda.pl/2186961800_1734383027_thumb.jpg [Read more]

p.kaczmarek2 16 Dec 2024 22:06

Now you need a Github API key, a PR link, and device IP. btw: Shall I do the same for https://github.com/openshwprojects/BK7231GUIFlashTool ? [Read more]

DeDaMrAz 16 Dec 2024 22:12

Test successful! https://obrazki.elektroda.pl/6735248300_1734383534_thumb.jpg https://obrazki.elektroda.pl/8129852400_1734383542_thumb.jpg https://obrazki.elektroda.pl/7681850... [Read more]

divadiow 16 Dec 2024 22:39

cool https://obrazki.elektroda.pl/7010300000_1734385182_thumb.jpg [Read more]

DeDaMrAz 16 Dec 2024 22:42

This will help new chip implementation and testing and speed up the process but a large margin!! Now I can't wait for my new modules to arrive :D [Read more]

p.kaczmarek2 16 Dec 2024 22:47

I hope you guys realize that now, if you push a change to that pull request, the tool will automatically update your device. It queries Github PR in the background constantly, just to detect the change.... [Read more]

DeDaMrAz 16 Dec 2024 22:55

Suggestion, as you already have a mechanism to determine what chip type is on that IP, a log window would be nice where that info would be displayed. Such is current build, platform (maybe option for future... [Read more]

divadiow 16 Dec 2024 23:00

build, still running, already showing https://obrazki.elektroda.pl/9125516000_1734386421_thumb.jpg [Read more]

p.kaczmarek2 16 Dec 2024 23:03

I think I've handled this issue. If commit is available, but there are no artifacts yet, it shall retry every 5 seconds with a new message in log: https://obrazki.elektroda.pl/9784584900_173438658... [Read more]

p.kaczmarek2 20 Dec 2024 10:03

Another idea. What if we implement this tool in the Web App or like in a Web Page? So it's done online? A web utility that can be run anywhere, and can either update OBKs to given release, or to given... [Read more]

divadiow 20 Dec 2024 10:09

that sounds excellent [Read more]

insmod 20 Dec 2024 10:10

If it's web (html/js), then count me out. But, maybe use .net8 and avalonia, then it will be cross-platform too. And it may work in browser with wasm. [Read more]

max4elektroda 20 Dec 2024 10:36

My 2 cents: Web App - very good, Web Page - even better [Read more]

DeDaMrAz 20 Dec 2024 13:00

For me it really does not matter if it is web based or an win application. [Read more]

p.kaczmarek2 21 Dec 2024 21:57

I will try to make web version someday, but first I will focus on finishing C# one. @insmod you're doing great things with porting so focus on that for now if you can. We can do testing much faster... [Read more]

DeDaMrAz 22 Dec 2024 01:12

And it works like a charm... https://obrazki.elektroda.pl/5500997300_1734814706_thumb.jpg Added after 3 [hours] 13 [minutes]: Auto build PR for PROTA tool added. https://github.com/op... [Read more]

JimmyBob 27 Dec 2024 10:29

It helped me, Thank you so much. [Read more]

divadiow 03 Jan 2025 10:06

regarding the URL pattern matching https://obrazki.elektroda.pl/9288791700_1735895056_thumb.jpg Is there an API/technological reason an URL like this couldn't be used also to get artefacts... [Read more]

FAQ

TL;DR: In 3 API stages, "works like a charm," this C# workflow helps firmware developers list PRs, get the latest commit SHA, fetch GitHub Actions artifacts, and download ZIP builds for OTA testing. It also led to PROTA, which polls GitHub and can auto-update multiple devices from one PR. [#21357982]

Why it matters: This gives firmware testers a repeatable way to move from a pull request to a flashable build without manually opening GitHub Actions pages.

Approach Current thread status Best fit Limitation
Windows C# app Working and prioritized first Fastest path to a usable updater Windows-focused for now
Web app / web page Requested and viewed positively Run anywhere online Deferred until the C# version is finished
.NET 8 Avalonia with WASM Suggested by a participant Cross-platform, possible browser path Only a proposal in the thread

Key insight: The most important design choice is to treat the PR as the entry point, then resolve commit → check-runs → artifacts. If artifacts are not ready yet, retry instead of failing immediately. [#21351438]

Quick Facts

  • The sample commit check-runs response shows 18 check runs for one SHA, which is enough to map a single commit to multiple workflow outcomes. [#21348573]
  • The sample artifacts response shows 15 artifacts for one Actions run, each with an archive_download_url that points to a ZIP download. [#21348573]
  • PROTA was updated to retry every 5 seconds when a commit exists but artifacts are not published yet, reducing false failures during active CI builds. [#21351438]
  • The tool was reported as working with Beken and ESP32 targets, and later gained support for multiple IP addresses in one update flow. [#21350736]
  • A practical test setup mentioned using 3 devices in a chain so repeated PR flashes become easier during hardware bring-up and regression testing. [#21350736]

How do I programmatically list GitHub pull requests for openshwprojects/OpenBK7231T_App in C# using Octokit?

Use GitHubClient from Octokit, set owner = "openshwprojects" and repo = "OpenBK7231T_App", then call client.PullRequest.GetAllForRepository(owner, repo). Iterate the returned list and print pr.Number, pr.Title, pr.User.Login, and pr.State. The example wraps this inside RunAsync().GetAwaiter().GetResult() because Octokit uses async tasks. That gives you the same PR set shown on the repository Pull Requests page, but in C# code. [#21348573]

What is Octokit, and why would you use it instead of calling the GitHub API directly with HttpClient?

"Octokit" is a C# client library that accesses the GitHub API, its key characteristic is that it exposes GitHub objects such as pull requests and commits as typed async methods. Use it when you want fast PR and commit access with less boilerplate. The thread uses Octokit for listing pull requests and commits, but switches to HttpClient for workflows and artifacts because the author had issues with Octokit there. That mixed approach keeps simple tasks simple and still allows raw endpoint access when needed. [#21348573]

How can I get the latest commit SHA from a GitHub pull request before looking up workflow runs and artifacts?

Call client.PullRequest.Commits(owner, repo, pr.Number) and take the last item. The example uses var lastCommit = commits.LastOrDefault(); and then reads lastCommit.Sha. That SHA becomes the input for the next API call to /commits/{sha}/check-runs. If the PR has no commits, LastOrDefault() returns null, so check that before building workflow URLs. [#21348573]

What is a GitHub Actions artifact, and how is it different from a GitHub Release download?

"GitHub Actions artifact" is a build output package that a workflow stores for later download, its key characteristic is that it is tied to a specific workflow run rather than a formal repository release. In the thread, build files may exist only inside GitHub Actions details and may not appear as GitHub Releases. That is why the updater reads archive_download_url from the artifacts API and downloads ZIP files directly from the run. [#21348573]

How do I fetch GitHub check-runs or workflow information for a specific commit SHA from the GitHub API?

Send an authenticated GET request to /repos/{owner}/{repo}/commits/{sha}/check-runs with HttpClient. The example adds a Bearer token and a User-Agent header, then deserializes the JSON into CheckRunsResponse. In the sample response, one commit returned total_count: 18, and each check_run included name, status, html_url, and details_url. That data is enough to enumerate workflow activity for the commit. [#21348573]

Why do GitHub artifact requests need an access token even if listing pull requests can work without one?

Artifact access needs a token in this workflow because unauthenticated API use hits limits quickly, while authenticated requests get a higher limit. The thread explicitly says listing pull requests does not require a token, but artifacts do, and the sample code sets Credentials = new Credentials(GitHubToken) or sends a Bearer token with HttpClient. The token is also required if you want write access later, so the safer pattern is to create a scoped token and avoid broad permissions. [#21348573]

What causes the GitHub API rate limit exceeded error, and how do authenticated requests help when downloading artifacts?

The error happens when too many unauthenticated API requests come from one IP. The thread shows the exact failure text: API rate limit exceeded, followed by GitHub’s note that authenticated requests get a higher rate limit. Artifact download flows generate several calls per PR: pull request lookup, commit lookup, check-runs lookup, artifact lookup, and ZIP download. Adding a GitHub token raises the allowed request budget and makes repeated polling practical. [#21348573]

How can I extract the GitHub Actions run ID from a details_url like /actions/runs/... in C#?

Use a regular expression on details_url. The sample getSecondID() method matches runs/(\d+) and returns the first capture group. If details_url is https://github.com/.../actions/runs/12305496423/job/..., the method returns 12305496423. That run ID is then inserted into /actions/runs/{runId}/artifacts to fetch downloadable ZIP metadata. [#21348573]

What is the best way to deserialize GitHub check-runs and artifacts JSON into C# classes with System.Text.Json?

Create small DTO classes that match only the fields you need, then deserialize with JsonSerializer.Deserialize<T>(). The thread uses CheckRunsResponse with a [JsonPropertyName("check_runs")] property and a CheckRun class with fields like id, name, status, html_url, and details_url. For artifacts, it uses ArtifactResponse and Artifact with name and archive_download_url. This keeps the parser minimal even when the GitHub JSON is large. [#21348573]

How do I download artifact ZIP files from archive_download_url in C# and save them with the artifact name?

Use HttpClient, authenticate, stream the response, and write it to {artifactName}.zip. A simple 3-step flow works: 1. Read each artifact’s archive_download_url. 2. Call GetAsync(url) with the Bearer token and User-Agent. 3. Copy response.Content into a FileStream created with Path.Combine(Directory.GetCurrentDirectory(), $"{artifactName}.zip"). The example prints the saved path after each successful download. [#21348573]

Why would a tool like PROTA find a commit but no artifacts yet, and how should it retry until the build finishes?

A commit can appear before the GitHub Actions build has finished publishing artifacts. The thread describes exactly that edge case and says the tool should not stop there. Instead, it now retries every 5 seconds and adds a new log message until artifacts appear. That design matches real CI timing, where commit metadata is visible first and ZIP outputs arrive later. [#21351438]

How does PROTA detect the correct binary for each target device platform when flashing multiple IPs such as Beken and ESP32 devices?

It detects the chip type from the target device and uses that to choose the matching binary. The author’s TODO says the tool should send a Tasmota STATUS packet instead of relying on a chip-type combobox, and later reports, "managed to call STATUS." After that, support for multiple IPs was added, and the author says it should choose the correct binary for each target platform. The thread also states the tool was tested with Beken and ESP32. [#21351410]

PROTA currently expects a pull request URL, so how could support for direct GitHub Actions run links be added for bulk flashing or GA builds?

Support could be added by accepting /actions/runs/{id} URLs as a second input pattern and skipping the PR-to-commit step. The thread confirms the current tool is designed for PR links like /pull/<PR number>, but one participant asks whether direct Actions run links would be useful for bulk flashing and GA builds. That means the practical extension is URL pattern detection: PR URLs follow the existing path, while run URLs can go straight to artifacts lookup. [#21374917]

Web app vs Windows C# app vs .NET 8 Avalonia with WASM — which approach makes the most sense for a cross-platform OBKotaTool or PROTA updater?

The Windows C# app makes the most sense first, because it already works and the author chose to finish it before starting a web version. The thread shows strong interest in a web app or web page, while another participant suggested .NET 8 Avalonia with possible browser WASM support for cross-platform use. So the best roadmap in this discussion is: finish the current C# tool, then evaluate web delivery or Avalonia for portability. [#21357978]

How does the EF tab fit in with the PROTA tool, and why might it appear to do nothing?

The thread does not explain how the EF tab fits into PROTA, so its role remains unclear here. One participant asked on 2025-04-14 how that tab relates to the tool and said they could not get it to do anything, but no follow-up answer is included in the provided posts. If you are documenting the tool, treat the EF tab as unresolved until its purpose is described elsewhere. [#21518979]
Generated by the language model.
%}