diff --git a/script/get-changes-since b/script/get-pull-requests-since similarity index 94% rename from script/get-changes-since rename to script/get-pull-requests-since index 3b889ce991..c8509480a6 100755 --- a/script/get-changes-since +++ b/script/get-pull-requests-since @@ -22,12 +22,12 @@ async function main() { const startDate = new Date(process.argv[2]); const today = new Date(); - console.log(`Changes from ${startDate} to ${today}\n`); + console.log(`Pull requests from ${startDate} to ${today}\n`); let pullRequestNumbers = getPullRequestNumbers(startDate, today); // Fetch the pull requests from the GitHub API. - console.log("Merged Pull requests:"); + console.log("Merged pull requests:"); for (const pullRequestNumber of pullRequestNumbers) { const webURL = `https://github.com/zed-industries/zed/pull/${pullRequestNumber}`; const apiURL = `https://api.github.com/repos/zed-industries/zed/pulls/${pullRequestNumber}`; diff --git a/script/get-release-notes-since b/script/get-release-notes-since new file mode 100755 index 0000000000..20a6fc18de --- /dev/null +++ b/script/get-release-notes-since @@ -0,0 +1,125 @@ +#!/usr/bin/env node --redirect-warnings=/dev/null + +const { execFileSync } = require("child_process"); +const { GITHUB_ACCESS_TOKEN } = process.env; + +main(); + +async function main() { + const startDate = new Date(process.argv[2]); + const today = new Date(); + + console.log(`Release notes from ${startDate} to ${today}\n`); + + const releases = await getReleases(startDate, today); + const previewReleases = releases.filter((release) => + release.tagName.includes("-pre"), + ); + + const stableReleases = releases.filter( + (release) => !release.tagName.includes("-pre"), + ); + + // Filter out all preview release, as all of those changes have made it to the stable release, except for the latest preview release + const aggregatedReleases = stableReleases + .concat(previewReleases[0]) + .reverse(); + + const aggregatedReleaseTitles = aggregatedReleases + .map((release) => release.name) + .join(", "); + + console.log(); + console.log(`Release titles: ${aggregatedReleaseTitles}`); + + console.log("Release notes:"); + console.log(); + + for (const release of aggregatedReleases) { + const publishedDate = release.publishedAt.split("T")[0]; + console.log(`${release.name}: ${publishedDate}`); + console.log(); + console.log(release.description); + console.log(); + } +} + +async function getReleases(startDate, endDate) { + const query = ` + query ($owner: String!, $repo: String!, $cursor: String) { + repository(owner: $owner, name: $repo) { + releases(first: 100, orderBy: {field: CREATED_AT, direction: DESC}, after: $cursor) { + nodes { + tagName + name + createdAt + publishedAt + description + url + author { + login + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + `; + + let allReleases = []; + let hasNextPage = true; + let cursor = null; + + while (hasNextPage) { + const response = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${GITHUB_ACCESS_TOKEN}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + query, + variables: { owner: "zed-industries", repo: "zed", cursor }, + }), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + if (data.errors) { + throw new Error(`GraphQL error: ${JSON.stringify(data.errors)}`); + } + + if (!data.data || !data.data.repository || !data.data.repository.releases) { + throw new Error(`Unexpected response structure: ${JSON.stringify(data)}`); + } + + const releases = data.data.repository.releases.nodes; + allReleases = allReleases.concat(releases); + + hasNextPage = data.data.repository.releases.pageInfo.hasNextPage; + cursor = data.data.repository.releases.pageInfo.endCursor; + + lastReleaseOnPage = releases[releases.length - 1]; + + if ( + releases.length > 0 && + new Date(lastReleaseOnPage.createdAt) < startDate + ) { + break; + } + } + + const filteredReleases = allReleases.filter((release) => { + const releaseDate = new Date(release.createdAt); + return releaseDate >= startDate && releaseDate <= endDate; + }); + + return filteredReleases; +}