diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aed3868..2d3346a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,16 @@ The following rule governs code contributions: ## Issues and Planning -* We use GitHub issues to track bugs and enhancement requests. +We follow a shared issue lifecycle across all `cloudoperators` repositories. See the **[Issue Lifecycle documentation](./ISSUE_LIFECYCLE.md)** for the full process including: -* Please provide as much context as possible when you open an issue. The information you provide must be comprehensive enough to reproduce that issue for the assignee. +* Automatic triage labeling +* Triage decision matrix +* Definition of Ready +* Refinement workflow +* Sprint/quarter planning + +Quick links: + +* [Issues needing triage (org-wide)](https://github.com/issues?q=org%3Acloudoperators+label%3Aneeds-triage+is%3Aopen+sort%3Acreated-asc) +* [Backlog (org-wide)](https://github.com/issues?q=org%3Acloudoperators+label%3Abacklog+is%3Aopen) +* [Project board](https://github.com/orgs/cloudoperators/projects/9) \ No newline at end of file diff --git a/ISSUE_LIFECYCLE.md b/ISSUE_LIFECYCLE.md new file mode 100644 index 0000000..5498fff --- /dev/null +++ b/ISSUE_LIFECYCLE.md @@ -0,0 +1,99 @@ +# Issue Lifecycle + +This document defines the issue workflow used across all repositories in the `cloudoperators` organization. + +## Overview + +```mermaid +flowchart TD + A([Issue Opened]) -->|auto-labeled by workflow| B[needs-triage] + B --> C{Triage} + + C -->|clear & well-scoped| D[label: backlog] + C -->|unclear scope| E[labels: needs-refinement + backlog] + C -->|duplicate / out of scope / won't fix| F([Closed]) + C -->|missing info| G[label: needs-more-info] + + G -->|reporter responds| C + + E --> H[Refinement] + H -->|Definition of Ready met| D + + D -->|issue-project-sync workflow| I[(cloudoperators project #9)] + I --> J[Sprint / Quarter Planning] + J --> K([In Progress → Done]) +``` + +## Stages + +### 1. Issue Opened → `needs-triage` + +Every new issue is automatically labeled `needs-triage` by the `issue-triage` workflow. A welcome comment is posted directing the reporter to this document. No manual action is required from the reporter. + +### 2. Triage (target: within 5 business days) + +Maintainers review issues using the org-wide triage view: + +🔗 **[All issues needing triage](https://github.com/issues?q=org%3Acloudoperators+label%3Aneeds-triage+is%3Aopen+sort%3Acreated-asc)** + +A maintainer removes `needs-triage` and takes **exactly one** of these actions: + +| Outcome | Action | +|---|---| +| Clear and well-scoped | Add label **`backlog`** — triggers automatic addition to the project | +| Unclear scope or missing acceptance criteria | Add label **`needs-refinement`** + add label **`backlog`** | +| Needs more info from reporter | Add label **`needs-more-info`** and post a comment specifying what is needed | +| Duplicate | Close with comment: "Duplicate of #NNN." | +| Out of scope / won't fix | Close with a short explanation comment | + +**Rules:** +- Always remove `needs-triage` when taking action. +- Always post a comment when closing an issue. +- When adding `needs-more-info`, be specific — do not just say "more info needed". + +### 3. Refinement → ready for implementation + +Issues labeled `needs-refinement` are discussed asynchronously in comments or during a refinement session. Use the project refinement view for priority ordering: + +🔗 **[Refinement view (project #9)](https://github.com/orgs/cloudoperators/projects/9/views/6)** + +An issue meets the **Definition of Ready** when ALL of the following are true: + +- [ ] Has a clear, single-sentence problem statement +- [ ] Has testable acceptance criteria (e.g., `- [ ] criterion`) +- [ ] Dependencies are identified (linked issues, or explicitly noted as none) + +Once ready, the maintainer removes `needs-refinement`. The issue remains in the backlog, ready to be pulled into a sprint. + +### 4. Backlog → Sprint / Quarter + +During sprint or quarter planning, maintainers move issues from the backlog into the upcoming iteration. The `backlog` label is removed manually when an issue is assigned to a sprint or quarter. + +## Label Reference + +| Label | Applied by | Meaning | +|---|---|---| +| `needs-triage` | Automation (on open) | New issue, not yet reviewed | +| `needs-refinement` | Maintainer | Needs scoping before implementation | +| `needs-more-info` | Maintainer | Waiting on reporter for details | +| `backlog` | Maintainer | Ready for planning; triggers addition to project #9 | +| `bug` | Issue template | Regression or unintended behavior | +| `feature` | Issue template | New capability request | + +## Repositories using this workflow + +- [greenhouse](https://github.com/cloudoperators/greenhouse) +- [shoot-grafter](https://github.com/cloudoperators/shoot-grafter) +- [repo-guard](https://github.com/cloudoperators/repo-guard) +- [cloudctl](https://github.com/cloudoperators/cloudctl) +- [owner-label-injector](https://github.com/cloudoperators/owner-label-injector) + +## Quick Links + +| View | URL | +|---|---| +| All issues needing triage | [org-wide `needs-triage`](https://github.com/issues?q=org%3Acloudoperators+label%3Aneeds-triage+is%3Aopen+sort%3Acreated-asc) | +| Backlog (all repos) | [org-wide `backlog`](https://github.com/issues?q=org%3Acloudoperators+label%3Abacklog+is%3Aopen) | +| Needs refinement | [org-wide `needs-refinement`](https://github.com/issues?q=org%3Acloudoperators+label%3Aneeds-refinement+is%3Aopen) | +| Project board | [cloudoperators project #9](https://github.com/orgs/cloudoperators/projects/9) | +| Refinement view | [project #9, view 6](https://github.com/orgs/cloudoperators/projects/9/views/6) | \ No newline at end of file diff --git a/skills/issue-triage.md b/skills/issue-triage.md new file mode 100644 index 0000000..3da4945 --- /dev/null +++ b/skills/issue-triage.md @@ -0,0 +1,109 @@ +# Skill: Issue Triage + +## Description + +This skill teaches an agent how to triage GitHub issues across all repositories in the `cloudoperators` organization. Use it whenever you are asked to triage, label, close, or comment on an issue. + +The full human-readable process is in [ISSUE_LIFECYCLE.md](../ISSUE_LIFECYCLE.md). + +--- + +## Trigger + +Activate this skill when asked to: + +- Triage an issue +- Review a `needs-triage` issue +- Apply or suggest labels on an issue +- Determine whether an issue is ready for the backlog + +--- + +## Step-by-Step Triage Process + +### 1. Check the current state + +Before acting, check: + +- Does the issue have `needs-triage`? If not, it may already be triaged — confirm before making changes. +- Does the issue have enough information to make a routing decision? + +### 2. Apply exactly one outcome + +Remove `needs-triage` and apply one of the following — never more than one: + +| Situation | Action | +|---|---| +| Issue is clear, scoped, and has acceptance criteria | Add label `backlog` | +| Issue scope is unclear or acceptance criteria are missing | Add labels `needs-refinement` + `backlog` | +| Issue is missing details needed to evaluate | Add label `needs-more-info` + post a comment specifying exactly what is needed | +| Issue is a duplicate | Close with a comment: "Duplicate of #." | +| Issue is out of scope / won't fix | Close with a short explanation comment | + +**Rules:** + +- Never apply `backlog` without removing `needs-triage`. +- Always post a comment when closing an issue. +- When adding `needs-more-info`, be specific — do not just say "more info needed". +- The `issue-project-sync` workflow automatically adds issues with `backlog` to the project board. Do not manually add issues to the project. + +### 3. Before applying `backlog` without `needs-refinement` — check the Definition of Ready + +Only apply `backlog` alone (without `needs-refinement`) when ALL of the following are true: + +- [ ] Has a clear, single-sentence problem statement +- [ ] Has testable acceptance criteria (e.g. `- [ ] criterion`) +- [ ] Dependencies are identified (linked issues, or explicitly noted as none) + +If any item is missing, apply both `needs-refinement` and `backlog`, and note what is missing in a comment. + +### 4. Do not touch the project board + +When `backlog` is applied, the `issue-project-sync` GitHub Action workflow automatically adds the issue to [cloudoperators project #9](https://github.com/orgs/cloudoperators/projects/9). Do not manually add issues to the project. + +--- + +## Label Reference + +| Label | Applied by | Meaning | +|---|---|---| +| `needs-triage` | Automation (on open) | New issue, not yet reviewed | +| `needs-refinement` | Maintainer / agent | Needs scoping before implementation | +| `needs-more-info` | Maintainer / agent | Waiting on reporter for details | +| `backlog` | Maintainer / agent | Ready for planning; triggers project addition | +| `bug` | Issue template | Regression or unintended behavior | +| `feature` | Issue template | New capability request | + +--- + +## Example Triage Comments + +**Sending to refinement:** +> Routing to refinement. The problem statement is clear, but the acceptance criteria are missing. Could you add a list of testable criteria so we can properly scope this before implementation? + +**Requesting more information:** +> Marking as `needs-more-info`. To evaluate this issue we need: +> +> - The version where this behaviour was observed +> - The full error message or relevant log output +> +> Please update the issue and we will re-triage. + +**Closing as duplicate:** +> Closing as duplicate of #42. Please follow that issue for updates. If you believe this is a distinct problem, reopen with additional context. + +**Closing as out of scope:** +> Thank you for the report. After review, this falls outside the current scope of the project. We are closing this for now. If the situation changes, feel free to reopen. + +**Approving to backlog:** +> Triaged. This is well-scoped with clear acceptance criteria. Moving to the backlog for sprint planning. + +--- + +## Useful Views + +| View | URL | +|---|---| +| All issues needing triage | [org-wide `needs-triage`](https://github.com/issues?q=org%3Acloudoperators+label%3Aneeds-triage+is%3Aopen+sort%3Acreated-asc) | +| Backlog (all repos) | [org-wide `backlog`](https://github.com/issues?q=org%3Acloudoperators+label%3Abacklog+is%3Aopen) | +| Refinement view | [project #9, view 6](https://github.com/orgs/cloudoperators/projects/9/views/6) | \ No newline at end of file diff --git a/workflows/issue-project-sync/README.md b/workflows/issue-project-sync/README.md new file mode 100644 index 0000000..aede169 --- /dev/null +++ b/workflows/issue-project-sync/README.md @@ -0,0 +1,67 @@ +# Issue Project Sync Workflow + +A reusable composite action that automatically adds issues to [cloudoperators project #9](https://github.com/orgs/cloudoperators/projects/9) when the `backlog` label is applied. Uses the official [actions/add-to-project](https://github.com/actions/add-to-project) action under the hood. + +## Usage + +Create `.github/workflows/issue-project-sync.yaml` in your repository: + +```yaml +name: Issue Project Sync +on: + issues: + types: [labeled] + +permissions: + issues: read + +jobs: + sync: + if: github.event.label.name == 'backlog' + runs-on: ubuntu-latest + steps: + - uses: cloudoperators/common/workflows/issue-project-sync@main + with: + GH_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }} +``` + +## What it does + +1. Triggered when any label is added to an issue +2. Filters to only run when the `backlog` label is applied +3. Uses `actions/add-to-project` to add the issue to the organization project + +## Prerequisites + +### Org-level secret: `GH_PROJECT_TOKEN` + +This workflow requires a GitHub token with elevated permissions to write to organization projects. Set this up once at the org level: + +1. Go to **GitHub → cloudoperators → Settings → Secrets and variables → Actions** +2. Click **New organization secret** +3. Configure: + - **Name:** `GH_PROJECT_TOKEN` + - **Value:** A Personal Access Token (classic) or GitHub App token with scopes: + - `project` (read/write) + - `repo` (to read issue metadata) + - **Repository access:** Select the repositories using this workflow: + - `greenhouse` + - `shoot-grafter` + - `repo-guard` + - `cloudctl` + - `owner-label-injector` + +### Labels + +The `backlog` label must exist in the repository: + +```bash +gh label create "backlog" --color "0e8a16" --description "Ready for sprint planning; triggers project addition" --repo cloudoperators/ +``` + +## Inputs + +| Input | Required | Default | Description | +|---|---|---|---| +| `GH_TOKEN` | **Yes** | — | GitHub token with `project` scope (org-level secret) | +| `PROJECT_URL` | No | `https://github.com/orgs/cloudoperators/projects/9` | Full URL of the GitHub project | \ No newline at end of file diff --git a/workflows/issue-project-sync/action.yaml b/workflows/issue-project-sync/action.yaml new file mode 100644 index 0000000..5bc201f --- /dev/null +++ b/workflows/issue-project-sync/action.yaml @@ -0,0 +1,20 @@ +name: issue-project-sync +description: Add issues labeled with 'backlog' to the cloudoperators project #9 + +inputs: + GH_TOKEN: + description: 'GitHub token with project write scope. Must be an org-level secret with project and repo permissions.' + required: true + PROJECT_URL: + description: 'The full URL of the GitHub project to add issues to' + required: false + default: 'https://github.com/orgs/cloudoperators/projects/9' + +runs: + using: "composite" + steps: + - name: Add issue to project + uses: actions/add-to-project@v1.0.2 + with: + project-url: ${{ inputs.PROJECT_URL }} + github-token: ${{ inputs.GH_TOKEN }} \ No newline at end of file diff --git a/workflows/issue-triage/README.md b/workflows/issue-triage/README.md new file mode 100644 index 0000000..acabd20 --- /dev/null +++ b/workflows/issue-triage/README.md @@ -0,0 +1,53 @@ +# Issue Triage Workflow + +A reusable composite action that automatically labels new issues with `needs-triage` and posts a welcome comment directing the reporter to the [Issue Lifecycle documentation](../../ISSUE_LIFECYCLE.md). + +## Usage + +Create `.github/workflows/issue-triage.yaml` in your repository: + +```yaml +name: Issue Triage +on: + issues: + types: [opened] + +permissions: + issues: write + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: cloudoperators/common/workflows/issue-triage@main +``` + +> **Important:** The calling workflow **must** declare `permissions: issues: write`. Without this, the action will fail in repos/orgs where the default `GITHUB_TOKEN` is read-only. + +## What it does + +1. Adds the `needs-triage` label to the newly opened issue +2. Posts a welcome comment with: + - Acknowledgment of the issue + - Link to the Issue Lifecycle documentation + - Reminder of what information helps with triage + +## Prerequisites + +- The `needs-triage` label must exist in the repository (see label setup below) +- The calling workflow must grant `permissions: issues: write` +- The default `GITHUB_TOKEN` is sufficient for the token — no additional secrets needed + +## Label Setup + +Create the required label in your repository: + +```bash +gh label create "needs-triage" --color "fbca04" --description "New issue, not yet reviewed" --repo cloudoperators/ +``` + +## Inputs + +| Input | Required | Default | Description | +|---|---|---|---| +| `GH_TOKEN` | No | `github.token` | GitHub token with issues write permission | \ No newline at end of file diff --git a/workflows/issue-triage/action.yaml b/workflows/issue-triage/action.yaml new file mode 100644 index 0000000..38a2d9b --- /dev/null +++ b/workflows/issue-triage/action.yaml @@ -0,0 +1,40 @@ +name: issue-triage +description: Auto-label new issues with needs-triage and post a welcome comment + +inputs: + GH_TOKEN: + description: 'GitHub token with issues write permission. The calling workflow must grant permissions: issues: write.' + required: false + default: ${{ github.token }} + +runs: + using: "composite" + steps: + - name: Add needs-triage label + shell: bash + env: + GH_TOKEN: ${{ inputs.GH_TOKEN }} + ISSUE_URL: ${{ github.event.issue.html_url }} + run: | + gh issue edit "$ISSUE_URL" --add-label "needs-triage" + + - name: Post welcome comment + shell: bash + env: + GH_TOKEN: ${{ inputs.GH_TOKEN }} + ISSUE_URL: ${{ github.event.issue.html_url }} + run: | + BODY=$(cat <<'EOF' +Thanks for opening this issue! 🎉 + +A maintainer will triage it within 5 business days. You can learn more about our issue workflow in the [Issue Lifecycle documentation](https://github.com/cloudoperators/common/blob/main/ISSUE_LIFECYCLE.md). + +In the meantime, please make sure you have provided: +- A clear problem statement +- Steps to reproduce (for bugs) +- Expected vs actual behavior + +This helps us route your issue faster. +EOF + ) + gh issue comment "$ISSUE_URL" --body "$BODY" \ No newline at end of file