Compare commits

..

No commits in common. "master" and "v2.3.3" have entirely different histories.

11 changed files with 99 additions and 378 deletions

View file

@ -10,7 +10,7 @@ jobs:
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v4 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version-file: ".tool-versions" node-version-file: ".tool-versions"
cache: "npm" cache: "npm"

View file

@ -1,23 +1,3 @@
## 2.4.0
## What's Changed
### Exciting New Features 🎉
* feat(action): respect working_directory for files globs by @stephenway in https://github.com/softprops/action-gh-release/pull/667
## 2.3.4
## What's Changed
### Bug fixes 🐛
* fix(action): handle 422 already_exists race condition by @stephenway in https://github.com/softprops/action-gh-release/pull/665
### Other Changes 🔄
- dependency updates
## 2.3.3 ## 2.3.3
## What's Changed ## What's Changed

View file

@ -1,11 +1,4 @@
import { import { asset, findTagFromReleases, mimeOrDefault, Release, Releaser } from '../src/github';
asset,
findTagFromReleases,
mimeOrDefault,
release,
Release,
Releaser,
} from '../src/github';
import { assert, describe, it } from 'vitest'; import { assert, describe, it } from 'vitest';
@ -234,75 +227,4 @@ describe('github', () => {
}); });
}); });
}); });
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: false,
prerelease: false,
assets: [],
},
}),
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);
});
});
}); });

View file

@ -39,18 +39,6 @@ describe('util', () => {
'loom', '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', () => { describe('releaseBody', () => {
it('uses input body', () => { it('uses input body', () => {
@ -122,52 +110,6 @@ describe('util', () => {
}), }),
); );
}); });
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', () => { describe('parseConfig', () => {
it('parses basic config', () => { it('parses basic config', () => {
@ -186,7 +128,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -215,7 +156,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -243,7 +183,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -272,7 +211,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -305,7 +243,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: 'env-token', github_token: 'env-token',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -335,7 +272,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: 'input-token', github_token: 'input-token',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -364,7 +300,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -392,7 +327,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: false, input_append_body: false,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -420,7 +354,6 @@ describe('util', () => {
github_ref: '', github_ref: '',
github_repository: '', github_repository: '',
github_token: '', github_token: '',
input_working_directory: undefined,
input_append_body: true, input_append_body: true,
input_body: undefined, input_body: undefined,
input_body_path: undefined, input_body_path: undefined,
@ -455,10 +388,6 @@ describe('util', () => {
'tests/data/foo/bar.txt', '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', () => { describe('unmatchedPatterns', () => {
@ -468,12 +397,6 @@ describe('util', () => {
['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', () => { describe('replaceSpacesWithDots', () => {
@ -490,36 +413,3 @@ describe('util', () => {
}); });
}); });
}); });
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',
]);
});
});

View file

@ -27,9 +27,6 @@ inputs:
files: files:
description: "Newline-delimited list of path globs for asset files to upload" description: "Newline-delimited list of path globs for asset files to upload"
required: false required: false
working_directory:
description: "Base directory to resolve 'files' globs against (defaults to job working-directory)"
required: false
overwrite_files: overwrite_files:
description: "Overwrite existing files with the same name. Defaults to true" description: "Overwrite existing files with the same name. Defaults to true"
required: false required: false

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

144
package-lock.json generated
View file

@ -1,29 +1,29 @@
{ {
"name": "action-gh-release", "name": "action-gh-release",
"version": "2.4.0", "version": "2.3.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "action-gh-release", "name": "action-gh-release",
"version": "2.4.0", "version": "2.3.3",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",
"@actions/github": "^6.0.1", "@actions/github": "^6.0.1",
"@octokit/plugin-retry": "^8.0.2", "@octokit/plugin-retry": "^8.0.1",
"@octokit/plugin-throttling": "^11.0.2", "@octokit/plugin-throttling": "^11.0.1",
"glob": "^11.0.3", "glob": "^11.0.3",
"mime-types": "^3.0.1" "mime-types": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^9.0.0", "@types/glob": "^9.0.0",
"@types/mime-types": "^3.0.1", "@types/mime-types": "^3.0.1",
"@types/node": "^20.19.19", "@types/node": "^20.19.11",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.3",
"@vitest/coverage-v8": "^3.2.4", "@vitest/coverage-v8": "^3.2.4",
"prettier": "3.6.2", "prettier": "3.6.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.9.3", "typescript": "^5.9.2",
"typescript-formatter": "^7.2.2", "typescript-formatter": "^7.2.2",
"vitest": "^3.1.4" "vitest": "^3.1.4"
} }
@ -1009,13 +1009,13 @@
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==" "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
}, },
"node_modules/@octokit/plugin-retry": { "node_modules/@octokit/plugin-retry": {
"version": "8.0.2", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.1.tgz",
"integrity": "sha512-mVPCe77iaD8g1lIX46n9bHPUirFLzc3BfIzsZOpB7bcQh1ecS63YsAgcsyMGqvGa2ARQWKEFTrhMJX2MLJVHVw==", "integrity": "sha512-KUoYR77BjF5O3zcwDQHRRZsUvJwepobeqiSSdCJ8lWt27FZExzb0GgVxrhhfuyF6z2B2zpO0hN5pteni1sqWiw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/request-error": "^7.0.1", "@octokit/request-error": "^7.0.0",
"@octokit/types": "^15.0.0", "@octokit/types": "^14.0.0",
"bottleneck": "^2.15.3" "bottleneck": "^2.15.3"
}, },
"engines": { "engines": {
@ -1026,27 +1026,27 @@
} }
}, },
"node_modules/@octokit/plugin-retry/node_modules/@octokit/openapi-types": { "node_modules/@octokit/plugin-retry/node_modules/@octokit/openapi-types": {
"version": "26.0.0", "version": "25.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz",
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", "integrity": "sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@octokit/plugin-retry/node_modules/@octokit/types": { "node_modules/@octokit/plugin-retry/node_modules/@octokit/types": {
"version": "15.0.0", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.0.0.tgz",
"integrity": "sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==", "integrity": "sha512-VVmZP0lEhbo2O1pdq63gZFiGCKkm8PPp8AUOijlwPO6hojEVjspA0MWKP7E4hbvGxzFKNqKr6p0IYtOH/Wf/zA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^26.0.0" "@octokit/openapi-types": "^25.0.0"
} }
}, },
"node_modules/@octokit/plugin-throttling": { "node_modules/@octokit/plugin-throttling": {
"version": "11.0.2", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.1.tgz",
"integrity": "sha512-ntNIig4zZhQVOZF4fG9Wt8QCoz9ehb+xnlUwp74Ic2ANChCk8oKmRwV9zDDCtrvU1aERIOvtng8wsalEX7Jk5Q==", "integrity": "sha512-S+EVhy52D/272L7up58dr3FNSMXWuNZolkL4zMJBNIfIxyZuUcczsQAU4b5w6dewJXnKYVgSHSV5wxitMSW1kw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^15.0.0", "@octokit/types": "^14.0.0",
"bottleneck": "^2.15.3" "bottleneck": "^2.15.3"
}, },
"engines": { "engines": {
@ -1057,18 +1057,18 @@
} }
}, },
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": { "node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": {
"version": "26.0.0", "version": "25.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz",
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", "integrity": "sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": { "node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": {
"version": "15.0.0", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.0.0.tgz",
"integrity": "sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==", "integrity": "sha512-VVmZP0lEhbo2O1pdq63gZFiGCKkm8PPp8AUOijlwPO6hojEVjspA0MWKP7E4hbvGxzFKNqKr6p0IYtOH/Wf/zA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^26.0.0" "@octokit/openapi-types": "^25.0.0"
} }
}, },
"node_modules/@octokit/request": { "node_modules/@octokit/request": {
@ -1089,30 +1089,30 @@
} }
}, },
"node_modules/@octokit/request-error": { "node_modules/@octokit/request-error": {
"version": "7.0.1", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz",
"integrity": "sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==", "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^15.0.0" "@octokit/types": "^14.0.0"
}, },
"engines": { "engines": {
"node": ">= 20" "node": ">= 20"
} }
}, },
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
"version": "26.0.0", "version": "25.1.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz",
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@octokit/request-error/node_modules/@octokit/types": { "node_modules/@octokit/request-error/node_modules/@octokit/types": {
"version": "15.0.0", "version": "14.1.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz",
"integrity": "sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==", "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^26.0.0" "@octokit/openapi-types": "^25.1.0"
} }
}, },
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": { "node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
@ -1482,9 +1482,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.19.19", "version": "20.19.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz",
"integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "integrity": "sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1492,11 +1492,10 @@
} }
}, },
"node_modules/@vercel/ncc": { "node_modules/@vercel/ncc": {
"version": "0.38.4", "version": "0.38.3",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.4.tgz", "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.3.tgz",
"integrity": "sha512-8LwjnlP39s08C08J5NstzriPvW1SP8Zfpp1BvC2sI35kPeZnHfxVkCwu4/+Wodgnd60UtT1n8K8zw+Mp7J9JmQ==", "integrity": "sha512-rnK6hJBS6mwc+Bkab+PGPs9OiS0i/3kdTO+CkI8V0/VrW3vmz7O2Pxjw/owOlmo6PKEIxRSeZKv/kuL9itnpYA==",
"dev": true, "dev": true,
"license": "MIT",
"bin": { "bin": {
"ncc": "dist/ncc/cli.js" "ncc": "dist/ncc/cli.js"
} }
@ -2114,14 +2113,10 @@
"peer": true "peer": true
}, },
"node_modules/fdir": { "node_modules/fdir": {
"version": "6.5.0", "version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true, "dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": { "peerDependencies": {
"picomatch": "^3 || ^4" "picomatch": "^3 || ^4"
}, },
@ -2476,11 +2471,10 @@
"dev": true "dev": true
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "4.0.3", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -2721,14 +2715,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.15", "version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"fdir": "^6.5.0", "fdir": "^6.4.4",
"picomatch": "^4.0.3" "picomatch": "^4.0.2"
}, },
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
@ -2817,9 +2810,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.9.3", "version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
@ -2880,18 +2873,17 @@
"dev": true "dev": true
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "7.1.5", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.0.tgz",
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", "integrity": "sha512-ixXJB1YRgDIw2OszKQS9WxGHKwLdCsbQNkpJN171udl6szi/rIySHL6/Os3s2+oE4P/FLD4dxg4mD7Wust+u5g==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.5.0", "fdir": "^6.4.6",
"picomatch": "^4.0.3", "picomatch": "^4.0.2",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"rollup": "^4.43.0", "rollup": "^4.40.0",
"tinyglobby": "^0.2.15" "tinyglobby": "^0.2.14"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"

View file

@ -1,6 +1,6 @@
{ {
"name": "action-gh-release", "name": "action-gh-release",
"version": "2.4.0", "version": "2.3.3",
"private": true, "private": true,
"description": "GitHub Action for creating GitHub Releases", "description": "GitHub Action for creating GitHub Releases",
"main": "lib/main.js", "main": "lib/main.js",
@ -24,20 +24,20 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",
"@actions/github": "^6.0.1", "@actions/github": "^6.0.1",
"@octokit/plugin-retry": "^8.0.2", "@octokit/plugin-retry": "^8.0.1",
"@octokit/plugin-throttling": "^11.0.2", "@octokit/plugin-throttling": "^11.0.1",
"glob": "^11.0.3", "glob": "^11.0.3",
"mime-types": "^3.0.1" "mime-types": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^9.0.0", "@types/glob": "^9.0.0",
"@types/mime-types": "^3.0.1", "@types/mime-types": "^3.0.1",
"@types/node": "^20.19.19", "@types/node": "^20.19.11",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.3",
"@vitest/coverage-v8": "^3.2.4", "@vitest/coverage-v8": "^3.2.4",
"prettier": "3.6.2", "prettier": "3.6.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.9.3", "typescript": "^5.9.2",
"typescript-formatter": "^7.2.2", "typescript-formatter": "^7.2.2",
"vitest": "^3.1.4" "vitest": "^3.1.4"
} }

View file

@ -388,18 +388,8 @@ async function createRelease(
throw error; throw error;
case 422: case 422:
// Check if this is a race condition with "already_exists" error console.log('Skip retry - validation failed');
const errorData = error.response?.data; throw error;
if (errorData?.errors?.[0]?.code === 'already_exists') {
console.log(
'⚠️ Release already exists (race condition detected), retrying to find and update existing release...',
);
// Don't throw - allow retry to find existing release
} else {
console.log('Skip retry - validation failed');
throw error;
}
break;
} }
console.log(`retrying... (${maxRetries - 1} retries remaining)`); console.log(`retrying... (${maxRetries - 1} retries remaining)`);

View file

