diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2f2bb6..22a6cab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # @changesets/action +## 1.8.2 + +### Patch Changes + +- [`e47dcdc`](https://github.com/changesets/action/commit/e47dcdcda2d3c570ab43fc31f1ac43872b47a5a4) Thanks [@openscript](https://github.com/openscript)! - Filter clientside for Forgejo + +## 1.8.1 + +### Patch Changes + +- [`2135466`](https://github.com/changesets/action/commit/213546601666ba543dd4a716db7b148c55f4c36f) Thanks [@openscript](https://github.com/openscript)! - Encode branch and base + ## 1.8.0 ### Minor Changes @@ -11,6 +23,7 @@ - [#502](https://github.com/changesets/action/pull/502) [`6002dbd`](https://github.com/changesets/action/commit/6002dbd987f49a3c0a134910d9c7bca975b79977) Thanks [@oshytiko](https://github.com/oshytiko)! - Fixed initial `.changeset` state being picked up, when `cwd` parameter is provided - [#536](https://github.com/changesets/action/pull/536) [`81b3f61`](https://github.com/changesets/action/commit/81b3f61ebffcb868f73e4c0b2682517149c834a2) Thanks [@radnan](https://github.com/radnan)! - Fixed `.changeset` state being picked for the version command when `cwd` parameter is provided +- [`905ea6d`](https://github.com/changesets/action/commit/905ea6d481f54d210f11da2daa15655dadd89f15) Thanks [@openscript](https://github.com/openscript)! - Add Forgejo/Gitea actions support ## 1.7.0 diff --git a/src/run.test.ts b/src/run.test.ts index ff1b268c..eaf1cb57 100644 --- a/src/run.test.ts +++ b/src/run.test.ts @@ -5,7 +5,7 @@ import { createFixture } from "fs-fixture"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { Git } from "./git.ts"; import { setupOctokit } from "./octokit.ts"; -import { runVersion } from "./run.ts"; +import { isForgejoOrGitea, runVersion } from "./run.ts"; vi.mock("@actions/github", () => ({ context: { @@ -427,3 +427,23 @@ fluminis divesque vulnere aquis parce lapsis rabie si visa fulmineis. expect(mockedGraphql.mock.calls[0]).toMatchSnapshot(); }); }); + +describe("isForgejoOrGitea", () => { + it("returns false when no Forgejo/Gitea env vars are set", () => { + delete process.env.GITEA_ACTIONS; + delete process.env.FORGEJO_ACTIONS; + expect(isForgejoOrGitea()).toBe(false); + }); + + it("returns true when GITEA_ACTIONS is set", () => { + process.env.GITEA_ACTIONS = "true"; + expect(isForgejoOrGitea()).toBe(true); + delete process.env.GITEA_ACTIONS; + }); + + it("returns true when FORGEJO_ACTIONS is set", () => { + process.env.FORGEJO_ACTIONS = "true"; + expect(isForgejoOrGitea()).toBe(true); + delete process.env.FORGEJO_ACTIONS; + }); +}); diff --git a/src/run.ts b/src/run.ts index 818edfb6..d33e3ba1 100644 --- a/src/run.ts +++ b/src/run.ts @@ -20,6 +20,69 @@ import { const require = createRequire(import.meta.url); +/** + * Detects if we're running on Forgejo or Gitea Actions. + * These platforms set specific environment variables when running actions. + */ +export function isForgejoOrGitea(): boolean { + return !!(process.env.GITEA_ACTIONS || process.env.FORGEJO_ACTIONS); +} + +type PullRequestData = { + number: number; + title: string; + body: string | null; + state: string; + head?: { ref: string }; + base?: { ref: string }; +}; + +/** + * Fetches existing pull requests from the version branch to the base branch. + * Uses different API endpoints for GitHub vs Forgejo/Gitea. + * + * GitHub: GET /repos/{owner}/{repo}/pulls?state=open&head={owner}:{branch}&base={base} + * Forgejo/Gitea: List all open PRs and filter client-side (their list API doesn't support head/base filters) + */ +export async function getExistingPullRequests( + octokit: Octokit, + options: { + owner: string; + repo: string; + head: string; + base: string; + } +): Promise { + if (isForgejoOrGitea()) { + core.info("Detected Forgejo/Gitea environment, using compatible API"); + // Forgejo/Gitea list endpoint doesn't support head/base filters, + // so we list all open PRs and filter client-side + const response = await octokit.rest.pulls.list({ + owner: options.owner, + repo: options.repo, + state: "open", + }); + // Filter by head and base branch + const filtered = response.data.filter( + (pr) => pr.head.ref === options.head && pr.base.ref === options.base + ); + core.info( + `Found ${response.data.length} open PR(s), ${filtered.length} matching head=${options.head} base=${options.base}` + ); + return filtered; + } else { + // GitHub API: GET /repos/{owner}/{repo}/pulls with query params + const response = await octokit.rest.pulls.list({ + owner: options.owner, + repo: options.repo, + state: "open", + head: `${options.owner}:${options.head}`, + base: options.base, + }); + return response.data; + } +} + // GitHub Issues/PRs messages have a max size limit on the // message body payload. // `body is too long (maximum is 65536 characters)`. @@ -71,12 +134,12 @@ type PublishedPackage = { name: string; version: string }; type PublishResult = | { - published: true; - publishedPackages: PublishedPackage[]; - } + published: true; + publishedPackages: PublishedPackage[]; + } | { - published: false; - }; + published: false; + }; export async function runPublish({ script, @@ -108,7 +171,7 @@ export async function runPublish({ if (pkg === undefined) { throw new Error( `Package "${pkgName}" not found.` + - "This is probably a bug in the action, please open an issue", + "This is probably a bug in the action, please open an issue", ); } releasedPackages.push(pkg); @@ -127,7 +190,7 @@ export async function runPublish({ if (packages.length === 0) { throw new Error( `No package found.` + - "This is probably a bug in the action, please open an issue", + "This is probably a bug in the action, please open an issue", ); } let pkg = packages[0]; @@ -199,11 +262,10 @@ export async function getVersionPrBody({ prBodyMaxCharacters, branch, }: GetMessageOptions) { - let messageHeader = `This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and ${ - hasPublishScript - ? `the packages will be published to npm automatically` - : `publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing)` - }. If you're not ready to do a release yet, that's fine, whenever you add more changesets to ${branch}, this PR will be updated. + let messageHeader = `This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and ${hasPublishScript + ? `the packages will be published to npm automatically` + : `publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing)` + }. If you're not ready to do a release yet, that's fine, whenever you add more changesets to ${branch}, this PR will be updated. `; let messagePrestate = !!preState ? `⚠️⚠️⚠️⚠️⚠️⚠️ @@ -330,9 +392,8 @@ export async function runVersion({ ); const finalPrTitle = `${prTitle}${!!preState ? ` (${preState.tag})` : ""}`; - const finalCommitMessage = `${commitMessage}${ - !!preState ? ` (${preState.tag})` : "" - }`; + const finalCommitMessage = `${commitMessage}${!!preState ? ` (${preState.tag})` : "" + }`; /** * Fetch any existing pull requests that are open against the branch, @@ -341,15 +402,15 @@ export async function runVersion({ * (`@changesets/ghcommit` has to reset the branch to the same commit as the base, * which GitHub will then react to by closing the PRs) */ - const existingPullRequests = await octokit.rest.pulls.list({ - ...github.context.repo, - state: "open", - head: `${github.context.repo.owner}:${versionBranch}`, + const existingPullRequests = await getExistingPullRequests(octokit, { + owner: github.context.repo.owner, + repo: github.context.repo.repo, + head: versionBranch, base: branch, }); core.info( `Existing pull requests: ${JSON.stringify( - existingPullRequests.data, + existingPullRequests, null, 2, )}`, @@ -369,7 +430,7 @@ export async function runVersion({ prBodyMaxCharacters, }); - if (existingPullRequests.data.length === 0) { + if (existingPullRequests.length === 0) { core.info("creating pull request"); const { data: newPullRequest } = await octokit.rest.pulls.create({ base: branch, @@ -384,7 +445,7 @@ export async function runVersion({ pullRequestNumber: newPullRequest.number, }; } else { - const [pullRequest] = existingPullRequests.data; + const [pullRequest] = existingPullRequests; core.info(`updating found pull request #${pullRequest.number}`); const convertPullRequestToDraftMutation =