mirror of
				https://github.com/softprops/action-gh-release.git
				synced 2025-11-04 13:49:25 +00:00 
			
		
		
		
	* Initial plan * fix: gracefully fallback to body when body_path cannot be read Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>
		
			
				
	
	
		
			526 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			526 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import {
 | 
						|
  alignAssetName,
 | 
						|
  isTag,
 | 
						|
  parseConfig,
 | 
						|
  parseInputFiles,
 | 
						|
  paths,
 | 
						|
  releaseBody,
 | 
						|
  unmatchedPatterns,
 | 
						|
  uploadUrl,
 | 
						|
} from '../src/util';
 | 
						|
 | 
						|
import { assert, describe, expect, it } from 'vitest';
 | 
						|
 | 
						|
describe('util', () => {
 | 
						|
  describe('uploadUrl', () => {
 | 
						|
    it('strips template', () => {
 | 
						|
      assert.equal(
 | 
						|
        uploadUrl(
 | 
						|
          'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}',
 | 
						|
        ),
 | 
						|
        'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets',
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
  describe('parseInputFiles', () => {
 | 
						|
    it('parses empty strings', () => {
 | 
						|
      assert.deepStrictEqual(parseInputFiles(''), []);
 | 
						|
    });
 | 
						|
    it('parses comma-delimited strings', () => {
 | 
						|
      assert.deepStrictEqual(parseInputFiles('foo,bar'), ['foo', 'bar']);
 | 
						|
    });
 | 
						|
    it('parses newline and comma-delimited (and then some)', () => {
 | 
						|
      assert.deepStrictEqual(parseInputFiles('foo,bar\nbaz,boom,\n\ndoom,loom '), [
 | 
						|
        'foo',
 | 
						|
        'bar',
 | 
						|
        'baz',
 | 
						|
        'boom',
 | 
						|
        'doom',
 | 
						|
        'loom',
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
    it('handles globs with brace groups containing commas', () => {
 | 
						|
      assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb,tar.gz}\nfoo,bar'), [
 | 
						|
        './**/*.{exe,deb,tar.gz}',
 | 
						|
        'foo',
 | 
						|
        'bar',
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
    it('handles single-line brace pattern correctly', () => {
 | 
						|
      assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb,tar.gz}'), [
 | 
						|
        './**/*.{exe,deb,tar.gz}',
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
  });
 | 
						|
  describe('releaseBody', () => {
 | 
						|
    it('uses input body', () => {
 | 
						|
      assert.equal(
 | 
						|
        'foo',
 | 
						|
        releaseBody({
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_body: 'foo',
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: false,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        }),
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('uses input body path', () => {
 | 
						|
      assert.equal(
 | 
						|
        'bar',
 | 
						|
        releaseBody({
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: '__tests__/release.txt',
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: false,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        }),
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('defaults to body path when both body and body path are provided', () => {
 | 
						|
      assert.equal(
 | 
						|
        'bar',
 | 
						|
        releaseBody({
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_body: 'foo',
 | 
						|
          input_body_path: '__tests__/release.txt',
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: false,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        }),
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('falls back to body when body_path is missing', () => {
 | 
						|
      assert.equal(
 | 
						|
        releaseBody({
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_body: 'fallback-body',
 | 
						|
          input_body_path: '__tests__/does-not-exist.txt',
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: false,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        }),
 | 
						|
        'fallback-body',
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('returns undefined when body_path is missing and body is not provided', () => {
 | 
						|
      assert.equal(
 | 
						|
        releaseBody({
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: '__tests__/does-not-exist.txt',
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: false,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        }),
 | 
						|
        undefined,
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
  describe('parseConfig', () => {
 | 
						|
    it('parses basic config', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          // note: inputs declared in actions.yml, even when declared not required,
 | 
						|
          // are still provided by the actions runtime env as empty strings instead of
 | 
						|
          // the normal absent env value one would expect. this breaks things
 | 
						|
          // as an empty string !== undefined in terms of what we pass to the api
 | 
						|
          // so we cover that in a test case here to ensure undefined values are actually
 | 
						|
          // resolved as undefined and not empty strings
 | 
						|
          INPUT_TARGET_COMMITISH: '',
 | 
						|
          INPUT_DISCUSSION_CATEGORY_NAME: '',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('parses basic config with commitish', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_TARGET_COMMITISH: 'affa18ef97bc9db20076945705aba8c516139abd',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: 'affa18ef97bc9db20076945705aba8c516139abd',
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('supports discussion category names', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_DISCUSSION_CATEGORY_NAME: 'releases',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: 'releases',
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('supports generating release notes', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_GENERATE_RELEASE_NOTES: 'true',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: true,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('prefers GITHUB_TOKEN over token input for backwards compatibility', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_DRAFT: 'false',
 | 
						|
          INPUT_PRERELEASE: 'true',
 | 
						|
          INPUT_PRESERVE_ORDER: 'true',
 | 
						|
          GITHUB_TOKEN: 'env-token',
 | 
						|
          INPUT_TOKEN: 'input-token',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: 'env-token',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: true,
 | 
						|
          input_preserve_order: true,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('uses input token as the source of GITHUB_TOKEN by default', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_DRAFT: 'false',
 | 
						|
          INPUT_PRERELEASE: 'true',
 | 
						|
          INPUT_TOKEN: 'input-token',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: 'input-token',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: true,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('parses basic config with draft and prerelease', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_DRAFT: 'false',
 | 
						|
          INPUT_PRERELEASE: 'true',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: false,
 | 
						|
          input_prerelease: true,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('parses basic config where make_latest is passed', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_MAKE_LATEST: 'false',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: false,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_name: undefined,
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: 'false',
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
    it('parses basic config with append_body', () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        parseConfig({
 | 
						|
          INPUT_APPEND_BODY: 'true',
 | 
						|
        }),
 | 
						|
        {
 | 
						|
          github_ref: '',
 | 
						|
          github_repository: '',
 | 
						|
          github_token: '',
 | 
						|
          input_working_directory: undefined,
 | 
						|
          input_append_body: true,
 | 
						|
          input_body: undefined,
 | 
						|
          input_body_path: undefined,
 | 
						|
          input_draft: undefined,
 | 
						|
          input_prerelease: undefined,
 | 
						|
          input_preserve_order: undefined,
 | 
						|
          input_files: [],
 | 
						|
          input_overwrite_files: undefined,
 | 
						|
          input_name: undefined,
 | 
						|
          input_tag_name: undefined,
 | 
						|
          input_fail_on_unmatched_files: false,
 | 
						|
          input_target_commitish: undefined,
 | 
						|
          input_discussion_category_name: undefined,
 | 
						|
          input_generate_release_notes: false,
 | 
						|
          input_make_latest: undefined,
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
  describe('isTag', () => {
 | 
						|
    it('returns true for tags', async () => {
 | 
						|
      assert.equal(isTag('refs/tags/foo'), true);
 | 
						|
    });
 | 
						|
    it('returns false for other kinds of refs', async () => {
 | 
						|
      assert.equal(isTag('refs/heads/master'), false);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('paths', () => {
 | 
						|
    it('resolves files given a set of paths', async () => {
 | 
						|
      assert.deepStrictEqual(paths(['tests/data/**/*', 'tests/data/does/not/exist/*']), [
 | 
						|
        'tests/data/foo/bar.txt',
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
 | 
						|
    it('resolves files relative to working_directory', async () => {
 | 
						|
      assert.deepStrictEqual(paths(['data/**/*'], 'tests'), ['tests/data/foo/bar.txt']);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('unmatchedPatterns', () => {
 | 
						|
    it("returns the patterns that don't match any files", async () => {
 | 
						|
      assert.deepStrictEqual(
 | 
						|
        unmatchedPatterns(['tests/data/**/*', 'tests/data/does/not/exist/*']),
 | 
						|
        ['tests/data/does/not/exist/*'],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('resolves unmatched relative to working_directory', async () => {
 | 
						|
      assert.deepStrictEqual(unmatchedPatterns(['data/does/not/exist/*'], 'tests'), [
 | 
						|
        'data/does/not/exist/*',
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('replaceSpacesWithDots', () => {
 | 
						|
    it('replaces all spaces with dots', () => {
 | 
						|
      expect(alignAssetName('John Doe.bla')).toBe('John.Doe.bla');
 | 
						|
    });
 | 
						|
 | 
						|
    it('handles names with multiple spaces', () => {
 | 
						|
      expect(alignAssetName('John William Doe.bla')).toBe('John.William.Doe.bla');
 | 
						|
    });
 | 
						|
 | 
						|
    it('returns the same string if there are no spaces', () => {
 | 
						|
      expect(alignAssetName('JohnDoe')).toBe('JohnDoe');
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
describe('parseInputFiles edge cases', () => {
 | 
						|
  it('handles multiple brace groups on same line', () => {
 | 
						|
    assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb},./dist/**/*.{zip,tar.gz}'), [
 | 
						|
      './**/*.{exe,deb}',
 | 
						|
      './dist/**/*.{zip,tar.gz}',
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
 | 
						|
  it('handles nested braces', () => {
 | 
						|
    assert.deepStrictEqual(parseInputFiles('path/{a,{b,c}}/file.txt'), ['path/{a,{b,c}}/file.txt']);
 | 
						|
  });
 | 
						|
 | 
						|
  it('handles empty comma-separated values', () => {
 | 
						|
    assert.deepStrictEqual(parseInputFiles('foo,,bar'), ['foo', 'bar']);
 | 
						|
  });
 | 
						|
 | 
						|
  it('handles commas with spaces around braces', () => {
 | 
						|
    assert.deepStrictEqual(parseInputFiles(' ./**/*.{exe,deb} , file.txt '), [
 | 
						|
      './**/*.{exe,deb}',
 | 
						|
      'file.txt',
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
 | 
						|
  it('handles mixed newlines and commas with braces', () => {
 | 
						|
    assert.deepStrictEqual(parseInputFiles('file1.txt\n./**/*.{exe,deb},file2.txt\nfile3.txt'), [
 | 
						|
      'file1.txt',
 | 
						|
      './**/*.{exe,deb}',
 | 
						|
      'file2.txt',
 | 
						|
      'file3.txt',
 | 
						|
    ]);
 | 
						|
  });
 | 
						|
});
 |