GitLab Commands

Overview

The netapi gitlab commands provide CLI access to GitLab’s REST API. All commands support -f json for jq piping.

Prerequisites

# Set GitLab token (personal access token)
export GITLAB_TOKEN="glpat-..."

# Optional: Custom GitLab instance (defaults to gitlab.com)
export GITLAB_URL="https://gitlab.example.com"

Commands (23 total)

Command Description

user

Get user info

search-users

Search users

projects

List user projects

project

Get project details

search

Search projects

branches

List branches

commits

List commits

tags

List tags

releases

List releases

languages

Get language breakdown

issues

List issues

issue

Get issue details

mrs

List merge requests

mr

Get MR details

mr-changes

List MR files

groups

List groups

group

Get group details

group-projects

List group projects

group-members

List group members

pipelines

List pipelines

pipeline

Get pipeline details

pipeline-jobs

List pipeline jobs

api

Raw API request

JSON Output

All commands support -f json:

netapi gitlab projects -f json
netapi gitlab project namespace/project -f json
netapi gitlab mrs namespace/project -f json

jq Patterns

Exploring Structure

# See all keys in first object
netapi gitlab projects -f json | jq '.[0] | keys'

# Keys with types
netapi gitlab projects -f json | jq '.[0] | to_entries | .[] | "\(.key): \(.value | type)"'

# Full first object
netapi gitlab projects -f json | jq '.[0]'

Project Operations

# List all project names
netapi gitlab projects -f json | jq -r '.[].path_with_namespace'

# Filter by visibility
netapi gitlab projects -f json | jq -r '.[] | select(.visibility == "private") | .path_with_namespace'

# Get specific fields
netapi gitlab projects -f json | jq '.[] | {name: .path_with_namespace, stars: .star_count, visibility}'

# Sort by activity
netapi gitlab projects -f json | jq 'sort_by(.last_activity_at) | reverse | .[] | "\(.path_with_namespace): \(.last_activity_at[0:10])"'

# Projects with CI enabled
netapi gitlab projects -f json | jq '.[] | select(.jobs_enabled) | .path_with_namespace'

Single Project

# Full project details
netapi gitlab project mygroup/myproject -f json | jq '.'

# Summary object
netapi gitlab project mygroup/myproject -f json | jq '{
  name: .path_with_namespace,
  visibility,
  stars: .star_count,
  forks: .forks_count,
  issues: .open_issues_count,
  default_branch,
  created: .created_at[0:10],
  updated: .last_activity_at[0:10],
  web_url
}'

# Clone URLs
netapi gitlab project mygroup/myproject -f json | jq '{http: .http_url_to_repo, ssh: .ssh_url_to_repo}'

Language Breakdown

# Languages with percentages
netapi gitlab languages mygroup/myproject -f json | jq 'to_entries | sort_by(-.value) | .[] | "\(.key): \(.value)%"'

Commits

# Recent commits - short format
netapi gitlab commits mygroup/myproject -l 10 -f json | jq -r '.[] | "\(.short_id) \(.author_name): \(.title)"'

# Commits by author
netapi gitlab commits mygroup/myproject -f json | jq -r '.[].author_name' | sort | uniq -c | sort -rn

# Commits with date
netapi gitlab commits mygroup/myproject -f json | jq '.[] | {
  sha: .short_id,
  author: .author_name,
  date: .created_at[0:10],
  message: .title
}'

Merge Requests

# Open MRs - titles only
netapi gitlab mrs mygroup/myproject -f json | jq -r '.[] | "!\(.iid): \(.title)"'

# MRs with stats
netapi gitlab mrs mygroup/myproject -f json | jq '.[] | {
  iid,
  title,
  author: .author.username,
  source: .source_branch,
  target: .target_branch,
  created: .created_at[0:10],
  state
}'

# Get specific MR
netapi gitlab mr mygroup/myproject 42 -f json | jq '{
  title,
  state,
  author: .author.username,
  source_branch,
  target_branch,
  web_url
}'

# MR changes (files)
netapi gitlab mr-changes mygroup/myproject 42 -f json | jq '.changes[] | {
  file: .new_path,
  new: .new_file,
  deleted: .deleted_file,
  renamed: .renamed_file
}'

