.agents/skills/make-github-actions-workflow/SKILL.md
Create and configure GitHub Actions workflows that follow this repository's conventions and patterns. Workflows automate tasks like CI validation, PR management, issue labeling, and notifications.
This repository uses specific patterns across all workflows. Follow these conventions when creating new workflows:
.github/workflows/label-and-milestone-issues.yml, validate-pr-target-branch.ymlubuntu-latest for general-purpose jobsubuntu-24.04 when a specific OS version is needed (e.g., copilot setup steps)permissions: {}pull-requests: writeissues: writecontents: readpull_request_target instead of pull_request
pull_request_target workflows run in the base repository context with its permissions. Do not check out or execute code from the PR branch in these workflows. Instead, use the event payload and/or GitHub API (actions/github-script, github.rest.*, etc.) to inspect and act on the PR safely.actions/github-script@v8 for complex logic instead of shell scriptsasync/await — the github object (Octokit) and context are availablegithub.rest.* for REST API calls and github.graphql() for GraphQL queriescontext.payload.pull_request, context.repo.owner, context.repo.repoconsole.log() for debugging; use core.setFailed() for errorsBefore writing the workflow, clarify:
| Use case | Event | Notes |
|---|---|---|
| PR opened/updated | pull_request | Read-only access to PR |
| PR with write access | pull_request_target | Can comment, label, close |
| PR merged | pull_request_target: [closed] | Check github.event.pull_request.merged == true |
| CI checks complete | check_suite: [completed] | Filter app.slug != 'github-actions' to skip self |
| Code pushed | push | Filter by branches/paths |
| Manual trigger | workflow_dispatch | Add inputs: for parameters |
| Scheduled | schedule | Use cron syntax |
Create the YAML file following this template:
# Description of what this workflow does and why.
name: Descriptive Workflow Name
on:
<trigger_event>:
types: [<event_types>]
permissions:
<resource>: <read|write>
jobs:
<job-name>:
if: <guard_condition> # Optional: skip when not needed
runs-on: ubuntu-latest
steps:
- name: Descriptive step name
uses: actions/github-script@v8
with:
script: |
// Your logic here
Add conditions to avoid unnecessary runs:
if: for event payload checks (e.g., github.event.check_suite.app.slug != 'github-actions')return in scripts for PR author, draft status, etc.After creating the workflow:
actions/github-script@v8 for complex logicper_page: 100)Study these workflows as reference:
| Workflow | Trigger | Purpose |
|---|---|---|
validate-pr-target-branch.yml | pull_request_target: [opened, edited, reopened] | Closes external PRs targeting release branches, adds community labels |
label-and-milestone-issues.yml | pull_request_target: [closed] | Labels and milestones issues when their fixing PR is merged |
copilot-setup-steps.yml | workflow_dispatch, push, pull_request | Sets up the development environment for Copilot |
inter-branch-merge-flow.yml | push to release/** | Triggers inter-branch merge via arcade |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: 'Comment text'
});
const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.actor
});
const hasWriteAccess = ['admin', 'write'].includes(permissions.permission);
const shaTag = `<!-- tag: ${headSha} -->`;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100
});
if (comments.some(c => c.body?.includes(shaTag))) {
console.log('Already processed');
return;
}
const { data: fileData } = await github.rest.repos.getContent({
owner, repo,
path: 'eng/Versions.props',
ref: commitSha
});
const content = Buffer.from(fileData.content, 'base64').toString('utf-8');