DEV Community

Cover image for Building jargons.dev [#5]: The Fork Script
Olabode Lawal-Shittabey
Olabode Lawal-Shittabey

Posted on • Edited on

Building jargons.dev [#5]: The Fork Script

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..

  1. Fork Project Repo
  2. Create a Branch
  3. Commit Changes to the Branch (add new mdx file in src/pages/word/ directory for new word or edit existing ones, in our case)
  4. 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

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 the isRepositoryForkUpdated 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 forkRepositoryfunction 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.

Changes Made

  • Implemented the main forkRepository function within script; this function is the main exported function that performs the main fork operation; it accepts a userOctokit (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 the fork of null
      • 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 the updatedSHA and a boolean isUpdated 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 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 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 the userOctokit instance. (This starts the fork process, we do not know exactly when the process completes 🤔)
  • 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 resolve repoOwner and repoName from a repository fullname.

Related Issue

Resolves #2

Screencast/Screenshot

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 a response.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.

Changes Made

  • Returned fork repo - this is a repo fullname value returned from the isRepositoryForked helper function; I hereby return it as main returned value from the forkRepository 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 the forkRepository 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

📖

Top comments (0)