# Merged MRs
netapi gitlab mrs mygroup/myproject -s merged -f json | jq '.[] | {iid, title, merged: .merged_at[0:10]}'

Issues

# Open issues - titles
netapi gitlab issues mygroup/myproject -f json | jq -r '.[] | "#\(.iid): \(.title)"'

# Issues with labels
netapi gitlab issues mygroup/myproject -f json | jq '.[] | {
  iid,
  title,
  author: .author.username,
  labels
}'

# Filter by label
netapi gitlab issues mygroup/myproject -f json | jq '.[] | select(.labels | index("bug"))'

# Issues by state
netapi gitlab issues mygroup/myproject -s closed -f json | jq '.[] | {iid, title, closed: .closed_at[0:10]}'

Pipelines

# Recent pipelines
netapi gitlab pipelines mygroup/myproject -f json | jq '.[] | {id, status, ref, created: .created_at[0:10]}'

# Failed pipelines
netapi gitlab pipelines mygroup/myproject -f json | jq '.[] | select(.status == "failed") | {id, ref}'

# Pipeline details
netapi gitlab pipeline mygroup/myproject 12345 -f json | jq '{id, status, ref, sha: .sha[0:8], web_url}'

# Pipeline jobs
netapi gitlab pipeline-jobs mygroup/myproject 12345 -f json | jq '.[] | {
  name,
  stage,
  status,
  duration: (if .duration then "\(.duration | floor)s" else null end)
}'

# Failed jobs only
netapi gitlab pipeline-jobs mygroup/myproject 12345 -f json | jq '.[] | select(.status == "failed") | {name, stage}'

Groups

# List groups
netapi gitlab groups -f json | jq -r '.[].full_path'

# Group details
netapi gitlab group mygroup -f json | jq '{name, full_path, visibility, description, web_url}'

# Group projects sorted by stars
netapi gitlab group-projects mygroup -f json | jq 'sort_by(-.star_count) | .[] | "\(.path): \(.star_count) stars"'

# Group members with access levels
netapi gitlab group-members mygroup -f json | jq '.[] | {
  username,
  name,
  access: (
    if .access_level == 50 then "Owner"
    elif .access_level == 40 then "Maintainer"
    elif .access_level == 30 then "Developer"
    elif .access_level == 20 then "Reporter"
    else "Guest"
    end
  )
}'
# Search projects
netapi gitlab search "ansible" -f json | jq '.[] | {name: .path_with_namespace, stars: .star_count}'

# Search users
netapi gitlab search-users "john" -f json | jq '.[] | {username, name, state}'

Raw API Access

# Any GET endpoint
netapi gitlab api /users | jq '.[0]'

# Project variables
netapi gitlab api /projects/mygroup%2Fmyproject/variables | jq '.[] | {key, protected}'

# Project hooks
netapi gitlab api /projects/mygroup%2Fmyproject/hooks | jq '.[] | {url, push_events}'
URL-encode project paths: mygroup/myprojectmygroup%2Fmyproject

Environment Variables

Variable Description

GITLAB_TOKEN

Personal access token (required)

GITLAB_URL

GitLab instance URL (default: gitlab.com)

Useful jq Recipes

Export to CSV

netapi gitlab projects -f json | jq -r '.[] | [.path_with_namespace, .visibility, .star_count] | @csv'

Count by Field

# Projects by visibility
netapi gitlab projects -f json | jq 'group_by(.visibility) | map({visibility: .[0].visibility, count: length})'

# MRs by state
netapi gitlab mrs mygroup/myproject -s all -f json | jq 'group_by(.state) | map({state: .[0].state, count: length})'

Pipeline Stats

# Pipeline success rate
netapi gitlab pipelines mygroup/myproject -l 100 -f json | jq '
  group_by(.status) |
  map({status: .[0].status, count: length}) |
  sort_by(-.count)
'

# Average pipeline duration (requires completed pipelines)
netapi gitlab pipelines mygroup/myproject -f json | jq '[.[] | select(.duration) | .duration] | if length > 0 then (add / length | floor) else 0 end'

Recent Activity

# Projects updated today
netapi gitlab projects -f json | jq --arg d "$(date -I)" '.[] | select(.last_activity_at | startswith($d)) | .path_with_namespace'