Created
June 28, 2024 11:24
-
-
Save dennisameling/67b05435e394a029a4aeb2fa13d84502 to your computer and use it in GitHub Desktop.
ClickUp to GitLab integration - automating linking your GitLab repositories to ClickUp projects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ========= CONFIGURATION ========= | |
* 1. Set the `teamId` to the ID of the ClickUp team you want to add the repositories to. | |
* 2. Set the `clickUpProjects` to the IDs of the ClickUp projects you want to associate the repositories with. | |
* 3. Set the `headers` to the headers you need to authenticate with ClickUp. | |
*/ | |
const teamId = 1234567 | |
const clickUpProjects = [] | |
const headers = { | |
"Authorization": "Bearer YOUR_AUTH_TOKEN_HERE" | |
} | |
const baseUrl = `https://prod-us-west-2-2.clickup.com/integrations/v2/gl/team/${teamId}` | |
// The GitLab-to-ClickUp project mapping still seems to be using an old/legacy URL | |
const legacyBaseUrl = `https://prod-us-west-2-2.clickup.com/integrations/v1/team/${teamId}/gl_repo` | |
/** | |
* ========= FUNCTIONS ========= | |
* | |
* You typically shouldn't need to modify these functions. Skip to the "RUNNING THE SCRIPT" section below. | |
*/ | |
const deleteAllRepos = async () => { | |
const repos = await fetch( | |
`${baseUrl}/repo`, | |
{ headers } | |
) | |
const parsedRepos = await repos.json() | |
console.log(`Found ${parsedRepos.length} repos to delete`) | |
for (const repo of parsedRepos) { | |
console.log(`Deleting ${repo.gl_repo_name} (${repo.gl_repo_id})...`) | |
await fetch( | |
`${baseUrl}/repo/${repo.gl_repo_id}`, | |
{ | |
method: 'DELETE', | |
headers | |
} | |
) | |
console.log(`Deleted ${repo.gl_repo_name} (${repo.gl_repo_id}).`) | |
} | |
console.log('All repos deleted') | |
} | |
const getAllRespositories = async () => { | |
const allRepos = [] | |
let page = 1 | |
while (page > 0) { | |
const reposResponse = await fetchAvailableRepositories(page) | |
allRepos.push(...reposResponse.repos) | |
console.log(`Fetched ${reposResponse.repos.length} repos. Total so far: ${allRepos.length}`) | |
if (!reposResponse.hasMore) { | |
console.log('Finished fetching repos.') | |
break | |
} | |
page++ | |
} | |
return allRepos | |
} | |
/** | |
* Repos have the following structure: | |
* { | |
* "gl_repo_id": "12345678", | |
* "gl_repo_name": "repo-name-here", | |
* "gl_repo_owner": "12345678", | |
* "gl_repo_owner_name": "subgroup-name-here", | |
* "gl_repo_full_slug": "your-group-here/subgroup-name-here/repo-name-here", | |
* "gl_repo_slug": "repo-slug-here" | |
* } | |
*/ | |
const fetchAvailableRepositories = async (page) => { | |
const response = await fetch( | |
`${baseUrl}/repos/search?query=&page=${page}`, | |
{ headers } | |
) | |
// Returns "repos" (array of repos) and "hasMore" (integer if there are more pages to fetch, and "false" (boolean) otherwise) | |
return await response.json() | |
} | |
const addRepository = async (repo) => { | |
console.log(`Adding repo ${repo.gl_repo_name}...`) | |
const response = await fetch( | |
`${baseUrl}/repo`, | |
{ | |
method: 'POST', | |
headers: { | |
...headers, | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify(repo) | |
} | |
) | |
const responseBody = await response.json() | |
if (response.status === 400 && responseBody?.ECODE === "GLR_011") { | |
console.log(`Repo ${repo.gl_repo_name} already exists. Skipping.`) | |
} else if (!response.ok) { | |
throw new Error(`Failed to add ${repo.gl_repo_name}. Status: ${response.status}. Data: ${await response.json()}`) | |
} else { | |
console.log(`Added ${repo.gl_repo_name}.`) | |
} | |
} | |
const configureClickUpProjectsForRepos = async (repos) => { | |
console.log(`Configuring ClickUp projects for all repos... This might take a while!`) | |
const response = await fetch( | |
`${legacyBaseUrl}/projects`, | |
{ | |
method: 'POST', | |
headers: { | |
...headers, | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ | |
repos: repos.map(repo => ({ | |
gl_repo_id: repo.gl_repo_id, | |
projects: clickUpProjects | |
})) | |
}) | |
} | |
) | |
if (!response.ok) { | |
throw new Error(`Failed to configure projects for all repos. Status: ${response.status}. Data: ${await response.json()}`) | |
} else { | |
console.log(`Configured projects for all repos.`) | |
} | |
} | |
/** | |
* ========= RUNNING THE SCRIPT ========= | |
* | |
* By default, the script will: | |
* - Fetch all available GitLab repositories | |
* - Add them to ClickUp | |
* - Configure the projects for which each repo should be available | |
* | |
* If you want to remove all repos from ClickUp first (e.g. when you want to reauthorize | |
* with a different user), you can uncomment the `deleteAllRepos` function below. | |
*/ | |
// deleteAllRepos() | |
getAllRespositories().then(async repos => { | |
// Add repos to ClickUp | |
for (const repo of repos) { | |
await addRepository(repo) | |
} | |
// Configure the projects for which each repo should be available | |
await configureClickUpProjectsForRepos(repos) | |
console.log('All done!') | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment