Initial commit
This commit is contained in:
272
skills/buildkite-status/references/url-parsing.md
Normal file
272
skills/buildkite-status/references/url-parsing.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# Buildkite URL Parsing Reference
|
||||
|
||||
This document explains Buildkite URL formats and how to extract information from them.
|
||||
|
||||
## URL Formats
|
||||
|
||||
Buildkite uses several URL patterns for builds and jobs:
|
||||
|
||||
### Build URL (Most Common)
|
||||
|
||||
```
|
||||
https://buildkite.com/{org}/{pipeline}/builds/{number}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
https://buildkite.com/gusto/payroll-building-blocks/builds/29627
|
||||
```
|
||||
|
||||
Extracting:
|
||||
|
||||
- `org`: "gusto"
|
||||
- `pipeline`: "payroll-building-blocks"
|
||||
- `number`: "29627"
|
||||
|
||||
### Step/Job URL (From Build Page)
|
||||
|
||||
```
|
||||
https://buildkite.com/{org}/{pipeline}/builds/{number}/steps/{view}?sid={step-id}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
https://buildkite.com/gusto/payroll-building-blocks/builds/29627/steps/canvas?sid=019a5f23-8109-4656-a033-bd62a82ca239
|
||||
```
|
||||
|
||||
Extracting:
|
||||
|
||||
- `org`: "gusto"
|
||||
- `pipeline`: "payroll-building-blocks"
|
||||
- `number`: "29627"
|
||||
- `view`: "canvas" (UI view type)
|
||||
- `sid`: "019a5f23-8109-4656-a033-bd62a82ca239" (step ID)
|
||||
|
||||
**IMPORTANT**: The `sid` (step ID) is NOT the same as job UUID. See "Step IDs vs Job UUIDs" below.
|
||||
|
||||
### Job Detail URL
|
||||
|
||||
```
|
||||
https://buildkite.com/{org}/{pipeline}/builds/{number}/jobs/{job-uuid}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
https://buildkite.com/gusto/payroll-building-blocks/builds/29627/jobs/019a5f20-2d30-4c67-9edd-87fb92e1f487
|
||||
```
|
||||
|
||||
Extracting:
|
||||
|
||||
- `org`: "gusto"
|
||||
- `pipeline`: "payroll-building-blocks"
|
||||
- `number`: "29627"
|
||||
- `job-uuid`: "019a5f20-2d30-4c67-9edd-87fb92e1f487"
|
||||
|
||||
**NOTE**: This format contains the actual job UUID needed for log retrieval.
|
||||
|
||||
## Step IDs vs Job UUIDs
|
||||
|
||||
**Critical distinction**: Buildkite has two types of identifiers that are easily confused.
|
||||
|
||||
### Step IDs
|
||||
|
||||
- **Source**: Query parameter `sid` in step URLs
|
||||
- **Format**: ULID format (e.g., `019a5f23-8109-4656-a033-bd62a82ca239`)
|
||||
- **Purpose**: Frontend UI routing
|
||||
- **Use**: Navigating to specific steps in web UI
|
||||
- **API Usage**: ❌ NOT accepted by MCP tools
|
||||
|
||||
### Job UUIDs
|
||||
|
||||
- **Source**: `uuid` field in API responses
|
||||
- **Format**: ULID format (e.g., `019a5f20-2d30-4c67-9edd-87fb92e1f487`)
|
||||
- **Purpose**: Backend job identification
|
||||
- **Use**: API calls to get logs, job details, etc.
|
||||
- **API Usage**: ✅ Required by MCP `get_logs` tool
|
||||
|
||||
### Why the Confusion?
|
||||
|
||||
Both use ULID format (starts with `019a5f...`), but:
|
||||
|
||||
- Step IDs come from URLs → Web UI routing
|
||||
- Job UUIDs come from API responses → Backend identification
|
||||
|
||||
**You cannot use a step ID for log retrieval.** Always get job UUID from `buildkite:get_build` API.
|
||||
|
||||
## Resolving Step ID to Job UUID
|
||||
|
||||
When given a step URL with `sid` parameter:
|
||||
|
||||
**Step 1: Extract build identifiers**
|
||||
|
||||
```javascript
|
||||
// From: https://buildkite.com/gusto/payroll-building-blocks/builds/29627/steps/canvas?sid=019a5f23...
|
||||
const org = 'gusto';
|
||||
const pipeline = 'payroll-building-blocks';
|
||||
const build = '29627';
|
||||
// Ignore the sid parameter
|
||||
```
|
||||
|
||||
**Step 2: Get job details from API**
|
||||
|
||||
```javascript
|
||||
mcp__MCPProxy__call_tool('buildkite:get_build', {
|
||||
org_slug: org,
|
||||
pipeline_slug: pipeline,
|
||||
build_number: build,
|
||||
detail_level: 'detailed',
|
||||
job_state: 'failed', // If investigating failures
|
||||
});
|
||||
```
|
||||
|
||||
**Step 3: Match job by properties**
|
||||
|
||||
The API response includes all jobs. Match by:
|
||||
|
||||
- `label` field (e.g., "ste rspec", "Rubocop")
|
||||
- `state` field (e.g., "failed")
|
||||
- `type` field (e.g., "script")
|
||||
- `step_key` field if available
|
||||
|
||||
**Step 4: Extract job UUID**
|
||||
|
||||
```javascript
|
||||
// From API response
|
||||
const job = response.jobs.find(
|
||||
(j) => j.label === 'ste rspec' && j.state === 'failed'
|
||||
);
|
||||
const jobUuid = job.uuid; // e.g., "019a5f20-2d30-4c67-9edd-87fb92e1f487"
|
||||
```
|
||||
|
||||
**Step 5: Use job UUID for logs**
|
||||
|
||||
```javascript
|
||||
mcp__MCPProxy__call_tool('buildkite:get_logs', {
|
||||
org_slug: org,
|
||||
pipeline_slug: pipeline,
|
||||
build_number: build,
|
||||
job_id: jobUuid, // NOT the step ID from URL
|
||||
});
|
||||
```
|
||||
|
||||
## Parsing Logic
|
||||
|
||||
### Simple Regex Approach
|
||||
|
||||
```javascript
|
||||
function parseBuildkiteUrl(url) {
|
||||
// Match build URL pattern
|
||||
const buildMatch = url.match(
|
||||
/buildkite\.com\/([^/]+)\/([^/]+)\/builds\/(\d+)/
|
||||
);
|
||||
|
||||
if (!buildMatch) {
|
||||
throw new Error('Invalid Buildkite URL');
|
||||
}
|
||||
|
||||
return {
|
||||
org: buildMatch[1],
|
||||
pipeline: buildMatch[2],
|
||||
buildNumber: buildMatch[3],
|
||||
};
|
||||
}
|
||||
|
||||
// Usage
|
||||
const info = parseBuildkiteUrl(
|
||||
'https://buildkite.com/gusto/payroll-building-blocks/builds/29627'
|
||||
);
|
||||
// => { org: "gusto", pipeline: "payroll-building-blocks", buildNumber: "29627" }
|
||||
```
|
||||
|
||||
### Extracting Step ID (If Needed)
|
||||
|
||||
```javascript
|
||||
function parseStepUrl(url) {
|
||||
const base = parseBuildkiteUrl(url);
|
||||
|
||||
// Extract step ID from query parameter
|
||||
const sidMatch = url.match(/[?&]sid=([^&]+)/);
|
||||
|
||||
return {
|
||||
...base,
|
||||
stepId: sidMatch ? sidMatch[1] : null,
|
||||
};
|
||||
}
|
||||
|
||||
// Usage
|
||||
const info = parseStepUrl(
|
||||
'https://buildkite.com/gusto/payroll-building-blocks/builds/29627/steps/canvas?sid=019a5f23...'
|
||||
);
|
||||
// => { org: "gusto", pipeline: "payroll-building-blocks", buildNumber: "29627", stepId: "019a5f23..." }
|
||||
```
|
||||
|
||||
**Remember**: The `stepId` is useful for debugging but cannot be used for API calls. Always fetch job UUID from the API.
|
||||
|
||||
## Common URL Patterns in Practice
|
||||
|
||||
### Pattern 1: User Shares Failing Build URL
|
||||
|
||||
**URL**: `https://buildkite.com/org/pipeline/builds/123`
|
||||
|
||||
**Workflow**:
|
||||
|
||||
1. Extract org/pipeline/build
|
||||
2. Call `get_build` with `detail_level: "summary"`
|
||||
3. Check build state
|
||||
4. If failed, call `get_build` with `detail_level: "detailed"` and `job_state: "failed"`
|
||||
5. Get logs for each failed job
|
||||
|
||||
### Pattern 2: User Shares Step URL (Clicked on Specific Job)
|
||||
|
||||
**URL**: `https://buildkite.com/org/pipeline/builds/123/steps/canvas?sid=019a5f23...`
|
||||
|
||||
**Workflow**:
|
||||
|
||||
1. Extract org/pipeline/build (ignore `sid`)
|
||||
2. Call `get_build` with `detail_level: "detailed"`
|
||||
3. Find job matching user's intent (often the failed one)
|
||||
4. Extract job UUID
|
||||
5. Get logs for that job
|
||||
|
||||
The `sid` hints at which job the user was looking at, but you must resolve it via the API.
|
||||
|
||||
### Pattern 3: User Provides Job UUID Directly
|
||||
|
||||
**URL**: `https://buildkite.com/org/pipeline/builds/123/jobs/019a5f20-...`
|
||||
|
||||
**Workflow**:
|
||||
|
||||
1. Extract org/pipeline/build/job-uuid
|
||||
2. Call `get_logs` directly with the job UUID
|
||||
3. No resolution needed - this is the actual job UUID
|
||||
|
||||
This is the ideal format but least common in practice.
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### Multiple Jobs with Same Label
|
||||
|
||||
Some pipelines parallelize jobs:
|
||||
|
||||
- "rspec (1/10)"
|
||||
- "rspec (2/10)"
|
||||
- "rspec (3/10)"
|
||||
|
||||
When resolving, match the full label string including the partition number.
|
||||
|
||||
### Dynamic Pipeline Steps
|
||||
|
||||
Some pipelines generate steps dynamically. The step structure may not be predictable from the URL alone. Always query the API to see actual job structure.
|
||||
|
||||
### Retried Jobs
|
||||
|
||||
When jobs are retried, multiple job UUIDs exist for the same step. The API returns the most recent attempt. Check `retries_count` and `retry_source` fields if investigating retry behavior.
|
||||
|
||||
## See Also
|
||||
|
||||
- [SKILL.md](../SKILL.md) - Main skill documentation
|
||||
- [tool-capabilities.md](tool-capabilities.md) - Tool limitations and capabilities
|
||||
- [troubleshooting.md](troubleshooting.md) - Common errors
|
||||
Reference in New Issue
Block a user