| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- name: Bounty detector
- on:
- issues:
- types: [labeled]
- permissions:
- issues: write
- pull-requests: read
- jobs:
- notify:
- runs-on: ubuntu-latest
- if: startsWith(github.event.label.name, 'diff:')
- steps:
- - name: Comment bounty info
- uses: actions/github-script@v7
- env:
- FORUM_URL: "https://hub.jmonkeyengine.org/t/bounty-program-trial-starts-today/49394/"
- RESERVE_HOURS: "48"
- TIMER_SVG_BASE: "https://jme-bounty-reservation-indicator.rblb.workers.dev/timer.svg"
- with:
- script: |
- const issue = context.payload.issue;
- const actor = context.actor;
- const issueOwner = issue.user?.login;
- if (!issueOwner) return;
- const forumUrl = process.env.FORUM_URL || "TBD";
- const reserveHours = Number(process.env.RESERVE_HOURS || "48");
- const svgBase = process.env.TIMER_SVG_BASE || "";
- // "previous contributor" = has at least one merged PR authored in this repo
- const repoFull = `${context.repo.owner}/${context.repo.repo}`;
- const q = `repo:${repoFull} type:pr author:${issueOwner} is:merged`;
- let isPreviousContributor = false;
- try {
- const search = await github.rest.search.issuesAndPullRequests({ q, per_page: 1 });
- isPreviousContributor = (search.data.total_count ?? 0) > 0;
- } catch (e) {
- isPreviousContributor = false;
- }
- // Reserve only if previous contributor AND labeler is NOT the issue owner
- const shouldReserve = isPreviousContributor && (actor !== issueOwner);
- const lines = [];
- lines.push(`## 💰 This issue has a bounty`);
- lines.push(`Resolve it to receive a reward.`);
- lines.push(`For details (amount, rules, eligibility), see: ${forumUrl}`);
- lines.push("");
- lines.push(`If you want to start working on this, **comment on this issue** with your intent.`);
- lines.push(`If accepted by a maintainer, the issue will be **assigned** to you.`);
- lines.push("");
- if (shouldReserve && svgBase) {
- const reservedUntil = new Date(Date.now() + reserveHours * 60 * 60 * 1000);
- const reservedUntilIso = reservedUntil.toISOString();
- const svgUrl =
- `${svgBase}` +
- `?until=${encodeURIComponent(reservedUntilIso)}` +
- `&user=${encodeURIComponent(issueOwner)}` +
- `&theme=dark`;
- lines.push(``);
- lines.push("");
- }
- // Avoid duplicate comments for the same label
- const comments = await github.rest.issues.listComments({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issue.number,
- per_page: 100,
- });
- const already = comments.data.some(c =>
- c.user?.login === "github-actions[bot]" &&
- typeof c.body === "string" &&
- c.body.includes("This issue has a bounty")
- );
- if (already) return;
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: issue.number,
- body: lines.join("\n"),
- });
|