act
act copied to clipboard
gh command not found
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
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: https://github.com/nektos/act/issues/1799