Docker image pr fix
Skill opensourceways/agent-skills/skills/infrastructure/docker-image-pr-fix
Automatically analyze and fix CI-failed Pull Requests on GitCode/GitHub. Use when a PR has failed CI checks and needs diagnosis and repair. Triggers include "fix this PR", "repair failed CI", "analyze PR failure", or when given a PR URL with CI failures. Works with any Docker-based CI/CD pipeline and automatically creates a new PR with fixes.From its SKILL.md
npx -y skills add opensourceways/agent-skills --skill docker-image-pr-fixAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.7 KB, as published. Nobody here has run it
Fix Failed CI PR
Automatically diagnose and fix CI failures in Pull Requests, then create a new PR with the solution. Works with GitCode and GitHub repositories using Docker-based CI pipelines.
Workflow
1. Parse Input and Extract Repository Info
Accept PR reference in two formats:
- Full URL:
https://gitcode.com/{owner}/{repo}/pull/{number} - PR number only:
{number}(infers repo from git remotes)
Extract from arguments:
- PR number
- Repository owner and name
- Git platform (GitCode/GitHub)
If only PR number provided, infer from git remotes:
# Get upstream remote URL
UPSTREAM_URL=$(git remote get-url upstream)
# Example: https://gitcode.com/openeuler/openeuler-docker-images.git
# Parse to extract: owner=openeuler, repo=openeuler-docker-images
2. Fetch PR Metadata via API
Use platform API to retrieve PR details.
GitCode API:
TOKEN=$(python3 -c "import urllib.parse; line=[l for l in open('/root/.git-credentials') if 'gitcode' in l][0]; token=urllib.parse.urlparse(line.strip()).password; print(token)")
curl -s "https://gitcode.com/api/v5/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}?access_token=$TOKEN"
GitHub API:
TOKEN=$(python3 -c "import urllib.parse; line=[l for l in open('/root/.git-credentials') if 'github' in l][0]; token=urllib.parse.urlparse(line.strip()).password; print(token)")
curl -s -H "Authorization: token $TOKEN" "https://api.github.com/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}"
Extract key information:
title: PR titlelabels: Verify failure labels (ci_failed, failing, etc.)head.ref: Source branch namehead.repo.full_name: Source repositorybase.ref: Target branch (master/main)body: PR description
3. Analyze PR Changes
Fetch and examine the source branch:
# Find the remote for source repository
SOURCE_REMOTE=$(git remote -v | grep "${HEAD_REPO_OWNER}" | head -1 | awk '{print $1}')
# Fetch source branch
git fetch ${SOURCE_REMOTE} "${HEAD_REF}"
# View changed files
git diff upstream/${BASE_BRANCH}...FETCH_HEAD --name-only
# Examine full diff (focus on Dockerfiles)
git diff upstream/${BASE_BRANCH}...FETCH_HEAD
4. Retrieve CI Failure Logs
Extract CI log links from PR comments:
# GitCode
curl -s "https://gitcode.com/api/v5/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}/comments?access_token=$TOKEN&per_page=100"
# GitHub
curl -s -H "Authorization: token $TOKEN" "https://api.github.com/repos/${OWNER}/${REPO}/issues/${PR_NUMBER}/comments?per_page=100"
Search for comments containing failure indicators:
- Keywords:
FAILED,check_build,ci_failed,Actions failed - Extract Jenkins/GitHub Actions log URLs
Use WebFetch to read log content and locate error lines. Focus on:
- First occurrence of
Error:orerror: - Architecture-specific failures (x86_64 vs aarch64)
- Truncated logs (check content before "Content truncated")
5. Diagnose Failure Pattern
Analyze the error logs to identify the failure mode:
Pattern A: Upstream Binary Package Unavailable
Symptoms: Download returns 404, "Not Found" errors
Verification:
curl -sI <package_download_url> | grep "HTTP"
Fix Strategy: Multi-stage Docker build copying from official image
ARG VERSION=x.y.z
FROM upstream/official-image:v${VERSION} AS source
FROM base-image:tag
COPY --from=source /path/to/binary /path/to/binary
Validation:
- Search DockerHub/Quay for official image
docker pulland locate binary:docker run --rm --entrypoint which <image> <binary>
Pattern B: Dependency Compatibility Issues
Symptoms: ImportError, AttributeError, ModuleNotFoundError
Fix Strategy:
- Pin dependency versions:
RUN pip install package==x.y.z - Patch configuration:
RUN sed -i 's/old/new/' script.sh - Upgrade/downgrade toolchain
Pattern C: CI Infrastructure Issues
Symptoms: Error occurs in CI script stage (not Docker build)
Indicators:
- Partial architecture success (aarch64 ✓, x86_64 ✗)
- Errors from CI tools themselves (eulerpublisher)
Fix Strategy: Comment /retest to trigger retry
Pattern D: Source Code/Configuration Errors
Symptoms: Build errors, syntax errors, configuration format errors
D1: Missing System Packages
- Error:
command not found: groupadd,command not found: make - Fix: Install required packages
# Missing groupadd/useradd RUN yum install -y shadow-utils # Missing make/gcc RUN yum install -y make gcc # Missing autoconf RUN yum install -y autoconf automake
D2: Shell Syntax Errors
- Error: Variable expansion issues, command substitution errors
- Common mistakes:
$nprocshould be$(nproc)for command substitution- Unescaped special characters
- Fix: Correct shell syntax
# Wrong RUN make -j$nproc # Correct RUN make -j$(nproc)
D3: Dockerfile Logic Errors
- Error: Step ordering issues, path errors, ARG/ENV misuse
- Fix: Reorganize Dockerfile structure
6. Implement Fix
Create a new branch and apply fixes:
# Create fix branch based on target branch
git checkout -b fix/<component>-<version> upstream/${BASE_BRANCH}
Modify files (common Docker image repository structure):
<Category>/<component>/<version>/<base-version>/Dockerfile<Category>/<component>/<version>/<base-version>/*.yaml<Category>/<component>/meta.yml<Category>/<component>/README.md<Category>/<component>/doc/image-info.yml
Maintain consistent formatting with other versions in the same directory.
7. Commit and Push
git add <modified_files>
git commit -m "Fix <component> <version> build failure
Fix PR #${ORIGINAL_PR_NUMBER} CI failure: <brief_reason>.
<detailed_fix_description>
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>"
git push origin fix/<component>-<version>
8. Create New PR via API
Use platform API to create the fix PR:
import urllib.request, urllib.parse, json
# Read token
with open("/root/.git-credentials") as f:
for line in f:
if "gitcode" in line or "github" in line:
token = urllib.parse.urlparse(line.strip()).password
platform = "gitcode" if "gitcode" in line else "github"
break
# Get current user
current_user = $(git config --get user.name)
# Construct API request
if platform == "gitcode":
api_url = f"https://gitcode.com/api/v5/repos/{owner}/{repo}/pulls"
data = {
"access_token": token,
"title": f"Fix {component} {version} build (fix #{original_pr})",
"head": f"{current_user}:fix/{component}-{version}",
"base": base_branch,
"body": f"{original_body}\n\n## Fix\n{fix_description}"
}
headers = {"Content-Type": "application/json", "PRIVATE-TOKEN": token}
else: # GitHub
api_url = f"https://api.github.com/repos/{owner}/{repo}/pulls"
data = {
"title": f"Fix {component} {version} build (fix #{original_pr})",
"head": f"{current_user}:fix/{component}-{version}",
"base": base_branch,
"body": f"{original_body}\n\n## Fix\n{fix_description}"
}
headers = {"Content-Type": "application/json", "Authorization": f"token {token}"}
req = urllib.request.Request(api_url, data=json.dumps(data).encode(), headers=headers, method="POST")
9. Verify New PR CI Status
- Wait 2-3 minutes for CI to start
- Poll PR comments for CI status
- If still failing:
- CI infrastructure issue: Comment
/retest - Code issue: Return to step 5 for re-analysis
- CI infrastructure issue: Comment
Failure Pattern Decision Tree
CI Failed
├─ Error in CI script stage?
│ ├─ Yes → Pattern C (Infrastructure) → /retest
│ └─ No → Continue
│
├─ Download returns 404?
│ ├─ Yes → Pattern A (Package unavailable) → Multi-stage build
│ └─ No → Continue
│
├─ "command not found"?
│ ├─ Yes → Pattern D1 (Missing package) → yum install
│ └─ No → Continue
│
├─ Shell variable/syntax issue?
│ ├─ Yes → Pattern D2 (Syntax) → Fix syntax
│ └─ No → Continue
│
└─ ImportError / dependency error?
└─ Yes → Pattern B (Compatibility) → Pin versions/sed fix
Error Message Quick Reference
| Error Message | Pattern | Typical Fix |
|---|---|---|
404 Not Found (download failure) | A | Multi-stage build from official image |
command not found: groupadd | D1 | yum install -y shadow-utils |
command not found: make | D1 | yum install -y make |
ImportError: cannot import | B or C | Check if eulerpublisher issue; else fix deps |
$nproc not expanded | D2 | Change to $(nproc) |
pip install compatibility | B | Pin version or sed fix script |
| Single arch failure + eulerpublisher | C | /retest |
autoreconf: command not found | D1 | yum install -y autoconf automake |
Handling Special Cases
Different Architecture Failures
Both architectures fail: Indicates code/dependency issue Single architecture fails: Likely CI infrastructure problem
Compare logs from both architectures to identify patterns.
Log Truncation
Jenkins logs may be truncated due to length. When using WebFetch:
- Focus on lines before "Content truncated"
- Search for keywords:
Error,error,FAILED,命令未找到 - Check both architecture-specific logs
Complex Errors Requiring Manual Intervention
If automated diagnosis is inconclusive:
- Document findings from log analysis
- Suggest potential approaches
- Request user decision before implementing fixes
Shell Variable Expansion
Distinguish between:
$var- Variable reference$(cmd)- Command substitution${var}- Variable expansion (recommended, more explicit)
Prerequisites
Environment
- Target repository cloned locally
- Git remotes configured:
origin: Your fork repositoryupstream: Main repository (merge target)
Credentials
- GitCode/GitHub token stored in
~/.git-credentials - Format:
https://username:[email protected]orhttps://username:[email protected] - File permissions: 600
Tools
curl: API requestspython3: JSON parsing and API callsdocker: Image verification (optional)git: Version control
Output Format
After completion, output:
✅ PR Fix Complete
📋 Original PR: #<number> - <title>
🔍 Root Cause: <root_cause>
🛠️ Fix Strategy: <fix_strategy>
🔗 New PR: #<new_number>
URL: <pr_url>
⏳ CI Status: <ci_status>
- x86_64: <status>
- aarch64: <status>
💡 Suggestion: <next_steps_if_needed>
Success Stories
| PR # | Application | Issue Type | Fix PR | Status |
|---|---|---|---|---|
| #1838 | grafana-agent 0.44.7 | Pattern A - RPM unavailable | #1857 | ✅ Success (aarch64 ✓, x86_64 needs retest) |
| #1837 | mlflow 3.9.0 | Pattern D1 - Missing shadow-utils | #1858 | ⏳ CI running |
| #1835 | snort3 3.10.2.0 | Pattern D2 - Shell syntax error | #1859 | ⏳ CI running |
Important Notes
- Permissions: Requires push access to fork repository
- Token Security: Ensure
~/.git-credentialshas 600 permissions - Parallel Builds: Different architectures may have different results
- Automation Limits: Complex errors may need manual intervention
- Log Analysis: Prioritize failed architecture logs; compare both when both fail
Troubleshooting Tips
Quick Error Type Identification
-
Check error stage:
- CI script stage (eulerpublisher errors) → Pattern C
- Docker build stage → Continue diagnosis
-
Check architecture failure pattern:
- Both architectures fail → Code/dependency issue
- Single architecture fails → Possible CI infrastructure issue
-
Find key error messages:
command not found → Missing system package (Pattern D1) HTTP 404 → Upstream package unavailable (Pattern A) ImportError → Dependency compatibility (Pattern B) syntax error → Shell/Dockerfile syntax (Pattern D2) $variable unexpanded → Command substitution syntax (Pattern D2)
Common Pitfalls
-
Don't only check the last line: Real error may be earlier. Look for first
Error:occurrence. -
Watch for log truncation: Use WebFetch to get critical sections.
-
Verify fixes before pushing (optional):
cd <Dockerfile_directory> docker build -t test:local .