Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/gitlab

README.md

275 lines · 10.4 KB · Markdown

@kody/gitlab

Intent

Reusable GitLab REST helpers for Kody agents. One package covers bring-your-own OAuth applications and personal access tokens for projects, issues, merge requests, pipelines, and generic REST. Multi-account routing is an integrationName (OAuth) or secretName (PAT) parameter — there are no hard-coded personal aliases or project paths.

What this package does

After you connect GitLab to Kody, agents can:

  • Call the GitLab REST API with the correct saved credential (request, paginate)
  • Verify which GitLab identity will perform an action (get-current-user)
  • List and fetch projects, issues, merge requests, and pipelines
  • Preview or apply writes (issues/create, issues/update, merge-requests/*, pipelines/*)

It does not register a GitLab OAuth application for you. There is no built-in GitLab platform app.

Share this listing at https://kody.codes/@kody/gitlab

Auth lanes

LaneCredentialWhen to use
A. Personal access tokenUser secret (documented name gitlabAccessToken) passed as secretNameFastest for many automations; best for read-only work via read_api.
B. Bring-your-own OAuth AppSaved integration named gitlab (or another name you pass as integrationName)When you want refreshable OAuth instead of a PAT.

Required host for gitlab.com: gitlab.com. Self-hosted instances use that instance host instead.

secretName selects the PAT lane and ignores integrationName.

Lane A: personal access token

  1. Open GitLab personal access tokens and create a token. Use read_api for read-only helpers, or api for writes.
  2. Copy the token once. Never paste it into chat.
  3. Save it in Kody and approve the host:
https://kody.codes/account/secrets/new?name=gitlabAccessToken&description=GitLab%20personal%20access%20token&allowedHosts=gitlab.com&scope=user
  1. Call helpers with secretName: 'gitlabAccessToken' (or your chosen secret name).

Lane B: bring-your-own OAuth application

There is no built-in GitLab OAuth app. Create one, then connect it.

  1. Open GitLab applicationsAdd new application.
  2. Set the Redirect URI exactly to https://kody.codes/connect/oauth (self-hosted Kody uses that deployment origin plus /connect/oauth).
  3. Enable Confidential and the api scope (read_api plus read_user is enough for read-only helpers).
  4. Copy the application id and secret. Never paste the secret into chat.
  5. Connect:
https://kody.codes/connect/oauth?provider=gitlab&authorizeUrl=https%3A%2F%2Fgitlab.com%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fgitlab.com%2Foauth%2Ftoken&flow=confidential&scopes=api&allowedHosts=gitlab.com&apiBaseUrl=https%3A%2F%2Fgitlab.com%2Fapi%2Fv4&dashboardUrl=https%3A%2F%2Fgitlab.com%2F-%2Fprofile%2Fapplications

Decoded: authorize https://gitlab.com/oauth/authorize, token https://gitlab.com/oauth/token, flow=confidential, scopes api, host gitlab.com. Paste the client ID and secret into the Kody setup form, then authorize GitLab.

Default helper input: omit integrationName and secretName. The package uses OAuth integration gitlab.

Reconnect later at https://kody.codes/connect/oauth?provider=gitlab (or ?provider=<your-integration-name>).

Self-hosted GitLab

Pass instanceUrl (origin) or apiBaseUrl (https://gitlab.example.com/api/v4) on every call. Approve that instance host on the secret or OAuth connect URL.

OAuth for another instance (change provider for extra accounts):

https://kody.codes/connect/oauth?provider=gitlab&authorizeUrl=https%3A%2F%2Fgitlab.example.com%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fgitlab.example.com%2Foauth%2Ftoken&flow=confidential&scopes=api&allowedHosts=gitlab.example.com&apiBaseUrl=https%3A%2F%2Fgitlab.example.com%2Fapi%2Fv4

PAT for another instance: use the same /account/secrets/new URL with allowedHosts set to that host.

Multiple GitLab identities

Every export accepts optional integrationName (OAuth, default gitlab) and secretName (PAT). Connect extra accounts under their own integration names — for example gitlab-work — by changing provider in the connect URL. Pass that name on every call. Do not hard-code personal aliases in forks of this package.

import getGitlabCurrentUser from 'kody:@kody/gitlab/get-current-user'

export default async function main() {
	return await getGitlabCurrentUser({ integrationName: 'gitlab-work' })
}

account is accepted as an alias for integrationName.

Mutations and dryRun

Create, update, merge, retry, cancel, and REST methods other than GET / HEAD / OPTIONS require:

  • dryRun: true — validate and return a preview; GitLab is not written
  • confirm: true — perform the live write
import createGitlabIssue from 'kody:@kody/gitlab/issues/create'

export default async function main() {
	return await createGitlabIssue({
		project: 'example-group/example-project',
		title: 'Example',
		dryRun: true,
	})
}

Smoke tests

Run these from execute after connect (or after PAT host approval). Prefer packages.invoke against a fork of this package so secret mounts and OAuth run in package runtime.

Package overview (no credentials)
import describeGitlab from 'kody:@kody/gitlab'

export default async function main() {
	return await describeGitlab()
}
Identity (Lane B — OAuth)
import getGitlabCurrentUser from 'kody:@kody/gitlab/get-current-user'

export default async function main() {
	return await getGitlabCurrentUser()
	// or: getGitlabCurrentUser({ integrationName: 'gitlab' })
}

A successful response includes username for the connected GitLab user.

Raw OAuth equivalent (integration bootstrap):

import { createAuthenticatedFetch } from 'kody:runtime'

export default async function main() {
	const gitlabFetch = await createAuthenticatedFetch('gitlab')
	const response = await gitlabFetch('https://gitlab.com/api/v4/user')
	if (!response.ok) {
		throw new Error(`GitLab smoke test failed: ${response.status} ${await response.text()}`)
	}
	const user = (await response.json()) as { username: string }
	return { username: user.username }
}
Identity (Lane A — PAT)
import getGitlabCurrentUser from 'kody:@kody/gitlab/get-current-user'

export default async function main() {
	return await getGitlabCurrentUser({ secretName: 'gitlabAccessToken' })
}

Raw PAT equivalent:

export default async function main() {
	const response = await fetch('https://gitlab.com/api/v4/user', {
		headers: {
			'PRIVATE-TOKEN': '{{secret:gitlabAccessToken}}',
		},
	})
	if (!response.ok) {
		throw new Error(`GitLab smoke test failed: ${response.status} ${await response.text()}`)
	}
	const user = (await response.json()) as { username: string }
	return { username: user.username }
}
Mutation preview
import gitlabRequest from 'kody:@kody/gitlab/request'

export default async function main() {
	return await gitlabRequest({
		method: 'POST',
		path: '/projects/example-group%2Fexample-project/issues',
		body: { title: 'Example', description: 'Preview only' },
		dryRun: true,
	})
}
Dynamic invoke

Prefer static kody:@kody/gitlab/... imports. Use packages.invoke when the export name is data or you need this package's runtime:

import { packages } from 'kody:runtime'

export default async function main() {
	return await packages.invoke({
		kodyId: 'gitlab',
		exportName: './get-current-user',
		params: {},
	})
}

Pass the bare kody id gitlab, not @kody/gitlab.

Exports

  • kody:@kody/gitlab — package overview and setup URLs
  • kody:@kody/gitlab/accounts — OAuth vs PAT lane guidance
  • kody:@kody/gitlab/get-current-user — identity smoke test
  • kody:@kody/gitlab/paginate — REST pagination helper
  • kody:@kody/gitlab/request — REST request helper
  • kody:@kody/gitlab/types — shared TypeScript types
  • kody:@kody/gitlab/projects/list — list projects
  • kody:@kody/gitlab/projects/get — fetch one project
  • kody:@kody/gitlab/issues/list — list issues
  • kody:@kody/gitlab/issues/get — fetch one issue
  • kody:@kody/gitlab/issues/create — create an issue (dryRun / confirm)
  • kody:@kody/gitlab/issues/update — update an issue (dryRun / confirm)
  • kody:@kody/gitlab/merge-requests/list — list merge requests
  • kody:@kody/gitlab/merge-requests/get — fetch one merge request
  • kody:@kody/gitlab/merge-requests/create — create a merge request (dryRun / confirm)
  • kody:@kody/gitlab/merge-requests/update — update a merge request (dryRun / confirm)
  • kody:@kody/gitlab/merge-requests/merge — merge a merge request (dryRun / confirm)
  • kody:@kody/gitlab/pipelines/list — list pipelines
  • kody:@kody/gitlab/pipelines/get — fetch one pipeline
  • kody:@kody/gitlab/pipelines/create — create a pipeline (dryRun / confirm)
  • kody:@kody/gitlab/pipelines/retry — retry a pipeline (dryRun / confirm)
  • kody:@kody/gitlab/pipelines/cancel — cancel a pipeline (dryRun / confirm)

Project locators: { project }, { projectId }, { projectPath }, or { projectUrl }. Issue / merge-request / pipeline locators also accept the matching *Url or iid aliases.

Examples

REST read (default OAuth gitlab):

import gitlabRequest from 'kody:@kody/gitlab/request'

export default async function main() {
	const response = await gitlabRequest({
		path: '/projects',
		query: { membership: true, per_page: 5 },
		throwOnError: true,
	})
	return response.data
}

Project issues with an extra OAuth identity:

import listGitlabIssues from 'kody:@kody/gitlab/issues/list'

export default async function main() {
	return await listGitlabIssues({
		project: 'example-group/example-project',
		state: 'opened',
		integrationName: 'gitlab-work',
	})
}

Troubleshooting

  • The redirect_uri MUST match the registered callback URL: callback must be exactly https://kody.codes/connect/oauth.
  • 401 Unauthorized with a PAT: expired token, missing scope, or a stray space. Rotate at GitLab token settings and update the secret.
  • Self-hosted 401 / host-approval errors: approve the instance host on the secret or OAuth connect URL, and pass instanceUrl or apiBaseUrl.
  • Token exchange fails: GitLab confidential apps require the client secret. Regenerate the secret and reconnect.
  • Writes rejected with a mutation-guard error: pass dryRun: true or confirm: true.