make-github-actions-workflow
$
npx mdskill add dotnet/efcore/make-github-actions-workflowCreate 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.
SKILL.md
.github/skills/make-github-actions-workflowView on GitHub ↗
---
name: make-github-actions-workflow
description: 'Create GitHub Actions workflows for CI, automation, or PR management. Use when asked to create, scaffold, or add a GitHub Actions workflow (.yml file under .github/workflows/).'
---
# Create GitHub Actions Workflow
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.
## Repository Conventions
This repository uses specific patterns across all workflows. Follow these conventions when creating new workflows:
### File Location and Naming
- All workflows live in `.github/workflows/`
- Use kebab-case names: `label-and-milestone-issues.yml`, `validate-pr-target-branch.yml`
- Start with a descriptive comment block explaining the workflow's purpose
### Runner
- Use `ubuntu-latest` for general-purpose jobs
- Use `ubuntu-24.04` when a specific OS version is needed (e.g., copilot setup steps)
### Permissions
- **Always** declare explicit permissions — never rely on defaults
- Use **minimal permissions**: only request what the workflow needs
- Common patterns:
- Read-only: `permissions: {}`
- PR comments: `pull-requests: write`
- Issue management: `issues: write`
- Code read: `contents: read`
- For workflows that need write access to PRs from external contributors, use `pull_request_target` instead of `pull_request`
- **Security warning:** `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.
### Scripting
- Use `actions/github-script@v8` for complex logic instead of shell scripts
- Write JavaScript with `async/await` — the `github` object (Octokit) and `context` are available
- Use `github.rest.*` for REST API calls and `github.graphql()` for GraphQL queries
- Access PR/issue data via `context.payload.pull_request`, `context.repo.owner`, `context.repo.repo`
- Log with `console.log()` for debugging; use `core.setFailed()` for errors
### Error Handling
- Wrap API calls in try/catch blocks
- Collect errors and report at the end rather than failing on the first error
- Log skipped operations with a reason
## Workflow
### Step 1: Understand the Requirements
Before writing the workflow, clarify:
- [ ] What event(s) should trigger it? (push, pull_request, check_suite, schedule, etc.)
- [ ] What permissions are needed?
- [ ] What conditions should gate execution? (author, branch, labels, etc.)
- [ ] What API calls are needed?
- [ ] Are there rate limiting or idempotency concerns?
### Step 2: Choose the Trigger Event
| 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 |
### Step 3: Write the Workflow
Create the YAML file following this template:
```yaml
# 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
```
### Step 4: Implement Guard Conditions
Add conditions to avoid unnecessary runs:
- Job-level `if:` for event payload checks (e.g., `github.event.check_suite.app.slug != 'github-actions'`)
- Early `return` in scripts for PR author, draft status, etc.
- Idempotency checks (e.g., hidden HTML comments as tags to prevent duplicate actions)
### Step 5: Validate
After creating the workflow:
- [ ] Permissions are minimal and explicitly declared
- [ ] Uses `actions/github-script@v8` for complex logic
- [ ] Guard conditions prevent unnecessary runs
- [ ] API calls handle pagination where needed (use `per_page: 100`)
- [ ] Error handling doesn't silently swallow failures
- [ ] No secrets or tokens are hardcoded
- [ ] Workflow doesn't create infinite loops (e.g., a workflow that triggers itself)
## Existing Workflows in This Repository
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 |
## Common Patterns
### Commenting on a PR
```javascript
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: 'Comment text'
});
```
### Checking User Permissions
```javascript
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);
```
### Preventing Duplicate Comments (SHA Tag Pattern)
```javascript
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;
}
```
### Reading Repository Files at a Specific Commit
```javascript
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');
```
## References
- [GitHub Actions documentation](https://docs.github.com/en/actions)
- [Workflow syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions)
- [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)
- [actions/github-script](https://github.com/actions/github-script)
More from dotnet/efcore
- change-trackingImplementation details for EF Core change tracking. Use when changing InternalEntityEntry, ChangeDetector, SnapshotFactoryFactory, or related entity state, snapshot, or property accessor code.
- cosmos-providerImplementation details for the EF Core Azure Cosmos DB provider. Use when changing Cosmos-specific code.
- make-custom-agentCreate custom GitHub Copilot agents. Use when asked to create, scaffold, or configure a custom agent, declarative agent, or @-invokable chat participant for GitHub Copilot.
- make-instructionsCreate VS Code file-based instructions (.instructions.md files). Use when asked to create, scaffold, or add file-based instructions for Copilot. Generates .instructions.md with YAML frontmatter and background knowledge content.
- make-skillCreate new Agent Skills for GitHub Copilot. Use when asked to create, scaffold, or add a skill. Generates SKILL.md with frontmatter, directory structure, and optional resources.
- migrationsImplementation details for EF Core migrations. Use when changing MigrationsSqlGenerator, model diffing, migration operations, HistoryRepository, the Migrator or related classes.
- model-buildingImplementation details for EF Core model building. Use when changing ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, RuntimeModel, or related classes.
- query-pipelineImplementation details for EF Core LINQ query translation, SQL generation, and bulk operations (ExecuteUpdate/ExecuteDelete). Use when changing expression visitors, SqlExpressions, QuerySqlGenerator, ShaperProcessingExpressionVisitor, UpdateExpression, DeleteExpression, or related classes.
- run-apichiefRun ApiChief in the EF Core repo to emit baselines, summaries, deltas, review files, or breaking-change checks. Use when refreshing `*.baseline.json`, preparing API review artifacts, or validating API changes.
- scaffoldingImplementation details for EF Core scaffolding (reverse engineering). Use when changing ef dbcontext scaffold pipeline implementation, database schema reading, CSharpModelGenerator, or related classes.