@openhands/extensions 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/README.md +3 -2
- package/automations/catalog/github-pr-reviewer.json +1 -1
- package/automations/catalog/github-repo-monitor.json +1 -1
- package/marketplaces/openhands-extensions.json +13 -0
- package/package.json +1 -1
- package/plugins/issue-duplicate-checker/action.yml +2 -2
- package/plugins/pr-review/README.md +1 -1
- package/plugins/qa-changes/action.yml +4 -2
- package/plugins/release-notes/action.yml +3 -2
- package/plugins/release-notes/workflows/release-notes.yml +10 -4
- package/plugins/vulnerability-remediation/README.md +4 -2
- package/plugins/vulnerability-remediation/action.yml +8 -4
- package/pyproject.toml +1 -1
- package/scripts/sync_extensions.py +2 -1
- package/skills/github-actions/.plugin/plugin.json +19 -0
- package/skills/github-actions/README.md +190 -0
- package/skills/github-actions/SKILL.md +44 -0
- package/skills/github-pr-reviewer/SKILL.md +183 -40
- package/skills/github-pr-reviewer/references/state-schema.md +98 -0
- package/skills/github-pr-reviewer/scripts/main.py +625 -0
- package/skills/github-repo-monitor/README.md +1 -1
- package/skills/github-repo-monitor/SKILL.md +9 -9
- package/skills/github-repo-monitor/references/github-api.md +3 -3
- package/skills/github-repo-monitor/scripts/main.py +11 -11
- package/skills/index.js +16 -4
- package/skills/openhands-sdk/SKILL.md +3 -0
- package/skills/slack-channel-monitor/README.md +2 -1
- package/skills/slack-channel-monitor/SKILL.md +22 -4
- package/tests/test_sync_extensions.py +14 -0
- /package/plugins/issue-duplicate-checker/scripts/{post_duplicate_notice.js → post_duplicate_notice.cjs} +0 -0
- /package/plugins/issue-duplicate-checker/scripts/{remove_duplicate_candidate_label.js → remove_duplicate_candidate_label.cjs} +0 -0
- /package/skills/github-pr-reviewer/commands/{pr-reviewer:setup.md → pr-reviewer-setup.md} +0 -0
- /package/skills/github-repo-monitor/commands/{github-monitor:poll.md → github-monitor-poll.md} +0 -0
- /package/skills/incident-retrospective/commands/{incident-retro:setup.md → incident-retro-setup.md} +0 -0
- /package/skills/linear-triage/commands/{linear-triage:setup.md → linear-triage-setup.md} +0 -0
- /package/skills/openhands-automation/commands/{automation:create.md → automation-create.md} +0 -0
- /package/skills/research-brief/commands/{research-brief:setup.md → research-brief-setup.md} +0 -0
- /package/skills/slack-channel-monitor/commands/{slack-monitor:poll.md → slack-monitor-poll.md} +0 -0
- /package/skills/slack-standup-digest/commands/{standup-digest:setup.md → standup-digest-setup.md} +0 -0
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ See [`integrations/README.md`](integrations/README.md), [`automations/README.md`
|
|
|
60
60
|
## Extensions Catalog
|
|
61
61
|
|
|
62
62
|
<!-- BEGIN AUTO-GENERATED CATALOG -->
|
|
63
|
-
This repository contains **2 marketplace(s)** with **
|
|
63
|
+
This repository contains **2 marketplace(s)** with **57 extensions** (47 skills, 10 plugins).
|
|
64
64
|
|
|
65
65
|
### large-codebase
|
|
66
66
|
|
|
@@ -79,7 +79,7 @@ OpenHands skills for interacting, improving, and refactoring large codebases
|
|
|
79
79
|
|
|
80
80
|
Official skills and plugins for OpenHands — the open-source AI software engineer.
|
|
81
81
|
|
|
82
|
-
**
|
|
82
|
+
**53 extensions** (45 skills, 8 plugins)
|
|
83
83
|
|
|
84
84
|
| Name | Type | Description | Commands |
|
|
85
85
|
|------|------|-------------|----------|
|
|
@@ -100,6 +100,7 @@ Official skills and plugins for OpenHands — the open-source AI software engine
|
|
|
100
100
|
| flarglebargle | skill | A test skill that responds to the magic word 'flarglebargle' with a compliment. Use for testing skill activation and ... | — |
|
|
101
101
|
| frontend-design | skill | Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks ... | — |
|
|
102
102
|
| github | skill | Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable a... | — |
|
|
103
|
+
| github-actions | skill | Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating wo... | — |
|
|
103
104
|
| github-pr-review | skill | Post structured PR reviews to GitHub with inline comments/suggestions in a single API call. | `/github-pr-review` |
|
|
104
105
|
| github-pr-reviewer | skill | Create an automation that reviews GitHub pull requests when they are opened or updated. Inspects the diff, changed fi... | `/pr-reviewer:setup` |
|
|
105
106
|
| github-repo-monitor | skill | Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger p... | `/github-monitor:poll` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "github-pr-reviewer",
|
|
3
|
-
"name": "GitHub
|
|
3
|
+
"name": "GitHub Code Review Agent",
|
|
4
4
|
"category": "Code review",
|
|
5
5
|
"description": "Watch pull requests, inspect the diff, and leave a concise review with risks and suggested follow-ups.",
|
|
6
6
|
"requiredIntegrationIds": [
|
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
"popularityRank": 98,
|
|
8
8
|
"estimatedSetupMinutes": 5,
|
|
9
9
|
"prompt": "/github-monitor:poll",
|
|
10
|
-
"exampleImplementation": "Trigger: cron, every minute (configurable)\nRequired secret:
|
|
10
|
+
"exampleImplementation": "Trigger: cron, every minute (configurable)\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN\n\n1. Poll GitHub for new issue and PR comments since the last run.\n2. Match comments containing the trigger phrase (case-insensitive, default: @OpenHands).\n3. Post an acknowledgment comment with a link to the new OpenHands conversation.\n4. Forward follow-up replies in the same thread to the running conversation.\n5. Post the agent's final response back to GitHub when the conversation completes."
|
|
11
11
|
}
|
|
@@ -238,6 +238,19 @@
|
|
|
238
238
|
"workflows"
|
|
239
239
|
]
|
|
240
240
|
},
|
|
241
|
+
{
|
|
242
|
+
"name": "github-actions",
|
|
243
|
+
"source": "./skills/github-actions",
|
|
244
|
+
"description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.",
|
|
245
|
+
"category": "integration",
|
|
246
|
+
"keywords": [
|
|
247
|
+
"github-actions",
|
|
248
|
+
"workflows",
|
|
249
|
+
"ci-cd",
|
|
250
|
+
"automation",
|
|
251
|
+
"actions"
|
|
252
|
+
]
|
|
253
|
+
},
|
|
241
254
|
{
|
|
242
255
|
"name": "github-pr-review",
|
|
243
256
|
"source": "./skills/github-pr-review",
|
package/package.json
CHANGED
|
@@ -258,7 +258,7 @@ runs:
|
|
|
258
258
|
if: inputs.mode == 'issue-check' && steps.parsed_result.outputs.should_comment == 'true'
|
|
259
259
|
uses: actions/github-script@v9
|
|
260
260
|
env:
|
|
261
|
-
ACTION_SCRIPT: ${{ github.action_path }}/scripts/post_duplicate_notice.
|
|
261
|
+
ACTION_SCRIPT: ${{ github.action_path }}/scripts/post_duplicate_notice.cjs
|
|
262
262
|
ISSUE_NUMBER: ${{ inputs.issue-number }}
|
|
263
263
|
SUMMARY: ${{ steps.parsed_result.outputs.summary }}
|
|
264
264
|
CANDIDATE_ISSUES_JSON: ${{ steps.parsed_result.outputs.candidate_issues_json }}
|
|
@@ -341,7 +341,7 @@ runs:
|
|
|
341
341
|
if: inputs.mode == 'remove-label'
|
|
342
342
|
uses: actions/github-script@v9
|
|
343
343
|
env:
|
|
344
|
-
ACTION_SCRIPT: ${{ github.action_path }}/scripts/remove_duplicate_candidate_label.
|
|
344
|
+
ACTION_SCRIPT: ${{ github.action_path }}/scripts/remove_duplicate_candidate_label.cjs
|
|
345
345
|
with:
|
|
346
346
|
github-token: ${{ inputs.github-token }}
|
|
347
347
|
script: |
|
|
@@ -69,7 +69,7 @@ Add the following secrets in your repository settings (**Settings → Secrets an
|
|
|
69
69
|
| `GITHUB_TOKEN` | Auto | Provided automatically by GitHub Actions |
|
|
70
70
|
| `LMNR_SKILLS_API_KEY` | No | Laminar API key (org-level secret; mapped to `LMNR_PROJECT_API_KEY` env var in workflows) |
|
|
71
71
|
|
|
72
|
-
**Note**:
|
|
72
|
+
**Note**: To post review comments from a bot account instead of `GITHUB_TOKEN`, use a bot token scoped to the repository's trust boundary. On **public** repositories, use `OPENHANDS_BOT_GITHUB_PAT_PUBLIC` — a fine-grained token limited to public repositories. On **private** repositories, use a bot token scoped to that repository. Never give a public repository a token that can reach private repositories.
|
|
73
73
|
|
|
74
74
|
### 3. Customize the Workflow (Optional)
|
|
75
75
|
|
|
@@ -119,6 +119,8 @@ runs:
|
|
|
119
119
|
env:
|
|
120
120
|
LLM_API_KEY: ${{ inputs.llm-api-key }}
|
|
121
121
|
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
122
|
+
GITHUB_EVENT_PULL_REQUEST_TITLE: ${{ github.event.pull_request.title }}
|
|
123
|
+
INPUTS_LLM_MODEL: ${{ inputs.llm-model }}
|
|
122
124
|
run: |
|
|
123
125
|
if [ -z "$LLM_API_KEY" ]; then
|
|
124
126
|
echo "Error: llm-api-key is required."
|
|
@@ -130,9 +132,9 @@ runs:
|
|
|
130
132
|
fi
|
|
131
133
|
|
|
132
134
|
echo "PR Number: ${{ github.event.pull_request.number }}"
|
|
133
|
-
echo "PR Title: $
|
|
135
|
+
echo "PR Title: $GITHUB_EVENT_PULL_REQUEST_TITLE"
|
|
134
136
|
echo "Repository: ${{ github.repository }}"
|
|
135
|
-
echo "LLM model: $
|
|
137
|
+
echo "LLM model: $INPUTS_LLM_MODEL"
|
|
136
138
|
|
|
137
139
|
- name: Run QA validation
|
|
138
140
|
if: steps.preflight.outputs.skip != 'true'
|
|
@@ -109,9 +109,10 @@ runs:
|
|
|
109
109
|
shell: bash
|
|
110
110
|
env:
|
|
111
111
|
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
112
|
+
INPUTS_TAG: ${{ inputs.tag }}
|
|
112
113
|
run: |
|
|
113
114
|
if [ -f release_notes.md ]; then
|
|
114
|
-
echo "Updating release notes for tag $
|
|
115
|
-
gh release edit "$
|
|
115
|
+
echo "Updating release notes for tag $INPUTS_TAG"
|
|
116
|
+
gh release edit "$INPUTS_TAG" --notes-file release_notes.md || \
|
|
116
117
|
echo "Note: Could not update release. Release may not exist yet."
|
|
117
118
|
fi
|
|
@@ -38,11 +38,14 @@ jobs:
|
|
|
38
38
|
|
|
39
39
|
- name: Determine tag
|
|
40
40
|
id: get-tag
|
|
41
|
+
env:
|
|
42
|
+
GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }}
|
|
43
|
+
GITHUB_REF_NAME: ${{ github.ref_name }}
|
|
41
44
|
run: |
|
|
42
45
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
43
|
-
echo "tag=$
|
|
46
|
+
echo "tag=$GITHUB_EVENT_INPUTS_TAG" >> $GITHUB_OUTPUT
|
|
44
47
|
else
|
|
45
|
-
echo "tag=$
|
|
48
|
+
echo "tag=$GITHUB_REF_NAME" >> $GITHUB_OUTPUT
|
|
46
49
|
fi
|
|
47
50
|
|
|
48
51
|
- name: Generate Release Notes
|
|
@@ -57,10 +60,13 @@ jobs:
|
|
|
57
60
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
58
61
|
|
|
59
62
|
- name: Display generated notes
|
|
63
|
+
env:
|
|
64
|
+
TAG: ${{ steps.get-tag.outputs.tag }}
|
|
65
|
+
PREVIOUS_TAG: ${{ steps.release-notes.outputs.previous-tag }}
|
|
60
66
|
run: |
|
|
61
|
-
echo "## Release Notes for $
|
|
67
|
+
echo "## Release Notes for $TAG"
|
|
62
68
|
echo ""
|
|
63
|
-
echo "Previous tag: $
|
|
69
|
+
echo "Previous tag: $PREVIOUS_TAG"
|
|
64
70
|
echo "Commits: ${{ steps.release-notes.outputs.commit-count }}"
|
|
65
71
|
echo "Contributors: ${{ steps.release-notes.outputs.contributor-count }}"
|
|
66
72
|
echo "New contributors: ${{ steps.release-notes.outputs.new-contributor-count }}"
|
|
@@ -90,12 +90,14 @@ on:
|
|
|
90
90
|
|
|
91
91
|
### Optional: Use a Bot Account
|
|
92
92
|
|
|
93
|
-
For better PR attribution, use a bot PAT:
|
|
93
|
+
For better PR attribution, use a bot PAT scoped to the repository's trust boundary. On **public** repositories, use the public-scoped token:
|
|
94
94
|
|
|
95
95
|
```yaml
|
|
96
|
-
github-token: ${{ secrets.
|
|
96
|
+
github-token: ${{ secrets.OPENHANDS_BOT_GITHUB_PAT_PUBLIC || secrets.GITHUB_TOKEN }}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
On **private** repositories, use a bot token scoped to that repository instead. Never give a public repository a token that can reach private repositories.
|
|
100
|
+
|
|
99
101
|
## Usage
|
|
100
102
|
|
|
101
103
|
### Automatic Scheduled Scans
|
|
@@ -96,6 +96,10 @@ runs:
|
|
|
96
96
|
env:
|
|
97
97
|
LLM_API_KEY: ${{ inputs.llm-api-key }}
|
|
98
98
|
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
99
|
+
INPUTS_EXTENSIONS_VERSION: ${{ inputs.extensions-version }}
|
|
100
|
+
INPUTS_LLM_MODEL: ${{ inputs.llm-model }}
|
|
101
|
+
INPUTS_SEVERITY_THRESHOLD: ${{ inputs.severity-threshold }}
|
|
102
|
+
INPUTS_MAX_VULNERABILITIES: ${{ inputs.max-vulnerabilities }}
|
|
99
103
|
run: |
|
|
100
104
|
if [ -z "$LLM_API_KEY" ]; then
|
|
101
105
|
echo "Error: llm-api-key is required."
|
|
@@ -108,10 +112,10 @@ runs:
|
|
|
108
112
|
fi
|
|
109
113
|
|
|
110
114
|
echo "Repository: ${{ github.repository }}"
|
|
111
|
-
echo "Extensions Version: $
|
|
112
|
-
echo "LLM Model: $
|
|
113
|
-
echo "Severity Threshold: $
|
|
114
|
-
echo "Max Vulnerabilities: $
|
|
115
|
+
echo "Extensions Version: $INPUTS_EXTENSIONS_VERSION"
|
|
116
|
+
echo "LLM Model: $INPUTS_LLM_MODEL"
|
|
117
|
+
echo "Severity Threshold: $INPUTS_SEVERITY_THRESHOLD"
|
|
118
|
+
echo "Max Vulnerabilities: $INPUTS_MAX_VULNERABILITIES"
|
|
115
119
|
|
|
116
120
|
- name: Run vulnerability scan
|
|
117
121
|
id: scan
|
package/pyproject.toml
CHANGED
|
@@ -143,7 +143,8 @@ def collect_needed_commands() -> list[CommandSpec]:
|
|
|
143
143
|
meta = parse_frontmatter(skill_md.read_text())
|
|
144
144
|
desc = str(meta.get("description", ""))
|
|
145
145
|
for trigger in slash_triggers(meta):
|
|
146
|
-
|
|
146
|
+
# Replace colons with dashes for cross-platform filename compatibility
|
|
147
|
+
cmd_name = trigger.lstrip("/").replace(":", "-")
|
|
147
148
|
cmd_path = skill_dir / "commands" / f"{cmd_name}.md"
|
|
148
149
|
needed.append(CommandSpec(path=cmd_path, trigger=trigger, description=desc))
|
|
149
150
|
return needed
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "github-actions",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "OpenHands",
|
|
7
|
+
"email": "contact@all-hands.dev"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/OpenHands/extensions",
|
|
10
|
+
"repository": "https://github.com/OpenHands/extensions",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"github-actions",
|
|
14
|
+
"workflows",
|
|
15
|
+
"ci-cd",
|
|
16
|
+
"automation",
|
|
17
|
+
"actions"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# GitHub Actions Skill
|
|
2
|
+
|
|
3
|
+
A skill focused on **effectiveness** when working with GitHub Actions — monitoring runs, reading logs, and developing actions with confidence rather than guessing.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This skill provides guidance for:
|
|
8
|
+
- Creating and structuring workflows
|
|
9
|
+
- Building custom composite and reusable actions
|
|
10
|
+
- Testing actions locally (before burning CI minutes) and in CI
|
|
11
|
+
- Debugging failed workflows from real evidence (logs), not assumptions
|
|
12
|
+
- Avoiding common pitfalls around permissions, secrets, and fork PRs
|
|
13
|
+
|
|
14
|
+
## When to Use This Skill
|
|
15
|
+
|
|
16
|
+
- Creating new GitHub Actions workflows
|
|
17
|
+
- Building custom composite or reusable actions
|
|
18
|
+
- Debugging workflow failures
|
|
19
|
+
- Setting up CI/CD pipelines
|
|
20
|
+
- Troubleshooting permission or secret issues
|
|
21
|
+
- Testing actions before merging to main
|
|
22
|
+
|
|
23
|
+
## Cost Awareness
|
|
24
|
+
|
|
25
|
+
Every workflow run consumes CI minutes (billed minutes on private repos, shared capacity on public ones).
|
|
26
|
+
Plan before you push:
|
|
27
|
+
|
|
28
|
+
- Prefer one targeted commit that exercises the change over multiple speculative pushes
|
|
29
|
+
- Use `workflow_dispatch` with inputs to manually trigger only what you need
|
|
30
|
+
- Use `paths:` filters and `if:` conditions so jobs only run when relevant
|
|
31
|
+
- Run with `act` locally before opening a PR when feasible
|
|
32
|
+
- Cancel obsolete runs with `concurrency:` groups (don't pay for runs you've already invalidated)
|
|
33
|
+
- Use the smallest matrix that proves the change works; expand only if needed
|
|
34
|
+
|
|
35
|
+
## Develop With Confidence: The Loop
|
|
36
|
+
|
|
37
|
+
Don't change → push → hope. Use this loop:
|
|
38
|
+
|
|
39
|
+
1. **Read** the existing workflow / action carefully. Note triggers, permissions, inputs, env, and secrets.
|
|
40
|
+
2. **Reproduce locally** with `act` when possible (see below).
|
|
41
|
+
3. **Add visibility** — debug steps that print non-secret inputs, refs, and intermediate state.
|
|
42
|
+
4. **Push a single focused commit**, then watch the run live.
|
|
43
|
+
5. **Read the full failed-job log** (not just the summary) before editing.
|
|
44
|
+
6. **Form a hypothesis from the log**, change the smallest thing that tests it, push, watch again.
|
|
45
|
+
|
|
46
|
+
## Monitoring Runs With `gh`
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Watch the most recent run from the current branch in real time
|
|
50
|
+
gh run watch
|
|
51
|
+
|
|
52
|
+
# Watch a specific run
|
|
53
|
+
gh run watch <run-id>
|
|
54
|
+
|
|
55
|
+
# Auto-refresh PR checks until they finish (every 10s)
|
|
56
|
+
gh pr checks <pr-number> --watch --interval 10
|
|
57
|
+
|
|
58
|
+
# List recent runs for the repo / branch
|
|
59
|
+
gh run list --branch <branch> --limit 10
|
|
60
|
+
|
|
61
|
+
# Get the run ID for the latest run on a branch
|
|
62
|
+
gh run list --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Reading Logs (Don't Guess)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Full log for a run
|
|
69
|
+
gh run view <run-id> --log
|
|
70
|
+
|
|
71
|
+
# Just the failed steps (much shorter)
|
|
72
|
+
gh run view <run-id> --log-failed
|
|
73
|
+
|
|
74
|
+
# Log for a specific job (useful for matrix builds)
|
|
75
|
+
gh run view <run-id> --log --job <job-id>
|
|
76
|
+
|
|
77
|
+
# List jobs for a run to find the job ID
|
|
78
|
+
gh run view <run-id> --json jobs --jq '.jobs[] | {id, name, conclusion}'
|
|
79
|
+
|
|
80
|
+
# Rerun only the failed jobs (avoid paying to rerun green ones)
|
|
81
|
+
gh run rerun <run-id> --failed
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When a step fails, look for:
|
|
85
|
+
- The exact command that exited non-zero (above the `##[error]` line)
|
|
86
|
+
- The shell — bash on Linux, `pwsh` on Windows runners — error messages differ
|
|
87
|
+
- Values printed by your debug step; compare against what the workflow *thought* it was passing in
|
|
88
|
+
|
|
89
|
+
## Adding Visibility to Actions
|
|
90
|
+
|
|
91
|
+
When creating a new action or hitting a tricky bug, add debug steps. Don't leave them in indefinitely — remove or guard them with `if: runner.debug == '1'` once the issue is understood.
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
steps:
|
|
95
|
+
# Print non-secret inputs and context at the start
|
|
96
|
+
- name: Debug - inputs and context
|
|
97
|
+
if: runner.debug == '1' || inputs.debug == 'true'
|
|
98
|
+
run: |
|
|
99
|
+
echo "Event: ${{ github.event_name }}"
|
|
100
|
+
echo "Ref: ${{ github.ref }}"
|
|
101
|
+
echo "SHA: ${{ github.sha }}"
|
|
102
|
+
echo "Actor: ${{ github.actor }}"
|
|
103
|
+
echo "PWD: $(pwd)"
|
|
104
|
+
echo "Input.my-param: ${{ inputs.my-param }}"
|
|
105
|
+
echo "Files:"
|
|
106
|
+
ls -la
|
|
107
|
+
|
|
108
|
+
# ... your real steps ...
|
|
109
|
+
|
|
110
|
+
# Verify outcome before the job ends
|
|
111
|
+
- name: Debug - verify outputs
|
|
112
|
+
if: always() && (runner.debug == '1' || inputs.debug == 'true')
|
|
113
|
+
run: |
|
|
114
|
+
echo "Generated files:"
|
|
115
|
+
ls -la dist/ || echo "dist/ not found"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
To enable `runner.debug == '1'` for a single run, re-run the workflow with **"Enable debug logging"** checked, or set the repo secret `ACTIONS_RUNNER_DEBUG=true`.
|
|
119
|
+
|
|
120
|
+
**Never** echo `${{ secrets.* }}` — GitHub masks them, but encoded forms (base64, hex, JSON-wrapped) can leak through.
|
|
121
|
+
|
|
122
|
+
## Testing Locally With `act`
|
|
123
|
+
|
|
124
|
+
`act` ([nektos/act](https://github.com/nektos/act)) runs workflows in Docker locally (Docker must be installed and running). Use it to iterate without burning CI minutes.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Run the default push event
|
|
128
|
+
act
|
|
129
|
+
|
|
130
|
+
# Simulate a pull_request event
|
|
131
|
+
act pull_request
|
|
132
|
+
|
|
133
|
+
# Run a specific job
|
|
134
|
+
act -j build
|
|
135
|
+
|
|
136
|
+
# Pass secrets
|
|
137
|
+
act -s GITHUB_TOKEN="$GITHUB_TOKEN"
|
|
138
|
+
|
|
139
|
+
# Use a larger image closer to GitHub's runner
|
|
140
|
+
act -P ubuntu-latest=catthehacker/ubuntu:full-latest
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Caveats: `act` does not perfectly emulate GitHub's runners. Things that may differ: pre-installed tools, `GITHUB_TOKEN` permissions, OIDC, the `secrets.GITHUB_TOKEN` value, and macOS/Windows runners. Treat green-on-`act` as a strong signal, not a guarantee.
|
|
144
|
+
|
|
145
|
+
## Testing Custom Actions Requires Merge to Main
|
|
146
|
+
|
|
147
|
+
A repository-local custom action referenced as `uses: ./.github/actions/my-action` works from any branch, but:
|
|
148
|
+
|
|
149
|
+
- A custom action published as `uses: owner/repo/action@ref` must have the action's files **on `ref`** to be resolvable
|
|
150
|
+
- `@main` or `@v1` must already exist when the workflow that consumes it runs
|
|
151
|
+
- This is why a brand-new action typically must land on `main` first, then be consumed from feature branches that reference `@main` (or a tag)
|
|
152
|
+
|
|
153
|
+
If you need to iterate on an action and its consumer together, point `uses:` at a SHA on your branch, or develop the action via the local `./.github/actions/…` path until it's stable.
|
|
154
|
+
|
|
155
|
+
## Common Pitfalls
|
|
156
|
+
|
|
157
|
+
1. **Custom action not found from a PR** — the action's ref doesn't exist yet. Merge to `main` (or push a tag), then consume.
|
|
158
|
+
2. **`GITHUB_TOKEN` permissions** — defaults can be read-only. Set `permissions:` explicitly at the workflow or job level.
|
|
159
|
+
3. **`pull_request` vs `pull_request_target`** — `pull_request` runs in the fork's context (no secrets); `pull_request_target` runs with repo secrets against the base — **dangerous** if you check out PR code and execute it. Don't.
|
|
160
|
+
4. **Secrets in fork PRs** — even non-`*_target` workflows hide secrets from forks. Don't design workflows that require secrets to run on community PRs.
|
|
161
|
+
5. **`schedule:` triggers only fire from the default branch** — a `schedule:` trigger added in a PR only fires after it lands on the default branch; `workflow_dispatch` similarly won't appear in the Actions tab UI until merged to default (though it can be triggered via API on any branch); `pull_request`-triggered workflows do run on the PR that introduces them.
|
|
162
|
+
6. **Path filters are OR, not AND** — any matching path triggers; you can't require all paths.
|
|
163
|
+
7. **Matrix `fail-fast: true`** (default) cancels other matrix legs on first failure — turn off when you need full coverage.
|
|
164
|
+
8. **Artifacts** — files don't persist between jobs unless uploaded via `actions/upload-artifact` and downloaded in the consuming job.
|
|
165
|
+
9. **`env:` scope** — env at workflow, job, and step levels all exist. Step-level shadows job-level shadows workflow-level. Surprises follow if you forget.
|
|
166
|
+
10. **Pin versions** — use `@v4` (or better, a SHA) rather than `@main`. Floating refs break builds when upstream changes.
|
|
167
|
+
|
|
168
|
+
## Best Practices
|
|
169
|
+
|
|
170
|
+
1. **Pin action versions** — `@v4` or SHA, not `@main`
|
|
171
|
+
2. **Least privilege** — set `permissions:` to the minimum needed
|
|
172
|
+
3. **Debug steps when introducing or debugging** — remove or gate them with `runner.debug` afterward
|
|
173
|
+
4. **Cache dependencies** — `actions/cache` saves real minutes
|
|
174
|
+
5. **Concurrency** — cancel obsolete runs:
|
|
175
|
+
```yaml
|
|
176
|
+
concurrency:
|
|
177
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
178
|
+
cancel-in-progress: true
|
|
179
|
+
```
|
|
180
|
+
6. **Timeouts** — set `timeout-minutes:` on jobs that can hang
|
|
181
|
+
7. **Fail loudly** — `set -euo pipefail` in non-trivial bash steps
|
|
182
|
+
8. **Document non-obvious triggers/inputs** at the top of the workflow file
|
|
183
|
+
|
|
184
|
+
## Resources
|
|
185
|
+
|
|
186
|
+
- [GitHub Actions documentation](https://docs.github.com/en/actions)
|
|
187
|
+
- [`act` — run actions locally](https://github.com/nektos/act)
|
|
188
|
+
- [`gh run` CLI reference](https://cli.github.com/manual/gh_run)
|
|
189
|
+
- [github skill](https://github.com/OpenHands/extensions/tree/main/skills/github) — GitHub API, PRs, issues, and repos
|
|
190
|
+
- [github-pr-review skill](https://github.com/OpenHands/extensions/tree/main/skills/github-pr-review) — post structured code reviews via the GitHub API
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-actions
|
|
3
|
+
description: Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.
|
|
4
|
+
triggers:
|
|
5
|
+
- github actions
|
|
6
|
+
- github workflow
|
|
7
|
+
- actions workflow
|
|
8
|
+
- gh actions
|
|
9
|
+
- .github/workflows
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# GitHub Actions Guide
|
|
13
|
+
|
|
14
|
+
## Critical Rules
|
|
15
|
+
|
|
16
|
+
**Custom Action Deployment:**
|
|
17
|
+
- New custom actions MUST be merged to the main branch before they can be used
|
|
18
|
+
- After the initial merge, they should be tested from feature branches
|
|
19
|
+
|
|
20
|
+
**Debug Steps:**
|
|
21
|
+
Add debug steps that print non-secret parameters when:
|
|
22
|
+
- Creating a new action, OR
|
|
23
|
+
- Troubleshooting a particularly tricky issue
|
|
24
|
+
|
|
25
|
+
(Not required for every workflow - use when needed)
|
|
26
|
+
|
|
27
|
+
## Effectiveness Principles
|
|
28
|
+
|
|
29
|
+
Actions cost CI minutes. Be deliberate, not iterative:
|
|
30
|
+
|
|
31
|
+
1. **Monitor, don't poll** - use `gh run watch` / `gh pr checks --watch` to follow runs live
|
|
32
|
+
2. **Read logs, don't guess** - fetch the failed job's log before changing code
|
|
33
|
+
3. **Print actual values** - debug steps reveal the real `inputs`/`github` context, not your assumptions
|
|
34
|
+
4. **Test locally first** - `act` runs workflows on your machine and avoids burning CI minutes
|
|
35
|
+
5. **Plan the smallest reproduction** - one job, minimal matrix, narrow trigger before scaling up
|
|
36
|
+
|
|
37
|
+
See [README.md](README.md) for the full debugging workflow, `gh` commands, and YAML debug-step examples.
|
|
38
|
+
|
|
39
|
+
## Key Gotchas
|
|
40
|
+
|
|
41
|
+
1. **Secrets unavailable in fork PRs** - `pull_request` has no secrets for forks; `pull_request_target` does but **never check out or execute fork PR code inside it** (RCE with write permissions)
|
|
42
|
+
2. **Pin action versions** - Use `@v4` or SHA, not `@main` (prevents breaking changes)
|
|
43
|
+
3. **Explicit permissions** - Set `permissions:` block for GITHUB_TOKEN operations
|
|
44
|
+
4. **Artifacts for job-to-job data** - Files don't persist between jobs without `upload-artifact`/`download-artifact`
|