A GitHub CLI extension that deploys, configures, and monitors Apache DevLake instances from the command line.
One CLI to go from zero to DORA dashboards: deploy DevLake (locally or on Azure), create GitHub + Copilot connections, add repository scopes, build a DORA project, and trigger data syncs — all without touching the Config UI.
# Install the extension
gh extension install DevExpGBB/gh-devlake
# Deploy DevLake locally (downloads official Docker Compose files)
gh devlake deploy local --dir ./my-devlake
cd my-devlake && docker compose up -d
# Wait ~2 minutes, then configure everything in one shot
gh devlake configure full --org my-org --repos my-org/repo1,my-org/repo2
# Check health and connections
gh devlake statusgh extension install DevExpGBB/gh-devlakegit clone https://github.com/DevExpGBB/gh-devlake.git
cd gh-devlake
go build -o gh-devlake.exe . # Windows
go build -o gh-devlake . # Linux/macOS
gh extension install .| Requirement | When needed |
|---|---|
GitHub CLI (gh) |
Always — this is a gh extension |
| Go 1.22+ | Building from source only |
| Docker | deploy local, cleanup --local |
Azure CLI (az) |
deploy azure, cleanup --azure |
| GitHub PAT | configure connections / configure full |
Required PAT scopes:
| Plugin | Required Scopes | Notes |
|---|---|---|
| GitHub | repo, read:org, read:user |
repo covers repo:status and repo_deployment |
| GitHub Copilot | manage_billing:copilot, read:org |
Add read:enterprise for enterprise-level metrics |
The extension manages three phases of DevLake setup:
Phase 1 — Deploy Phase 2 — Connections Phase 3 — Scopes & Project
───────────────── ───────────────────── ──────────────────────────
deploy local configure connections configure scopes
deploy azure
─── or combine ───
cleanup configure full (Phase 2 + 3 in one step)
Auto-discovery finds your DevLake instance automatically:
--urlflag (explicit)- State files (
.devlake-azure.json,.devlake-local.json) in the current directory - Well-known localhost ports (
8080,8085)
State files track deployment info, connection IDs, and project configuration so commands can chain together without re-specifying IDs.
Check DevLake health and list configured connections.
gh devlake status
gh devlake status --url http://localhost:8085Output:
═══════════════════════════════════════════
DevLake Status
═══════════════════════════════════════════
Deployment [.devlake-local.json]
──────────────────────────────────────────
Method: local
Deployed: 2026-02-18 12:00 UTC
Services
──────────────────────────────────────────
Backend ✅ http://localhost:8080
Grafana ✅ http://localhost:3002
Connections
──────────────────────────────────────────
GitHub ID=1 "GitHub - my-org"
GitHub Copilot ID=1 "Copilot - my-org" [org: my-org]
Project
──────────────────────────────────────────
Name: my-org
Blueprint: 1
Repos: my-org/app1, my-org/app2
═══════════════════════════════════════════
Download official Apache DevLake Docker Compose files, generate an encryption secret, and prepare for docker compose up.
gh devlake deploy local
gh devlake deploy local --version v1.0.2 --dir ./devlake| Flag | Default | Description |
|---|---|---|
--dir |
. |
Target directory for files |
--version |
latest |
DevLake release version (e.g., v1.0.2) |
What it does:
- Fetches the latest release tag from GitHub (or uses
--version) - Downloads
docker-compose.ymlandenv.example - Renames
env.example→.env - Generates and injects a cryptographic
ENCRYPTION_SECRET - Checks that Docker is available
After running: cd <dir> && docker compose up -d, then wait ~2 minutes.
Endpoints:
- Config UI: http://localhost:4000
- Grafana: http://localhost:3002 (admin/admin)
- Backend API: http://localhost:8080
Deploy DevLake to Azure using Bicep templates (Container Instances + MySQL Flexible Server + Key Vault).
# Official Apache images (no ACR, ~$30-50/month)
gh devlake deploy azure --resource-group devlake-rg --location eastus --official
# Custom images built from source (with ACR, ~$50-75/month)
gh devlake deploy azure --resource-group devlake-rg --location eastus
# Build from a remote fork
gh devlake deploy azure --resource-group devlake-rg --location eastus \
--repo-url https://github.com/my-fork/incubator-devlake| Flag | Default | Description |
|---|---|---|
--resource-group |
(required) | Azure Resource Group name |
--location |
(required) | Azure region (e.g., eastus) |
--base-name |
devlake |
Base name for Azure resources |
--official |
false |
Use official Docker Hub images (no ACR) |
--skip-image-build |
false |
Skip Docker image build step |
--repo-url |
Clone a remote repo for building |
What it does:
- Checks Azure CLI login (prompts
az loginif needed) - Creates the resource group
- Generates MySQL password and encryption secret
- Optionally builds + pushes Docker images to ACR
- Deploys infrastructure via Bicep
- Waits for the backend to respond, triggers DB migration
- Saves
.devlake-azure.jsonstate file
Create a plugin connection in DevLake using a PAT. If --plugin is not specified, prompts interactively.
gh devlake configure connections --plugin github --org my-org
gh devlake configure connections --plugin gh-copilot --org my-org
gh devlake configure connections --org my-org --name "My GitHub" --proxy http://proxy:8080
gh devlake configure connections --org my-org --endpoint https://github.example.com/api/v3/| Flag | Default | Description |
|---|---|---|
--plugin |
(interactive) | Plugin to configure (github, gh-copilot) |
--org |
(required for Copilot) | GitHub organization slug |
--enterprise |
GitHub enterprise slug (for Copilot enterprise metrics) | |
--name |
Plugin - org |
Connection display name |
--endpoint |
https://api.github.com/ |
API endpoint (for GitHub Enterprise Server) |
--proxy |
HTTP proxy URL | |
--token |
GitHub PAT (highest priority) | |
--env-file |
.devlake.env |
Path to env file containing GITHUB_PAT |
--skip-cleanup |
false |
Don't delete .devlake.env after setup |
Token resolution order:
--tokenflag.devlake.envfile (GITHUB_PAT=orGITHUB_TOKEN=orGH_TOKEN=)$GITHUB_TOKEN/$GH_TOKENenvironment variables- Interactive masked prompt (terminal only)
What it does:
- Auto-discovers DevLake instance
- Resolves the GitHub PAT (displays required scopes if prompting interactively)
- Prompts for connection name (Enter accepts default), proxy (Enter skips)
- For GitHub: offers Cloud vs Enterprise Server endpoint choice
- Tests the connection payload (GitHub only)
- Creates the plugin connection
- Saves connection ID to the state file
- Deletes
.devlake.env(tokens now stored encrypted in DevLake)
After creating connections, run configure scopes to create a project and start data collection.
Add repository scopes, create a DORA project with a blueprint, and trigger the first data sync.
# Specify repos directly
gh devlake configure scopes --org my-org --repos my-org/app1,my-org/app2
# Load repos from a file (one owner/repo per line)
gh devlake configure scopes --org my-org --repos-file repos.txt
# Interactive selection via gh CLI
gh devlake configure scopes --org my-org
# Custom DORA patterns
gh devlake configure scopes --org my-org --repos my-org/app1 \
--deployment-pattern "(?i)(deploy|release)" \
--production-pattern "(?i)(prod|production)" \
--incident-label "bug/incident"| Flag | Default | Description |
|---|---|---|
--org |
GitHub organization slug | |
--repos |
Comma-separated repos (owner/repo) |
|
--repos-file |
Path to file with repos (one per line) | |
--project-name |
(org name) | DevLake project name |
--deployment-pattern |
(?i)deploy |
Regex matching deployment CI/CD workflows |
--production-pattern |
(?i)prod |
Regex matching production environments |
--incident-label |
incident |
Issue label identifying incidents |
--cron |
0 0 * * * |
Blueprint sync schedule (daily midnight) |
--time-after |
(6 months ago) | Only collect data after this date |
--skip-copilot |
false |
Skip adding Copilot org scope |
--skip-sync |
false |
Skip triggering the first data sync |
--wait |
true |
Wait for pipeline to complete |
--timeout |
5m |
Max time to wait for pipeline |
--github-connection-id |
(auto) | Override auto-detected GitHub connection ID |
--copilot-connection-id |
(auto) | Override auto-detected Copilot connection ID |
What it does:
- Discovers DevLake and resolves connection IDs (from state file or API)
- Resolves repos (from flag, file, or interactive
gh repo listselection) - Looks up repo details via
gh api repos/<owner>/<repo> - Creates a DORA scope config (deployment/production patterns, incident label)
- Adds repo scopes to the GitHub connection
- Adds Copilot org scope (unless
--skip-copilot) - Creates a DevLake project with DORA metrics enabled
- Configures the project's blueprint with connection scopes
- Triggers the first data sync and monitors the pipeline
Combine connections + scopes configuration in one step (Phase 2 + Phase 3).
gh devlake configure full --org my-org --repos my-org/app1,my-org/app2
gh devlake configure full --org my-org --repos-file repos.txt
gh devlake configure full --org my-org --enterprise my-ent --skip-syncAccepts all flags from both configure connections and configure scopes. Runs Phase 2 first, then Phase 3 — wiring connection IDs automatically between the two phases.
Tear down DevLake resources. Auto-detects deployment type from state files.
gh devlake cleanup # auto-detect mode
gh devlake cleanup --local # stop Docker Compose containers
gh devlake cleanup --azure --force # delete Azure resource group (no prompt)| Flag | Default | Description |
|---|---|---|
--azure |
false |
Force Azure cleanup mode |
--local |
false |
Force local cleanup mode |
--force |
false |
Skip confirmation prompt |
--keep-resource-group |
false |
Delete resources but keep the Azure RG |
--state-file |
(auto) | Path to state file |
The extension never stores your PAT in command history or logs:
- Create a
.devlake.envfile:GITHUB_TOKEN=ghp_your_token_here - Run the configure command — the token is read from the file:
gh devlake configure connections --org my-org
- After success,
.devlake.envis automatically deleted (use--skip-cleanupto keep it). Tokens are now stored encrypted in DevLake's database.
The .devlake.env file is in .gitignore by default.
| File | Created By | Purpose |
|---|---|---|
.devlake-azure.json |
deploy azure |
Azure resources, endpoints, suffix |
.devlake-local.json |
configure connections |
Endpoints, connection IDs (local deploys) |
.devlake.env |
User (Phase 2) | Ephemeral — PATs for connection creation, auto-deleted |
State files enable command chaining — configure scopes reads connection IDs saved by configure connections, so you don't need to pass --github-connection-id.
# 1. Install
gh extension install DevExpGBB/gh-devlake
# 2. Deploy DevLake locally
gh devlake deploy local --dir ./devlake
cd devlake && docker compose up -d
# Wait ~2 minutes for services to start
# 3. Check health
gh devlake status
# 4. Create a secrets file (paste your PAT, save it)
echo "GITHUB_TOKEN=" > .devlake.env
# Edit .devlake.env and add your PAT after the =
# 5. Configure everything
gh devlake configure full --org my-org --repos my-org/app1,my-org/app2
# 6. Open Grafana dashboards
# http://localhost:3002 (admin/admin)
# Navigate to DORA dashboard
# 7. When done, tear down
gh devlake cleanup --local| Flag | Default | Description |
|---|---|---|
--url |
(auto-discovered) | DevLake API base URL |
--help |
Show help for any command |
Use --url to target a specific DevLake instance. If omitted, the extension auto-discovers from state files or well-known localhost ports.
go build -o gh-devlake.exe . # Build (Windows)
go build -o gh-devlake . # Build (Linux/macOS)
go test ./... -v # Run tests
gh extension install . # Install locally for testing├── main.go # Entry point
├── cmd/ # Cobra command tree
│ ├── root.go # Root command + global flags
│ ├── status.go # status — health + connections
│ ├── deploy.go # deploy parent + cleanup wiring
│ ├── deploy_local.go # deploy local (Docker Compose)
│ ├── deploy_azure.go # deploy azure (Bicep)
│ ├── cleanup.go # cleanup (Azure + local)
│ ├── configure.go # configure parent command
│ ├── configure_connections.go # configure connections (single plugin)
│ ├── configure_scopes.go # configure scopes + project + sync
│ ├── configure_full.go # configure full (connections + scopes)
│ ├── connection_types.go # plugin registry & connection builder
├── internal/
│ ├── azure/ # Azure CLI wrapper + embedded Bicep
│ ├── devlake/ # DevLake REST API client + discovery
│ ├── docker/ # Docker CLI wrapper
│ ├── download/ # HTTP download + GitHub releases
│ ├── envfile/ # .devlake.env parser
│ ├── gh/ # GitHub CLI wrapper (repo lookup)
│ ├── prompt/ # Interactive terminal prompts
│ ├── repofile/ # Repo list file parser (CSV/TXT)
│ ├── secrets/ # Cryptographic secret generation
│ └── token/ # PAT resolution chain
└── LICENSE
MIT — see LICENSE.