@ -12,7 +12,7 @@ async function run() {
throw new Error(`⚠️ GitHub Releases requires a tag`); throw new Error(`⚠️ GitHub Releases requires a tag`);
} }
if (config.input_files) { if (config.input_files) {
const patterns = unmatchedPatterns(config.input_files, config.input_working_directory); const patterns = unmatchedPatterns(config.input_files);
patterns.forEach((pattern) => { patterns.forEach((pattern) => {
if (config.input_fail_on_unmatched_files) { if (config.input_fail_on_unmatched_files) {
throw new Error(`⚠️ Pattern '${pattern}' does not match any files.`); throw new Error(`⚠️ Pattern '${pattern}' does not match any files.`);
@ -50,7 +50,7 @@ async function run() {
//); //);
const rel = await release(config, new GitHubReleaser(gh)); const rel = await release(config, new GitHubReleaser(gh));
if (config.input_files && config.input_files.length > 0) { if (config.input_files && config.input_files.length > 0) {
const files = paths(config.input_files, config.input_working_directory); const files = paths(config.input_files);
if (files.length == 0) { if (files.length == 0) {
if (config.input_fail_on_unmatched_files) { if (config.input_fail_on_unmatched_files) {
throw new Error(`⚠️ ${config.input_files} does not include a valid file.`); throw new Error(`⚠️ ${config.input_files} does not include a valid file.`);

View file

@ -1,6 +1,5 @@
import * as glob from 'glob'; import * as glob from 'glob';
import { statSync, readFileSync } from 'fs'; import { statSync, readFileSync } from 'fs';
import * as pathLib from 'path';
export interface Config { export interface Config {
github_token: string; github_token: string;
@ -13,7 +12,6 @@ export interface Config {
input_body?: string; input_body?: string;
input_body_path?: string; input_body_path?: string;
input_files?: string[]; input_files?: string[];
input_working_directory?: string;
input_overwrite_files?: boolean; input_overwrite_files?: boolean;
input_draft?: boolean; input_draft?: boolean;
input_preserve_order?: boolean; input_preserve_order?: boolean;
@ -35,53 +33,23 @@ export const uploadUrl = (url: string): string => {
}; };
export const releaseBody = (config: Config): string | undefined => { export const releaseBody = (config: Config): string | undefined => {
if (config.input_body_path) { return (
try { (config.input_body_path && readFileSync(config.input_body_path).toString('utf8')) ||
const contents = readFileSync(config.input_body_path, 'utf8'); config.input_body
return contents; );
} catch (err: any) {
console.warn(
`⚠️ Failed to read body_path "${config.input_body_path}" (${err?.code ?? 'ERR'}). Falling back to 'body' input.`,
);
}
}
return config.input_body;
}; };
type Env = { [key: string]: string | undefined }; type Env = { [key: string]: string | undefined };
const smartSplit = (input: string): string[] => {
const result: string[] = [];
let current = '';
let braceDepth = 0;
for (const ch of input) {
if (ch === '{') {
braceDepth++;
}
if (ch === '}') {
braceDepth--;
}
if (ch === ',' && braceDepth === 0) {
if (current.trim()) {
result.push(current.trim());
}
current = '';
} else {
current += ch;
}
}
if (current.trim()) {
result.push(current.trim());
}
return result;
};
export const parseInputFiles = (files: string): string[] => { export const parseInputFiles = (files: string): string[] => {
return files return files.split(/\r?\n/).reduce<string[]>(
.split(/\r?\n/) (acc, line) =>
.flatMap((line) => smartSplit(line)) acc
.filter((pat) => pat.trim() !== ''); .concat(line.split(','))
.filter((pat) => pat)
.map((pat) => pat.trim()),
[],
);
}; };
export const parseConfig = (env: Env): Config => { export const parseConfig = (env: Env): Config => {
@ -94,7 +62,6 @@ export const parseConfig = (env: Env): Config => {
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 || ''),
input_working_directory: env.INPUT_WORKING_DIRECTORY || undefined,
input_overwrite_files: env.INPUT_OVERWRITE_FILES input_overwrite_files: env.INPUT_OVERWRITE_FILES
? env.INPUT_OVERWRITE_FILES == 'true' ? env.INPUT_OVERWRITE_FILES == 'true'
: undefined, : undefined,
@ -117,34 +84,17 @@ const parseMakeLatest = (value: string | undefined): 'true' | 'false' | 'legacy'
return undefined; return undefined;
}; };
export const paths = (patterns: string[], cwd?: string): string[] => { export const paths = (patterns: string[]): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => {
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false }); return acc.concat(glob.sync(pattern).filter((path) => statSync(path).isFile()));
const resolved = matches
.map((p) => (cwd ? pathLib.join(cwd, p) : p))
.filter((p) => {
try {
return statSync(p).isFile();
} catch {
return false;
}
});
return acc.concat(resolved);
}, []); }, []);
}; };
export const unmatchedPatterns = (patterns: string[], cwd?: string): string[] => { export const unmatchedPatterns = (patterns: string[]): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => {
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false }); return acc.concat(
const files = matches.filter((p) => { glob.sync(pattern).filter((path) => statSync(path).isFile()).length == 0 ? [pattern] : [],
try { );
const full = cwd ? pathLib.join(cwd, p) : p;
return statSync(full).isFile();
} catch {
return false;
}
});
return acc.concat(files.length == 0 ? [pattern] : []);
}, []); }, []);
}; };