Skip to content

Instantly share code, notes, and snippets.

@diofeher
Last active November 22, 2022 22:07
Show Gist options
  • Save diofeher/715de40aa61644b3d0ea6a41096f921d to your computer and use it in GitHub Desktop.
Save diofeher/715de40aa61644b3d0ea6a41096f921d to your computer and use it in GitHub Desktop.
Connecting a Google Form to create issues in a Github project

Connecting a Google Form to Github Projects

Create a Github App

Use the following doc: https://docs.github.com/en/developers/apps/building-github-apps/creating-a-github-app

  1. Needed Permissions
Issues - Read and Write
Projects - Read and Write

Install on the selected repo and get the installation token.

  1. Download the private key generated by the app

Application code

  1. Using github GraphQL API (https://docs.github.com/en/graphql/overview/explorer) get the project v2 ID:
query {
  organization(login: "<org-name>") {
    projectsV2(last: 100) {
      nodes {
        title
        id
      }
    }
  }
}

Code Application:

const createJwt = ({ privateKey, appId, data = {} }) => {
  // Sign token using HMAC with SHA-256 algorithm
  const header = {
    alg: 'RS256',
    typ: 'JWT',
  };

  const now = Date.now();
  const expires = new Date(now);
  expires.setMinutes(expires.getMinutes() + 1);

  // iat = issued time, exp = expiration time
  const payload = {
    exp: Math.round(expires.getTime() / 1000),
    iat: Math.round(now / 1000),
    iss: `${appId}`,
  };

  console.log(payload);
  // add user payload
  Object.keys(data).forEach(function (key) {
    payload[key] = data[key];
  });

  const base64Encode = (text, json = true) => {
    const data = json ? JSON.stringify(text) : text;
    return Utilities.base64EncodeWebSafe(data).replace(/=+$/, '');
  };

  const toSign = `${base64Encode(header)}.${base64Encode(payload)}`;
  const signatureBytes = Utilities.computeRsaSha256Signature(toSign, privateKey);
  const signature = base64Encode(signatureBytes, false);
  return `${toSign}.${signature}`;
};

function loadPrivateKey() {
  try {
    const properties = PropertiesService.getScriptProperties();
    const privateKey = String.fromCharCode(
      ...Utilities.base64Decode(
        properties.getProperty('GITHUB_PRIVATE_KEY')
      )
    );
    return privateKey;
  } catch (err) {
    Logger.log('Failed with error %s', err.message);
  }
}

function onFormSubmit(e) {
  const jwtData = createJwt({
    privateKey: loadPrivateKey(),
    appId: <app-id-from-github-app>
  });

  const email = e.values[1];

  var body = `# Details

Submitted by: ${email}`;

  const options = {
    "method": "POST",
    "headers": {
      "Authorization": `Bearer ${jwtData}`,
      "Accept": "application/vnd.github+json" 
    },
  };
  const response = UrlFetchApp.fetch("https://api.github.com/app/installations/<access-token-installation-n>/access_tokens", options);
  console.log('got access token', response.toString());
  
  const responseJSON = JSON.parse(response.getContentText());
  const optionsIssues = {
    method: "POST",
    headers: {
      Authorization: `Bearer ${responseJSON.token}`,
      Accept: "application/vnd.github+json" 
    },
    payload: JSON.stringify({
      title,
      body,
      labels: [
           title
       ]
    })
  };
  console.log(optionsIssues);
  const response2 = UrlFetchApp.fetch("https://api.github.com/repos/<org-name>/<repo-name>/issues", optionsIssues);
  const response2JSON = JSON.parse(response2.getContentText());
  const issueId = response2JSON.node_id;
  console.log('created issue', response2JSON);

  const projectQuery = `mutation {
    addProjectV2ItemById(input: {projectId: "<node-id-from-step-1>" contentId: "${issueId}"}) {
      item {
        id
      }
    }
  }`;
  const projectBody = {
    method: "POST",
    headers: {
      Authorization: `Bearer ${responseJSON.token}`,
      Accept: "application/vnd.github+json" 
    },
    payload: JSON.stringify({ query: projectQuery })
  }

  console.log('project payload', projectBody);
  const response3 = UrlFetchApp.fetch("https://api.github.com/graphql", projectBody);
  console.log(response3.toString());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment