Skip to content

gh command not found #2696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
GeorgeXCV opened this issue Mar 17, 2025 · 1 comment
Open

gh command not found #2696

GeorgeXCV opened this issue Mar 17, 2025 · 1 comment
Labels
kind/bug Something isn't working

Comments

@GeorgeXCV
Copy link

Bug report info

WARN  ⚠ You are using Apple M-series chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠  
[Generate PR Dashboard for Slack/generate_dashboard] 🚀  Start image=catthehacker/ubuntu:act-latest
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
[Generate PR Dashboard for Slack/generate_dashboard] using DockerAuthConfig authentication for docker pull
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/***/null"] cmd=[] network="host"
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/***/null"] cmd=[] network="host"
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[Generate PR Dashboard for Slack/generate_dashboard] ⭐ Run Main Generate PR Dashboard for Slack
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/generate_dashboard] user= workdir=
| /var/run/act/workflow/generate_dashboard: line 3: gh: command not found
[Generate PR Dashboard for Slack/generate_dashboard]   ❌  Failure - Main Generate PR Dashboard for Slack
[Generate PR Dashboard for Slack/generate_dashboard] exitcode '127': command not found, please refer to https://github.com/nektos/act/issues/107 for more information
[Generate PR Dashboard for Slack/generate_dashboard] 🏁  Job failed
Error: Job 'generate_dashboard' failed

Command used with act

act -j generate_dashboard --env-file .env -P ubuntu-latest=catthehacker/ubuntu:act-latest

Describe issue

Same error all the time, tried a million docker images, tried adding install to workflow itself and get more errors.

Link to GitHub repository

No response

Workflow content

name: Generate PR Dashboard for Slack

on:
  schedule:
    - cron: '0 9 * * 1-5'  # Run at 9 AM Monday-Friday
  workflow_dispatch:  # Allow manual triggering

jobs:
  generate_dashboard:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: read
      issues: read
    
    steps:
      - name: Generate PR Dashboard for Slack
        id: generate_dashboard
        run: |
          # Get all open PRs
          gh pr list --json number,title,author,createdAt,updatedAt,reviewDecision,isDraft,labels,url --limit 100 > prs.json
          
          # Process the PR data to include author's real name
          jq '[ .[] | {
            number: .number,
            title: .title,
            author: .author.login,
            authorName: .author.login,
            reviewDecision: .reviewDecision,
            isDraft: .isDraft,
            createdAt: .createdAt,
            updatedAt: .updatedAt,
            labels: .labels,
            url: .url
          }]' prs.json > processed_prs.json
          
          # Fetch real names for each unique author
          jq -r '.[] | .author.login' prs.json | sort -u > authors.txt
          while read -r author; do
            # Get user info including real name
            user_info=$(gh api users/$author)
            name=$(echo "$user_info" | jq -r '.name // ""')
            
            # If real name exists, update the author name in the processed data
            if [ -n "$name" ] && [ "$name" != "null" ]; then
              jq --arg author "$author" --arg name "$name" '[ .[] | if .author == $author then .authorName = $name else . end ]' processed_prs.json > temp.json
              mv temp.json processed_prs.json
            fi
          done < authors.txt
          
          # Use the processed data for the rest of the script
          mv processed_prs.json prs.json
          
          # Summary statistics
          TOTAL_PRS=$(jq '. | length' prs.json)
          APPROVED_PRS=$(jq '[.[] | select(.reviewDecision == "APPROVED")] | length' prs.json)
          PENDING_PRS=$(jq '[.[] | select(.reviewDecision == "REVIEW_REQUIRED" and .isDraft == false)] | length' prs.json)
          CHANGES_PRS=$(jq '[.[] | select(.reviewDecision == "CHANGES_REQUESTED")] | length' prs.json)
          DRAFT_PRS=$(jq '[.[] | select(.isDraft == true)] | length' prs.json)
          
          # Create Slack message blocks
          cat > slack_payload.json << EOF
          {
            "blocks": [
              {
                "type": "header",
                "text": {
                  "type": "plain_text",
                  "text": "📊 PR Dashboard - $(date '+%A, %B %d')",
                  "emoji": true
                }
              },
              {
                "type": "section",
                "fields": [
                  {
                    "type": "mrkdwn",
                    "text": "*Total PRs:* $TOTAL_PRS"
                  },
                  {
                    "type": "mrkdwn",
                    "text": "*Approved:* $APPROVED_PRS"
                  },
                  {
                    "type": "mrkdwn",
                    "text": "*Needs Review:* $PENDING_PRS"
                  },
                  {
                    "type": "mrkdwn",
                    "text": "*Changes Requested:* $CHANGES_PRS"
                  }
                ]
              },
              {
                "type": "divider"
              }
            ]
          }
          EOF
          
          # Add PRs waiting for review section if there are any
          if [ "$PENDING_PRS" -gt 0 ]; then
            # Add section header
            jq '.blocks += [{
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": "*⏳ PRs Waiting for Review*"
              }
            }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
            
            # Get PRs waiting for review, sorted by age
            jq -c '.[] | select(.reviewDecision == "REVIEW_REQUIRED" and .isDraft == false) | {
              number: .number,
              title: .title,
              author: .author,
              authorName: .authorName,
              created: .createdAt,
              url: .url,
              age: ((now - (.createdAt | fromdate)) / 86400) | floor
            }' prs.json | jq -s 'sort_by(-.age)' > pending_prs.json
            
            # Add each PR as a separate section (up to 5)
            jq -c '.[:5] | .[]' pending_prs.json | while read -r pr; do
              PR_NUMBER=$(echo "$pr" | jq -r '.number')
              PR_TITLE=$(echo "$pr" | jq -r '.title')
              PR_AUTHOR=$(echo "$pr" | jq -r '.author')
              PR_AGE=$(echo "$pr" | jq -r '.age')
              PR_URL=$(echo "$pr" | jq -r '.url')
              
              # Add emoji based on age
              AGE_EMOJI="🟢"
              if [ "$PR_AGE" -gt 3 ]; then
                AGE_EMOJI="🟠"
              fi
              if [ "$PR_AGE" -gt 5 ]; then
                AGE_EMOJI="🔴"
              fi
              
              jq '.blocks += [{
                "type": "section",
                "text": {
                  "type": "mrkdwn",
                  "text": "'"$AGE_EMOJI"' <'"$PR_URL"'|#'"$PR_NUMBER"': '"${PR_TITLE//\"/\\\"}"'> by '"$PR_AUTHOR"'\n_Waiting for '"$PR_AGE"' days_"
                }
              }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
            done
            
            # Add divider
            jq '.blocks += [{
              "type": "divider"
            }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
          fi
          
          # Add PRs with changes requested section if there are any
          if [ "$CHANGES_PRS" -gt 0 ]; then
            # Add section header
            jq '.blocks += [{
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": "*🔄 PRs with Changes Requested*"
              }
            }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
            
            # Get PRs with changes requested, sorted by age
            jq -c '.[] | select(.reviewDecision == "CHANGES_REQUESTED") | {
              number: .number,
              title: .title,
              author: .author.login,
              updated: .updatedAt,
              url: .url,
              age: ((now - (.updatedAt | fromdate)) / 86400) | floor
            }' prs.json | jq -s 'sort_by(-.age)' > changes_prs.json
            
            # Add each PR as a separate section (up to 5)
            jq -c '.[:5] | .[]' changes_prs.json | while read -r pr; do
              PR_NUMBER=$(echo "$pr" | jq -r '.number')
              PR_TITLE=$(echo "$pr" | jq -r '.title')
              PR_AUTHOR=$(echo "$pr" | jq -r '.author')
              PR_AGE=$(echo "$pr" | jq -r '.age')
              PR_URL=$(echo "$pr" | jq -r '.url')
              
              # Add emoji based on age
              AGE_EMOJI="🟢"
              if [ "$PR_AGE" -gt 3 ]; then
                AGE_EMOJI="🟠"
              fi
              if [ "$PR_AGE" -gt 5 ]; then
                AGE_EMOJI="🔴"
              fi
              
              jq '.blocks += [{
                "type": "section",
                "text": {
                  "type": "mrkdwn",
                  "text": "'"$AGE_EMOJI"' <'"$PR_URL"'|#'"$PR_NUMBER"': '"${PR_TITLE//"/\\\"}\"`"'> by '"$PR_AUTHOR"'\n_Changes requested '"$PR_AGE"' days ago_"
                }
              }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
            done
            
            # Add divider
            jq '.blocks += [{
              "type": "divider"
            }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
          fi
          
          # Add footer with link to all PRs
          jq '.blocks += [{
            "type": "context",
            "elements": [{
              "type": "mrkdwn",
              "text": "<https://github.com/${{ github.repository }}/pulls|View all open PRs> • <https://github.com/${{ github.repository }}/pulls?q=is%3Apr+is%3Aopen+review%3Arequired|Needs review> • <https://github.com/${{ github.repository }}/pulls?q=is%3Apr+is%3Aopen+review%3Achanges_requested|Changes requested>"
            }]
          }]' slack_payload.json > temp.json && mv temp.json slack_payload.json
          
          # Send to Slack
          curl -X POST \
            -H 'Content-type: application/json' \
            --data @slack_payload.json \
            ${{ secrets.SLACK_WEBHOOK_CHANNEL }}
          
          echo "Dashboard sent to #test Slack channel"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CHANNEL }}

Relevant log output

WARN  ⚠ You are using Apple M-series chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠  
[Generate PR Dashboard for Slack/generate_dashboard] 🚀  Start image=catthehacker/ubuntu:act-latest
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
[Generate PR Dashboard for Slack/generate_dashboard] using DockerAuthConfig authentication for docker pull
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/***/null"] cmd=[] network="host"
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/***/null"] cmd=[] network="host"
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[Generate PR Dashboard for Slack/generate_dashboard] ⭐ Run Main Generate PR Dashboard for Slack
[Generate PR Dashboard for Slack/generate_dashboard]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/generate_dashboard] user= workdir=
| /var/run/act/workflow/generate_dashboard: line 3: gh: command not found
[Generate PR Dashboard for Slack/generate_dashboard]   ❌  Failure - Main Generate PR Dashboard for Slack
[Generate PR Dashboard for Slack/generate_dashboard] exitcode '127': command not found, please refer to https://github.com/nektos/act/issues/107 for more information
[Generate PR Dashboard for Slack/generate_dashboard] 🏁  Job failed
Error: Job 'generate_dashboard' failed

Additional information

No response

@GeorgeXCV GeorgeXCV added the kind/bug Something isn't working label Mar 17, 2025
@mcascone
Copy link

act images don't include some very basic tools, including gh, jq, gcloud cli, etc. You can pull the much larger catthehacker images, or install just what you need on local images you build yourself. I did that here: #1799

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants