Skip to content

test(release): add unit tests when searching for a release #603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 18, 2025
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
256 changes: 254 additions & 2 deletions __tests__/github.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import * as assert from "assert";
import { text } from "stream/consumers";
import { mimeOrDefault, asset } from "../src/github";
import {
mimeOrDefault,
asset,
Releaser,
Release,
findTagFromReleases,
} from "../src/github";

describe("github", () => {
describe("mimeOrDefault", () => {
Expand All @@ -20,4 +25,251 @@ describe("github", () => {
assert.equal(size, 10);
});
});

describe("findTagFromReleases", () => {
const owner = "owner";
const repo = "repo";

const mockRelease: Release = {
id: 1,
upload_url: `https://api.github.com/repos/${owner}/${repo}/releases/1/assets`,
html_url: `https://github.com/${owner}/${repo}/releases/tag/v1.0.0`,
tag_name: "v1.0.0",
name: "Test Release",
body: "Test body",
target_commitish: "main",
draft: false,
prerelease: false,
assets: [],
} as const;

const mockReleaser: Releaser = {
getReleaseByTag: () => Promise.reject("Not implemented"),
createRelease: () => Promise.reject("Not implemented"),
updateRelease: () => Promise.reject("Not implemented"),
allReleases: async function* () {
yield { data: [mockRelease] };
},
} as const;

describe("when the tag_name is not an empty string", () => {
const targetTag = "v1.0.0";

it("finds a matching release in first batch of results", async () => {
const targetRelease = {
...mockRelease,
owner,
repo,
tag_name: targetTag,
};
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};

const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [targetRelease] };
yield { data: [otherRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
targetTag,
);

assert.deepStrictEqual(result, targetRelease);
});

it("finds a matching release in second batch of results", async () => {
const targetRelease = {
...mockRelease,
owner,
repo,
tag_name: targetTag,
};
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};

const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [otherRelease] };
yield { data: [targetRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
targetTag,
);
assert.deepStrictEqual(result, targetRelease);
});

it("returns undefined when a release is not found in any batch", async () => {
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};
const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [otherRelease] };
yield { data: [otherRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
targetTag,
);

assert.strictEqual(result, undefined);
});

it("returns undefined when no releases are returned", async () => {
const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
targetTag,
);

assert.strictEqual(result, undefined);
});
});

describe("when the tag_name is an empty string", () => {
const emptyTag = "";

it("finds a matching release in first batch of results", async () => {
const targetRelease = {
...mockRelease,
owner,
repo,
tag_name: emptyTag,
};
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};

const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [targetRelease] };
yield { data: [otherRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
emptyTag,
);

assert.deepStrictEqual(result, targetRelease);
});

it("finds a matching release in second batch of results", async () => {
const targetRelease = {
...mockRelease,
owner,
repo,
tag_name: emptyTag,
};
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};

const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [otherRelease] };
yield { data: [targetRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
emptyTag,
);
assert.deepStrictEqual(result, targetRelease);
});

it("returns undefined when a release is not found in any batch", async () => {
const otherRelease = {
...mockRelease,
owner,
repo,
tag_name: "v1.0.1",
};
const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [otherRelease] };
yield { data: [otherRelease] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
emptyTag,
);

assert.strictEqual(result, undefined);
});

it("returns undefined when no releases are returned", async () => {
const releaser = {
...mockReleaser,
allReleases: async function* () {
yield { data: [] };
},
};

const result = await findTagFromReleases(
releaser,
owner,
repo,
emptyTag,
);

assert.strictEqual(result, undefined);
});
});
});
});
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

42 changes: 32 additions & 10 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,18 +225,13 @@ export const release = async (
const discussion_category_name = config.input_discussion_category_name;
const generate_release_notes = config.input_generate_release_notes;
try {
// you can't get an existing draft by tag
// so we must find one in the list of all releases
let _release: Release | undefined = undefined;
for await (const response of releaser.allReleases({
const _release: Release | undefined = await findTagFromReleases(
releaser,
owner,
repo,
})) {
_release = response.data.find((release) => release.tag_name === tag);
if (_release !== undefined) {
break;
}
}
tag,
);

if (_release === undefined) {
return await createRelease(
tag,
Expand Down Expand Up @@ -331,6 +326,33 @@ export const release = async (
}
};

/**
* Finds a release by tag name from all a repository's releases.
*
* @param releaser - The GitHub API wrapper for release operations
* @param owner - The owner of the repository
* @param repo - The name of the repository
* @param tag - The tag name to search for
* @returns The release with the given tag name, or undefined if no release with that tag name is found
*/
export async function findTagFromReleases(
releaser: Releaser,
owner: string,
repo: string,
tag: string,
): Promise<Release | undefined> {
for await (const { data: releases } of releaser.allReleases({
owner,
repo,
})) {
const release = releases.find((release) => release.tag_name === tag);
if (release) {
return release;
}
}
return undefined;
}

async function createRelease(
tag: string,
config: Config,
Expand Down