-
Notifications
You must be signed in to change notification settings - Fork 0
architecture Crawling Process
The COPIMA CLI Crawler uses a systematic four-step process to extract all accessible data from a GitLab instance.
The crawling process is divided into four sequential steps:
- Areas - Discover all groups and projects (GraphQL)
- Users - Collect all user information (GraphQL)
- Resources - Extract issues, MRs, labels, and more (GraphQL)
- Repository - Crawl commits, branches, and files (REST)
Each step builds on the previous one, creating a complete picture of the GitLab instance.
Each step has a focused responsibility:
- Step 1 provides the inventory (what exists)
- Step 2 provides the actors (who is involved)
- Step 3 provides the content (development artifacts)
- Step 4 provides the code (repository data)
- Steps 1-3 use GraphQL for efficient batch queries
- Step 4 uses REST API for resources only available there
Steps are independently resumable:
- Failed step can be retried without re-running successful ones
- Different steps can be run on different schedules
- Selective crawling (e.g., only areas and users)
Purpose: Discover the organizational structure of the GitLab instance.
query GetGroups {
groups {
nodes {
id
name
fullPath
path
visibility
description
createdAt
updatedAt
parentId
subgroups {
nodes { id }
}
}
}
}Captured Data:
- Group ID (GitLab GID)
- Full path (e.g.,
org-team-subteam) - Name and description
- Visibility (public, internal, private)
- Parent/child relationships
- Creation and update timestamps
query GetProjects {
projects {
nodes {
id
name
fullPath
path
visibility
description
namespace {
id
fullPath
}
createdAt
updatedAt
archived
emptyRepo
defaultBranch
}
}
}Captured Data:
- Project ID (GitLab GID)
- Full path (e.g.,
org-team-project) - Name and description
- Visibility level
- Parent group
- Repository state (empty, archived)
- Default branch name
- Timestamps
output/
├── groups.jsonl # All groups (flat list)
├── projects.jsonl # All projects (flat list)
└── group1/
├── groups.jsonl # This group's metadata
└── subgroup1/
├── groups.jsonl # Subgroup metadata
└── project1/
└── projects.jsonl # Project metadata
- Inventory - Know what to crawl in later steps
- Hierarchy - Establish folder structure for output
- Access - Identify which resources are accessible
- Efficiency - Small dataset, completes quickly
- Fast: Usually completes in seconds to minutes
- Lightweight: Only metadata, no large objects
- Scalable: Can handle thousands of groups/projects
Purpose: Collect information about all users in the instance.
query GetUsers {
users {
nodes {
id
username
name
email
publicEmail
state
webUrl
avatarUrl
bio
location
organization
createdAt
confirmed
bot
}
}
}Captured Data:
- User ID (GitLab GID)
- Username (login)
- Full name
- Email addresses
- Account state (active, blocked, banned)
- Profile information (bio, location, organization)
- Avatar URL
- Bot status
- Creation date
output/
└── users.jsonl # All users (global file)
Users are stored in a single global file, not in group/project folders.
- References - Later steps reference user IDs
- Global - Users aren't scoped to groups/projects
- Deduplication - Prevents storing same user multiple times in step 3
- Only public profile information is collected
- Email addresses may be hidden based on user privacy settings
- Respects GitLab's visibility and permission system
- Fast: Completes in minutes for most instances
- Size: ~1-2 KB per user
- Scalable: Can handle 100,000+ users
Purpose: Extract development artifacts and metadata for all groups and projects.
This is the most comprehensive step, collecting the bulk of GitLab data.
query GetMembers($fullPath: ID!) {
group(fullPath: $fullPath) {
groupMembers {
nodes {
id
accessLevel
createdAt
expiresAt
user {
id
username
}
}
}
}
}Access Levels:
- 10: Guest
- 20: Reporter
- 30: Developer
- 40: Maintainer
- 50: Owner
labels {
nodes {
id
title
description
color
textColor
}
}milestones {
nodes {
id
title
description
state
dueDate
startDate
createdAt
updatedAt
}
}issues {
nodes {
id
iid
title
description
state
author { id username }
assignees { nodes { id username } }
labels { nodes { id title } }
milestone { id title }
createdAt
updatedAt
closedAt
dueDate
webUrl
}
}mergeRequests {
nodes {
id
iid
title
description
state
author { id username }
assignees { nodes { id username } }
reviewers { nodes { id username } }
labels { nodes { id title } }
sourceBranch
targetBranch
createdAt
updatedAt
mergedAt
webUrl
headPipeline { id status }
}
}awardEmoji {
nodes {
name
user { id username }
}
}epics {
nodes {
id
iid
title
description
state
author { id username }
parent { id iid }
children { nodes { id iid } }
createdAt
updatedAt
closedAt
}
}boards {
nodes {
id
name
lists {
nodes {
id
position
label { id title }
}
}
}
}auditEvents {
nodes {
id
action
authorName
entityPath
createdAt
}
}releases {
nodes {
id
name
tagName
tagPath
description
releasedAt
createdAt
author { id username }
milestones { nodes { id title } }
}
}pipelines {
nodes {
id
iid
status
ref
sha
source
createdAt
updatedAt
finishedAt
duration
coverage
user { id username }
}
}snippets {
nodes {
id
title
description
visibility
author { id username }
createdAt
updatedAt
}
}containerRepositories {
nodes {
id
name
path
location
createdAt
}
}output/
├── users.jsonl
└── group1/
├── groups.jsonl
├── members.jsonl # Group members
├── labels.jsonl # Group labels
├── milestones.jsonl # Group milestones
├── issues.jsonl # Group issues
├── merge_requests.jsonl # Group MRs
├── epics.jsonl # Group epics
├── boards.jsonl # Group boards
└── project1/
├── projects.jsonl
├── members.jsonl # Project members
├── labels.jsonl # Project labels
├── issues.jsonl # Project issues
├── merge_requests.jsonl # Project MRs
├── pipelines.jsonl # CI/CD pipelines
├── releases.jsonl # Project releases
└── snippets.jsonl # Code snippets
- Dependencies - Needs areas and users from steps 1-2
- Deduplication - Uses user data to avoid duplicates
- Volume - Largest dataset, benefits from established structure
- Slow: Can take hours for large instances
- Large: Gigabytes of data possible
- Resumable: Checkpoint after each group/project
Purpose: Extract repository-level data not available via GraphQL.
GET /api/v4/projects/:id/repository/branchesData:
- Branch name
- Last commit SHA
- Protected status
- Merged status
- Default branch flag
GET /api/v4/projects/:id/repository/commitsData:
- Commit SHA
- Parent SHAs
- Author and committer
- Message (title + body)
- Timestamp
- Stats (additions, deletions, total)
- File diffs (optional)
GET /api/v4/projects/:id/repository/tagsData:
- Tag name
- Target commit
- Message (annotated tags)
- Release info
- Timestamp
GET /api/v4/projects/:id/repository/treeData:
- File/directory paths
- File types (blob, tree)
- File sizes
- File modes (permissions)
GET /api/v4/projects/:id/repository/files/:path/rawData:
- Raw file content
- Binary or text
- Encoding info
output/
└── group1/
└── project1/
├── branches.jsonl # All branches
├── tags.jsonl # All tags
├── commits.jsonl # Commit history
├── tree.jsonl # File tree
└── files/ # File contents (optional)
├── README.md
└── src/
└── main.js
GraphQL has limited support for:
- Full commit history with diffs
- Repository file tree traversal
- Raw file contents
- Detailed branch/tag metadata
REST API provides complete access to these resources.
- Very Slow: Most time-consuming step
- Huge: Can generate gigabytes per project
- Network-Bound: Many small API calls
- Optional: Can be skipped if not needed
repository:
# Crawl branches
branches: true
# Crawl commits (expensive!)
commits: true
commitsDepth: 100 # Limit to recent commits
# Crawl tags
tags: true
# Crawl file tree
tree: true
# Download file contents (very expensive!)
files: false
filesInclude:
- "*.md"
- "*.txt"
filesExclude:
- "*.bin"
- "*.exe"# Step 1 only
copima-cli-crawler areas
# Step 2 only
copima-cli-crawler users
# Step 3 only
copima-cli-crawler resources
# Step 4 only
copima-cli-crawler repository# Steps 1 and 2
copima-cli-crawler crawl --steps areas,users
# Steps 1, 2, and 3 (skip repository)
copima-cli-crawler crawl --steps areas,users,resources
# All steps (default)
copima-cli-crawler crawlStep 1 (Areas)
↓
├─► Step 2 (Users) ─────────┐
│ │
└─► Step 3 (Resources) ◄─────┘
↓
└─► Step 4 (Repository)
- Step 2 requires Step 1 (needs project list)
- Step 3 requires Steps 1 & 2 (needs areas and user references)
- Step 4 requires Step 1 (needs project list)
# Run all steps
copima-cli-crawler crawl# Run steps 1-3, skip repository
copima-cli-crawler crawl --steps areas,users,resources
# Run repository later if needed
copima-cli-crawler repository# Run in stages over multiple days
copima-cli-crawler areas
copima-cli-crawler users
copima-cli-crawler resources --resume true
# Skip repository or limit scope
copima-cli-crawler repository --commits-depth 10# Re-run specific steps
copima-cli-crawler crawl --steps resources --resume true
# Deduplication prevents duplicates| Step | API | Speed | Size | Required |
|---|---|---|---|---|
| Areas | GraphQL | Fast | KB-MB | Yes |
| Users | GraphQL | Fast | MB | Yes |
| Resources | GraphQL | Slow | MB-GB | Yes |
| Repository | REST | Very Slow | GB-TB | Optional |
The four-step process provides a structured, efficient, and resumable way to extract all data from a GitLab instance.
Crawling Process Version: 1.0.0
Last Updated: 2025-10-19