mirror of
https://github.com/github/awesome-copilot.git
synced 2026-10-12 23:04:14 +00:00
Route workshop changes to workshop reviewers (#4743)
* Cleanup of CODEOWNER Removed a lot of excessive codeowners Created a new team for reviewing/approving workshops Removed workflow that did auto-assignment * Route workshop changes to workshop reviewers Add workshop ownership, intent labeling, reviewer routing, approval-domain coverage, and maintainer documentation for the new workshop review team. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -52,10 +52,16 @@ pools:
|
|||||||
team: github/awesome-copilot-content-reviewers
|
team: github/awesome-copilot-content-reviewers
|
||||||
reviewers: [] # TODO: add at least three reviewers for skills, agents, and instructions.
|
reviewers: [] # TODO: add at least three reviewers for skills, agents, and instructions.
|
||||||
backup: [] # TODO: add backup content reviewers.
|
backup: [] # TODO: add backup content reviewers.
|
||||||
|
workshops:
|
||||||
|
team: github/awesome-copilot-workshop-reviewers
|
||||||
|
reviewers: [] # TODO: add at least three workshop reviewers.
|
||||||
|
backup: [] # TODO: add backup workshop reviewers.
|
||||||
|
|
||||||
# Intent labels (applied by .github/workflows/label-pr-intent*.yml) mapped to
|
# Intent labels (applied by .github/workflows/label-pr-intent*.yml) mapped to
|
||||||
# pools. Order is priority: the first route whose label is on the PR wins.
|
# pools. Order is priority: the first route whose label is on the PR wins.
|
||||||
routes:
|
routes:
|
||||||
|
- label: workshops
|
||||||
|
pool: workshops
|
||||||
- label: canvas-extension
|
- label: canvas-extension
|
||||||
pool: canvas
|
pool: canvas
|
||||||
- label: external-plugin
|
- label: external-plugin
|
||||||
|
|||||||
@@ -143,6 +143,12 @@ domains:
|
|||||||
content:
|
content:
|
||||||
paths: ["agents/**", "instructions/**", "skills/**", "workflows/**", "hooks/**"]
|
paths: ["agents/**", "instructions/**", "skills/**", "workflows/**", "hooks/**"]
|
||||||
pools: ["content"]
|
pools: ["content"]
|
||||||
|
workshops:
|
||||||
|
paths:
|
||||||
|
- "website/**/cli-for-beginners/**"
|
||||||
|
- "website/**/app-for-beginners/**"
|
||||||
|
- "website/**/copilot-workshops/**"
|
||||||
|
pools: ["workshops"]
|
||||||
# Files outside every domain (repository automation such as `.github/workflows/**`,
|
# Files outside every domain (repository automation such as `.github/workflows/**`,
|
||||||
# `eng/**`, review policy, and docs) are owned by the core pools.
|
# `eng/**`, review policy, and docs) are owned by the core pools.
|
||||||
|
|
||||||
|
|||||||
-1965
File diff suppressed because one or more lines are too long
@@ -1,94 +0,0 @@
|
|||||||
---
|
|
||||||
description: "Updates the CODEOWNERS file when a maintainer comments #codeowner on a pull request"
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
if: ${{ contains(github.event.comment.body, '#codeowner') && github.event.issue.pull_request }}
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
issues: read
|
|
||||||
copilot-requests: write
|
|
||||||
tools:
|
|
||||||
github:
|
|
||||||
toolsets: [default]
|
|
||||||
safe-outputs:
|
|
||||||
create-pull-request:
|
|
||||||
base-branch: main
|
|
||||||
title-prefix: "[codeowner] "
|
|
||||||
draft: false
|
|
||||||
add-comment:
|
|
||||||
max: 1
|
|
||||||
noop:
|
|
||||||
---
|
|
||||||
|
|
||||||
# Codeowner Update Agent
|
|
||||||
|
|
||||||
You are a CODEOWNERS file updater for the **${{ github.repository }}** repository. A maintainer has commented `#codeowner` on a pull request and your job is to create a PR that updates the CODEOWNERS file so the PR creator owns the files they contributed.
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
- **Triggering PR:** #${{ github.event.issue.number }}
|
|
||||||
- **Comment author:** @${{ github.actor }}
|
|
||||||
- **Comment body:** "${{ steps.sanitized.outputs.text }}"
|
|
||||||
|
|
||||||
## Instructions
|
|
||||||
|
|
||||||
### 1. Validate the Trigger
|
|
||||||
|
|
||||||
- Confirm the comment body contains `#codeowner`.
|
|
||||||
- If the check fails, exit with a `noop`.
|
|
||||||
|
|
||||||
### 2. Gather PR Information
|
|
||||||
|
|
||||||
- Use the GitHub tools to get details for pull request #${{ github.event.issue.number }}.
|
|
||||||
- Record the **PR creator's username** (the user who opened the PR — `user.login` from the PR object).
|
|
||||||
- Retrieve the full list of files changed in the PR.
|
|
||||||
|
|
||||||
### 3. Filter Relevant Files
|
|
||||||
|
|
||||||
Only include files whose paths start with one of these directories:
|
|
||||||
|
|
||||||
- `agents/`
|
|
||||||
- `skills/`
|
|
||||||
- `instructions/`
|
|
||||||
- `workflows/`
|
|
||||||
- `hooks/`
|
|
||||||
- `plugins/`
|
|
||||||
|
|
||||||
If **no files** match these directories, exit with a `noop` message: "No files in agents/, skills/, instructions/, workflows/, hooks/, or plugins/ directories were found in this PR."
|
|
||||||
|
|
||||||
### 4. Read the Current CODEOWNERS File
|
|
||||||
|
|
||||||
Read the `CODEOWNERS` file from the root of the repository on the `main` branch. Parse its existing entries so you can avoid creating duplicates.
|
|
||||||
|
|
||||||
### 5. Build the Updated CODEOWNERS File
|
|
||||||
|
|
||||||
For each matched file path from the PR:
|
|
||||||
|
|
||||||
- Construct a CODEOWNERS entry: `/<file-path> @<pr-creator-username>`
|
|
||||||
- For files inside `skills/`, `hooks/`, or `plugins/` (which are directory-based resources), use the **directory pattern** instead of individual file paths. For example, if the PR touches `skills/my-skill/SKILL.md` and `skills/my-skill/template.txt`, add a single entry: `/skills/my-skill/ @<pr-creator-username>`
|
|
||||||
- If an entry for that exact path already exists in CODEOWNERS, **replace** the owner with the PR creator rather than adding a duplicate line.
|
|
||||||
|
|
||||||
Insert the new entries in the CODEOWNERS file grouped under a comment block:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Added via #codeowner from PR #<pr-number>
|
|
||||||
/<path> @<username>
|
|
||||||
```
|
|
||||||
|
|
||||||
Place this block at the end of the file, before any trailing newline.
|
|
||||||
|
|
||||||
### 6. Create the Pull Request
|
|
||||||
|
|
||||||
Use `create-pull-request` to open a PR with the updated `CODEOWNERS` file. The PR should:
|
|
||||||
|
|
||||||
- **Title:** `Update CODEOWNERS for PR #${{ github.event.issue.number }}`
|
|
||||||
- **Body:** A summary listing every new or updated CODEOWNERS entry and the PR creator who was assigned ownership.
|
|
||||||
- **Only modify the `CODEOWNERS` file** — do not touch any other files.
|
|
||||||
|
|
||||||
### 7. Post a Confirmation Comment
|
|
||||||
|
|
||||||
After successfully creating the PR, use `add-comment` on the triggering PR to let the team know. Include a link to the newly created CODEOWNERS PR.
|
|
||||||
|
|
||||||
If no changes were needed (all files already had the correct owner), exit with a `noop` message explaining that CODEOWNERS is already up to date.
|
|
||||||
@@ -46,6 +46,7 @@ jobs:
|
|||||||
'agent',
|
'agent',
|
||||||
'instructions',
|
'instructions',
|
||||||
'new-submission',
|
'new-submission',
|
||||||
|
'workshops',
|
||||||
'website-update',
|
'website-update',
|
||||||
'external-plugin',
|
'external-plugin',
|
||||||
'hooks',
|
'hooks',
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ jobs:
|
|||||||
'agent': true,
|
'agent': true,
|
||||||
'instructions': true,
|
'instructions': true,
|
||||||
'new-submission': true,
|
'new-submission': true,
|
||||||
|
'workshops': true,
|
||||||
'website-update': true,
|
'website-update': true,
|
||||||
'external-plugin': true,
|
'external-plugin': true,
|
||||||
'hooks': true,
|
'hooks': true,
|
||||||
@@ -78,6 +79,9 @@ jobs:
|
|||||||
websiteUpdate: [
|
websiteUpdate: [
|
||||||
/^website\//
|
/^website\//
|
||||||
],
|
],
|
||||||
|
workshops: [
|
||||||
|
/^website\/(?:.*\/)?(?:cli-for-beginners|app-for-beginners|copilot-workshops)\//
|
||||||
|
],
|
||||||
externalPlugin: [
|
externalPlugin: [
|
||||||
/^plugins\/external\.json$/
|
/^plugins\/external\.json$/
|
||||||
],
|
],
|
||||||
@@ -130,6 +134,10 @@ jobs:
|
|||||||
desiredLabels.add('instructions');
|
desiredLabels.add('instructions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filenames.some((filename) => matchesAny(filename, patterns.workshops))) {
|
||||||
|
desiredLabels.add('workshops');
|
||||||
|
}
|
||||||
|
|
||||||
if (filenames.some((filename) => matchesAny(filename, patterns.websiteUpdate))) {
|
if (filenames.some((filename) => matchesAny(filename, patterns.websiteUpdate))) {
|
||||||
desiredLabels.add('website-update');
|
desiredLabels.add('website-update');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ jobs:
|
|||||||
color: '006B75',
|
color: '006B75',
|
||||||
description: 'PR adds at least one new contribution'
|
description: 'PR adds at least one new contribution'
|
||||||
},
|
},
|
||||||
|
'workshops': {
|
||||||
|
color: '7057FF',
|
||||||
|
description: 'PR touches Copilot workshop content'
|
||||||
|
},
|
||||||
'website-update': {
|
'website-update': {
|
||||||
color: '0052CC',
|
color: '0052CC',
|
||||||
description: 'PR touches website content or code'
|
description: 'PR touches website content or code'
|
||||||
|
|||||||
+5
-57
@@ -2,9 +2,7 @@
|
|||||||
#
|
#
|
||||||
# - Teams own paths; no individual is the default owner. Do not add individual
|
# - Teams own paths; no individual is the default owner. Do not add individual
|
||||||
# users to the `*` rule or to the team block below.
|
# users to the `*` rule or to the team block below.
|
||||||
# - The last matching rule wins, so per-resource owners appended at the end of
|
# - The last matching rule wins.
|
||||||
# this file (for example by the `#codeowner` automation) override the team
|
|
||||||
# defaults for their specific paths.
|
|
||||||
# - Reviewer pools used for automatic review requests live in
|
# - Reviewer pools used for automatic review requests live in
|
||||||
# .github/review-routing.yml.
|
# .github/review-routing.yml.
|
||||||
|
|
||||||
@@ -22,57 +20,7 @@
|
|||||||
/.github/ @github/awesome-copilot-core-maintainers
|
/.github/ @github/awesome-copilot-core-maintainers
|
||||||
/eng/ @github/awesome-copilot-core-maintainers
|
/eng/ @github/awesome-copilot-core-maintainers
|
||||||
|
|
||||||
# Adding Dan Wahlin as the owner for the CLI for Beginners content and images
|
# Copilot workshops
|
||||||
/website/src/content/docs/learning-hub/cli-for-beginners/ @DanWahlin
|
/website/**/cli-for-beginners/ @github/awesome-copilot-workshop-reviewers
|
||||||
/website/src/images/cli-for-beginners/ @DanWahlin
|
/website/**/app-for-beginners/ @github/awesome-copilot-workshop-reviewers
|
||||||
|
/website/**/copilot-workshops/ @github/awesome-copilot-workshop-reviewers
|
||||||
# Copilot app for Beginners course and public images
|
|
||||||
/website/src/content/docs/learning-hub/app-for-beginners/ @DanWahlin
|
|
||||||
/website/public/images/learning-hub/copilot-app-for-beginners/ @DanWahlin
|
|
||||||
|
|
||||||
# Agentic Workflows
|
|
||||||
/workflows/ @brunoborges
|
|
||||||
/.github/workflows/validate-agentic-workflows-pr.yml @brunoborges
|
|
||||||
|
|
||||||
# Copilot review policy
|
|
||||||
/.github/skills/code-review/ @aaronpowell
|
|
||||||
/.github/copilot-instructions.md @aaronpowell
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #930
|
|
||||||
/plugins/automate-this/ @dvelton
|
|
||||||
/skills/automate-this/ @dvelton
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #915
|
|
||||||
/skills/cli-mastery/ @DUBSOpenHub
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #929
|
|
||||||
/plugins/napkin/ @dvelton
|
|
||||||
/skills/napkin/ @dvelton
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #888
|
|
||||||
/skills/github-issues/ @labudis
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #884
|
|
||||||
/skills/github-issues/ @labudis
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #889
|
|
||||||
/skills/copilot-spaces/ @labudis
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #978
|
|
||||||
/agents/doublecheck.agent.md @dvelton
|
|
||||||
/plugins/doublecheck/ @dvelton
|
|
||||||
/skills/doublecheck/ @dvelton
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #990
|
|
||||||
/skills/issue-fields-migration/ @labudis
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #1009
|
|
||||||
/skills/publish-to-pages/ @AndreaGriffiths11
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #1049
|
|
||||||
/skills/codeql/ @VeVarunSharma
|
|
||||||
/skills/dependabot/ @VeVarunSharma
|
|
||||||
/skills/secret-scanning/ @VeVarunSharma
|
|
||||||
|
|
||||||
# Added via #codeowner from PR #1118
|
|
||||||
/agents/github-actions-node-upgrade.agent.md @joshjohanning
|
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ The root [`CODEOWNERS`](../../CODEOWNERS) file assigns every path to a team, not
|
|||||||
| `/plugins/` | `@github/awesome-copilot-plugin-reviewers` |
|
| `/plugins/` | `@github/awesome-copilot-plugin-reviewers` |
|
||||||
| `/agents/`, `/instructions/`, `/skills/`, `/hooks/`, `/workflows/` | `@github/awesome-copilot-content-reviewers` |
|
| `/agents/`, `/instructions/`, `/skills/`, `/hooks/`, `/workflows/` | `@github/awesome-copilot-content-reviewers` |
|
||||||
| `/.github/` (including GitHub Actions workflows), `/eng/` | `@github/awesome-copilot-core-maintainers` |
|
| `/.github/` (including GitHub Actions workflows), `/eng/` | `@github/awesome-copilot-core-maintainers` |
|
||||||
|
| Copilot workshop content under `/website/` | `@github/awesome-copilot-workshop-reviewers` |
|
||||||
|
|
||||||
GitHub applies the **last** matching rule, so the per-resource entries at the bottom of the file override the team defaults for their paths. Those entries are added through the `#codeowner` command (`.github/workflows/codeowner-update.md`), which only appends a block at the end of the file. The existing per-resource entries are kept as they are for now; removing them is planned as a separate cleanup. When you edit `CODEOWNERS` by hand:
|
GitHub applies the **last** matching rule, so the workshop entries at the bottom of the file override the default team for their paths. When you edit `CODEOWNERS` by hand:
|
||||||
|
|
||||||
- Keep the `*` rule and the domain team block at the top of the file.
|
- Keep the `*` rule and the domain team block at the top of the file.
|
||||||
- Never add an individual user to the `*` rule.
|
- Never add an individual user to the `*` rule.
|
||||||
- Append new per-resource owners at the end of the file.
|
- Add more-specific path owners after the broader rules they override.
|
||||||
|
|
||||||
## Reviewer pools (`.github/review-routing.yml`)
|
## Reviewer pools (`.github/review-routing.yml`)
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ Current routes, in priority order:
|
|||||||
|
|
||||||
| Intent label | Pool |
|
| Intent label | Pool |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| `workshops` | `workshops` |
|
||||||
| `canvas-extension` | `canvas` |
|
| `canvas-extension` | `canvas` |
|
||||||
| `external-plugin`, `plugin` | `plugin` |
|
| `external-plugin`, `plugin` | `plugin` |
|
||||||
| `skills`, `agent`, `instructions`, `workflow`, `hooks` | `content` |
|
| `skills`, `agent`, `instructions`, `workflow`, `hooks` | `content` |
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export const INTENT_LABELS = Object.freeze([
|
|||||||
"new-submission",
|
"new-submission",
|
||||||
"plugin",
|
"plugin",
|
||||||
"skills",
|
"skills",
|
||||||
|
"workshops",
|
||||||
"website-update",
|
"website-update",
|
||||||
"workflow",
|
"workflow",
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -46,9 +46,11 @@ function rawConfig(overrides = {}) {
|
|||||||
canvas: { team: "github/canvas", reviewers: ["canvas1", "canvas2", "canvas3"], backup: ["canvasBackup"] },
|
canvas: { team: "github/canvas", reviewers: ["canvas1", "canvas2", "canvas3"], backup: ["canvasBackup"] },
|
||||||
plugin: { team: "github/plugin", reviewers: ["plugin1"], backup: [] },
|
plugin: { team: "github/plugin", reviewers: ["plugin1"], backup: [] },
|
||||||
content: { team: "github/content", reviewers: [], backup: [] },
|
content: { team: "github/content", reviewers: [], backup: [] },
|
||||||
|
workshops: { team: "github/workshops", reviewers: ["workshop1"], backup: [] },
|
||||||
automation: { team: "github/automation", reviewers: ["auto1"], backup: ["autoBackup"] },
|
automation: { team: "github/automation", reviewers: ["auto1"], backup: ["autoBackup"] },
|
||||||
},
|
},
|
||||||
routes: [
|
routes: [
|
||||||
|
{ label: "workshops", pool: "workshops" },
|
||||||
{ label: "workflow", pool: "automation" },
|
{ label: "workflow", pool: "automation" },
|
||||||
{ label: "hooks", pool: "automation" },
|
{ label: "hooks", pool: "automation" },
|
||||||
{ label: "canvas-extension", pool: "canvas" },
|
{ label: "canvas-extension", pool: "canvas" },
|
||||||
@@ -97,6 +99,7 @@ describe("configuration", () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
loaded.routes.map((route) => [route.label, route.pool]),
|
loaded.routes.map((route) => [route.label, route.pool]),
|
||||||
[
|
[
|
||||||
|
["workshops", "workshops"],
|
||||||
["canvas-extension", "canvas"],
|
["canvas-extension", "canvas"],
|
||||||
["external-plugin", "plugin"],
|
["external-plugin", "plugin"],
|
||||||
["plugin", "plugin"],
|
["plugin", "plugin"],
|
||||||
@@ -108,7 +111,7 @@ describe("configuration", () => {
|
|||||||
["website-update", "core-maintainers"],
|
["website-update", "core-maintainers"],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert.deepEqual(Object.keys(loaded.pools).sort(), ["canvas", "content", "core-maintainers", "plugin"]);
|
assert.deepEqual(Object.keys(loaded.pools).sort(), ["canvas", "content", "core-maintainers", "plugin", "workshops"]);
|
||||||
assert.equal(loaded.defaultPool, "core-maintainers");
|
assert.equal(loaded.defaultPool, "core-maintainers");
|
||||||
assert.equal(loaded.escalationPool, "core-maintainers");
|
assert.equal(loaded.escalationPool, "core-maintainers");
|
||||||
});
|
});
|
||||||
@@ -165,6 +168,7 @@ describe("reviewer selection", () => {
|
|||||||
assert.equal(selectPool(["skills", "plugin"], cfg), "plugin");
|
assert.equal(selectPool(["skills", "plugin"], cfg), "plugin");
|
||||||
assert.equal(selectPool(["plugin", "canvas-extension"], cfg), "canvas");
|
assert.equal(selectPool(["plugin", "canvas-extension"], cfg), "canvas");
|
||||||
assert.equal(selectPool(["canvas-extension", "workflow"], cfg), "automation");
|
assert.equal(selectPool(["canvas-extension", "workflow"], cfg), "automation");
|
||||||
|
assert.equal(selectPool(["website-update", "workshops"], cfg), "workshops");
|
||||||
assert.equal(selectPool(["website-update"], cfg), "core-maintainers");
|
assert.equal(selectPool(["website-update"], cfg), "core-maintainers");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ const routing = {
|
|||||||
canvas: { team: "github/canvas", reviewers: ["canvasa"], backup: [] },
|
canvas: { team: "github/canvas", reviewers: ["canvasa"], backup: [] },
|
||||||
plugin: { team: "github/plugin", reviewers: [], backup: [] },
|
plugin: { team: "github/plugin", reviewers: [], backup: [] },
|
||||||
content: { reviewers: [] },
|
content: { reviewers: [] },
|
||||||
|
workshops: { team: "github/workshops", reviewers: ["workshopa"], backup: [] },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -255,7 +256,11 @@ test("latest review state wins and changes requested blocks", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("medium tier requires a domain reviewer when the pool is staffed", () => {
|
test("medium tier requires a domain reviewer when the pool is staffed", () => {
|
||||||
const permissions = new Map([["alice", "write"], ["canvasa", "write"]]);
|
const permissions = new Map([
|
||||||
|
["alice", "write"],
|
||||||
|
["canvasa", "write"],
|
||||||
|
["workshopa", "write"],
|
||||||
|
]);
|
||||||
const files = [file("extensions/x/extension.mjs", { status: "added" })];
|
const files = [file("extensions/x/extension.mjs", { status: "added" })];
|
||||||
const base = { tier: "medium", tiers, author: "author", permissions, routing, files };
|
const base = { tier: "medium", tiers, author: "author", permissions, routing, files };
|
||||||
assert.equal(evaluateApprovals({ ...base, reviews: [review("alice", "APPROVED")] }).satisfied, false);
|
assert.equal(evaluateApprovals({ ...base, reviews: [review("alice", "APPROVED")] }).satisfied, false);
|
||||||
@@ -270,6 +275,13 @@ test("medium tier requires a domain reviewer when the pool is staffed", () => {
|
|||||||
assert.equal(unstaffed.satisfied, true, "falls back to any writer when the domain pool is empty");
|
assert.equal(unstaffed.satisfied, true, "falls back to any writer when the domain pool is empty");
|
||||||
assert.ok(unstaffed.notes.length > 0);
|
assert.ok(unstaffed.notes.length > 0);
|
||||||
|
|
||||||
|
const workshop = evaluateApprovals({
|
||||||
|
...base,
|
||||||
|
files: [file("website/src/content/docs/learning-hub/copilot-workshops/lesson.md", { status: "added" })],
|
||||||
|
reviews: [review("workshopa", "APPROVED")],
|
||||||
|
});
|
||||||
|
assert.equal(workshop.satisfied, true);
|
||||||
|
|
||||||
const noRouting = evaluateApprovals({ ...base, routing: null, reviews: [review("alice", "APPROVED")] });
|
const noRouting = evaluateApprovals({ ...base, routing: null, reviews: [review("alice", "APPROVED")] });
|
||||||
assert.equal(noRouting.satisfied, true);
|
assert.equal(noRouting.satisfied, true);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user