diff --git a/.github/oss-weekend.json b/.github/oss-weekend.json index c88187cd..409daa28 100644 --- a/.github/oss-weekend.json +++ b/.github/oss-weekend.json @@ -1,9 +1,10 @@ { "active": true, "mode": "weekend", - "startsAt": "2026-03-27T01:31:56.951Z", - "startsAtText": "Friday, March 27, 2026", - "reopensOn": "2026-04-06", - "reopensOnText": "Monday, April 6, 2026", + "startsAt": "2026-04-02T09:13:17.643Z", + "startsAtText": "Thursday, April 2, 2026", + "reopensOn": "2026-04-13", + "reopensOnText": "Monday, April 13, 2026", + "reason": "at the moment i'm deep in refactoring internals, and need to focus.", "discordUrl": "https://discord.com/invite/3cU7Bz4UPx" } diff --git a/.github/workflows/oss-weekend-issues.yml b/.github/workflows/oss-weekend-issues.yml index 75960cd6..3c21c114 100644 --- a/.github/workflows/oss-weekend-issues.yml +++ b/.github/workflows/oss-weekend-issues.yml @@ -57,6 +57,13 @@ jobs: return; } + const approvedContent = await getTextFile('.github/APPROVED_CONTRIBUTORS'); + const approvedList = approvedContent + .split('\n') + .map(line => line.trim().toLowerCase()) + .filter(line => line && !line.startsWith('#')); + const isApprovedContributor = approvedList.includes(issueAuthor.toLowerCase()); + let weekendState; try { weekendState = JSON.parse(await getTextFile('.github/oss-weekend.json')); @@ -73,12 +80,19 @@ jobs: return; } + if (isApprovedContributor) { + console.log(`${issueAuthor} is in the approved contributors list`); + return; + } + const reopenDate = weekendState.reopensOnText || weekendState.reopensOn || 'after the weekend'; const discordUrl = weekendState.discordUrl || 'https://discord.com/invite/3cU7Bz4UPx'; + const reason = typeof weekendState.reason === 'string' && weekendState.reason.trim() ? weekendState.reason.trim() : null; const message = [ `Hi @${issueAuthor}, thanks for opening an issue.`, '', - `OSS weekend is active until ${reopenDate}, so new issues are being auto-closed for now.`, + `OSS weekend is active until ${reopenDate}, so new issues from unapproved contributors are being auto-closed for now.`, + ...(reason ? ['', `Current focus: ${reason}`] : []), '', `Please reopen or submit this issue again after ${reopenDate}. For support, join [Discord](${discordUrl}).`, ].join('\n'); diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml index 60c4335a..842b7135 100644 --- a/.github/workflows/pr-gate.yml +++ b/.github/workflows/pr-gate.yml @@ -81,34 +81,6 @@ jobs: .filter(line => line && !line.startsWith('#')); const isApprovedContributor = approvedList.includes(prAuthor.toLowerCase()); - let weekendState = null; - try { - weekendState = JSON.parse(await getTextFile('.github/oss-weekend.json')); - } catch (error) { - if (!(error && typeof error === 'object' && 'status' in error && error.status === 404)) { - throw error; - } - } - - if (weekendState?.active && isApprovedContributor) { - console.log(`${prAuthor} is approved, but OSS weekend is active`); - - const reopenDate = weekendState.reopensOnText || weekendState.reopensOn || 'after the weekend'; - const discordUrl = weekendState.discordUrl || 'https://discord.com/invite/3cU7Bz4UPx'; - const message = [ - `Hi @${prAuthor}, thanks for the PR.`, - '', - `OSS weekend is active until ${reopenDate}, so external PRs are being paused for now.`, - '', - 'You are already on the approved contributors list, so you can resubmit this PR after the weekend without reapproval.', - '', - `This PR will be closed automatically. For support, join [Discord](${discordUrl}).`, - ].join('\n'); - - await closePullRequest(message); - return; - } - if (isApprovedContributor) { console.log(`${prAuthor} is in the approved contributors list`); return; diff --git a/README.md b/README.md index 047d87ec..5ba926e2 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # 🏖️ OSS Weekend -**Issue tracker reopens Monday, April 6, 2026.** +**Issue tracker reopens Monday, April 13, 2026.** -OSS weekend runs Friday, March 27, 2026 through Monday, April 6, 2026. New issues are auto-closed during this time. For support, join [Discord](https://discord.com/invite/3cU7Bz4UPx). +OSS weekend runs Thursday, April 2, 2026 through Monday, April 13, 2026. New issues and PRs from unapproved contributors are auto-closed during this time. Approved contributors can still open issues and PRs. For support, join [Discord](https://discord.com/invite/3cU7Bz4UPx). + +Current focus: at the moment i'm deep in refactoring internals, and need to focus. --- diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 9bc12d30..1c0fcd71 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -1,9 +1,11 @@ # 🏖️ OSS Weekend -**Issue tracker reopens Monday, April 6, 2026.** +**Issue tracker reopens Monday, April 13, 2026.** -OSS weekend runs Friday, March 27, 2026 through Monday, April 6, 2026. New issues are auto-closed during this time. For support, join [Discord](https://discord.com/invite/3cU7Bz4UPx). +OSS weekend runs Thursday, April 2, 2026 through Monday, April 13, 2026. New issues and PRs from unapproved contributors are auto-closed during this time. Approved contributors can still open issues and PRs. For support, join [Discord](https://discord.com/invite/3cU7Bz4UPx). + +Current focus: at the moment i'm deep in refactoring internals, and need to focus. --- diff --git a/scripts/oss-weekend.mjs b/scripts/oss-weekend.mjs index 3b9868be..415cab05 100644 --- a/scripts/oss-weekend.mjs +++ b/scripts/oss-weekend.mjs @@ -9,6 +9,11 @@ const MARKER_START = ""; const MARKER_END = ""; const DISCORD_URL = "https://discord.com/invite/3cU7Bz4UPx"; +function normalizeReason(reason) { + const trimmedReason = reason.trim(); + return trimmedReason ? trimmedReason : null; +} + function parseArgs(argv) { const options = {}; @@ -69,9 +74,10 @@ function parseDateInput(value) { return new Date(Date.UTC(Number(year), Number(month) - 1, Number(day), 12, 0, 0)); } -function buildBanner(now, endDate) { +function buildBanner(now, endDate, reason) { const startDate = formatLongDate(now); const reopenDate = formatLongDate(endDate); + const normalizedReason = normalizeReason(reason ?? ""); return [ MARKER_START, @@ -79,7 +85,8 @@ function buildBanner(now, endDate) { "", `**Issue tracker reopens ${reopenDate}.**`, "", - `OSS weekend runs ${startDate} through ${reopenDate}. New issues are auto-closed during this time. For support, join [Discord](${DISCORD_URL}).`, + `OSS weekend runs ${startDate} through ${reopenDate}. New issues and PRs from unapproved contributors are auto-closed during this time. Approved contributors can still open issues and PRs. For support, join [Discord](${DISCORD_URL}).`, + ...(normalizedReason ? ["", `Current focus: ${normalizedReason}`] : []), MARKER_END, "", "---", @@ -88,8 +95,8 @@ function buildBanner(now, endDate) { ].join("\n"); } -function upsertBanner(readme, now, endDate) { - const banner = buildBanner(now, endDate); +function upsertBanner(readme, now, endDate, reason) { + const banner = buildBanner(now, endDate, reason); const bannerPattern = new RegExp( `${escapeRegExp(MARKER_START)}[\\s\\S]*?${escapeRegExp(MARKER_END)}\\n\\n---\\n\\n?`, "m", @@ -121,7 +128,9 @@ function parseReadmePaths(cliOptions) { .filter(Boolean); } -function buildState(now, endDateInput, endDate) { +function buildState(now, endDateInput, endDate, reason) { + const normalizedReason = normalizeReason(reason ?? ""); + return JSON.stringify( { active: true, @@ -130,6 +139,7 @@ function buildState(now, endDateInput, endDate) { startsAtText: formatLongDate(now), reopensOn: endDateInput, reopensOnText: formatLongDate(endDate), + reason: normalizedReason, discordUrl: DISCORD_URL, }, null, @@ -229,6 +239,7 @@ function printUsage() { " --end-date=YYYY-MM-DD Required for --mode=close.", " --readme=PATHS Optional comma-separated README paths. Defaults to README.md,packages/coding-agent/README.md.", " --state=PATH Optional state file path. Defaults to .github/oss-weekend.json.", + " --reason=TEXT Optional reason shown in the README banner and weekend auto-close comments.", " --git Stage only the OSS weekend files, commit, and push after updating them.", " --dry-run Preview without editing files or running git operations.", " --now=ISO Optional current timestamp override for testing.", @@ -257,6 +268,7 @@ async function main() { const readmePaths = parseReadmePaths(cliOptions); const statePath = getOption("state", cliOptions, "OSS_WEEKEND_STATE_PATH", DEFAULT_STATE_PATH); const endDateInput = getOption("end-date", cliOptions, "OSS_WEEKEND_END_DATE", ""); + const reason = normalizeReason(getOption("reason", cliOptions, "OSS_WEEKEND_REASON", "")); const now = nowInput ? new Date(nowInput) : new Date(); if (Number.isNaN(now.getTime())) { @@ -272,7 +284,7 @@ async function main() { for (const readmePath of readmePaths) { const currentReadme = await readFile(readmePath, "utf8"); - const nextReadme = mode === "close" ? upsertBanner(currentReadme, now, endDate) : removeBanner(currentReadme); + const nextReadme = mode === "close" ? upsertBanner(currentReadme, now, endDate, reason) : removeBanner(currentReadme); const changed = nextReadme !== currentReadme; if (changed && !dryRun) { @@ -283,7 +295,7 @@ async function main() { } const currentState = await readOptionalFile(statePath); - const nextState = mode === "close" ? buildState(now, endDateInput, endDate) : null; + const nextState = mode === "close" ? buildState(now, endDateInput, endDate, reason) : null; const stateChanged = mode === "close" ? currentState !== nextState : currentState !== null; if (!dryRun) { @@ -317,6 +329,7 @@ async function main() { git_commands: gitResult ? gitResult.commands.join(" && ") : "", end_date: endDate ? endDateInput : "", end_date_text: endDate ? formatLongDate(endDate) : "", + reason: reason ?? "", now_utc: now.toISOString(), now_berlin: new Intl.DateTimeFormat("sv-SE", { timeZone: TIME_ZONE,