GitHub

inviteCollaboratorsToRepos

Code

const axios = require('axios');
const runCollaboratorRequests = require('./collaborators');

/*
    @param org = String
    @param repos = Array
    @param collaborators = Array
    @param token = String
*/
async function inviteCollaboratorsToRepos(org, repos, collaborators, token) {
    return runCollaboratorRequests(org, repos, collaborators, token,
        (url, headers) => axios.put(url, {}, { headers }));
}

module.exports = inviteCollaboratorsToRepos;

The endpoint guard, the iteration over repositories and collaborators, and the per collaborator result shape are shared with removeCollaboratorsFromRepos in src/github/collaborators.js. That file is internal machinery and is not part of the published surface, so it is not importable on its own:

const path = require('path');
const { readPropertiesFile, requireHttpsUrl, resolveSecureUrl } = require('../essential');

/*
    @param org = String
    @param repos = Array
    @param collaborators = Array
    @param token = String
    @param send = Function, sends one request given the resolved URL and the headers
*/
async function runCollaboratorRequests(org, repos, collaborators, token, send) {
    const filePath = path.join(__dirname, 'properties', 'api.properties');
    const config = readPropertiesFile(filePath);

    if (!config.repocollaboratorurl) {
        throw new Error("Collaborator URL is missing in the configuration.");
    }

    requireHttpsUrl(config.repocollaboratorurl, 'repocollaboratorurl');

    const headers = {
        Authorization: `Bearer ${token}`,
        Accept: 'application/vnd.github.v3+json',
    };

    const results = await Promise.all(repos.map(async (repo, i) => {
        const repoResults = [];

        for (let j = 0; j < collaborators[i].length; j++) {
            const collaborator = collaborators[i][j];
            const replacements = { organization: org, repository: repo, collaborator };

            try {
                await send(resolveSecureUrl(config.repocollaboratorurl, replacements, 'repocollaboratorurl'), headers);

                repoResults.push({ collaborator, success: true });
            } catch (error) {
                repoResults.push({ collaborator, success: false, error: error.message });
            }
        }

        return { repo, results: repoResults };
    }));

    return results;
}

module.exports = runCollaboratorRequests;

Usage

/*
    @param org = String
    @param repos = Array
    @param collaborators = Array
    @param token = String
*/
const { inviteCollaboratorsToRepos } = require('jwz/github');

const org = 'your-org-name';
const repos = ['your-repoA', 'your-repoB'];
const collaborators = [['collaboratorA1', 'collaboratorA2'], ['collaboratorB1']];
const token = 'your-token';

const res = await inviteCollaboratorsToRepos(org, repos, collaborators, token);
console.log(res);

Explanation

The inviteCollaboratorsToRepos function invites collaborators to specific GitHub repositories within an organization. It reads configuration details from an external properties file and uses Axios for API requests. Here's a breakdown:

  • Parameters:
    • org: The name of the GitHub organization.
    • repos: An array of repository names where collaborators will be invited.
    • collaborators: A nested array of collaborators to invite for each repository. Each sub-array corresponds to a repository in the repos array.
    • token: A GitHub personal access token for authentication.
  • Logic:
    • Reads the collaborator API URL from a properties file.
    • Checks the endpoint uses https, and throws before the token is sent if it does not.
    • Iterates over repositories and their respective collaborators.
    • Uses the GitHub API to send invitations to collaborators.
    • Records a failed request against the collaborator it happened to, and continues with the rest.
  • Output:
    • An array of results, where each result contains:
      • repo: The repository name.
      • results: An array of objects with each collaborator's success status and error details (if any).