Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions .github/workflows/compliance-close.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,37 @@ jobs:
const now = Date.now();
const twoHours = 2 * 60 * 60 * 1000;
const orgMemberAssociations = new Set(['OWNER', 'MEMBER']);
const agentLogin = 'opencode-agent[bot]';
const { data: file } = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: '.github/TEAM_MEMBERS',
ref: 'dev',
});
const teamMembers = new Set(
Buffer.from(file.content, 'base64')
.toString()
.split('\n')
.map((line) => line.trim().toLowerCase())
.filter(Boolean)
);

function isExempt(item) {
const login = item.user?.login?.toLowerCase();
return (
login === agentLogin ||
orgMemberAssociations.has(item.author_association) ||
(login && teamMembers.has(login))
);
}

for (const item of items) {
const isPR = !!item.pull_request;
const kind = isPR ? 'PR' : 'issue';
const login = item.user?.login;

if (orgMemberAssociations.has(item.author_association)) {
core.info(`Skipping ${kind} #${item.number}; author association is ${item.author_association}`);
if (isExempt(item)) {
core.info(`Skipping ${kind} #${item.number}; author ${login || 'unknown'} is exempt`);
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/duplicate-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,31 @@ jobs:
with:
fetch-depth: 1

- name: Check exempt issue author
id: author
run: |
LOGIN="${{ github.event.issue.user.login }}"
ASSOCIATION="${{ github.event.issue.author_association }}"

if [ "$LOGIN" = "opencode-agent[bot]" ] ||
[ "$ASSOCIATION" = "OWNER" ] ||
[ "$ASSOCIATION" = "MEMBER" ] ||
grep -qxiF "$LOGIN" .github/TEAM_MEMBERS; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping issue automation for exempt author: $LOGIN ($ASSOCIATION)"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- uses: ./.github/actions/setup-bun
if: steps.author.outputs.skip != 'true'

- name: Install opencode
if: steps.author.outputs.skip != 'true'
run: curl -fsSL https://opencode.ai/install | bash

- name: Check duplicates and compliance
if: steps.author.outputs.skip != 'true'
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -132,12 +151,31 @@ jobs:
with:
fetch-depth: 1

- name: Check exempt issue author
id: author
run: |
LOGIN="${{ github.event.issue.user.login }}"
ASSOCIATION="${{ github.event.issue.author_association }}"

if [ "$LOGIN" = "opencode-agent[bot]" ] ||
[ "$ASSOCIATION" = "OWNER" ] ||
[ "$ASSOCIATION" = "MEMBER" ] ||
grep -qxiF "$LOGIN" .github/TEAM_MEMBERS; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping issue automation for exempt author: $LOGIN ($ASSOCIATION)"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- uses: ./.github/actions/setup-bun
if: steps.author.outputs.skip != 'true'

- name: Install opencode
if: steps.author.outputs.skip != 'true'
run: curl -fsSL https://opencode.ai/install | bash

- name: Recheck compliance
if: steps.author.outputs.skip != 'true'
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,32 @@ jobs:
with:
fetch-depth: 1

- name: Check exempt issue author
id: author
run: |
LOGIN="${{ github.event.issue.user.login }}"
ASSOCIATION="${{ github.event.issue.author_association }}"

if [ "$LOGIN" = "opencode-agent[bot]" ] ||
[ "$ASSOCIATION" = "OWNER" ] ||
[ "$ASSOCIATION" = "MEMBER" ] ||
grep -qxiF "$LOGIN" .github/TEAM_MEMBERS; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping issue automation for exempt author: $LOGIN ($ASSOCIATION)"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Setup Bun
if: steps.author.outputs.skip != 'true'
uses: ./.github/actions/setup-bun

- name: Install opencode
if: steps.author.outputs.skip != 'true'
run: curl -fsSL https://opencode.ai/install | bash

- name: Triage issue
if: steps.author.outputs.skip != 'true'
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
19 changes: 19 additions & 0 deletions script/github/close-issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ if (!token) {
}

const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000)
const agentLogin = "opencode-agent[bot]"
const teamMembers = new Set(
(await Bun.file(new URL("../../.github/TEAM_MEMBERS", import.meta.url)).text())
.split("\n")
.map((line) => line.trim().toLowerCase())
.filter(Boolean),
)
const teamAssociations = new Set(["OWNER", "MEMBER"])

type Issue = {
number: number
updated_at: string
author_association: string
user: { login: string } | null
}

const headers = {
Expand All @@ -24,6 +34,11 @@ const headers = {
"X-GitHub-Api-Version": "2022-11-28",
}

function shouldSkip(i: Issue) {
const login = i.user?.login.toLowerCase()
return login === agentLogin || (login ? teamMembers.has(login) : false) || teamAssociations.has(i.author_association)
}

async function close(num: number) {
const base = `https://api.github.com/repos/${repo}/issues/${num}`

Expand Down Expand Up @@ -63,6 +78,10 @@ async function main() {
for (const i of all) {
const updated = new Date(i.updated_at)
if (updated < cutoff) {
if (shouldSkip(i)) {
console.log(`Skipping stale issue #${i.number}; author ${i.user?.login ?? "unknown"} is exempt`)
continue
}
stale.push(i.number)
} else {
console.log(`\nFound fresh issue #${i.number}, stopping`)
Expand Down
Loading