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
10 changes: 6 additions & 4 deletions .github/workflows/listings-radar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,16 +302,18 @@ jobs:
'queued again.',
].join('\n');

// Assigned so GitHub emails a direct link. Same reasoning as in
// outreach-watch.yml: a queued draft that nobody is told about
// is a draft nobody submits.
// Deliberately not assigned. A raw candidate is not finished
// work, and the owner's inbox is for finished work only -
// reviewing the first assigned queue found eight leads and zero
// actionable ones. It is labelled `do-akceptacji` after
// qualification, and ready-for-approval.yml does the assigning
// then, which is also the only way the notification fires.
const created = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Listing: ${c.full_name}`.slice(0, 200),
body,
labels: [LABEL],
assignees: [context.repo.owner],
});
core.notice(`Queued #${created.data.number} — ${c.url}`);
}
Expand Down
13 changes: 6 additions & 7 deletions .github/workflows/outreach-watch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -362,19 +362,18 @@ jobs:
'again.',
].join('\n');

// Assigned, not just labelled. A draft that nobody is told
// about is a draft nobody posts, and the queue's whole value is
// speed - an answer four days late lands on a thread nobody is
// reading. GitHub emails the assignee with a direct link, which
// is the whole notification mechanism needed here: open the
// link, read the thread, post or close.
// Deliberately not assigned. A raw candidate is not finished
// work, and the owner's inbox is for finished work only -
// reviewing the first assigned queue found eight leads and zero
// actionable ones. It is labelled `do-akceptacji` after
// qualification, and ready-for-approval.yml does the assigning
// then, which is also the only way the notification fires.
const created = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Outreach: ${c.title}`.slice(0, 200),
body,
labels: [LABEL],
assignees: [context.repo.owner],
});
core.notice(`Queued #${created.data.number} — ${c.url}`);
}
Expand Down
81 changes: 81 additions & 0 deletions .github/workflows/ready-for-approval.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Do akceptacji

# Turns a finished piece of work into an email in the owner's inbox, in
# Polish, with the one action to take.
#
# Two problems this exists to solve, both found the hard way on 2026-08-17:
#
# 1. The discovery bots used to assign every raw candidate to the owner,
# so the inbox filled with things that were not ready. Reviewing that
# queue found eight leads and zero actionable ones - five threads
# closed and resolved, two dead since 2022, one already answered by
# the owner. Nothing should reach the inbox until it is finished.
#
# 2. GitHub suppresses notifications for the actor who performed the
# action. Assigning the owner using the owner's own token emails
# nobody, which is exactly what happened to those ten issues. This
# workflow runs as github-actions[bot], a different actor, so the
# assignment actually notifies.
#
# So: label an issue `do-akceptacji` once it is genuinely finished, and this
# assigns the owner and posts the Polish instruction. The label is the
# handover; the email is its side effect.

on:
issues:
types: [labeled]

permissions:
issues: write

jobs:
assign:
if: github.event.label.name == 'do-akceptacji'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v8
with:
script: |
const owner = context.repo.owner;
const issue_number = context.issue.number;

// Assigning is what sends the mail. Skip it if the owner is
// already assigned, so re-labelling does not silently do nothing
// and look like a failure.
const current = (context.payload.issue.assignees || []).map(a => a.login);
if (!current.includes(owner)) {
await github.rest.issues.addAssignees({
owner, repo: context.repo.repo, issue_number,
assignees: [owner],
});
core.notice(`Przypisano ${owner} — mail powinien wyjść.`);
} else {
core.warning(
`${owner} był już przypisany, więc GitHub nie wyśle powiadomienia ` +
`o przypisaniu. Komentarz poniżej i tak trafi na maila.`);
}

// The comment carries the instruction. Polish, because the owner
// reads these; the draft or entry inside the issue stays in the
// language it will be posted in, which is English.
const body = [
'## Gotowe do akceptacji',
'',
'Ta sprawa jest skompletowana. Nic tu nie trzeba dopisywać ani poprawiać.',
'',
'**Co zrobić:** przeczytaj treść powyżej i wykonaj **jedną** czynność, którą opisuje —',
'wklej gotową odpowiedź, zgłoś wpis albo kliknij przycisk. Potem zamknij to zgłoszenie.',
'',
'**Jeśli coś jest nie tak** — nie poprawiaj tego ręcznie. Zdejmij etykietę',
'`do-akceptacji` i napisz w komentarzu, co nie gra. Poprawka trafi tam, gdzie',
'powstał błąd, żeby nie wrócił.',
'',
'---',
'',
'_Treść przeznaczona do publikacji jest po angielsku celowo — w takim języku zostanie',
'wklejona. Ta instrukcja jest po polsku, bo czytasz ją tylko Ty._',
].join('\n');

await github.rest.issues.createComment({
owner, repo: context.repo.repo, issue_number, body,
});
Loading