DEV Community

Cover image for How I built a small ReactJS app to automatically invite collaborators to a private GitHub repo 👌
Alex Gurr
Alex Gurr

Posted on

How I built a small ReactJS app to automatically invite collaborators to a private GitHub repo 👌

I currently maintain a GitHub repo called react-coding-challenges. It involves a variety of different difficulty challenges people can check out and complete. I also have a separate, private repository for the solutions to these challenges. The solutions are invite-only, meaning I need to invite each person as a collaborator before they get access (see the why here).

This was fine at the start, with a small amount of people requesting access. Now however, I have a steady stream of requests (usually via email which goes in to my spam folder) and it's becoming increasingly difficult/time consuming to manually do this process.

So what did I do? I built a MERN application that can automate this entire process with no-touch. Check it out at solutions.alexgurr.com.

How Does It Work?

Client

The user clicks the main CTA button cta

This uses a great library called react-github-login.

  import GitHubLogin from 'react-github-login';

  <GitHubLogin
    clientId="CLIENT_ID"
    onSuccess={joinRepo}
    onFailure={onFailure}

    // We only need the read:user scope to determine who the user is
    scope="read:user"

    // This is irrelevant because the auth window gets closed
    redirectUri=""

    // Use animate.css to give the button a pulse effect
    className={`button animate__animated animate__pulse animate__infinite animate__slow ${loading ? 'is-loading' : ''}`}
  >
    <div>
      <span className="icon">
        <i className="fab fa-github"></i>
      </span>
      <span>Let Me In</span>
    </div>
  </GitHubLogin>
Enter fullscreen mode Exit fullscreen mode

 

The library starts the GitHub OAuth login process and calls our callback with an oAuth code

  const joinRepo = async ({ code }) => {
    try {
      // The code gets sent to the server
      await axios.post(config.serverUrl, { code });

      setJoined(true);
    } catch(e) {
      // if it's a 409, the user is already in the repository
      if (e.response && e.response.status && e.response.status === 409) {
        setAlreadyIn(true);

        return void setJoined(true);
      }

      toast("Oops, something went wrong.", { type: 'error', position: "bottom-left", hideProgressBar: true })
    }
  }
Enter fullscreen mode Exit fullscreen mode

success

 

Server

Generate an access token for the user, using a client secret/id & the client code

  const { data } = await axios.post('https://github.com/login/oauth/access_token', {
    client_id: 'ID',
    client_secret: 'SECRET',
    code: code
  });
Enter fullscreen mode Exit fullscreen mode

 

Retrieve the user's information using the generated access token

  const { data: user } = await axios.get('https://api.github.com/user', {
    headers: { Authorization: `token ${data.split('&')[0].split('=')[1]}` }
  });
Enter fullscreen mode Exit fullscreen mode

 

Check if the user's a collaborator already

We use the @octokit/rest library for the more complex GitHub API actions, which is a node GitHub SDK

  await octokit.repos.checkCollaborator({
    owner: GITHUB_UN,
    repo: 'react-coding-solutions',
    username
  });
Enter fullscreen mode Exit fullscreen mode

If they are already a collaborator, we return at this point and return a response with 409 status code.

 

Invite the user as a collaborator and return a success (201) response

  await octokit.repos.addCollaborator({
    owner: GITHUB_UN,
    repo: 'react-coding-solutions',
    username
  });
Enter fullscreen mode Exit fullscreen mode

 

Store the user record in our database

We use mongodb and mongoose as our user record store. This record write is non-blocking and we don't wait for it to finish before returning a response.

  User.create({ username });
Enter fullscreen mode Exit fullscreen mode

 
 
Overall, this was quite an easy app to build. I hope this gives some insight into how you could invite users to GitHub repos, or provide some inspiration to go and automate things!

Discussion (0)