Building jargons.dev [#5]: The Fork Script
Olabode Lawal-Shittabey
Posted on September 9, 2024
This is the first of 4 scripts I set out to write as stated in the system architecture. Felt pumped! it was a step in the direction of creating the "wiki" experience that gets a contribution to Open source without interfacing with the GitHub UI 😁.
What are these scripts?
These are js
files that holds some related helper functions particularly meant to be used to interact with the GitHub APIs; they are either consumed within the same script or exported to be used to perform their base functionality elsewhere within the project. They accept an authenticated Octokit instance of a user as params out of others, this instance is used to perform actions/functions through the GitHub APIs on behalf of the authenticated user.
The need to create a flow of contributing to Open source without interfacing with the GitHub UI meant that we had to automate some process - simulating every steps a user will take if they were to contribute via the GitHub UI, the steps are as follows..
- Fork Project Repo
- Create a Branch
- Commit Changes to the Branch (add new mdx file in
src/pages/word/
directory for new word or edit existing ones, in our case) - Create a Pull Request (Submit the word changes, in our case)
A Truth worth stating
I started writing this script right after the initial commit, this was infact the PR #2, but it took a hit during the long month break 🫣 i took from the project before getting back to work on the base dictionary feature.
The Script
The task here was to create "The Fork Script" — whose end goal is to create/get a fork of the jargons.dev repo on/from a user's account. It should house every function that'll do the following.
- Check whether a Fork of jargons.dev already exists on a user's account
- If Fork Exists
- Check if the Fork is in-Sync with upstream (i.e. up-to-date with jargons.dev repo main branch); IF NOT — Update the fork
- If NO Fork is found
- Create the Fork
- If Fork Exists
Understanding the assignment, I "delved" straight into working on the script.
I already I'm very used to the GitHub APIs due to my frequent consumption in my everyday work on Hearts ❤️... So I had the GitHub's Fork Documentation looking like a broski to me 😌...
The Steps
- I created a main
forkRepository
function which was the main entry point to executing the fork functionality - it leads everywhere else - I added the following functions, which mostly served as helper to the obvious main
forkRepository
function-
isRepositoryForked
- this function checks whether the jargons.dev repository is already forked to the current authencated user's account -
isRepositoryForkUpdated
- to check whether the fork (if found) is (in Sync with head repo) up-to-date with main jargons.dev repo -
updateRepositoryFork
- used to update (Sync) repository to state of main (head) jargons.dev repository -
getBranch
- is a base utility (required at the point of writing this script) used to fetch Branch/Ref details for the jargons.dev repo and user's fork to use in the comparison that is done in theisRepositoryForkUpdated
helper to perform its primary function; it uses the the GitHub References endpoint.
-
My weird assumption
Running through my mind 🤔 as I wrote this script was a thought that I held onto after reading the below quoted paragraph on the GitHub Fork Documentation
Note: Forking a Repository happens asynchronously. You may have to wait a short period of time before you can access the git objects. If this takes longer than 5 minutes, be sure to contact GitHub Support.
I misunderstood this and assumed that we were only going to be able to initiate a fork process, move on and surely not gonna be able to wait for a response object that returns the details of the new fork because we don't know when the fork process completes.
This assumption forced me to not return any data from the main forkRepository
function and I was already starting to think at this point - how am I gonna get the fork details to process to the next phase of the contribution process!? Hmm, maybe I'll use webhooks 🤔!?
It turned out I was overthinking it 😂, I realised later that I will infact get a response details for the fork and this led me to do a follow up PR to address returning the data required from the fork response object for consumption in the contribution process.
The PR
Main:
feat: implement `fork` repository script #3
This Pull Request implements the fork
script; this script is intended to be used to programmatically fork the main project repo to a user account; It houses a main function and other helper functions it uses to perform some necessary actions in order to ensure an efficient repo fork operation.
- Implemented the main
forkRepository
function within script; this function is the main exported function that performs the main fork operation; it accepts auserOctokit
(a user authenticated object with permission to act on behalf of the user) instance and the project's repository details i.e.repoDetails
object and it does the following...- It checks whether the project repository has already been forked to the user's account using the
isRepositoryForked
helper function; this returns thefork
ofnull
- If the repo has already been forked, then we perform a check whether the fork is up-to-date/in sync with main project repo using the
isRepositoryForkUpdated
helper function; this returns theupdatedSHA
and a booleanisUpdated
property that confirm whether fork is up-to-date- If fork is not up-to-date; then we perform the update by bringing it in sync with the main project repo using the
updateRepositoryFork
helper function
- If fork is not up-to-date; then we perform the update by bringing it in sync with the main project repo using the
- If repo is up-to-date/in sync with main project repo; we cancel out of the operation at this point with an early return;
- If the repo has already been forked, then we perform a check whether the fork is up-to-date/in sync with main project repo using the
- If the project repository is not forked onto the user's account; then we proceed to initiating a fork process by calling the
"POST /repos/{owner}/{repo}/forks"
endpoint using theuserOctokit
instance. (This starts the fork process, we do not know exactly when the process completes 🤔)
- It checks whether the project repository has already been forked to the user's account using the
- Implement the following helper functions consumed within the main
forkRepository
function and within other helper functions too-
updateRepositoryFork
- used to update (Sync) repository to state of main (head) repository -
isRepositoryForkUpdated
- used to check whether a fork is (in Sync with head repo) up-to-date with main repo -
getBranch
- used to fetch a Branch/Ref details -
isRepositoryForked
- used to check for the presence of a specific repo in a user's fork repo list
-
- Added
getRepoParts
to/lib/utils
; its a utility function that is used to resolverepoOwner
andrepoName
from a repository fullname.
Resolves #2
https://github.com/babblebey/jargons.dev/assets/25631971/16221b7e-3c28-4c6c-a1f3-24d583ce7e3a
📖
Follow-up:
feat: return repo `fullname` in fork script #29
This PR is a follow-up to a missing step in the fork
script initial implementation at #3; the fork script failed to return a repo
which can be used to in the next step of computation. This was because of a weird assumption I had during the initial implementation. 😆See my assumption below...
I assume that the call to the
"POST /repos/{owner}/{repo}/forks"
endpoint only assures of initiating a fork process without assuring us of a response at all. Meaning we might not exactly get aresponse.data
following the call
...but that wasn't true, I found out that a response.data
actually comes, but it might just take some time and only in cases where the repo being forked is huge.... and at the moment forking the project repo happens in less than 5secs.
- Returned
fork
repo - this is a repo fullname value returned from theisRepositoryForked
helper function; I hereby return it as main returned value from theforkRepository
function execution in the condition where the repo is already forked on a executing user's account - Returned
response.data.full_name
- this is a newly created fork repo fullname; Its a value from the response to the"POST /repos/{owner}/{repo}/forks"
endpoint call; I hereby return it as main retuned value from theforkRepository
function execution in cases where there was no fork already already found on the executing user's account - Cherry picked some changes from #25 to use on here
- f12f25f548a5c5836e9be7d601ed226c5269f5ee
- 436ceea649b67812c0ec1164fde95d443ce556e0
📖
Posted on September 9, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.