Skip to main content

Linking GitHub usernames with Indent

If you're using Indent to manage GitHub, you'll need to link your team's GitHub usernames to their usernames in Slack. This guide will walk you through how to do that automatically.

Prerequisites

1. Get your API key

First, you'll need an Indent space and API token which you can find here: indent.com/api-keys

Current User
Sign in to get API key
  • Can take actions on your behalf
  • Appears in audit log as you
Indent Space
Access Token
Note: this token is short lived and will expire soon
.env
INDENT_SPACE=
INDENT_API_TOKEN=************************************************************************************

The INDENT_SPACE is the Indent account you want to use for requests and an INDENT_API_TOKEN which is used for authentication. There are two kinds of API tokens: short-lived user access tokens and long-lived service account tokens. Read more about API authentication.

2. Prepare CSV of usernames

Create a folder for your project:

mkdir indent-guide-link-github

Next, you'll need to prepare a CSV file with the GitHub usernames you want to link. The CSV should have a header row with the column names email and github_id:

github_usernames.csv
email,github_id
[email protected],user-example-on-github
[email protected],other-example-on-github

3. Upload GitHub usernames

Finally, you can run the following script to link the GitHub usernames with Indent. Ensure that you've exported the INDENT_SPACE and INDENT_API_TOKEN environment variables.

You can initialize a new Node.js project and install the dependencies:

npm init -y
npm install --save papaparse axios

Then in a file called index.mjs (the extension .mjs allows use of import keyword) you can add the following code:

index.mjs
import fs from 'fs'
import axios from 'axios'
import Papa from 'papaparse'

async function readCSV(filePath) {
const csvFile = fs.readFileSync(filePath, 'utf8')
return new Promise((resolve, reject) => {
Papa.parse(csvFile, {
header: true,
complete: resolve,
error: reject,
})
})
}

async function updateResources(csvFilePath) {
const parsedCSV = await readCSV(csvFilePath)
const { resources: users } = await listUsers()

const updates = parsedCSV.data
.map(
({
email,
// Replace with the actual column name for the GitHub ID
github_id: githubId,
}) => {
const user = users.find((u) => u.email === email)
if (user && user.labels['github/id'] !== githubId) {
return {
...user,
labels: { ...user.labels, 'github/id': githubId },
}
}
}
)
.filter(Boolean)

if (updates.length > 0) {
await bulkUpdate({ resources: updates })
console.log(`Updated ${updates.length} users:`)
updates.forEach((u) =>
console.log(` - ${u.email} (${u.kind}) :: ${u.labels['github/id']}`)
)
} else {
console.log('No updates required.')
}
}

const spaceName = process.env.INDENT_SPACE
const accessToken = process.env.INDENT_API_TOKEN

async function listUsers() {
const api = client()
return await api({
method: 'get',
url: `/v1/spaces/${spaceName}/resources?labelSelector=indent.com/resource/kind=slack/user`,
}).then((r) => r.data)
}

async function bulkUpdate(req) {
const api = client()
return await api({
method: 'put',
url: `/v1/spaces/${spaceName}/resources:bulkUpdate`,
data: req,
}).then((r) => {
console.log(r.data)
return r.data
})
}

function client() {
if (!spaceName) {
throw new Error('INDENT_SPACE is required')
}
if (!accessToken) {
throw new Error('INDENT_API_TOKEN is required')
}
return axios.create({
baseURL: 'https://platform.indentapis.com',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
})
}

// Call the function with the path to your CSV file
updateResources('./github_usernames.csv').catch(console.error)

To run the script, use your API key from step 1 to run the following command:

INDENT_SPACE=my-space INDENT_API_TOKEN=access-token node index.mjs
Updated 2 users:
- [email protected] (slack/user) :: user-example-on-github
- [email protected] (slack/user) :: other-example-on-github