Another Copilot CLI issue #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 🤖 GitHub Copilot Coder (Master) | |
| # This is a reusable workflow that can be called from other repositories. | |
| # It contains the full implementation logic for the Copilot Coder. | |
| # | |
| # To use this workflow from another repository, create a caller workflow: | |
| # jobs: | |
| # copilot: | |
| # uses: <org>/GHES_CodingAgent/.github/workflows/copilot-coder-master.yml@main | |
| # secrets: inherit | |
| on: | |
| # Direct trigger (for this repository) | |
| issues: | |
| types: [labeled] | |
| # Reusable workflow trigger (for other repositories) | |
| workflow_call: | |
| secrets: | |
| GH_TOKEN: | |
| description: 'Classic PAT with repo and workflow scopes' | |
| required: true | |
| COPILOT_TOKEN: | |
| description: 'Token for GitHub Copilot API access' | |
| required: true | |
| CONTEXT7_API_KEY: | |
| description: 'API key for Context7 documentation service' | |
| required: false | |
| jobs: | |
| copilot-cli: | |
| # Only run when the issue has the 'copilot' label | |
| if: contains(github.event.issue.labels.*.name, 'copilot') | |
| runs-on: self-hosted | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| env: | |
| MODEL: claude-haiku-4.5 | |
| COPILOT_VERSION: 0.0.352 | |
| # Extract hostname from server URL (removes https:// prefix) | |
| GHES_HOSTNAME: ${{ github.server_url }} | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| ISSUE_TITLE: ${{ github.event.issue.title }} | |
| ISSUE_BODY: ${{ github.event.issue.body }} | |
| ISSUE_ASSIGNEE: ${{ github.event.issue.assignee.login }} | |
| ISSUE_CREATOR: ${{ github.event.issue.user.login }} | |
| REPO_NAME: ${{ github.repository }} | |
| BRANCH_NAME: copilot/${{ github.event.issue.number }} | |
| steps: | |
| - name: 🚀 Start Workflow | |
| run: | | |
| echo "🚀 GitHub Copilot Coder workflow started!" | |
| echo "═══════════════════════════════════════════════════════════" | |
| echo "📋 Issue: #${ISSUE_NUMBER}" | |
| echo "📌 Title: ${ISSUE_TITLE}" | |
| echo "👤 Creator: ${ISSUE_CREATOR}" | |
| echo "📦 Repository: ${REPO_NAME}" | |
| echo "🌿 Branch: ${BRANCH_NAME}" | |
| echo "═══════════════════════════════════════════════════════════" | |
| env: | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| ISSUE_TITLE: ${{ github.event.issue.title }} | |
| ISSUE_CREATOR: ${{ github.event.issue.user.login }} | |
| REPO_NAME: ${{ github.repository }} | |
| BRANCH_NAME: copilot/${{ github.event.issue.number }} | |
| - name: 🔐 Configure Git Credentials for GHES | |
| run: | | |
| # Extract hostname from server URL (remove https:// prefix) | |
| GHES_HOST=$(echo "${{ github.server_url }}" | sed 's|https://||') | |
| echo "GHES_HOST=${GHES_HOST}" >> $GITHUB_ENV | |
| git config --global credential.helper store | |
| echo "https://x-access-token:${{ github.token }}@${GHES_HOST}" >> ~/.git-credentials | |
| chmod 600 ~/.git-credentials | |
| echo "✅ Git credentials configured for GHES (${GHES_HOST})" | |
| - name: 📥 Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ github.token }} | |
| persist-credentials: true | |
| - name: 🔐 Configure GitHub CLI for GHES | |
| run: | | |
| # Configure gh to use GHES instance (GHES_HOST set in previous step) | |
| gh auth login --hostname "${GHES_HOST}" --with-token <<< "${{ secrets.GH_TOKEN }}" | |
| gh auth status --hostname "${GHES_HOST}" | |
| echo "✅ GitHub CLI configured for GHES (${GHES_HOST})" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: 🏷️ Update Issue Labels - In Progress | |
| run: | | |
| gh issue edit ${{ env.ISSUE_NUMBER }} \ | |
| --add-label "in-progress" \ | |
| --remove-label "copilot" | |
| # Add comment to notify that Copilot is working on this issue | |
| COMMENT="## 🤖 Copilot is on it! | |
| Copilot has been assigned to work on this issue. You can view progress under [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}), and once completed a PR will be linked here." | |
| gh issue comment "${{ env.ISSUE_NUMBER }}" --body "${COMMENT}" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: 🐍 Setup Python (Latest) | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.x' | |
| - name: 📦 Install uv/uvx | |
| run: | | |
| echo "Installing uvx (pipx runner)..." | |
| pip install --upgrade pip | |
| pip install uv | |
| echo "✅ Python and uv installed" | |
| python --version | |
| uv --version | |
| - name: ⚙️ Setup Node.js 22.x | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22.x' | |
| - name: 🔍 Detect NPM Global Path | |
| id: npm-path | |
| run: | | |
| NPM_PREFIX=$(npm config get prefix) | |
| echo "NPM_GLOBAL_PATH=${NPM_PREFIX}/lib/node_modules" >> $GITHUB_ENV | |
| echo "NPM global path: ${NPM_PREFIX}/lib/node_modules" | |
| - name: 📦 Cache Global NPM Packages | |
| uses: actions/cache@v3 | |
| with: | |
| key: npm-global-${{ runner.os }}-copilot-${{ env.COPILOT_VERSION }} | |
| path: ${{ env.NPM_GLOBAL_PATH }} | |
| restore-keys: | | |
| npm-global-${{ runner.os }}-copilot- | |
| - name: 📦 Install Copilot CLI | |
| run: | | |
| if ! command -v copilot &> /dev/null; then | |
| echo "Installing @github/copilot@${{ env.COPILOT_VERSION }}..." | |
| npm install -g @github/copilot@${{ env.COPILOT_VERSION }} | |
| else | |
| echo "✅ @github/copilot already installed (from cache)" | |
| copilot --version | |
| fi | |
| - name: ⚙️ Configure MCP Servers | |
| run: | | |
| mkdir -p ~/.config | |
| # Fetch mcp-config.json from the central GHES_CodingAgent repository | |
| echo "📥 Fetching MCP configuration from GHES_CodingAgent..." | |
| GHES_HOST=$(echo "${{ github.server_url }}" | sed 's|https://||') | |
| OWNER="${{ github.repository_owner }}" | |
| # Determine API base URL | |
| if [[ "$GHES_HOST" == "github.com" ]]; then | |
| API_BASE="https://api.github.com" | |
| else | |
| API_BASE="https://$GHES_HOST/api/v3" | |
| fi | |
| # Download mcp-config.json from GHES_CodingAgent repo | |
| curl -s \ | |
| -H "Authorization: Bearer ${{ secrets.GH_TOKEN }}" \ | |
| -H "Accept: application/vnd.github.v3.raw" \ | |
| "$API_BASE/repos/$OWNER/GHES_CodingAgent/contents/mcp-config.json" \ | |
| > ~/.config/mcp-config.json | |
| if [ -s ~/.config/mcp-config.json ]; then | |
| echo "✅ MCP configuration downloaded to ~/.config/mcp-config.json" | |
| cat ~/.config/mcp-config.json | |
| else | |
| echo "❌ Failed to download MCP configuration" | |
| exit 1 | |
| fi | |
| - name: 🧰 Check MCP Access | |
| run: | | |
| echo "🧰 Verifying MCP server access..." | |
| copilot -p "List tools defined in the current chat session (do not run commands, I am asking about tools defined in the LLM). Just the names in a table, nothing else." --allow-all-tools | |
| env: | |
| GH_TOKEN: ${{ secrets.COPILOT_TOKEN }} | |
| CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }} | |
| - name: 🌿 Create Feature Branch | |
| run: | | |
| echo "🌿 Creating feature branch..." | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git checkout -b ${{ env.BRANCH_NAME }} | |
| echo "✅ Branch ${{ env.BRANCH_NAME }} created" | |
| - name: 🤖 Implement Changes with Copilot | |
| timeout-minutes: 30 | |
| working-directory: ${{ github.workspace }} | |
| run: | | |
| echo "🤖 Running GitHub Copilot CLI..." | |
| echo "═══════════════════════════════════════════════════════════" | |
| echo "📋 Issue: #${ISSUE_NUMBER}" | |
| echo "📌 Title: ${ISSUE_TITLE}" | |
| echo "🗂️ Working Directory: $(pwd)" | |
| echo "═══════════════════════════════════════════════════════════" | |
| echo "This is the description that Copilot CLI is going to use to implement the task:" | |
| echo "${ISSUE_BODY}" | |
| mkdir -p logs | |
| # Save issue body to file to avoid injection | |
| printf '%s' "${ISSUE_BODY}" > /tmp/issue_description.txt | |
| # Run Copilot with file input | |
| # Note: -p flag runs in non-interactive mode | |
| # --add-dir allows Copilot to access files in the workspace directory | |
| copilot -p "Implement the GitHub issue following the description details: $(cat /tmp/issue_description.txt)" \ | |
| --add-dir "$(pwd)" \ | |
| --allow-all-tools \ | |
| --log-level all \ | |
| --log-dir logs \ | |
| --model "${MODEL}" | |
| # Clean up | |
| rm -f /tmp/issue_description.txt | |
| echo "✅ Implementation completed" | |
| env: | |
| GH_TOKEN: ${{ secrets.COPILOT_TOKEN }} | |
| CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }} | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| ISSUE_TITLE: ${{ github.event.issue.title }} | |
| ISSUE_BODY: ${{ github.event.issue.body }} | |
| MODEL: ${{ env.MODEL }} | |
| - name: 💾 Commit Changes | |
| run: | | |
| echo "📝 Preparing commit..." | |
| # Co-author info from issue creator | |
| CREATOR_NAME="${ISSUE_CREATOR}" | |
| CREATOR_EMAIL="${ISSUE_CREATOR}@users.noreply.github.com" | |
| echo "👤 Co-author: ${CREATOR_NAME} <${CREATOR_EMAIL}>" | |
| # Add all files except metadata files | |
| git add . | |
| # Exclude metadata files from commit | |
| for file in copilot-summary.md commit-message.md .final-commit-msg.txt .github/copilot-instructions.md; do | |
| if git ls-files --cached "$file" > /dev/null 2>&1; then | |
| git reset HEAD "$file" 2>/dev/null || true | |
| fi | |
| done | |
| # Check if there are any staged changes | |
| if ! git diff --cached --quiet; then | |
| echo "✅ Changes staged for commit" | |
| else | |
| echo "⚠️ No changes staged for commit" | |
| fi | |
| # Prepare final commit message with co-author | |
| if [ -f "commit-message.md" ]; then | |
| echo "✅ Using Copilot-generated commit message" | |
| { | |
| cat commit-message.md | |
| echo "" | |
| echo "" | |
| echo "Co-authored-by: ${CREATOR_NAME} <${CREATOR_EMAIL}>" | |
| } > .final-commit-msg.txt | |
| else | |
| echo "⚠️ commit-message.md not found, using default message" | |
| { | |
| echo "feat: Implement issue ${ISSUE_NUMBER}" | |
| echo "" | |
| echo "${ISSUE_TITLE}" | |
| echo "" | |
| echo "Changes implemented by GitHub Copilot CLI" | |
| echo "" | |
| echo "Co-authored-by: ${CREATOR_NAME} <${CREATOR_EMAIL}>" | |
| } > .final-commit-msg.txt | |
| fi | |
| # Create commit if there are staged changes | |
| if git diff --cached --quiet; then | |
| echo "⚠️ No staged changes to commit, skipping git commit" | |
| else | |
| git commit -F .final-commit-msg.txt | |
| echo "✅ Changes committed successfully" | |
| fi | |
| # Clean up | |
| rm -f .final-commit-msg.txt | |
| env: | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| ISSUE_TITLE: ${{ github.event.issue.title }} | |
| ISSUE_CREATOR: ${{ github.event.issue.user.login }} | |
| - name: 🚀 Push Branch | |
| run: | | |
| echo "🚀 Pushing branch to remote..." | |
| # Configure git remote with GH_TOKEN for authentication | |
| REMOTE_URL=$(git remote get-url origin) | |
| if [[ "$REMOTE_URL" == https://* ]]; then | |
| REPO_PATH=$(echo "$REMOTE_URL" | sed 's|https://[^/]*/||') | |
| GITHUB_HOST=$(echo "$REMOTE_URL" | sed 's|https://||' | sed 's|/.*||') | |
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@${GITHUB_HOST}/${REPO_PATH}" | |
| fi | |
| git push -u origin "${{ env.BRANCH_NAME }}" | |
| echo "✅ Branch pushed successfully" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: 📬 Create Pull Request | |
| id: create-pr | |
| run: | | |
| # Check if copilot-summary.md exists | |
| if [ -f "copilot-summary.md" ]; then | |
| PR_BODY=$(cat copilot-summary.md) | |
| else | |
| PR_BODY="## 🤖 Automated Implementation | |
| This PR was automatically generated by GitHub Copilot CLI. | |
| ### 📋 Related Issue | |
| Closes #${ISSUE_NUMBER} | |
| ### 📝 Changes | |
| Please review the changes made by Copilot CLI." | |
| fi | |
| # Save PR body to file to avoid injection | |
| printf '%s' "${PR_BODY}" > /tmp/pr_body.txt | |
| # Create PR and capture URL - use file for body | |
| PR_URL=$(gh pr create \ | |
| --title "${ISSUE_TITLE}" \ | |
| --body-file /tmp/pr_body.txt \ | |
| --base main \ | |
| --head "${BRANCH_NAME}" \ | |
| --assignee "${ISSUE_CREATOR}") | |
| # Clean up | |
| rm -f /tmp/pr_body.txt | |
| echo "PR_URL=${PR_URL}" >> $GITHUB_ENV | |
| echo "✅ Pull Request created: ${PR_URL}" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| ISSUE_TITLE: ${{ github.event.issue.title }} | |
| ISSUE_CREATOR: ${{ github.event.issue.user.login }} | |
| BRANCH_NAME: ${{ env.BRANCH_NAME }} | |
| - name: 💬 Add Completion Comment to Issue | |
| run: | | |
| echo "💬 Adding completion comment to issue #${ISSUE_NUMBER}..." | |
| COMMENT="## 🎉 Implementation Complete! | |
| The GitHub Copilot CLI has successfully implemented the changes for this issue. | |
| ### 📬 Pull Request | |
| A Pull Request has been created with the implementation: | |
| ${PR_URL} | |
| ### 👀 Next Steps | |
| 1. Review the Pull Request | |
| 2. Test the implementation | |
| 3. Approve and merge if everything looks good | |
| ### 📦 Logs | |
| Workflow logs and Copilot execution logs are available in the workflow run artifacts. | |
| --- | |
| *This comment was automatically generated by the GitHub Copilot Coder workflow.*" | |
| gh issue comment "${ISSUE_NUMBER}" --body "${COMMENT}" | |
| echo "✅ Comment added successfully" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| PR_URL: ${{ env.PR_URL }} | |
| - name: 🏷️ Update Issue Labels - Completed | |
| run: | | |
| gh issue edit ${{ env.ISSUE_NUMBER }} \ | |
| --add-label "ready-for-review" \ | |
| --remove-label "in-progress" | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN }} | |
| - name: 📦 Publish Logs | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: copilot-logs | |
| path: logs/ | |
| retention-days: 30 |