DEV Community

Alex Spinov
Alex Spinov

Posted on

GitLab Has a Free API: Here's How to Use It for DevOps Automation

GitLab's REST API is one of the most comprehensive in the DevOps world. You can manage repositories, trigger pipelines, review merge requests, manage issues, and automate your entire development workflow — all for free.

Why Use the GitLab API?

  • Automate merge request workflows and code reviews
  • Trigger pipelines from external events
  • Build custom dashboards for project management
  • Integrate GitLab with your existing tools

Getting Started

Get a Personal Access Token from Settings > Access Tokens:

export GITLAB_URL="https://gitlab.com/api/v4"
export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"

# List your projects
curl -s -H "PRIVATE-TOKEN: $GITLAB_TOKEN" "$GITLAB_URL/projects?owned=true&per_page=5" | jq '.[] | {id: .id, name: .name, web_url: .web_url}'

# Get project details
curl -s -H "PRIVATE-TOKEN: $GITLAB_TOKEN" "$GITLAB_URL/projects/12345" | jq '{name: .name, default_branch: .default_branch, star_count: .star_count, forks_count: .forks_count}'
Enter fullscreen mode Exit fullscreen mode

Python Client

import requests

class GitLabClient:
    def __init__(self, url='https://gitlab.com', token=None):
        self.url = f"{url}/api/v4"
        self.headers = {'PRIVATE-TOKEN': token}

    def get_projects(self, owned=True, per_page=20):
        resp = requests.get(f"{self.url}/projects", params={'owned': owned, 'per_page': per_page}, headers=self.headers)
        return resp.json()

    def get_pipelines(self, project_id, per_page=10):
        resp = requests.get(f"{self.url}/projects/{project_id}/pipelines", params={'per_page': per_page}, headers=self.headers)
        return resp.json()

    def trigger_pipeline(self, project_id, ref='main', variables=None):
        payload = {'ref': ref}
        if variables:
            payload['variables'] = variables
        resp = requests.post(f"{self.url}/projects/{project_id}/pipeline", json=payload, headers=self.headers)
        return resp.json()

    def get_merge_requests(self, project_id, state='opened'):
        resp = requests.get(f"{self.url}/projects/{project_id}/merge_requests", params={'state': state}, headers=self.headers)
        return resp.json()

    def create_merge_request(self, project_id, source_branch, target_branch, title, description=''):
        payload = {
            'source_branch': source_branch,
            'target_branch': target_branch,
            'title': title,
            'description': description
        }
        resp = requests.post(f"{self.url}/projects/{project_id}/merge_requests", json=payload, headers=self.headers)
        return resp.json()

    def create_issue(self, project_id, title, description='', labels=None):
        payload = {'title': title, 'description': description}
        if labels:
            payload['labels'] = ','.join(labels)
        resp = requests.post(f"{self.url}/projects/{project_id}/issues", json=payload, headers=self.headers)
        return resp.json()

# Usage
gl = GitLabClient(token='your-token')

# Check pipeline status
for pipeline in gl.get_pipelines(12345):
    print(f"Pipeline #{pipeline['id']}: {pipeline['status']} ({pipeline['ref']})")
Enter fullscreen mode Exit fullscreen mode

Pipeline Automation

def deploy_with_approval(gl, project_id, version, environment='production'):
    # Trigger deployment pipeline
    pipeline = gl.trigger_pipeline(project_id, ref='main', variables=[
        {'key': 'DEPLOY_VERSION', 'value': version},
        {'key': 'DEPLOY_ENV', 'value': environment}
    ])

    print(f"Pipeline #{pipeline['id']} triggered for {environment}")

    # Monitor pipeline
    import time
    while True:
        resp = requests.get(
            f"{gl.url}/projects/{project_id}/pipelines/{pipeline['id']}",
            headers=gl.headers
        )
        status = resp.json()['status']

        if status in ('success', 'failed', 'canceled'):
            print(f"Pipeline {status}!")
            return status == 'success'

        print(f"  Status: {status}...")
        time.sleep(10)

deploy_with_approval(gl, 12345, '2.1.0', 'staging')
Enter fullscreen mode Exit fullscreen mode

Merge Request Automation

def auto_review_mr(gl, project_id):
    mrs = gl.get_merge_requests(project_id, state='opened')

    for mr in mrs:
        mr_iid = mr['iid']

        # Get MR changes
        changes = requests.get(
            f"{gl.url}/projects/{project_id}/merge_requests/{mr_iid}/changes",
            headers=gl.headers
        ).json()

        # Auto-label based on files changed
        labels = set()
        for change in changes.get('changes', []):
            path = change['new_path']
            if path.startswith('src/api/'):
                labels.add('api')
            elif path.startswith('tests/'):
                labels.add('testing')
            elif path.endswith('.md'):
                labels.add('documentation')
            elif 'migration' in path:
                labels.add('database')

        if labels:
            requests.put(
                f"{gl.url}/projects/{project_id}/merge_requests/{mr_iid}",
                json={'labels': ','.join(labels)},
                headers=gl.headers
            )
            print(f"MR !{mr_iid}: added labels {labels}")

auto_review_mr(gl, 12345)
Enter fullscreen mode Exit fullscreen mode

Issue Management

def create_release_checklist(gl, project_id, version):
    checklist = f"""## Release {version} Checklist

- [ ] All tests passing on main
- [ ] Changelog updated
- [ ] Version bumped in package.json
- [ ] Database migrations tested
- [ ] Staging deployment verified
- [ ] Performance benchmarks run
- [ ] Security scan passed
- [ ] Documentation updated
- [ ] Release notes drafted
"""

    issue = gl.create_issue(
        project_id,
        title=f"Release {version}",
        description=checklist,
        labels=['release', 'process']
    )
    print(f"Release issue created: {issue['web_url']}")
    return issue

create_release_checklist(gl, 12345, '2.1.0')
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case

A platform team built a "deploy bot" using GitLab API. Developers type /deploy staging v2.1 in a merge request comment. The bot triggers the staging pipeline, waits for it to pass, runs smoke tests, and comments back with the deployment URL. Production deploys require two approvals — the bot checks MR approvals before triggering. Deployment friction dropped from 30 minutes to 2 minutes.

What You Can Build

  • Deploy bot triggered from MR comments
  • Auto-labeler categorizing MRs by files changed
  • Release manager automating version bumps and changelogs
  • Pipeline dashboard showing build health across all projects
  • Compliance checker ensuring MR policies are followed

Need custom DevOps automation? I build CI/CD tools and developer workflows.

Email me: spinov001@gmail.com
Check out my developer tools: https://apify.com/spinov001

Top comments (0)