mirror of
https://github.com/softprops/action-gh-release.git
synced 2025-11-23 11:50:51 +00:00
Previously, the releases were created and then artifacts (if any) were added to them. This broke when GitHub released "immutable" releases, which disallow changes after the release is published. Make it so that releases are always marked as "draft" when being worked on by the action, and unmarked as draft (if desired) once the action is completed. Fixes #653
310 lines
8.6 KiB
TypeScript
310 lines
8.6 KiB
TypeScript
import {
|
|
asset,
|
|
findTagFromReleases,
|
|
mimeOrDefault,
|
|
release,
|
|
Release,
|
|
Releaser,
|
|
} from '../src/github';
|
|
|
|
import { assert, describe, it } from 'vitest';
|
|
|
|
describe('github', () => {
|
|
describe('mimeOrDefault', () => {
|
|
it('returns a specific mime for common path', async () => {
|
|
assert.equal(mimeOrDefault('foo.tar.gz'), 'application/gzip');
|
|
});
|
|
it('returns default mime for uncommon path', async () => {
|
|
assert.equal(mimeOrDefault('foo.uncommon'), 'application/octet-stream');
|
|
});
|
|
});
|
|
|
|
describe('asset', () => {
|
|
it('derives asset info from a path', async () => {
|
|
const { name, mime, size } = asset('tests/data/foo/bar.txt');
|
|
assert.equal(name, 'bar.txt');
|
|
assert.equal(mime, 'text/plain');
|
|
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'),
|
|
finalizeRelease: () => 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);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
it('handles 422 already_exists error gracefully', async () => {
|
|
const mockReleaser: Releaser = {
|
|
getReleaseByTag: () => Promise.reject('Not implemented'),
|
|
createRelease: () =>
|
|
Promise.reject({
|
|
status: 422,
|
|
response: { data: { errors: [{ code: 'already_exists' }] } },
|
|
}),
|
|
updateRelease: () =>
|
|
Promise.resolve({
|
|
data: {
|
|
id: 1,
|
|
upload_url: 'test',
|
|
html_url: 'test',
|
|
tag_name: 'v1.0.0',
|
|
name: 'test',
|
|
body: 'test',
|
|
target_commitish: 'main',
|
|
draft: true,
|
|
prerelease: false,
|
|
assets: [],
|
|
},
|
|
}),
|
|
finalizeRelease: async () => {},
|
|
allReleases: async function* () {
|
|
yield {
|
|
data: [
|
|
{
|
|
id: 1,
|
|
upload_url: 'test',
|
|
html_url: 'test',
|
|
tag_name: 'v1.0.0',
|
|
name: 'test',
|
|
body: 'test',
|
|
target_commitish: 'main',
|
|
draft: false,
|
|
prerelease: false,
|
|
assets: [],
|
|
},
|
|
],
|
|
};
|
|
},
|
|
} as const;
|
|
|
|
const config = {
|
|
github_token: 'test-token',
|
|
github_ref: 'refs/tags/v1.0.0',
|
|
github_repository: 'owner/repo',
|
|
input_tag_name: undefined,
|
|
input_name: undefined,
|
|
input_body: undefined,
|
|
input_body_path: undefined,
|
|
input_files: [],
|
|
input_draft: undefined,
|
|
input_prerelease: undefined,
|
|
input_preserve_order: undefined,
|
|
input_overwrite_files: undefined,
|
|
input_fail_on_unmatched_files: false,
|
|
input_target_commitish: undefined,
|
|
input_discussion_category_name: undefined,
|
|
input_generate_release_notes: false,
|
|
input_append_body: false,
|
|
input_make_latest: undefined,
|
|
};
|
|
|
|
const result = await release(config, mockReleaser, 1);
|
|
assert.ok(result);
|
|
assert.equal(result.id, 1);
|
|
});
|
|
});
|
|
});
|