mirror of
https://github.com/softprops/action-gh-release.git
synced 2026-03-19 21:39:03 +08:00
fix: normalize refs-tag inputs (#755)
Signed-off-by: Rui Chen <rui@chenrui.dev>
This commit is contained in:
@@ -189,7 +189,7 @@ The following are optional as `step.with` keys
|
|||||||
| `files` | String | Newline-delimited globs of paths to assets to upload for release. Escape glob metacharacters when you need to match a literal filename that contains them, such as `[` or `]`. On Windows, both `\` and `/` separators are accepted. |
|
| `files` | String | Newline-delimited globs of paths to assets to upload for release. Escape glob metacharacters when you need to match a literal filename that contains them, such as `[` or `]`. On Windows, both `\` and `/` separators are accepted. |
|
||||||
| `overwrite_files` | Boolean | Indicator of whether files should be overwritten when they already exist. Defaults to true |
|
| `overwrite_files` | Boolean | Indicator of whether files should be overwritten when they already exist. Defaults to true |
|
||||||
| `name` | String | Name of the release. defaults to tag name |
|
| `name` | String | Name of the release. defaults to tag name |
|
||||||
| `tag_name` | String | Name of a tag. defaults to `github.ref_name` |
|
| `tag_name` | String | Name of a tag. defaults to `github.ref_name`. `refs/tags/<name>` values are normalized to `<name>`. |
|
||||||
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
|
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
|
||||||
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
|
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
|
||||||
| `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Defaults to repository default branch. |
|
| `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Defaults to repository default branch. |
|
||||||
|
|||||||
@@ -498,6 +498,58 @@ describe('github', () => {
|
|||||||
assert.equal(result.created, false);
|
assert.equal(result.created, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('normalizes refs/tags-prefixed input_tag_name values before reusing an existing release', async () => {
|
||||||
|
const existingRelease: Release = {
|
||||||
|
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: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateReleaseSpy = vi.fn(async () => ({ data: existingRelease }));
|
||||||
|
const getReleaseByTagSpy = vi.fn(async () => ({ data: existingRelease }));
|
||||||
|
const result = await release(
|
||||||
|
{
|
||||||
|
...config,
|
||||||
|
input_tag_name: 'refs/tags/v1.0.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getReleaseByTag: getReleaseByTagSpy,
|
||||||
|
createRelease: () => Promise.reject('Not implemented'),
|
||||||
|
updateRelease: updateReleaseSpy,
|
||||||
|
finalizeRelease: () => Promise.reject('Not implemented'),
|
||||||
|
allReleases: async function* () {
|
||||||
|
yield { data: [existingRelease] };
|
||||||
|
},
|
||||||
|
listReleaseAssets: () => Promise.reject('Not implemented'),
|
||||||
|
deleteReleaseAsset: () => Promise.reject('Not implemented'),
|
||||||
|
deleteRelease: () => Promise.reject('Not implemented'),
|
||||||
|
updateReleaseAsset: () => Promise.reject('Not implemented'),
|
||||||
|
uploadReleaseAsset: () => Promise.reject('Not implemented'),
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getReleaseByTagSpy).toHaveBeenCalledWith({
|
||||||
|
owner: 'owner',
|
||||||
|
repo: 'repo',
|
||||||
|
tag: 'v1.0.0',
|
||||||
|
});
|
||||||
|
expect(updateReleaseSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
tag_name: 'v1.0.0',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert.equal(result.release.id, existingRelease.id);
|
||||||
|
assert.equal(result.created, false);
|
||||||
|
});
|
||||||
|
|
||||||
it('reuses a canonical release after concurrent create success and removes empty duplicates', async () => {
|
it('reuses a canonical release after concurrent create success and removes empty duplicates', async () => {
|
||||||
const canonicalRelease: Release = {
|
const canonicalRelease: Release = {
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
alignAssetName,
|
alignAssetName,
|
||||||
isTag,
|
isTag,
|
||||||
normalizeGlobPattern,
|
normalizeGlobPattern,
|
||||||
|
normalizeTagName,
|
||||||
parseConfig,
|
parseConfig,
|
||||||
parseInputFiles,
|
parseInputFiles,
|
||||||
paths,
|
paths,
|
||||||
@@ -469,6 +470,10 @@ describe('util', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('normalizes refs/tags-prefixed input_tag_name values', () => {
|
||||||
|
expect(parseConfig({ INPUT_TAG_NAME: 'refs/tags/v1.2.3' }).input_tag_name).toBe('v1.2.3');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('isTag', () => {
|
describe('isTag', () => {
|
||||||
it('returns true for tags', async () => {
|
it('returns true for tags', async () => {
|
||||||
@@ -479,6 +484,16 @@ describe('util', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('normalizeTagName', () => {
|
||||||
|
it('strips refs/tags/ from explicit tag names', () => {
|
||||||
|
assert.equal(normalizeTagName('refs/tags/v1.2.3'), 'v1.2.3');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('leaves plain tag names unchanged', () => {
|
||||||
|
assert.equal(normalizeTagName('v1.2.3'), 'v1.2.3');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('paths', () => {
|
describe('paths', () => {
|
||||||
it('resolves files given a set of paths', async () => {
|
it('resolves files given a set of paths', async () => {
|
||||||
assert.deepStrictEqual(paths(['tests/data/**/*', 'tests/data/does/not/exist/*']), [
|
assert.deepStrictEqual(paths(['tests/data/**/*', 'tests/data/does/not/exist/*']), [
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ inputs:
|
|||||||
description: "Gives the release a custom name. Defaults to tag name"
|
description: "Gives the release a custom name. Defaults to tag name"
|
||||||
required: false
|
required: false
|
||||||
tag_name:
|
tag_name:
|
||||||
description: "Gives a tag name. Defaults to github.ref_name"
|
description: "Gives a tag name. Defaults to github.ref_name. refs/tags/<name> values are normalized to <name>."
|
||||||
required: false
|
required: false
|
||||||
draft:
|
draft:
|
||||||
description: "Creates a draft release. Defaults to false"
|
description: "Creates a draft release. Defaults to false"
|
||||||
|
|||||||
48
dist/index.js
vendored
48
dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@ import { statSync } from 'fs';
|
|||||||
import { open } from 'fs/promises';
|
import { open } from 'fs/promises';
|
||||||
import { lookup } from 'mime-types';
|
import { lookup } from 'mime-types';
|
||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
import { alignAssetName, Config, isTag, releaseBody } from './util';
|
import { alignAssetName, Config, isTag, normalizeTagName, releaseBody } from './util';
|
||||||
|
|
||||||
type GitHub = InstanceType<typeof GitHub>;
|
type GitHub = InstanceType<typeof GitHub>;
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ export const release = async (
|
|||||||
|
|
||||||
const [owner, repo] = config.github_repository.split('/');
|
const [owner, repo] = config.github_repository.split('/');
|
||||||
const tag =
|
const tag =
|
||||||
config.input_tag_name ||
|
normalizeTagName(config.input_tag_name) ||
|
||||||
(isTag(config.github_ref) ? config.github_ref.replace('refs/tags/', '') : '');
|
(isTag(config.github_ref) ? config.github_ref.replace('refs/tags/', '') : '');
|
||||||
|
|
||||||
const discussion_category_name = config.input_discussion_category_name;
|
const discussion_category_name = config.input_discussion_category_name;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export const parseConfig = (env: Env): Config => {
|
|||||||
github_ref: env.GITHUB_REF || '',
|
github_ref: env.GITHUB_REF || '',
|
||||||
github_repository: env.INPUT_REPOSITORY || env.GITHUB_REPOSITORY || '',
|
github_repository: env.INPUT_REPOSITORY || env.GITHUB_REPOSITORY || '',
|
||||||
input_name: env.INPUT_NAME,
|
input_name: env.INPUT_NAME,
|
||||||
input_tag_name: env.INPUT_TAG_NAME?.trim(),
|
input_tag_name: normalizeTagName(env.INPUT_TAG_NAME?.trim()),
|
||||||
input_body: env.INPUT_BODY,
|
input_body: env.INPUT_BODY,
|
||||||
input_body_path: env.INPUT_BODY_PATH,
|
input_body_path: env.INPUT_BODY_PATH,
|
||||||
input_files: parseInputFiles(env.INPUT_FILES || ''),
|
input_files: parseInputFiles(env.INPUT_FILES || ''),
|
||||||
@@ -170,6 +170,13 @@ export const isTag = (ref: string): boolean => {
|
|||||||
return ref.startsWith('refs/tags/');
|
return ref.startsWith('refs/tags/');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const normalizeTagName = (tag: string | undefined): string | undefined => {
|
||||||
|
if (!tag) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
return isTag(tag) ? tag.replace('refs/tags/', '') : tag;
|
||||||
|
};
|
||||||
|
|
||||||
export const alignAssetName = (assetName: string): string => {
|
export const alignAssetName = (assetName: string): string => {
|
||||||
return assetName.replace(/ /g, '.');
|
return assetName.replace(/ /g, '.');
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user