mirror of
				https://github.com/softprops/action-gh-release.git
				synced 2025-11-04 05:39:24 +00:00 
			
		
		
		
	Compare commits
	
		
			171 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					aec2ec56f9 | ||
| 
						 | 
					4db716b167 | ||
| 
						 | 
					14820f2cee | ||
| 
						 | 
					62c96d0c4e | ||
| 
						 | 
					7dc9b8ac0f | ||
| 
						 | 
					0f0e0b98e9 | ||
| 
						 | 
					97d42c1b50 | ||
| 
						 | 
					19cd0bcd2b | ||
| 
						 | 
					5d1b0b1164 | ||
| 
						 | 
					f6021cf9a4 | ||
| 
						 | 
					6cbd405e2c | ||
| 
						 | 
					fbadcc90e8 | ||
| 
						 | 
					4a840061c4 | ||
| 
						 | 
					7191749478 | ||
| 
						 | 
					126b1e7093 | ||
| 
						 | 
					f82d31e53e | ||
| 
						 | 
					f2352b97da | ||
| 
						 | 
					f0b3259de2 | ||
| 
						 | 
					f37a2f9143 | ||
| 
						 | 
					db560141c6 | ||
| 
						 | 
					40521a2029 | ||
| 
						 | 
					c8d8e91662 | ||
| 
						 | 
					605f567f95 | ||
| 
						 | 
					5822334cb4 | ||
| 
						 | 
					72f2c25fcb | ||
| 
						 | 
					552dc5524b | ||
| 
						 | 
					f3cad8bcbf | ||
| 
						 | 
					07a2257003 | ||
| 
						 | 
					d5382d3e6f | ||
| 
						 | 
					a0e2122208 | ||
| 
						 | 
					8836085300 | ||
| 
						 | 
					86463358d8 | ||
| 
						 | 
					46b284799f | ||
| 
						 | 
					37fd9d0351 | ||
| 
						 | 
					39ba0b9d81 | ||
| 
						 | 
					da05d55257 | ||
| 
						 | 
					6b18c2f260 | ||
| 
						 | 
					e2b105c98e | ||
| 
						 | 
					e707470492 | ||
| 
						 | 
					36833a1c71 | ||
| 
						 | 
					8bb7207875 | ||
| 
						 | 
					93bb5ff43e | ||
| 
						 | 
					581b12c87f | ||
| 
						 | 
					b540ad2354 | ||
| 
						 | 
					ac224e9440 | ||
| 
						 | 
					ab50eebb64 | ||
| 
						 | 
					670eb2f21a | ||
| 
						 | 
					4b4d743a9b | ||
| 
						 | 
					daffc988f2 | ||
| 
						 | 
					ffb524fa90 | ||
| 
						 | 
					a921960380 | ||
| 
						 | 
					51cfd90a6d | ||
| 
						 | 
					431939b21f | ||
| 
						 | 
					3792cde6c4 | ||
| 
						 | 
					1fd6f3f2b1 | ||
| 
						 | 
					7e44a1f6a7 | ||
| 
						 | 
					67b6c38432 | ||
| 
						 | 
					c43d7637b9 | ||
| 
						 | 
					c95fe14893 | ||
| 
						 | 
					deddb09c64 | ||
| 
						 | 
					33fcd69d45 | ||
| 
						 | 
					01050bd877 | ||
| 
						 | 
					92dffe6c28 | ||
| 
						 | 
					7b4da11513 | ||
| 
						 | 
					64f1fa19ef | ||
| 
						 | 
					9e35a64dfd | ||
| 
						 | 
					92bc83c421 | ||
| 
						 | 
					09f0e37203 | ||
| 
						 | 
					f138a07409 | ||
| 
						 | 
					39a5683760 | ||
| 
						 | 
					62368ac126 | ||
| 
						 | 
					181b5bc7bb | ||
| 
						 | 
					3284404123 | ||
| 
						 | 
					01570a1f39 | ||
| 
						 | 
					d5f028c822 | ||
| 
						 | 
					98daca21d1 | ||
| 
						 | 
					b019a5bbb6 | ||
| 
						 | 
					73e673b2de | ||
| 
						 | 
					e7a8f85e1c | ||
| 
						 | 
					04afa1392e | ||
| 
						 | 
					894468a03c | ||
| 
						 | 
					3bd23aa9ec | ||
| 
						 | 
					21eb2f9554 | ||
| 
						 | 
					cd8b57e572 | ||
| 
						 | 
					820a5adc43 | ||
| 
						 | 
					9d04f90cd8 | ||
| 
						 | 
					aaf1d5f6d5 | ||
| 
						 | 
					7d33a7ecc3 | ||
| 
						 | 
					4ab8bf77de | ||
| 
						 | 
					0a7d9cdbe4 | ||
| 
						 | 
					aec195fdab | ||
| 
						 | 
					b2cf127d24 | ||
| 
						 | 
					285c2f0c13 | ||
| 
						 | 
					c7857c88c0 | ||
| 
						 | 
					42b6106688 | ||
| 
						 | 
					79721680df | ||
| 
						 | 
					33892d43f0 | ||
| 
						 | 
					3362207ba1 | ||
| 
						 | 
					24a040e564 | ||
| 
						 | 
					9a28f2423f | ||
| 
						 | 
					e5aff6f50f | ||
| 
						 | 
					69d83aede9 | ||
| 
						 | 
					0ab9029cac | ||
| 
						 | 
					d1798aa3dc | ||
| 
						 | 
					c062e08bd5 | ||
| 
						 | 
					380635c4ad | ||
| 
						 | 
					20adb4259c | ||
| 
						 | 
					f808f15ba8 | ||
| 
						 | 
					6145241049 | ||
| 
						 | 
					4ac522d0bd | ||
| 
						 | 
					25849b1326 | ||
| 
						 | 
					62060560e3 | ||
| 
						 | 
					39aadf190d | ||
| 
						 | 
					6f3ab65323 | ||
| 
						 | 
					cdef11965e | ||
| 
						 | 
					48b853e7ea | ||
| 
						 | 
					82b4a28696 | ||
| 
						 | 
					fb2d03176f | ||
| 
						 | 
					08d85b1534 | ||
| 
						 | 
					a636f98a4d | ||
| 
						 | 
					288696be39 | ||
| 
						 | 
					6de5d7916c | ||
| 
						 | 
					a485adba73 | ||
| 
						 | 
					26f874e54a | ||
| 
						 | 
					810bfa2cd5 | ||
| 
						 | 
					019fc2114d | ||
| 
						 | 
					a74c6b72af | ||
| 
						 | 
					b909f761f0 | ||
| 
						 | 
					e49d08fa32 | ||
| 
						 | 
					f12ad255e1 | ||
| 
						 | 
					7039a825a7 | ||
| 
						 | 
					f9c2b6ca37 | ||
| 
						 | 
					73738a6293 | ||
| 
						 | 
					a500a35279 | ||
| 
						 | 
					69320dbe05 | ||
| 
						 | 
					9771ccf55f | ||
| 
						 | 
					0a76e4214a | ||
| 
						 | 
					3989e4b325 | ||
| 
						 | 
					72e945e627 | ||
| 
						 | 
					40bf9ec7aa | ||
| 
						 | 
					998623f0c3 | ||
| 
						 | 
					0979303f02 | ||
| 
						 | 
					9b795e5782 | ||
| 
						 | 
					9d7c94cfd0 | ||
| 
						 | 
					6ffed59e55 | ||
| 
						 | 
					1ce812a7bd | ||
| 
						 | 
					3198ee18f8 | ||
| 
						 | 
					7ee8e06381 | ||
| 
						 | 
					d99959edae | ||
| 
						 | 
					0e39c679e8 | ||
| 
						 | 
					20e085ccc7 | ||
| 
						 | 
					9f5c4d39bc | ||
| 
						 | 
					0bea76b227 | ||
| 
						 | 
					762fe13dfb | ||
| 
						 | 
					c0f2569fb9 | ||
| 
						 | 
					5743e06024 | ||
| 
						 | 
					fe71fd3b91 | ||
| 
						 | 
					9150ab13f3 | ||
| 
						 | 
					74195ccd05 | ||
| 
						 | 
					611b8bcc8e | ||
| 
						 | 
					1468521d63 | ||
| 
						 | 
					9e05c79559 | ||
| 
						 | 
					e985949726 | ||
| 
						 | 
					a6c7483a42 | ||
| 
						 | 
					975c1b265e | ||
| 
						 | 
					4634c16e79 | ||
| 
						 | 
					c9b46fe7aa | ||
| 
						 | 
					d4e8205d7e | ||
| 
						 | 
					9114792eb2 | ||
| 
						 | 
					b4025e2cdd | ||
| 
						 | 
					970e29c7f0 | 
							
								
								
									
										19
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,14 +1,29 @@
 | 
				
			|||||||
version: 2
 | 
					version: 2
 | 
				
			||||||
updates:
 | 
					updates:
 | 
				
			||||||
- package-ecosystem: npm
 | 
					  - package-ecosystem: npm
 | 
				
			||||||
    directory: "/"
 | 
					    directory: "/"
 | 
				
			||||||
    schedule:
 | 
					    schedule:
 | 
				
			||||||
      interval: weekly
 | 
					      interval: weekly
 | 
				
			||||||
 | 
					    groups:
 | 
				
			||||||
 | 
					      npm:
 | 
				
			||||||
 | 
					        patterns:
 | 
				
			||||||
 | 
					          - "*"
 | 
				
			||||||
    ignore:
 | 
					    ignore:
 | 
				
			||||||
      - dependency-name: node-fetch
 | 
					      - dependency-name: node-fetch
 | 
				
			||||||
        versions:
 | 
					        versions:
 | 
				
			||||||
          - ">=3.0.0"
 | 
					          - ">=3.0.0"
 | 
				
			||||||
- package-ecosystem: github-actions
 | 
					      - dependency-name: "@types/node"
 | 
				
			||||||
 | 
					        versions:
 | 
				
			||||||
 | 
					          - ">=22.0.0"
 | 
				
			||||||
 | 
					    commit-message:
 | 
				
			||||||
 | 
					      prefix: "chore(deps)"
 | 
				
			||||||
 | 
					  - package-ecosystem: github-actions
 | 
				
			||||||
    directory: "/"
 | 
					    directory: "/"
 | 
				
			||||||
    schedule:
 | 
					    schedule:
 | 
				
			||||||
      interval: weekly
 | 
					      interval: weekly
 | 
				
			||||||
 | 
					    groups:
 | 
				
			||||||
 | 
					      github-actions:
 | 
				
			||||||
 | 
					        patterns:
 | 
				
			||||||
 | 
					          - "*"
 | 
				
			||||||
 | 
					    commit-message:
 | 
				
			||||||
 | 
					      prefix: "chore(deps)"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								.github/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.github/release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					changelog:
 | 
				
			||||||
 | 
					  exclude:
 | 
				
			||||||
 | 
					    labels:
 | 
				
			||||||
 | 
					      - ignore-for-release
 | 
				
			||||||
 | 
					      - github-actions
 | 
				
			||||||
 | 
					    authors:
 | 
				
			||||||
 | 
					      - octocat
 | 
				
			||||||
 | 
					      - renovate[bot]
 | 
				
			||||||
 | 
					  categories:
 | 
				
			||||||
 | 
					    - title: Breaking Changes 🛠
 | 
				
			||||||
 | 
					      labels:
 | 
				
			||||||
 | 
					        - breaking-change
 | 
				
			||||||
 | 
					    - title: Exciting New Features 🎉
 | 
				
			||||||
 | 
					      labels:
 | 
				
			||||||
 | 
					        - enhancement
 | 
				
			||||||
 | 
					        - feature
 | 
				
			||||||
 | 
					    - title: Bug fixes 🐛
 | 
				
			||||||
 | 
					      labels:
 | 
				
			||||||
 | 
					        - bug
 | 
				
			||||||
 | 
					    - title: Other Changes 🔄
 | 
				
			||||||
 | 
					      labels:
 | 
				
			||||||
 | 
					        - "*"
 | 
				
			||||||
							
								
								
									
										18
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,14 +1,20 @@
 | 
				
			|||||||
name: Main
 | 
					name: main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
on: [pull_request, push]
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      # https://github.com/actions/checkout
 | 
					      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
 | 
				
			||||||
      - name: Checkout
 | 
					
 | 
				
			||||||
        uses: actions/checkout@v3
 | 
					      - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          node-version-file: ".tool-versions"
 | 
				
			||||||
 | 
					          cache: "npm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Install
 | 
					      - name: Install
 | 
				
			||||||
        run: npm ci
 | 
					        run: npm ci
 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,4 @@ __tests__/runner/*
 | 
				
			|||||||
# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
 | 
					# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
 | 
				
			||||||
# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
 | 
					# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
 | 
				
			||||||
node_modules
 | 
					node_modules
 | 
				
			||||||
 | 
					coverage
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								.prettierignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.prettierignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					# Build outputs
 | 
				
			||||||
 | 
					dist/
 | 
				
			||||||
 | 
					lib/
 | 
				
			||||||
 | 
					coverage/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dependencies
 | 
				
			||||||
 | 
					node_modules/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Misc
 | 
				
			||||||
 | 
					.github/
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					__tests__/release.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Package files
 | 
				
			||||||
 | 
					package-lock.json
 | 
				
			||||||
							
								
								
									
										11
									
								
								.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {import('prettier').Config}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  trailingComma: 'all',
 | 
				
			||||||
 | 
					  tabWidth: 2,
 | 
				
			||||||
 | 
					  semi: true,
 | 
				
			||||||
 | 
					  singleQuote: true,
 | 
				
			||||||
 | 
					  printWidth: 100,
 | 
				
			||||||
 | 
					  bracketSpacing: true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					nodejs 24.2.0
 | 
				
			||||||
							
								
								
									
										173
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,3 +1,176 @@
 | 
				
			|||||||
 | 
					## 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What's Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Exciting New Features 🎉
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* feat: add input option `overwrite_files` by @asfernandes in https://github.com/softprops/action-gh-release/pull/343
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- dependency updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.3.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* fix: revert fs `readableWebStream` change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Bug fixes 🐛
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* fix: fix file closing issue by @WailGree in https://github.com/softprops/action-gh-release/pull/629
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.3.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Migrate from jest to vitest
 | 
				
			||||||
 | 
					* Replace `mime` with `mime-types`
 | 
				
			||||||
 | 
					* Bump to use node 24
 | 
				
			||||||
 | 
					* Dependency updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.2.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What's Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Bug fixes 🐛
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* fix: updating release draft status from true to false by @galargh in https://github.com/softprops/action-gh-release/pull/316
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* chore: simplify ref_type test by @steinybot in https://github.com/softprops/action-gh-release/pull/598
 | 
				
			||||||
 | 
					* fix(docs): clarify the default for tag_name by @muzimuzhi in https://github.com/softprops/action-gh-release/pull/599
 | 
				
			||||||
 | 
					* test(release): add unit tests when searching for a release by @rwaskiewicz in https://github.com/softprops/action-gh-release/pull/603
 | 
				
			||||||
 | 
					* dependency updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What's Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Bug fixes 🐛
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* fix: big file uploads by @xen0n in https://github.com/softprops/action-gh-release/pull/562
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 22.10.1 to 22.10.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/559
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 22.10.2 to 22.10.5 by @dependabot in https://github.com/softprops/action-gh-release/pull/569
 | 
				
			||||||
 | 
					* chore: update error and warning messages for not matching files in files field by @ytimocin in https://github.com/softprops/action-gh-release/pull/568
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What's Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Exciting New Features 🎉
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* feat: read the release assets asynchronously by @xen0n in https://github.com/softprops/action-gh-release/pull/552
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Bug fixes 🐛
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* fix(docs): clarify the default for tag_name by @alexeagle in https://github.com/softprops/action-gh-release/pull/544
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* chore(deps): bump typescript from 5.6.3 to 5.7.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/548
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 22.9.0 to 22.9.4 by @dependabot in https://github.com/softprops/action-gh-release/pull/547
 | 
				
			||||||
 | 
					* chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 by @dependabot in https://github.com/softprops/action-gh-release/pull/545
 | 
				
			||||||
 | 
					* chore(deps): bump @vercel/ncc from 0.38.2 to 0.38.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/543
 | 
				
			||||||
 | 
					* chore(deps): bump prettier from 3.3.3 to 3.4.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/550
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 22.9.4 to 22.10.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/551
 | 
				
			||||||
 | 
					* chore(deps): bump prettier from 3.4.1 to 3.4.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/554
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What's Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Exciting New Features 🎉
 | 
				
			||||||
 | 
					* feat: add support for release assets with multiple spaces within the name by @dukhine in https://github.com/softprops/action-gh-release/pull/518
 | 
				
			||||||
 | 
					* feat: preserve upload order by @richarddd in https://github.com/softprops/action-gh-release/pull/500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 22.8.2 to 22.8.7 by @dependabot in https://github.com/softprops/action-gh-release/pull/539
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- maintenance release with updated dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					* chore(deps): bump prettier from 2.8.0 to 3.3.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/480
 | 
				
			||||||
 | 
					* chore(deps): bump @types/node from 20.14.9 to 20.14.11 by @dependabot in https://github.com/softprops/action-gh-release/pull/483
 | 
				
			||||||
 | 
					* chore(deps): bump @octokit/plugin-throttling from 9.3.0 to 9.3.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/484
 | 
				
			||||||
 | 
					* chore(deps): bump glob from 10.4.2 to 11.0.0 by @dependabot in https://github.com/softprops/action-gh-release/pull/477
 | 
				
			||||||
 | 
					* refactor: write jest config in ts by @chenrui333 in https://github.com/softprops/action-gh-release/pull/485
 | 
				
			||||||
 | 
					* chore(deps): bump @actions/github from 5.1.1 to 6.0.0 by @dependabot in https://github.com/softprops/action-gh-release/pull/470
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Bug fixes 🐛
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Fix missing update release body by @FirelightFlagboy in https://github.com/softprops/action-gh-release/pull/365
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Other Changes 🔄
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Bump @octokit/plugin-retry from 4.0.3 to 7.1.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/443
 | 
				
			||||||
 | 
					* Bump typescript from 4.9.5 to 5.5.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/467
 | 
				
			||||||
 | 
					* Bump @types/node from 20.14.6 to 20.14.8 by @dependabot in https://github.com/softprops/action-gh-release/pull/469
 | 
				
			||||||
 | 
					* Bump @types/node from 20.14.8 to 20.14.9 by @dependabot in https://github.com/softprops/action-gh-release/pull/473
 | 
				
			||||||
 | 
					* Bump typescript from 5.5.2 to 5.5.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/472
 | 
				
			||||||
 | 
					* Bump ts-jest from 29.1.5 to 29.2.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/479
 | 
				
			||||||
 | 
					* docs: document that existing releases are updated by @jvanbruegge in https://github.com/softprops/action-gh-release/pull/474
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- maintenance release with updated dependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Factor in file names with spaces when upserting files [#446](https://github.com/softprops/action-gh-release/pull/446) via [@MystiPanda](https://github.com/MystiPanda)
 | 
				
			||||||
 | 
					- Improvements to error handling [#449](https://github.com/softprops/action-gh-release/pull/449) via [@till](https://github.com/till)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Minor follow up to [#417](https://github.com/softprops/action-gh-release/pull/417). [#425](https://github.com/softprops/action-gh-release/pull/425)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Declare `make_latest` as an input field in `action.yml` [#419](https://github.com/softprops/action-gh-release/pull/419)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Revisit approach to [#384](https://github.com/softprops/action-gh-release/pull/384) making unresolved pattern failures opt-in [#417](https://github.com/softprops/action-gh-release/pull/417)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add support for make_latest property [#304](https://github.com/softprops/action-gh-release/pull/304) via [@samueljseay](https://github.com/samueljseay)
 | 
				
			||||||
 | 
					- Fail run if files setting contains invalid patterns [#384](https://github.com/softprops/action-gh-release/pull/384) via [@rpdelaney](https://github.com/rpdelaney)
 | 
				
			||||||
 | 
					- Add support for proxy env variables (don't use node-fetch) [#386](https://github.com/softprops/action-gh-release/pull/386/) via [@timor-raiman](https://github.com/timor-raiman)
 | 
				
			||||||
 | 
					- Suppress confusing warning when input_files is empty [#389](https://github.com/softprops/action-gh-release/pull/389) via [@Drowze](https://github.com/Drowze)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `2.0.0`!? this release corrects a disjunction between git tag versions used in the marketplace and versions list this file. Previous versions should have really been 1.\*. Going forward this should be better aligned.
 | 
				
			||||||
 | 
					- Upgrade action.yml declaration to node20 to address deprecations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.1.15
 | 
					## 0.1.15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Upgrade to action.yml declaration to node16 to address deprecations
 | 
					- Upgrade to action.yml declaration to node16 to address deprecations
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
Copyright (c) 2019 Doug Tangren
 | 
					Copyright (c) 2019-current Doug Tangren
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining
 | 
					Permission is hereby granted, free of charge, to any person obtaining
 | 
				
			||||||
a copy of this software and associated documentation files (the
 | 
					a copy of this software and associated documentation files (the
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										56
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								README.md
									
									
									
									
									
								
							@@ -21,6 +21,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<br />
 | 
					<br />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [🤸 Usage](#-usage)
 | 
				
			||||||
 | 
					  - [🚥 Limit releases to pushes to tags](#-limit-releases-to-pushes-to-tags)
 | 
				
			||||||
 | 
					  - [⬆️ Uploading release assets](#️-uploading-release-assets)
 | 
				
			||||||
 | 
					  - [📝 External release notes](#-external-release-notes)
 | 
				
			||||||
 | 
					  - [💅 Customizing](#-customizing)
 | 
				
			||||||
 | 
					    - [inputs](#inputs)
 | 
				
			||||||
 | 
					    - [outputs](#outputs)
 | 
				
			||||||
 | 
					    - [environment variables](#environment-variables)
 | 
				
			||||||
 | 
					  - [Permissions](#permissions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 🤸 Usage
 | 
					## 🤸 Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 🚥 Limit releases to pushes to tags
 | 
					### 🚥 Limit releases to pushes to tags
 | 
				
			||||||
@@ -41,10 +51,10 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v5
 | 
				
			||||||
      - name: Release
 | 
					      - name: Release
 | 
				
			||||||
        uses: softprops/action-gh-release@v1
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
					        if: github.ref_type == 'tag'
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can also use push config tag filter
 | 
					You can also use push config tag filter
 | 
				
			||||||
@@ -62,9 +72,9 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v5
 | 
				
			||||||
      - name: Release
 | 
					      - name: Release
 | 
				
			||||||
        uses: softprops/action-gh-release@v1
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### ⬆️ Uploading release assets
 | 
					### ⬆️ Uploading release assets
 | 
				
			||||||
@@ -75,6 +85,7 @@ GitHub release and all are optional.
 | 
				
			|||||||
A common case for GitHub releases is to upload your binary after its been validated and packaged.
 | 
					A common case for GitHub releases is to upload your binary after its been validated and packaged.
 | 
				
			||||||
Use the `with.files` input to declare a newline-delimited list of glob expressions matching the files
 | 
					Use the `with.files` input to declare a newline-delimited list of glob expressions matching the files
 | 
				
			||||||
you wish to upload to GitHub releases. If you'd like you can just list the files by name directly.
 | 
					you wish to upload to GitHub releases. If you'd like you can just list the files by name directly.
 | 
				
			||||||
 | 
					If a tag already has a GitHub release, the existing release will be updated with the release assets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Below is an example of uploading a single asset named `Release.txt`
 | 
					Below is an example of uploading a single asset named `Release.txt`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,14 +99,14 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v5
 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
        run: echo ${{ github.sha }} > Release.txt
 | 
					        run: echo ${{ github.sha }} > Release.txt
 | 
				
			||||||
      - name: Test
 | 
					      - name: Test
 | 
				
			||||||
        run: cat Release.txt
 | 
					        run: cat Release.txt
 | 
				
			||||||
      - name: Release
 | 
					      - name: Release
 | 
				
			||||||
        uses: softprops/action-gh-release@v1
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
					        if: github.ref_type == 'tag'
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          files: Release.txt
 | 
					          files: Release.txt
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -112,21 +123,23 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v5
 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
        run: echo ${{ github.sha }} > Release.txt
 | 
					        run: echo ${{ github.sha }} > Release.txt
 | 
				
			||||||
      - name: Test
 | 
					      - name: Test
 | 
				
			||||||
        run: cat Release.txt
 | 
					        run: cat Release.txt
 | 
				
			||||||
      - name: Release
 | 
					      - name: Release
 | 
				
			||||||
        uses: softprops/action-gh-release@v1
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
					        if: github.ref_type == 'tag'
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          files: |
 | 
					          files: |
 | 
				
			||||||
            Release.txt
 | 
					            Release.txt
 | 
				
			||||||
            LICENSE
 | 
					            LICENSE
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> **⚠️ Note:** Notice the `|` in the yaml syntax above ☝️. That let's you effectively declare a multi-line yaml string. You can learn more about multi-line yaml syntax [here](https://yaml-multiline.info)
 | 
					> **⚠️ Note:** Notice the `|` in the yaml syntax above ☝️. That lets you effectively declare a multi-line yaml string. You can learn more about multi-line yaml syntax [here](https://yaml-multiline.info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> **⚠️ Note for Windows:** Paths must use `/` as a separator, not `\`, as `\` is used to escape characters with special meaning in the pattern; for example, instead of specifying `D:\Foo.txt`, you must specify `D:/Foo.txt`. If you're using PowerShell, you can do this with `$Path = $Path -replace '\\','/'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 📝 External release notes
 | 
					### 📝 External release notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,19 +157,18 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v5
 | 
				
			||||||
      - name: Generate Changelog
 | 
					      - name: Generate Changelog
 | 
				
			||||||
        run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
 | 
					        run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
 | 
				
			||||||
      - name: Release
 | 
					      - name: Release
 | 
				
			||||||
        uses: softprops/action-gh-release@v1
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
					        if: github.ref_type == 'tag'
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          body_path: ${{ github.workspace }}-CHANGELOG.txt
 | 
					          body_path: ${{ github.workspace }}-CHANGELOG.txt
 | 
				
			||||||
 | 
					          repository: my_gh_org/my_gh_repo
 | 
				
			||||||
          # note you'll typically need to create a personal access token
 | 
					          # note you'll typically need to create a personal access token
 | 
				
			||||||
          # with permissions to create releases in the other repo
 | 
					          # with permissions to create releases in the other repo
 | 
				
			||||||
          token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
 | 
					          token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
 | 
				
			||||||
        env:
 | 
					 | 
				
			||||||
          GITHUB_REPOSITORY: my_gh_org/my_gh_repo
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 💅 Customizing
 | 
					### 💅 Customizing
 | 
				
			||||||
@@ -171,9 +183,11 @@ The following are optional as `step.with` keys
 | 
				
			|||||||
| `body_path`                | String  | Path to load text communicating notable changes in this release                                                                                                                                                                                                                                                                                                                                                                                 |
 | 
					| `body_path`                | String  | Path to load text communicating notable changes in this release                                                                                                                                                                                                                                                                                                                                                                                 |
 | 
				
			||||||
| `draft`                    | Boolean | Indicator of whether or not this release is a draft                                                                                                                                                                                                                                                                                                                                                                                             |
 | 
					| `draft`                    | Boolean | Indicator of whether or not this release is a draft                                                                                                                                                                                                                                                                                                                                                                                             |
 | 
				
			||||||
| `prerelease`               | Boolean | Indicator of whether or not is a prerelease                                                                                                                                                                                                                                                                                                                                                                                                     |
 | 
					| `prerelease`               | Boolean | Indicator of whether or not is a prerelease                                                                                                                                                                                                                                                                                                                                                                                                     |
 | 
				
			||||||
 | 
					| `preserve_order`           | Boolean | Indicator of whether order of files should be preserved when uploading assets                                                                                                                                                                                                                                                                                                                                                                   |
 | 
				
			||||||
| `files`                    | String  | Newline-delimited globs of paths to assets to upload for release                                                                                                                                                                                                                                                                                                                                                                                |
 | 
					| `files`                    | String  | Newline-delimited globs of paths to assets to upload for release                                                                                                                                                                                                                                                                                                                                                                                |
 | 
				
			||||||
 | 
					| `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`                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
					| `tag_name`                 | String  | Name of a tag. defaults to `github.ref_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.                                                                                                                                                                                                                                                                                                      |
 | 
				
			||||||
@@ -181,6 +195,7 @@ The following are optional as `step.with` keys
 | 
				
			|||||||
| `discussion_category_name` | String  | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository)                                                     |
 | 
					| `discussion_category_name` | String  | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository)                                                     |
 | 
				
			||||||
| `generate_release_notes`   | Boolean | Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise, a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes. See the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information |
 | 
					| `generate_release_notes`   | Boolean | Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise, a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes. See the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information |
 | 
				
			||||||
| `append_body`              | Boolean | Append to existing body instead of overwriting it                                                                                                                                                                                                                                                                                                                                                                                               |
 | 
					| `append_body`              | Boolean | Append to existing body instead of overwriting it                                                                                                                                                                                                                                                                                                                                                                                               |
 | 
				
			||||||
 | 
					| `make_latest`              | String  | Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest. Can be `true`, `false`, or `legacy`. Uses GitHub api defaults if not provided                                                                                                                                                                                                                            |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
💡 When providing a `body` and `body_path` at the same time, `body_path` will be
 | 
					💡 When providing a `body` and `body_path` at the same time, `body_path` will be
 | 
				
			||||||
attempted first, then falling back on `body` if the path can not be read from.
 | 
					attempted first, then falling back on `body` if the path can not be read from.
 | 
				
			||||||
@@ -194,7 +209,7 @@ release will retain its original info.
 | 
				
			|||||||
The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
 | 
					The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Name         | Type   | Description                                                                                                                                                                               |
 | 
					| Name         | Type   | Description                                                                                                                                                                               |
 | 
				
			||||||
| ------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
					| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
				
			||||||
| `url`        | String | Github.com URL for the release                                                                                                                                                            |
 | 
					| `url`        | String | Github.com URL for the release                                                                                                                                                            |
 | 
				
			||||||
| `id`         | String | Release ID                                                                                                                                                                                |
 | 
					| `id`         | String | Release ID                                                                                                                                                                                |
 | 
				
			||||||
| `upload_url` | String | URL for uploading assets to the release                                                                                                                                                   |
 | 
					| `upload_url` | String | URL for uploading assets to the release                                                                                                                                                   |
 | 
				
			||||||
@@ -232,4 +247,7 @@ permissions:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[GitHub token permissions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) can be set for an individual job, workflow, or for Actions as a whole.
 | 
					[GitHub token permissions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) can be set for an individual job, workflow, or for Actions as a whole.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that if you intend to run workflows on the release event (`on: { release: { types: [published] } }`), you need to use
 | 
				
			||||||
 | 
					a personal access token for this action, as the [default `secrets.GITHUB_TOKEN` does not trigger another workflow](https://github.com/actions/create-release/issues/71).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Doug Tangren (softprops) 2019
 | 
					Doug Tangren (softprops) 2019
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,308 @@
 | 
				
			|||||||
//import * as assert from "assert";
 | 
					import {
 | 
				
			||||||
//const assert = require('assert');
 | 
					  asset,
 | 
				
			||||||
import * as assert from "assert";
 | 
					  findTagFromReleases,
 | 
				
			||||||
import { mimeOrDefault, asset } from "../src/github";
 | 
					  mimeOrDefault,
 | 
				
			||||||
 | 
					  release,
 | 
				
			||||||
 | 
					  Release,
 | 
				
			||||||
 | 
					  Releaser,
 | 
				
			||||||
 | 
					} from '../src/github';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("github", () => {
 | 
					import { assert, describe, it } from 'vitest';
 | 
				
			||||||
  describe("mimeOrDefault", () => {
 | 
					
 | 
				
			||||||
    it("returns a specific mime for common path", async () => {
 | 
					describe('github', () => {
 | 
				
			||||||
      assert.equal(mimeOrDefault("foo.tar.gz"), "application/gzip");
 | 
					  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 () => {
 | 
					    it('returns default mime for uncommon path', async () => {
 | 
				
			||||||
      assert.equal(mimeOrDefault("foo.uncommon"), "application/octet-stream");
 | 
					      assert.equal(mimeOrDefault('foo.uncommon'), 'application/octet-stream');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("asset", () => {
 | 
					  describe('asset', () => {
 | 
				
			||||||
    it("derives asset info from a path", async () => {
 | 
					    it('derives asset info from a path', async () => {
 | 
				
			||||||
      const { name, mime, size, data } = asset("tests/data/foo/bar.txt");
 | 
					      const { name, mime, size } = asset('tests/data/foo/bar.txt');
 | 
				
			||||||
      assert.equal(name, "bar.txt");
 | 
					      assert.equal(name, 'bar.txt');
 | 
				
			||||||
      assert.equal(mime, "text/plain");
 | 
					      assert.equal(mime, 'text/plain');
 | 
				
			||||||
      assert.equal(size, 10);
 | 
					      assert.equal(size, 10);
 | 
				
			||||||
      assert.equal(data.toString(), "release me");
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,103 +1,118 @@
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
  releaseBody,
 | 
					  alignAssetName,
 | 
				
			||||||
  isTag,
 | 
					  isTag,
 | 
				
			||||||
  paths,
 | 
					 | 
				
			||||||
  parseConfig,
 | 
					  parseConfig,
 | 
				
			||||||
  parseInputFiles,
 | 
					  parseInputFiles,
 | 
				
			||||||
 | 
					  paths,
 | 
				
			||||||
 | 
					  releaseBody,
 | 
				
			||||||
  unmatchedPatterns,
 | 
					  unmatchedPatterns,
 | 
				
			||||||
  uploadUrl,
 | 
					  uploadUrl,
 | 
				
			||||||
} from "../src/util";
 | 
					} from '../src/util';
 | 
				
			||||||
import * as assert from "assert";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("util", () => {
 | 
					import { assert, describe, expect, it } from 'vitest';
 | 
				
			||||||
  describe("uploadUrl", () => {
 | 
					
 | 
				
			||||||
    it("strips template", () => {
 | 
					describe('util', () => {
 | 
				
			||||||
 | 
					  describe('uploadUrl', () => {
 | 
				
			||||||
 | 
					    it('strips template', () => {
 | 
				
			||||||
      assert.equal(
 | 
					      assert.equal(
 | 
				
			||||||
        uploadUrl(
 | 
					        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{?name,label}',
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets"
 | 
					        'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets',
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  describe("parseInputFiles", () => {
 | 
					  describe('parseInputFiles', () => {
 | 
				
			||||||
    it("parses empty strings", () => {
 | 
					    it('parses empty strings', () => {
 | 
				
			||||||
      assert.deepStrictEqual(parseInputFiles(""), []);
 | 
					      assert.deepStrictEqual(parseInputFiles(''), []);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("parses comma-delimited strings", () => {
 | 
					    it('parses comma-delimited strings', () => {
 | 
				
			||||||
      assert.deepStrictEqual(parseInputFiles("foo,bar"), ["foo", "bar"]);
 | 
					      assert.deepStrictEqual(parseInputFiles('foo,bar'), ['foo', 'bar']);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("parses newline and comma-delimited (and then some)", () => {
 | 
					    it('parses newline and comma-delimited (and then some)', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(parseInputFiles('foo,bar\nbaz,boom,\n\ndoom,loom '), [
 | 
				
			||||||
        parseInputFiles("foo,bar\nbaz,boom,\n\ndoom,loom "),
 | 
					        'foo',
 | 
				
			||||||
        ["foo", "bar", "baz", "boom", "doom", "loom"]
 | 
					        'bar',
 | 
				
			||||||
      );
 | 
					        'baz',
 | 
				
			||||||
 | 
					        'boom',
 | 
				
			||||||
 | 
					        'doom',
 | 
				
			||||||
 | 
					        'loom',
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  describe("releaseBody", () => {
 | 
					  describe('releaseBody', () => {
 | 
				
			||||||
    it("uses input body", () => {
 | 
					    it('uses input body', () => {
 | 
				
			||||||
      assert.equal(
 | 
					      assert.equal(
 | 
				
			||||||
        "foo",
 | 
					        'foo',
 | 
				
			||||||
        releaseBody({
 | 
					        releaseBody({
 | 
				
			||||||
          github_ref: "",
 | 
					          github_ref: '',
 | 
				
			||||||
          github_repository: "",
 | 
					          github_repository: '',
 | 
				
			||||||
          github_token: "",
 | 
					          github_token: '',
 | 
				
			||||||
          input_body: "foo",
 | 
					          input_body: 'foo',
 | 
				
			||||||
          input_body_path: undefined,
 | 
					          input_body_path: undefined,
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: false,
 | 
					          input_prerelease: false,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        })
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("uses input body path", () => {
 | 
					    it('uses input body path', () => {
 | 
				
			||||||
      assert.equal(
 | 
					      assert.equal(
 | 
				
			||||||
        "bar",
 | 
					        'bar',
 | 
				
			||||||
        releaseBody({
 | 
					        releaseBody({
 | 
				
			||||||
          github_ref: "",
 | 
					          github_ref: '',
 | 
				
			||||||
          github_repository: "",
 | 
					          github_repository: '',
 | 
				
			||||||
          github_token: "",
 | 
					          github_token: '',
 | 
				
			||||||
          input_body: undefined,
 | 
					          input_body: undefined,
 | 
				
			||||||
          input_body_path: "__tests__/release.txt",
 | 
					          input_body_path: '__tests__/release.txt',
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: false,
 | 
					          input_prerelease: false,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        })
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("defaults to body path when both body and body path are provided", () => {
 | 
					    it('defaults to body path when both body and body path are provided', () => {
 | 
				
			||||||
      assert.equal(
 | 
					      assert.equal(
 | 
				
			||||||
        "bar",
 | 
					        'bar',
 | 
				
			||||||
        releaseBody({
 | 
					        releaseBody({
 | 
				
			||||||
          github_ref: "",
 | 
					          github_ref: '',
 | 
				
			||||||
          github_repository: "",
 | 
					          github_repository: '',
 | 
				
			||||||
          github_token: "",
 | 
					          github_token: '',
 | 
				
			||||||
          input_body: "foo",
 | 
					          input_body: 'foo',
 | 
				
			||||||
          input_body_path: "__tests__/release.txt",
 | 
					          input_body_path: '__tests__/release.txt',
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: false,
 | 
					          input_prerelease: false,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        })
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  describe("parseConfig", () => {
 | 
					  describe('parseConfig', () => {
 | 
				
			||||||
    it("parses basic config", () => {
 | 
					    it('parses basic config', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          // note: inputs declared in actions.yml, even when declared not required,
 | 
					          // note: inputs declared in actions.yml, even when declared not required,
 | 
				
			||||||
@@ -106,230 +121,314 @@ describe("util", () => {
 | 
				
			|||||||
          // as an empty string !== undefined in terms of what we pass to the api
 | 
					          // 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
 | 
					          // so we cover that in a test case here to ensure undefined values are actually
 | 
				
			||||||
          // resolved as undefined and not empty strings
 | 
					          // resolved as undefined and not empty strings
 | 
				
			||||||
          INPUT_TARGET_COMMITISH: "",
 | 
					          INPUT_TARGET_COMMITISH: '',
 | 
				
			||||||
          INPUT_DISCUSSION_CATEGORY_NAME: "",
 | 
					          INPUT_DISCUSSION_CATEGORY_NAME: '',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: undefined,
 | 
					          input_draft: undefined,
 | 
				
			||||||
          input_prerelease: undefined,
 | 
					          input_prerelease: undefined,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("parses basic config with commitish", () => {
 | 
					    it('parses basic config with commitish', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_TARGET_COMMITISH: "affa18ef97bc9db20076945705aba8c516139abd",
 | 
					          INPUT_TARGET_COMMITISH: 'affa18ef97bc9db20076945705aba8c516139abd',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: undefined,
 | 
					          input_draft: undefined,
 | 
				
			||||||
          input_prerelease: undefined,
 | 
					          input_prerelease: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
 | 
					          input_target_commitish: 'affa18ef97bc9db20076945705aba8c516139abd',
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("supports discussion category names", () => {
 | 
					    it('supports discussion category names', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_DISCUSSION_CATEGORY_NAME: "releases",
 | 
					          INPUT_DISCUSSION_CATEGORY_NAME: 'releases',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: undefined,
 | 
					          input_draft: undefined,
 | 
				
			||||||
          input_prerelease: undefined,
 | 
					          input_prerelease: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: "releases",
 | 
					          input_discussion_category_name: 'releases',
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("supports generating release notes", () => {
 | 
					    it('supports generating release notes', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_GENERATE_RELEASE_NOTES: "true",
 | 
					          INPUT_GENERATE_RELEASE_NOTES: 'true',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: undefined,
 | 
					          input_draft: undefined,
 | 
				
			||||||
          input_prerelease: undefined,
 | 
					          input_prerelease: undefined,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: true,
 | 
					          input_generate_release_notes: true,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("prefers GITHUB_TOKEN over token input for backwards compatibility", () => {
 | 
					    it('prefers GITHUB_TOKEN over token input for backwards compatibility', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_DRAFT: "false",
 | 
					          INPUT_DRAFT: 'false',
 | 
				
			||||||
          INPUT_PRERELEASE: "true",
 | 
					          INPUT_PRERELEASE: 'true',
 | 
				
			||||||
          GITHUB_TOKEN: "env-token",
 | 
					          INPUT_PRESERVE_ORDER: 'true',
 | 
				
			||||||
          INPUT_TOKEN: "input-token",
 | 
					          GITHUB_TOKEN: 'env-token',
 | 
				
			||||||
 | 
					          INPUT_TOKEN: 'input-token',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: true,
 | 
					          input_prerelease: true,
 | 
				
			||||||
 | 
					          input_preserve_order: true,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("uses input token as the source of GITHUB_TOKEN by default", () => {
 | 
					    it('uses input token as the source of GITHUB_TOKEN by default', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_DRAFT: "false",
 | 
					          INPUT_DRAFT: 'false',
 | 
				
			||||||
          INPUT_PRERELEASE: "true",
 | 
					          INPUT_PRERELEASE: 'true',
 | 
				
			||||||
          INPUT_TOKEN: "input-token",
 | 
					          INPUT_TOKEN: 'input-token',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: true,
 | 
					          input_prerelease: true,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("parses basic config with draft and prerelease", () => {
 | 
					    it('parses basic config with draft and prerelease', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_DRAFT: "false",
 | 
					          INPUT_DRAFT: 'false',
 | 
				
			||||||
          INPUT_PRERELEASE: "true",
 | 
					          INPUT_PRERELEASE: 'true',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          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,
 | 
				
			||||||
          input_draft: false,
 | 
					          input_draft: false,
 | 
				
			||||||
          input_prerelease: true,
 | 
					          input_prerelease: true,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("parses basic config with append_body", () => {
 | 
					    it('parses basic config where make_latest is passed', () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        parseConfig({
 | 
					        parseConfig({
 | 
				
			||||||
          INPUT_APPEND_BODY: "true",
 | 
					          INPUT_MAKE_LATEST: 'false',
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          github_ref: "",
 | 
					          github_ref: '',
 | 
				
			||||||
          github_repository: "",
 | 
					          github_repository: '',
 | 
				
			||||||
          github_token: "",
 | 
					          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_append_body: true,
 | 
				
			||||||
          input_body: undefined,
 | 
					          input_body: undefined,
 | 
				
			||||||
          input_body_path: undefined,
 | 
					          input_body_path: undefined,
 | 
				
			||||||
          input_draft: undefined,
 | 
					          input_draft: undefined,
 | 
				
			||||||
          input_prerelease: undefined,
 | 
					          input_prerelease: undefined,
 | 
				
			||||||
 | 
					          input_preserve_order: undefined,
 | 
				
			||||||
          input_files: [],
 | 
					          input_files: [],
 | 
				
			||||||
 | 
					          input_overwrite_files: undefined,
 | 
				
			||||||
          input_name: undefined,
 | 
					          input_name: undefined,
 | 
				
			||||||
          input_tag_name: undefined,
 | 
					          input_tag_name: undefined,
 | 
				
			||||||
          input_fail_on_unmatched_files: false,
 | 
					          input_fail_on_unmatched_files: false,
 | 
				
			||||||
          input_target_commitish: undefined,
 | 
					          input_target_commitish: undefined,
 | 
				
			||||||
          input_discussion_category_name: undefined,
 | 
					          input_discussion_category_name: undefined,
 | 
				
			||||||
          input_generate_release_notes: false,
 | 
					          input_generate_release_notes: false,
 | 
				
			||||||
        }
 | 
					          input_make_latest: undefined,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  describe("isTag", () => {
 | 
					  describe('isTag', () => {
 | 
				
			||||||
    it("returns true for tags", async () => {
 | 
					    it('returns true for tags', async () => {
 | 
				
			||||||
      assert.equal(isTag("refs/tags/foo"), true);
 | 
					      assert.equal(isTag('refs/tags/foo'), true);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it("returns false for other kinds of refs", async () => {
 | 
					    it('returns false for other kinds of refs', async () => {
 | 
				
			||||||
      assert.equal(isTag("refs/heads/master"), false);
 | 
					      assert.equal(isTag('refs/heads/master'), false);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe("paths", () => {
 | 
					  describe('paths', () => {
 | 
				
			||||||
    it("resolves files given a set of paths", async () => {
 | 
					    it('resolves files given a set of paths', async () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(paths(['tests/data/**/*', 'tests/data/does/not/exist/*']), [
 | 
				
			||||||
        paths(["tests/data/**/*", "tests/data/does/not/exist/*"]),
 | 
					        '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', () => {
 | 
				
			||||||
    it("returns the patterns that don't match any files", async () => {
 | 
					    it("returns the patterns that don't match any files", async () => {
 | 
				
			||||||
      assert.deepStrictEqual(
 | 
					      assert.deepStrictEqual(
 | 
				
			||||||
        unmatchedPatterns(["tests/data/**/*", "tests/data/does/not/exist/*"]),
 | 
					        unmatchedPatterns(['tests/data/**/*', 'tests/data/does/not/exist/*']),
 | 
				
			||||||
        ["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');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								action.yml
									
									
									
									
									
								
							@@ -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.GITHUB_REF"
 | 
					    description: "Gives a tag name. Defaults to github.ref_name"
 | 
				
			||||||
    required: false
 | 
					    required: false
 | 
				
			||||||
  draft:
 | 
					  draft:
 | 
				
			||||||
    description: "Creates a draft release. Defaults to false"
 | 
					    description: "Creates a draft release. Defaults to false"
 | 
				
			||||||
@@ -21,9 +21,19 @@ inputs:
 | 
				
			|||||||
  prerelease:
 | 
					  prerelease:
 | 
				
			||||||
    description: "Identify the release as a prerelease. Defaults to false"
 | 
					    description: "Identify the release as a prerelease. Defaults to false"
 | 
				
			||||||
    required: false
 | 
					    required: false
 | 
				
			||||||
 | 
					  preserve_order:
 | 
				
			||||||
 | 
					    description: "Preserver the order of the artifacts when uploading"
 | 
				
			||||||
 | 
					    required: false
 | 
				
			||||||
  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:
 | 
				
			||||||
 | 
					    description: "Overwrite existing files with the same name. Defaults to true"
 | 
				
			||||||
 | 
					    required: false
 | 
				
			||||||
 | 
					    default: 'true'
 | 
				
			||||||
  fail_on_unmatched_files:
 | 
					  fail_on_unmatched_files:
 | 
				
			||||||
    description: "Fails if any of the `files` globs match nothing. Defaults to false"
 | 
					    description: "Fails if any of the `files` globs match nothing. Defaults to false"
 | 
				
			||||||
    required: false
 | 
					    required: false
 | 
				
			||||||
@@ -46,8 +56,11 @@ inputs:
 | 
				
			|||||||
  append_body:
 | 
					  append_body:
 | 
				
			||||||
    description: "Append to existing body instead of overwriting it. Default is false."
 | 
					    description: "Append to existing body instead of overwriting it. Default is false."
 | 
				
			||||||
    required: false
 | 
					    required: false
 | 
				
			||||||
 | 
					  make_latest:
 | 
				
			||||||
 | 
					    description: "Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest. Can be `true`, `false`, or `legacy`. Uses GitHub api default if not provided"
 | 
				
			||||||
 | 
					    required: false
 | 
				
			||||||
env:
 | 
					env:
 | 
				
			||||||
  "GITHUB_TOKEN": "As provided by Github Actions"
 | 
					  GITHUB_TOKEN: "As provided by Github Actions"
 | 
				
			||||||
outputs:
 | 
					outputs:
 | 
				
			||||||
  url:
 | 
					  url:
 | 
				
			||||||
    description: "URL to the Release HTML Page"
 | 
					    description: "URL to the Release HTML Page"
 | 
				
			||||||
@@ -58,7 +71,7 @@ outputs:
 | 
				
			|||||||
  assets:
 | 
					  assets:
 | 
				
			||||||
    description: "JSON array containing information about each uploaded asset, in the format given [here](https://docs.github.com/en/rest/reference/repos#upload-a-release-asset--code-samples) (minus the `uploader` field)"
 | 
					    description: "JSON array containing information about each uploaded asset, in the format given [here](https://docs.github.com/en/rest/reference/repos#upload-a-release-asset--code-samples) (minus the `uploader` field)"
 | 
				
			||||||
runs:
 | 
					runs:
 | 
				
			||||||
  using: "node16"
 | 
					  using: "node20"
 | 
				
			||||||
  main: "dist/index.js"
 | 
					  main: "dist/index.js"
 | 
				
			||||||
branding:
 | 
					branding:
 | 
				
			||||||
  color: "green"
 | 
					  color: "green"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										452
									
								
								dist/37.index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										452
									
								
								dist/37.index.js
									
									
									
									
										vendored
									
									
								
							@@ -1,452 +0,0 @@
 | 
				
			|||||||
"use strict";
 | 
					 | 
				
			||||||
exports.id = 37;
 | 
					 | 
				
			||||||
exports.ids = [37];
 | 
					 | 
				
			||||||
exports.modules = {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/***/ 4037:
 | 
					 | 
				
			||||||
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__webpack_require__.r(__webpack_exports__);
 | 
					 | 
				
			||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
 | 
					 | 
				
			||||||
/* harmony export */   "toFormData": () => (/* binding */ toFormData)
 | 
					 | 
				
			||||||
/* harmony export */ });
 | 
					 | 
				
			||||||
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2777);
 | 
					 | 
				
			||||||
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8010);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let s = 0;
 | 
					 | 
				
			||||||
const S = {
 | 
					 | 
				
			||||||
	START_BOUNDARY: s++,
 | 
					 | 
				
			||||||
	HEADER_FIELD_START: s++,
 | 
					 | 
				
			||||||
	HEADER_FIELD: s++,
 | 
					 | 
				
			||||||
	HEADER_VALUE_START: s++,
 | 
					 | 
				
			||||||
	HEADER_VALUE: s++,
 | 
					 | 
				
			||||||
	HEADER_VALUE_ALMOST_DONE: s++,
 | 
					 | 
				
			||||||
	HEADERS_ALMOST_DONE: s++,
 | 
					 | 
				
			||||||
	PART_DATA_START: s++,
 | 
					 | 
				
			||||||
	PART_DATA: s++,
 | 
					 | 
				
			||||||
	END: s++
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let f = 1;
 | 
					 | 
				
			||||||
const F = {
 | 
					 | 
				
			||||||
	PART_BOUNDARY: f,
 | 
					 | 
				
			||||||
	LAST_BOUNDARY: f *= 2
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const LF = 10;
 | 
					 | 
				
			||||||
const CR = 13;
 | 
					 | 
				
			||||||
const SPACE = 32;
 | 
					 | 
				
			||||||
const HYPHEN = 45;
 | 
					 | 
				
			||||||
const COLON = 58;
 | 
					 | 
				
			||||||
const A = 97;
 | 
					 | 
				
			||||||
const Z = 122;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const lower = c => c | 0x20;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const noop = () => {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MultipartParser {
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param {string} boundary
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	constructor(boundary) {
 | 
					 | 
				
			||||||
		this.index = 0;
 | 
					 | 
				
			||||||
		this.flags = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.onHeaderEnd = noop;
 | 
					 | 
				
			||||||
		this.onHeaderField = noop;
 | 
					 | 
				
			||||||
		this.onHeadersEnd = noop;
 | 
					 | 
				
			||||||
		this.onHeaderValue = noop;
 | 
					 | 
				
			||||||
		this.onPartBegin = noop;
 | 
					 | 
				
			||||||
		this.onPartData = noop;
 | 
					 | 
				
			||||||
		this.onPartEnd = noop;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.boundaryChars = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		boundary = '\r\n--' + boundary;
 | 
					 | 
				
			||||||
		const ui8a = new Uint8Array(boundary.length);
 | 
					 | 
				
			||||||
		for (let i = 0; i < boundary.length; i++) {
 | 
					 | 
				
			||||||
			ui8a[i] = boundary.charCodeAt(i);
 | 
					 | 
				
			||||||
			this.boundaryChars[ui8a[i]] = true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.boundary = ui8a;
 | 
					 | 
				
			||||||
		this.lookbehind = new Uint8Array(this.boundary.length + 8);
 | 
					 | 
				
			||||||
		this.state = S.START_BOUNDARY;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param {Uint8Array} data
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	write(data) {
 | 
					 | 
				
			||||||
		let i = 0;
 | 
					 | 
				
			||||||
		const length_ = data.length;
 | 
					 | 
				
			||||||
		let previousIndex = this.index;
 | 
					 | 
				
			||||||
		let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
 | 
					 | 
				
			||||||
		const boundaryLength = this.boundary.length;
 | 
					 | 
				
			||||||
		const boundaryEnd = boundaryLength - 1;
 | 
					 | 
				
			||||||
		const bufferLength = data.length;
 | 
					 | 
				
			||||||
		let c;
 | 
					 | 
				
			||||||
		let cl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const mark = name => {
 | 
					 | 
				
			||||||
			this[name + 'Mark'] = i;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const clear = name => {
 | 
					 | 
				
			||||||
			delete this[name + 'Mark'];
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const callback = (callbackSymbol, start, end, ui8a) => {
 | 
					 | 
				
			||||||
			if (start === undefined || start !== end) {
 | 
					 | 
				
			||||||
				this[callbackSymbol](ui8a && ui8a.subarray(start, end));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const dataCallback = (name, clear) => {
 | 
					 | 
				
			||||||
			const markSymbol = name + 'Mark';
 | 
					 | 
				
			||||||
			if (!(markSymbol in this)) {
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (clear) {
 | 
					 | 
				
			||||||
				callback(name, this[markSymbol], i, data);
 | 
					 | 
				
			||||||
				delete this[markSymbol];
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				callback(name, this[markSymbol], data.length, data);
 | 
					 | 
				
			||||||
				this[markSymbol] = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (i = 0; i < length_; i++) {
 | 
					 | 
				
			||||||
			c = data[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			switch (state) {
 | 
					 | 
				
			||||||
				case S.START_BOUNDARY:
 | 
					 | 
				
			||||||
					if (index === boundary.length - 2) {
 | 
					 | 
				
			||||||
						if (c === HYPHEN) {
 | 
					 | 
				
			||||||
							flags |= F.LAST_BOUNDARY;
 | 
					 | 
				
			||||||
						} else if (c !== CR) {
 | 
					 | 
				
			||||||
							return;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						index++;
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					} else if (index - 1 === boundary.length - 2) {
 | 
					 | 
				
			||||||
						if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
 | 
					 | 
				
			||||||
							state = S.END;
 | 
					 | 
				
			||||||
							flags = 0;
 | 
					 | 
				
			||||||
						} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
 | 
					 | 
				
			||||||
							index = 0;
 | 
					 | 
				
			||||||
							callback('onPartBegin');
 | 
					 | 
				
			||||||
							state = S.HEADER_FIELD_START;
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							return;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (c !== boundary[index + 2]) {
 | 
					 | 
				
			||||||
						index = -2;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (c === boundary[index + 2]) {
 | 
					 | 
				
			||||||
						index++;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.HEADER_FIELD_START:
 | 
					 | 
				
			||||||
					state = S.HEADER_FIELD;
 | 
					 | 
				
			||||||
					mark('onHeaderField');
 | 
					 | 
				
			||||||
					index = 0;
 | 
					 | 
				
			||||||
					// falls through
 | 
					 | 
				
			||||||
				case S.HEADER_FIELD:
 | 
					 | 
				
			||||||
					if (c === CR) {
 | 
					 | 
				
			||||||
						clear('onHeaderField');
 | 
					 | 
				
			||||||
						state = S.HEADERS_ALMOST_DONE;
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					index++;
 | 
					 | 
				
			||||||
					if (c === HYPHEN) {
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (c === COLON) {
 | 
					 | 
				
			||||||
						if (index === 1) {
 | 
					 | 
				
			||||||
							// empty header field
 | 
					 | 
				
			||||||
							return;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						dataCallback('onHeaderField', true);
 | 
					 | 
				
			||||||
						state = S.HEADER_VALUE_START;
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					cl = lower(c);
 | 
					 | 
				
			||||||
					if (cl < A || cl > Z) {
 | 
					 | 
				
			||||||
						return;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.HEADER_VALUE_START:
 | 
					 | 
				
			||||||
					if (c === SPACE) {
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					mark('onHeaderValue');
 | 
					 | 
				
			||||||
					state = S.HEADER_VALUE;
 | 
					 | 
				
			||||||
					// falls through
 | 
					 | 
				
			||||||
				case S.HEADER_VALUE:
 | 
					 | 
				
			||||||
					if (c === CR) {
 | 
					 | 
				
			||||||
						dataCallback('onHeaderValue', true);
 | 
					 | 
				
			||||||
						callback('onHeaderEnd');
 | 
					 | 
				
			||||||
						state = S.HEADER_VALUE_ALMOST_DONE;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.HEADER_VALUE_ALMOST_DONE:
 | 
					 | 
				
			||||||
					if (c !== LF) {
 | 
					 | 
				
			||||||
						return;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					state = S.HEADER_FIELD_START;
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.HEADERS_ALMOST_DONE:
 | 
					 | 
				
			||||||
					if (c !== LF) {
 | 
					 | 
				
			||||||
						return;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					callback('onHeadersEnd');
 | 
					 | 
				
			||||||
					state = S.PART_DATA_START;
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.PART_DATA_START:
 | 
					 | 
				
			||||||
					state = S.PART_DATA;
 | 
					 | 
				
			||||||
					mark('onPartData');
 | 
					 | 
				
			||||||
					// falls through
 | 
					 | 
				
			||||||
				case S.PART_DATA:
 | 
					 | 
				
			||||||
					previousIndex = index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (index === 0) {
 | 
					 | 
				
			||||||
						// boyer-moore derrived algorithm to safely skip non-boundary data
 | 
					 | 
				
			||||||
						i += boundaryEnd;
 | 
					 | 
				
			||||||
						while (i < bufferLength && !(data[i] in boundaryChars)) {
 | 
					 | 
				
			||||||
							i += boundaryLength;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						i -= boundaryEnd;
 | 
					 | 
				
			||||||
						c = data[i];
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (index < boundary.length) {
 | 
					 | 
				
			||||||
						if (boundary[index] === c) {
 | 
					 | 
				
			||||||
							if (index === 0) {
 | 
					 | 
				
			||||||
								dataCallback('onPartData', true);
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							index++;
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							index = 0;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					} else if (index === boundary.length) {
 | 
					 | 
				
			||||||
						index++;
 | 
					 | 
				
			||||||
						if (c === CR) {
 | 
					 | 
				
			||||||
							// CR = part boundary
 | 
					 | 
				
			||||||
							flags |= F.PART_BOUNDARY;
 | 
					 | 
				
			||||||
						} else if (c === HYPHEN) {
 | 
					 | 
				
			||||||
							// HYPHEN = end boundary
 | 
					 | 
				
			||||||
							flags |= F.LAST_BOUNDARY;
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							index = 0;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					} else if (index - 1 === boundary.length) {
 | 
					 | 
				
			||||||
						if (flags & F.PART_BOUNDARY) {
 | 
					 | 
				
			||||||
							index = 0;
 | 
					 | 
				
			||||||
							if (c === LF) {
 | 
					 | 
				
			||||||
								// unset the PART_BOUNDARY flag
 | 
					 | 
				
			||||||
								flags &= ~F.PART_BOUNDARY;
 | 
					 | 
				
			||||||
								callback('onPartEnd');
 | 
					 | 
				
			||||||
								callback('onPartBegin');
 | 
					 | 
				
			||||||
								state = S.HEADER_FIELD_START;
 | 
					 | 
				
			||||||
								break;
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						} else if (flags & F.LAST_BOUNDARY) {
 | 
					 | 
				
			||||||
							if (c === HYPHEN) {
 | 
					 | 
				
			||||||
								callback('onPartEnd');
 | 
					 | 
				
			||||||
								state = S.END;
 | 
					 | 
				
			||||||
								flags = 0;
 | 
					 | 
				
			||||||
							} else {
 | 
					 | 
				
			||||||
								index = 0;
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							index = 0;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (index > 0) {
 | 
					 | 
				
			||||||
						// when matching a possible boundary, keep a lookbehind reference
 | 
					 | 
				
			||||||
						// in case it turns out to be a false lead
 | 
					 | 
				
			||||||
						lookbehind[index - 1] = c;
 | 
					 | 
				
			||||||
					} else if (previousIndex > 0) {
 | 
					 | 
				
			||||||
						// if our boundary turned out to be rubbish, the captured lookbehind
 | 
					 | 
				
			||||||
						// belongs to partData
 | 
					 | 
				
			||||||
						const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
 | 
					 | 
				
			||||||
						callback('onPartData', 0, previousIndex, _lookbehind);
 | 
					 | 
				
			||||||
						previousIndex = 0;
 | 
					 | 
				
			||||||
						mark('onPartData');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						// reconsider the current character even so it interrupted the sequence
 | 
					 | 
				
			||||||
						// it could be the beginning of a new sequence
 | 
					 | 
				
			||||||
						i--;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				case S.END:
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
					throw new Error(`Unexpected state entered: ${state}`);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dataCallback('onHeaderField');
 | 
					 | 
				
			||||||
		dataCallback('onHeaderValue');
 | 
					 | 
				
			||||||
		dataCallback('onPartData');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Update properties for the next call
 | 
					 | 
				
			||||||
		this.index = index;
 | 
					 | 
				
			||||||
		this.state = state;
 | 
					 | 
				
			||||||
		this.flags = flags;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	end() {
 | 
					 | 
				
			||||||
		if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
 | 
					 | 
				
			||||||
			(this.state === S.PART_DATA && this.index === this.boundary.length)) {
 | 
					 | 
				
			||||||
			this.onPartEnd();
 | 
					 | 
				
			||||||
		} else if (this.state !== S.END) {
 | 
					 | 
				
			||||||
			throw new Error('MultipartParser.end(): stream ended unexpectedly');
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function _fileName(headerValue) {
 | 
					 | 
				
			||||||
	// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
 | 
					 | 
				
			||||||
	const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
 | 
					 | 
				
			||||||
	if (!m) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const match = m[2] || m[3] || '';
 | 
					 | 
				
			||||||
	let filename = match.slice(match.lastIndexOf('\\') + 1);
 | 
					 | 
				
			||||||
	filename = filename.replace(/%22/g, '"');
 | 
					 | 
				
			||||||
	filename = filename.replace(/&#(\d{4});/g, (m, code) => {
 | 
					 | 
				
			||||||
		return String.fromCharCode(code);
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
	return filename;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function toFormData(Body, ct) {
 | 
					 | 
				
			||||||
	if (!/multipart/i.test(ct)) {
 | 
					 | 
				
			||||||
		throw new TypeError('Failed to fetch');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!m) {
 | 
					 | 
				
			||||||
		throw new TypeError('no or bad content-type header, no multipart boundary');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const parser = new MultipartParser(m[1] || m[2]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	let headerField;
 | 
					 | 
				
			||||||
	let headerValue;
 | 
					 | 
				
			||||||
	let entryValue;
 | 
					 | 
				
			||||||
	let entryName;
 | 
					 | 
				
			||||||
	let contentType;
 | 
					 | 
				
			||||||
	let filename;
 | 
					 | 
				
			||||||
	const entryChunks = [];
 | 
					 | 
				
			||||||
	const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const onPartData = ui8a => {
 | 
					 | 
				
			||||||
		entryValue += decoder.decode(ui8a, {stream: true});
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const appendToFile = ui8a => {
 | 
					 | 
				
			||||||
		entryChunks.push(ui8a);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const appendFileToFormData = () => {
 | 
					 | 
				
			||||||
		const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
 | 
					 | 
				
			||||||
		formData.append(entryName, file);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const appendEntryToFormData = () => {
 | 
					 | 
				
			||||||
		formData.append(entryName, entryValue);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const decoder = new TextDecoder('utf-8');
 | 
					 | 
				
			||||||
	decoder.decode();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	parser.onPartBegin = function () {
 | 
					 | 
				
			||||||
		parser.onPartData = onPartData;
 | 
					 | 
				
			||||||
		parser.onPartEnd = appendEntryToFormData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		headerField = '';
 | 
					 | 
				
			||||||
		headerValue = '';
 | 
					 | 
				
			||||||
		entryValue = '';
 | 
					 | 
				
			||||||
		entryName = '';
 | 
					 | 
				
			||||||
		contentType = '';
 | 
					 | 
				
			||||||
		filename = null;
 | 
					 | 
				
			||||||
		entryChunks.length = 0;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	parser.onHeaderField = function (ui8a) {
 | 
					 | 
				
			||||||
		headerField += decoder.decode(ui8a, {stream: true});
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	parser.onHeaderValue = function (ui8a) {
 | 
					 | 
				
			||||||
		headerValue += decoder.decode(ui8a, {stream: true});
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	parser.onHeaderEnd = function () {
 | 
					 | 
				
			||||||
		headerValue += decoder.decode();
 | 
					 | 
				
			||||||
		headerField = headerField.toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (headerField === 'content-disposition') {
 | 
					 | 
				
			||||||
			// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
 | 
					 | 
				
			||||||
			const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (m) {
 | 
					 | 
				
			||||||
				entryName = m[2] || m[3] || '';
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			filename = _fileName(headerValue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (filename) {
 | 
					 | 
				
			||||||
				parser.onPartData = appendToFile;
 | 
					 | 
				
			||||||
				parser.onPartEnd = appendFileToFormData;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else if (headerField === 'content-type') {
 | 
					 | 
				
			||||||
			contentType = headerValue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		headerValue = '';
 | 
					 | 
				
			||||||
		headerField = '';
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for await (const chunk of Body) {
 | 
					 | 
				
			||||||
		parser.write(chunk);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	parser.end();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return formData;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/***/ })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
;
 | 
					 | 
				
			||||||
							
								
								
									
										21
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -1,11 +0,0 @@
 | 
				
			|||||||
module.exports = {
 | 
					 | 
				
			||||||
  clearMocks: true,
 | 
					 | 
				
			||||||
  moduleFileExtensions: ['js', 'ts'],
 | 
					 | 
				
			||||||
  testEnvironment: 'node',
 | 
					 | 
				
			||||||
  testMatch: ['**/*.test.ts'],
 | 
					 | 
				
			||||||
  testRunner: 'jest-circus/runner',
 | 
					 | 
				
			||||||
  transform: {
 | 
					 | 
				
			||||||
    '^.+\\.ts$': 'ts-jest'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  verbose: true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										9062
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9062
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								package.json
									
									
									
									
									
								
							@@ -1,14 +1,17 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "action-gh-release",
 | 
					  "name": "action-gh-release",
 | 
				
			||||||
  "version": "0.1.15",
 | 
					  "version": "2.4.0",
 | 
				
			||||||
  "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",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "build": "ncc build src/main.ts --minify",
 | 
					    "build": "ncc build src/main.ts --minify --target es2022",
 | 
				
			||||||
    "test": "jest",
 | 
					    "build-debug": "ncc build src/main.ts --v8-cache --source-map",
 | 
				
			||||||
 | 
					    "typecheck": "tsc --noEmit",
 | 
				
			||||||
 | 
					    "test": "vitest --coverage",
 | 
				
			||||||
    "fmt": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\"",
 | 
					    "fmt": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\"",
 | 
				
			||||||
    "fmtcheck": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\""
 | 
					    "fmtcheck": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\"",
 | 
				
			||||||
 | 
					    "updatetag": "git tag -d v2 && git push origin :v2 && git tag -a v2 -m '' && git push origin v2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
@@ -19,26 +22,23 @@
 | 
				
			|||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "author": "softprops",
 | 
					  "author": "softprops",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@actions/core": "^1.10.0",
 | 
					    "@actions/core": "^1.11.1",
 | 
				
			||||||
    "@actions/github": "^5.1.1",
 | 
					    "@actions/github": "^6.0.1",
 | 
				
			||||||
    "@octokit/plugin-retry": "^4.0.3",
 | 
					    "@octokit/plugin-retry": "^8.0.2",
 | 
				
			||||||
    "@octokit/plugin-throttling": "^4.3.2",
 | 
					    "@octokit/plugin-throttling": "^11.0.2",
 | 
				
			||||||
    "glob": "^8.0.3",
 | 
					    "glob": "^11.0.3",
 | 
				
			||||||
    "mime": "^3.0.0",
 | 
					    "mime-types": "^3.0.1"
 | 
				
			||||||
    "node-fetch": "^2.6.7"
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/glob": "^8.0.0",
 | 
					    "@types/glob": "^9.0.0",
 | 
				
			||||||
    "@types/jest": "^29.2.2",
 | 
					    "@types/mime-types": "^3.0.1",
 | 
				
			||||||
    "@types/mime": "^3.0.1",
 | 
					    "@types/node": "^20.19.19",
 | 
				
			||||||
    "@types/node": "^18.11.9",
 | 
					    "@vercel/ncc": "^0.38.4",
 | 
				
			||||||
    "@types/node-fetch": "^2.5.12",
 | 
					    "@vitest/coverage-v8": "^3.2.4",
 | 
				
			||||||
    "@vercel/ncc": "^0.34.0",
 | 
					    "prettier": "3.6.2",
 | 
				
			||||||
    "jest": "^29.3.1",
 | 
					    "ts-node": "^10.9.2",
 | 
				
			||||||
    "jest-circus": "^29.3.1",
 | 
					    "typescript": "^5.9.3",
 | 
				
			||||||
    "prettier": "2.7.1",
 | 
					    "typescript-formatter": "^7.2.2",
 | 
				
			||||||
    "ts-jest": "^29.0.3",
 | 
					    "vitest": "^3.1.4"
 | 
				
			||||||
    "typescript": "^4.8.4",
 | 
					 | 
				
			||||||
    "typescript-formatter": "^7.2.2"
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								release.sh
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								release.sh
									
									
									
									
									
								
							@@ -1,17 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
 | 
					 | 
				
			||||||
# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
 | 
					 | 
				
			||||||
# as such the following hack is how we dill with it
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ $# -ne 1 ]]; then
 | 
					 | 
				
			||||||
	echo "please pass a release version. i.e. $0 v1"
 | 
					 | 
				
			||||||
	exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git checkout -b releases/$1 # If this branch already exists, omit the -b flag
 | 
					 | 
				
			||||||
rm -rf node_modules
 | 
					 | 
				
			||||||
sed -i '/node_modules/d' .gitignore # Bash command that removes node_modules from .gitignore
 | 
					 | 
				
			||||||
npm install --production
 | 
					 | 
				
			||||||
git add node_modules -f .gitignore
 | 
					 | 
				
			||||||
git commit -m node_modules
 | 
					 | 
				
			||||||
git push origin releases/$1
 | 
					 | 
				
			||||||
							
								
								
									
										272
									
								
								src/github.ts
									
									
									
									
									
								
							
							
						
						
									
										272
									
								
								src/github.ts
									
									
									
									
									
								
							@@ -1,9 +1,9 @@
 | 
				
			|||||||
import fetch from "node-fetch";
 | 
					import { GitHub } from '@actions/github/lib/utils';
 | 
				
			||||||
import { GitHub } from "@actions/github/lib/utils";
 | 
					import { statSync } from 'fs';
 | 
				
			||||||
import { Config, isTag, releaseBody } from "./util";
 | 
					import { open } from 'fs/promises';
 | 
				
			||||||
import { statSync, readFileSync } from "fs";
 | 
					import { lookup } from 'mime-types';
 | 
				
			||||||
import { getType } from "mime";
 | 
					import { basename } from 'path';
 | 
				
			||||||
import { basename } from "path";
 | 
					import { alignAssetName, Config, isTag, releaseBody } from './util';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type GitHub = InstanceType<typeof GitHub>;
 | 
					type GitHub = InstanceType<typeof GitHub>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,7 +11,6 @@ export interface ReleaseAsset {
 | 
				
			|||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  mime: string;
 | 
					  mime: string;
 | 
				
			||||||
  size: number;
 | 
					  size: number;
 | 
				
			||||||
  data: Buffer;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Release {
 | 
					export interface Release {
 | 
				
			||||||
@@ -28,11 +27,7 @@ export interface Release {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Releaser {
 | 
					export interface Releaser {
 | 
				
			||||||
  getReleaseByTag(params: {
 | 
					  getReleaseByTag(params: { owner: string; repo: string; tag: string }): Promise<{ data: Release }>;
 | 
				
			||||||
    owner: string;
 | 
					 | 
				
			||||||
    repo: string;
 | 
					 | 
				
			||||||
    tag: string;
 | 
					 | 
				
			||||||
  }): Promise<{ data: Release }>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createRelease(params: {
 | 
					  createRelease(params: {
 | 
				
			||||||
    owner: string;
 | 
					    owner: string;
 | 
				
			||||||
@@ -45,6 +40,7 @@ export interface Releaser {
 | 
				
			|||||||
    target_commitish: string | undefined;
 | 
					    target_commitish: string | undefined;
 | 
				
			||||||
    discussion_category_name: string | undefined;
 | 
					    discussion_category_name: string | undefined;
 | 
				
			||||||
    generate_release_notes: boolean | undefined;
 | 
					    generate_release_notes: boolean | undefined;
 | 
				
			||||||
 | 
					    make_latest: 'true' | 'false' | 'legacy' | undefined;
 | 
				
			||||||
  }): Promise<{ data: Release }>;
 | 
					  }): Promise<{ data: Release }>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateRelease(params: {
 | 
					  updateRelease(params: {
 | 
				
			||||||
@@ -59,12 +55,10 @@ export interface Releaser {
 | 
				
			|||||||
    prerelease: boolean | undefined;
 | 
					    prerelease: boolean | undefined;
 | 
				
			||||||
    discussion_category_name: string | undefined;
 | 
					    discussion_category_name: string | undefined;
 | 
				
			||||||
    generate_release_notes: boolean | undefined;
 | 
					    generate_release_notes: boolean | undefined;
 | 
				
			||||||
 | 
					    make_latest: 'true' | 'false' | 'legacy' | undefined;
 | 
				
			||||||
  }): Promise<{ data: Release }>;
 | 
					  }): Promise<{ data: Release }>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  allReleases(params: {
 | 
					  allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }>;
 | 
				
			||||||
    owner: string;
 | 
					 | 
				
			||||||
    repo: string;
 | 
					 | 
				
			||||||
  }): AsyncIterableIterator<{ data: Release[] }>;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class GitHubReleaser implements Releaser {
 | 
					export class GitHubReleaser implements Releaser {
 | 
				
			||||||
@@ -92,7 +86,15 @@ export class GitHubReleaser implements Releaser {
 | 
				
			|||||||
    target_commitish: string | undefined;
 | 
					    target_commitish: string | undefined;
 | 
				
			||||||
    discussion_category_name: string | undefined;
 | 
					    discussion_category_name: string | undefined;
 | 
				
			||||||
    generate_release_notes: boolean | undefined;
 | 
					    generate_release_notes: boolean | undefined;
 | 
				
			||||||
 | 
					    make_latest: 'true' | 'false' | 'legacy' | undefined;
 | 
				
			||||||
  }): Promise<{ data: Release }> {
 | 
					  }): Promise<{ data: Release }> {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      typeof params.make_latest === 'string' &&
 | 
				
			||||||
 | 
					      !['true', 'false', 'legacy'].includes(params.make_latest)
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      params.make_latest = undefined;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this.github.rest.repos.createRelease(params);
 | 
					    return this.github.rest.repos.createRelease(params);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,17 +110,22 @@ export class GitHubReleaser implements Releaser {
 | 
				
			|||||||
    prerelease: boolean | undefined;
 | 
					    prerelease: boolean | undefined;
 | 
				
			||||||
    discussion_category_name: string | undefined;
 | 
					    discussion_category_name: string | undefined;
 | 
				
			||||||
    generate_release_notes: boolean | undefined;
 | 
					    generate_release_notes: boolean | undefined;
 | 
				
			||||||
 | 
					    make_latest: 'true' | 'false' | 'legacy' | undefined;
 | 
				
			||||||
  }): Promise<{ data: Release }> {
 | 
					  }): Promise<{ data: Release }> {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      typeof params.make_latest === 'string' &&
 | 
				
			||||||
 | 
					      !['true', 'false', 'legacy'].includes(params.make_latest)
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      params.make_latest = undefined;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this.github.rest.repos.updateRelease(params);
 | 
					    return this.github.rest.repos.updateRelease(params);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  allReleases(params: {
 | 
					  allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }> {
 | 
				
			||||||
    owner: string;
 | 
					 | 
				
			||||||
    repo: string;
 | 
					 | 
				
			||||||
  }): AsyncIterableIterator<{ data: Release[] }> {
 | 
					 | 
				
			||||||
    const updatedParams = { per_page: 100, ...params };
 | 
					    const updatedParams = { per_page: 100, ...params };
 | 
				
			||||||
    return this.github.paginate.iterator(
 | 
					    return this.github.paginate.iterator(
 | 
				
			||||||
      this.github.rest.repos.listReleases.endpoint.merge(updatedParams)
 | 
					      this.github.rest.repos.listReleases.endpoint.merge(updatedParams),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -128,12 +135,11 @@ export const asset = (path: string): ReleaseAsset => {
 | 
				
			|||||||
    name: basename(path),
 | 
					    name: basename(path),
 | 
				
			||||||
    mime: mimeOrDefault(path),
 | 
					    mime: mimeOrDefault(path),
 | 
				
			||||||
    size: statSync(path).size,
 | 
					    size: statSync(path).size,
 | 
				
			||||||
    data: readFileSync(path),
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mimeOrDefault = (path: string): string => {
 | 
					export const mimeOrDefault = (path: string): string => {
 | 
				
			||||||
  return getType(path) || "application/octet-stream";
 | 
					  return lookup(path) || 'application/octet-stream';
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const upload = async (
 | 
					export const upload = async (
 | 
				
			||||||
@@ -141,14 +147,21 @@ export const upload = async (
 | 
				
			|||||||
  github: GitHub,
 | 
					  github: GitHub,
 | 
				
			||||||
  url: string,
 | 
					  url: string,
 | 
				
			||||||
  path: string,
 | 
					  path: string,
 | 
				
			||||||
  currentAssets: Array<{ id: number; name: string }>
 | 
					  currentAssets: Array<{ id: number; name: string }>,
 | 
				
			||||||
): Promise<any> => {
 | 
					): Promise<any> => {
 | 
				
			||||||
  const [owner, repo] = config.github_repository.split("/");
 | 
					  const [owner, repo] = config.github_repository.split('/');
 | 
				
			||||||
  const { name, size, mime, data: body } = asset(path);
 | 
					  const { name, mime, size } = asset(path);
 | 
				
			||||||
  const currentAsset = currentAssets.find(
 | 
					  const currentAsset = currentAssets.find(
 | 
				
			||||||
    ({ name: currentName }) => currentName == name
 | 
					    // note: GitHub renames asset filenames that have special characters, non-alphanumeric characters, and leading or trailing periods. The "List release assets" endpoint lists the renamed filenames.
 | 
				
			||||||
 | 
					    // due to this renaming we need to be mindful when we compare the file name we're uploading with a name github may already have rewritten for logical comparison
 | 
				
			||||||
 | 
					    // see https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28#upload-a-release-asset
 | 
				
			||||||
 | 
					    ({ name: currentName }) => currentName == alignAssetName(name),
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  if (currentAsset) {
 | 
					  if (currentAsset) {
 | 
				
			||||||
 | 
					    if (config.input_overwrite_files === false) {
 | 
				
			||||||
 | 
					      console.log(`Asset ${name} already exists and overwrite_files is false...`);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
      console.log(`♻️ Deleting previously uploaded asset ${name}...`);
 | 
					      console.log(`♻️ Deleting previously uploaded asset ${name}...`);
 | 
				
			||||||
      await github.rest.repos.deleteReleaseAsset({
 | 
					      await github.rest.repos.deleteReleaseAsset({
 | 
				
			||||||
        asset_id: currentAsset.id || 1,
 | 
					        asset_id: currentAsset.id || 1,
 | 
				
			||||||
@@ -156,105 +169,107 @@ export const upload = async (
 | 
				
			|||||||
        repo,
 | 
					        repo,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  console.log(`⬆️ Uploading ${name}...`);
 | 
					  console.log(`⬆️ Uploading ${name}...`);
 | 
				
			||||||
  const endpoint = new URL(url);
 | 
					  const endpoint = new URL(url);
 | 
				
			||||||
  endpoint.searchParams.append("name", name);
 | 
					  endpoint.searchParams.append('name', name);
 | 
				
			||||||
  const resp = await fetch(endpoint, {
 | 
					  const fh = await open(path);
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const resp = await github.request({
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      url: endpoint.toString(),
 | 
				
			||||||
      headers: {
 | 
					      headers: {
 | 
				
			||||||
      "content-length": `${size}`,
 | 
					        'content-length': `${size}`,
 | 
				
			||||||
      "content-type": mime,
 | 
					        'content-type': mime,
 | 
				
			||||||
        authorization: `token ${config.github_token}`,
 | 
					        authorization: `token ${config.github_token}`,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    method: "POST",
 | 
					      data: fh.readableWebStream({ type: 'bytes' }),
 | 
				
			||||||
    body,
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  const json = await resp.json();
 | 
					    const json = resp.data;
 | 
				
			||||||
    if (resp.status !== 201) {
 | 
					    if (resp.status !== 201) {
 | 
				
			||||||
      throw new Error(
 | 
					      throw new Error(
 | 
				
			||||||
        `Failed to upload release asset ${name}. received status code ${
 | 
					        `Failed to upload release asset ${name}. received status code ${
 | 
				
			||||||
          resp.status
 | 
					          resp.status
 | 
				
			||||||
      }\n${json.message}\n${JSON.stringify(json.errors)}`
 | 
					        }\n${json.message}\n${JSON.stringify(json.errors)}`,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    console.log(`✅ Uploaded ${name}`);
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
 | 
					  } finally {
 | 
				
			||||||
 | 
					    await fh.close();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const release = async (
 | 
					export const release = async (
 | 
				
			||||||
  config: Config,
 | 
					  config: Config,
 | 
				
			||||||
  releaser: Releaser,
 | 
					  releaser: Releaser,
 | 
				
			||||||
  maxRetries: number = 3
 | 
					  maxRetries: number = 3,
 | 
				
			||||||
): Promise<Release> => {
 | 
					): Promise<Release> => {
 | 
				
			||||||
  if (maxRetries <= 0) {
 | 
					  if (maxRetries <= 0) {
 | 
				
			||||||
    console.log(`❌ Too many retries. Aborting...`);
 | 
					    console.log(`❌ Too many retries. Aborting...`);
 | 
				
			||||||
    throw new Error("Too many retries.");
 | 
					    throw new Error('Too many retries.');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [owner, repo] = config.github_repository.split("/");
 | 
					  const [owner, repo] = config.github_repository.split('/');
 | 
				
			||||||
  const tag =
 | 
					  const tag =
 | 
				
			||||||
    config.input_tag_name ||
 | 
					    config.input_tag_name ||
 | 
				
			||||||
    (isTag(config.github_ref)
 | 
					    (isTag(config.github_ref) ? config.github_ref.replace('refs/tags/', '') : '');
 | 
				
			||||||
      ? config.github_ref.replace("refs/tags/", "")
 | 
					 | 
				
			||||||
      : "");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const discussion_category_name = config.input_discussion_category_name;
 | 
					  const discussion_category_name = config.input_discussion_category_name;
 | 
				
			||||||
  const generate_release_notes = config.input_generate_release_notes;
 | 
					  const generate_release_notes = config.input_generate_release_notes;
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    // you can't get a an existing draft by tag
 | 
					    const _release: Release | undefined = await findTagFromReleases(releaser, owner, repo, tag);
 | 
				
			||||||
    // so we must find one in the list of all releases
 | 
					 | 
				
			||||||
    if (config.input_draft) {
 | 
					 | 
				
			||||||
      for await (const response of releaser.allReleases({
 | 
					 | 
				
			||||||
        owner,
 | 
					 | 
				
			||||||
        repo,
 | 
					 | 
				
			||||||
      })) {
 | 
					 | 
				
			||||||
        let release = response.data.find((release) => release.tag_name === tag);
 | 
					 | 
				
			||||||
        if (release) {
 | 
					 | 
				
			||||||
          return release;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    let existingRelease = await releaser.getReleaseByTag({
 | 
					 | 
				
			||||||
      owner,
 | 
					 | 
				
			||||||
      repo,
 | 
					 | 
				
			||||||
      tag,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const release_id = existingRelease.data.id;
 | 
					    if (_release === undefined) {
 | 
				
			||||||
 | 
					      return await createRelease(
 | 
				
			||||||
 | 
					        tag,
 | 
				
			||||||
 | 
					        config,
 | 
				
			||||||
 | 
					        releaser,
 | 
				
			||||||
 | 
					        owner,
 | 
				
			||||||
 | 
					        repo,
 | 
				
			||||||
 | 
					        discussion_category_name,
 | 
				
			||||||
 | 
					        generate_release_notes,
 | 
				
			||||||
 | 
					        maxRetries,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let existingRelease: Release = _release!;
 | 
				
			||||||
 | 
					    console.log(`Found release ${existingRelease.name} (with id=${existingRelease.id})`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const release_id = existingRelease.id;
 | 
				
			||||||
    let target_commitish: string;
 | 
					    let target_commitish: string;
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
      config.input_target_commitish &&
 | 
					      config.input_target_commitish &&
 | 
				
			||||||
      config.input_target_commitish !== existingRelease.data.target_commitish
 | 
					      config.input_target_commitish !== existingRelease.target_commitish
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
      console.log(
 | 
					      console.log(
 | 
				
			||||||
        `Updating commit from "${existingRelease.data.target_commitish}" to "${config.input_target_commitish}"`
 | 
					        `Updating commit from "${existingRelease.target_commitish}" to "${config.input_target_commitish}"`,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      target_commitish = config.input_target_commitish;
 | 
					      target_commitish = config.input_target_commitish;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      target_commitish = existingRelease.data.target_commitish;
 | 
					      target_commitish = existingRelease.target_commitish;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const tag_name = tag;
 | 
					    const tag_name = tag;
 | 
				
			||||||
    const name = config.input_name || existingRelease.data.name || tag;
 | 
					    const name = config.input_name || existingRelease.name || tag;
 | 
				
			||||||
    // revisit: support a new body-concat-strategy input for accumulating
 | 
					    // revisit: support a new body-concat-strategy input for accumulating
 | 
				
			||||||
    // body parts as a release gets updated. some users will likely want this while
 | 
					    // body parts as a release gets updated. some users will likely want this while
 | 
				
			||||||
    // others won't previously this was duplicating content for most which
 | 
					    // others won't previously this was duplicating content for most which
 | 
				
			||||||
    // no one wants
 | 
					    // no one wants
 | 
				
			||||||
    const workflowBody = releaseBody(config) || "";
 | 
					    const workflowBody = releaseBody(config) || '';
 | 
				
			||||||
    const existingReleaseBody = existingRelease.data.body || "";
 | 
					    const existingReleaseBody = existingRelease.body || '';
 | 
				
			||||||
    let body: string;
 | 
					    let body: string;
 | 
				
			||||||
    if (config.input_append_body && workflowBody && existingReleaseBody) {
 | 
					    if (config.input_append_body && workflowBody && existingReleaseBody) {
 | 
				
			||||||
      body = existingReleaseBody + "\n" + workflowBody;
 | 
					      body = existingReleaseBody + '\n' + workflowBody;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      body = workflowBody || existingReleaseBody;
 | 
					      body = workflowBody || existingReleaseBody;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const draft =
 | 
					    const draft = config.input_draft !== undefined ? config.input_draft : existingRelease.draft;
 | 
				
			||||||
      config.input_draft !== undefined
 | 
					 | 
				
			||||||
        ? config.input_draft
 | 
					 | 
				
			||||||
        : existingRelease.data.draft;
 | 
					 | 
				
			||||||
    const prerelease =
 | 
					    const prerelease =
 | 
				
			||||||
      config.input_prerelease !== undefined
 | 
					      config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
 | 
				
			||||||
        ? config.input_prerelease
 | 
					
 | 
				
			||||||
        : existingRelease.data.prerelease;
 | 
					    const make_latest = config.input_make_latest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const release = await releaser.updateRelease({
 | 
					    const release = await releaser.updateRelease({
 | 
				
			||||||
      owner,
 | 
					      owner,
 | 
				
			||||||
@@ -268,23 +283,79 @@ export const release = async (
 | 
				
			|||||||
      prerelease,
 | 
					      prerelease,
 | 
				
			||||||
      discussion_category_name,
 | 
					      discussion_category_name,
 | 
				
			||||||
      generate_release_notes,
 | 
					      generate_release_notes,
 | 
				
			||||||
 | 
					      make_latest,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return release.data;
 | 
					    return release.data;
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    if (error.status === 404) {
 | 
					    if (error.status !== 404) {
 | 
				
			||||||
 | 
					      console.log(
 | 
				
			||||||
 | 
					        `⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      throw error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return await createRelease(
 | 
				
			||||||
 | 
					      tag,
 | 
				
			||||||
 | 
					      config,
 | 
				
			||||||
 | 
					      releaser,
 | 
				
			||||||
 | 
					      owner,
 | 
				
			||||||
 | 
					      repo,
 | 
				
			||||||
 | 
					      discussion_category_name,
 | 
				
			||||||
 | 
					      generate_release_notes,
 | 
				
			||||||
 | 
					      maxRetries,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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,
 | 
				
			||||||
 | 
					  releaser: Releaser,
 | 
				
			||||||
 | 
					  owner: string,
 | 
				
			||||||
 | 
					  repo: string,
 | 
				
			||||||
 | 
					  discussion_category_name: string | undefined,
 | 
				
			||||||
 | 
					  generate_release_notes: boolean | undefined,
 | 
				
			||||||
 | 
					  maxRetries: number,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
  const tag_name = tag;
 | 
					  const tag_name = tag;
 | 
				
			||||||
  const name = config.input_name || tag;
 | 
					  const name = config.input_name || tag;
 | 
				
			||||||
  const body = releaseBody(config);
 | 
					  const body = releaseBody(config);
 | 
				
			||||||
  const draft = config.input_draft;
 | 
					  const draft = config.input_draft;
 | 
				
			||||||
  const prerelease = config.input_prerelease;
 | 
					  const prerelease = config.input_prerelease;
 | 
				
			||||||
  const target_commitish = config.input_target_commitish;
 | 
					  const target_commitish = config.input_target_commitish;
 | 
				
			||||||
      let commitMessage: string = "";
 | 
					  const make_latest = config.input_make_latest;
 | 
				
			||||||
 | 
					  let commitMessage: string = '';
 | 
				
			||||||
  if (target_commitish) {
 | 
					  if (target_commitish) {
 | 
				
			||||||
    commitMessage = ` using commit "${target_commitish}"`;
 | 
					    commitMessage = ` using commit "${target_commitish}"`;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
      console.log(
 | 
					  console.log(`👩🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`);
 | 
				
			||||||
        `👩🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    let release = await releaser.createRelease({
 | 
					    let release = await releaser.createRelease({
 | 
				
			||||||
      owner,
 | 
					      owner,
 | 
				
			||||||
@@ -297,24 +368,41 @@ export const release = async (
 | 
				
			|||||||
      target_commitish,
 | 
					      target_commitish,
 | 
				
			||||||
      discussion_category_name,
 | 
					      discussion_category_name,
 | 
				
			||||||
      generate_release_notes,
 | 
					      generate_release_notes,
 | 
				
			||||||
 | 
					      make_latest,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return release.data;
 | 
					    return release.data;
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
        // presume a race with competing metrix runs
 | 
					    // presume a race with competing matrix runs
 | 
				
			||||||
 | 
					    console.log(`⚠️ GitHub release failed with status: ${error.status}`);
 | 
				
			||||||
 | 
					    console.log(`${JSON.stringify(error.response.data)}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (error.status) {
 | 
				
			||||||
 | 
					      case 403:
 | 
				
			||||||
        console.log(
 | 
					        console.log(
 | 
				
			||||||
          `⚠️ GitHub release failed with status: ${
 | 
					          'Skip retry — your GitHub token/PAT does not have the required permission to create a release',
 | 
				
			||||||
            error.status
 | 
					 | 
				
			||||||
          }\n${JSON.stringify(error.response.data.errors)}\nretrying... (${
 | 
					 | 
				
			||||||
            maxRetries - 1
 | 
					 | 
				
			||||||
          } retries remaining)`
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        return release(config, releaser, maxRetries - 1);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      console.log(
 | 
					 | 
				
			||||||
        `⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        throw error;
 | 
					        throw error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case 404:
 | 
				
			||||||
 | 
					        console.log('Skip retry - discussion category mismatch');
 | 
				
			||||||
 | 
					        throw error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case 422:
 | 
				
			||||||
 | 
					        // Check if this is a race condition with "already_exists" error
 | 
				
			||||||
 | 
					        const errorData = error.response?.data;
 | 
				
			||||||
 | 
					        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)`);
 | 
				
			||||||
 | 
					    return release(config, releaser, maxRetries - 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										92
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/main.ts
									
									
									
									
									
								
							@@ -1,32 +1,25 @@
 | 
				
			|||||||
import {
 | 
					import { setFailed, setOutput } from '@actions/core';
 | 
				
			||||||
  paths,
 | 
					import { getOctokit } from '@actions/github';
 | 
				
			||||||
  parseConfig,
 | 
					import { GitHubReleaser, release, upload } from './github';
 | 
				
			||||||
  isTag,
 | 
					import { isTag, parseConfig, paths, unmatchedPatterns, uploadUrl } from './util';
 | 
				
			||||||
  unmatchedPatterns,
 | 
					 | 
				
			||||||
  uploadUrl,
 | 
					 | 
				
			||||||
} from "./util";
 | 
					 | 
				
			||||||
import { release, upload, GitHubReleaser } from "./github";
 | 
					 | 
				
			||||||
import { getOctokit } from "@actions/github";
 | 
					 | 
				
			||||||
import { setFailed, setOutput } from "@actions/core";
 | 
					 | 
				
			||||||
import { GitHub, getOctokitOptions } from "@actions/github/lib/utils";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { env } from "process";
 | 
					import { env } from 'process';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function run() {
 | 
					async function run() {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const config = parseConfig(env);
 | 
					    const config = parseConfig(env);
 | 
				
			||||||
    if (
 | 
					    if (!config.input_tag_name && !isTag(config.github_ref) && !config.input_draft) {
 | 
				
			||||||
      !config.input_tag_name &&
 | 
					 | 
				
			||||||
      !isTag(config.github_ref) &&
 | 
					 | 
				
			||||||
      !config.input_draft
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      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);
 | 
					      const patterns = unmatchedPatterns(config.input_files, config.input_working_directory);
 | 
				
			||||||
      patterns.forEach((pattern) =>
 | 
					      patterns.forEach((pattern) => {
 | 
				
			||||||
        console.warn(`🤔 Pattern '${pattern}' does not match any files.`)
 | 
					        if (config.input_fail_on_unmatched_files) {
 | 
				
			||||||
      );
 | 
					          throw new Error(`⚠️  Pattern '${pattern}' does not match any files.`);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          console.warn(`🤔 Pattern '${pattern}' does not match any files.`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
      if (patterns.length > 0 && config.input_fail_on_unmatched_files) {
 | 
					      if (patterns.length > 0 && config.input_fail_on_unmatched_files) {
 | 
				
			||||||
        throw new Error(`⚠️ There were unmatched files`);
 | 
					        throw new Error(`⚠️ There were unmatched files`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -41,9 +34,7 @@ async function run() {
 | 
				
			|||||||
      //new oktokit(
 | 
					      //new oktokit(
 | 
				
			||||||
      throttle: {
 | 
					      throttle: {
 | 
				
			||||||
        onRateLimit: (retryAfter, options) => {
 | 
					        onRateLimit: (retryAfter, options) => {
 | 
				
			||||||
          console.warn(
 | 
					          console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
 | 
				
			||||||
            `Request quota exhausted for request ${options.method} ${options.url}`
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          if (options.request.retryCount === 0) {
 | 
					          if (options.request.retryCount === 0) {
 | 
				
			||||||
            // only retries once
 | 
					            // only retries once
 | 
				
			||||||
            console.log(`Retrying after ${retryAfter} seconds!`);
 | 
					            console.log(`Retrying after ${retryAfter} seconds!`);
 | 
				
			||||||
@@ -52,41 +43,48 @@ async function run() {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        onAbuseLimit: (retryAfter, options) => {
 | 
					        onAbuseLimit: (retryAfter, options) => {
 | 
				
			||||||
          // does not retry, only logs a warning
 | 
					          // does not retry, only logs a warning
 | 
				
			||||||
          console.warn(
 | 
					          console.warn(`Abuse detected for request ${options.method} ${options.url}`);
 | 
				
			||||||
            `Abuse detected for request ${options.method} ${options.url}`
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    //);
 | 
					    //);
 | 
				
			||||||
    const rel = await release(config, new GitHubReleaser(gh));
 | 
					    const rel = await release(config, new GitHubReleaser(gh));
 | 
				
			||||||
    if (config.input_files) {
 | 
					    if (config.input_files && config.input_files.length > 0) {
 | 
				
			||||||
      const files = paths(config.input_files);
 | 
					      const files = paths(config.input_files, config.input_working_directory);
 | 
				
			||||||
      if (files.length == 0) {
 | 
					      if (files.length == 0) {
 | 
				
			||||||
        console.warn(`🤔 ${config.input_files} not include valid file.`);
 | 
					        if (config.input_fail_on_unmatched_files) {
 | 
				
			||||||
 | 
					          throw new Error(`⚠️ ${config.input_files} does not include a valid file.`);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          console.warn(`🤔 ${config.input_files} does not include a valid file.`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const currentAssets = rel.assets;
 | 
					      const currentAssets = rel.assets;
 | 
				
			||||||
      const assets = await Promise.all(
 | 
					
 | 
				
			||||||
        files.map(async (path) => {
 | 
					      const uploadFile = async (path) => {
 | 
				
			||||||
          const json = await upload(
 | 
					        const json = await upload(config, gh, uploadUrl(rel.upload_url), path, currentAssets);
 | 
				
			||||||
            config,
 | 
					        if (json) {
 | 
				
			||||||
            gh,
 | 
					 | 
				
			||||||
            uploadUrl(rel.upload_url),
 | 
					 | 
				
			||||||
            path,
 | 
					 | 
				
			||||||
            currentAssets
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          delete json.uploader;
 | 
					          delete json.uploader;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return json;
 | 
					        return json;
 | 
				
			||||||
        })
 | 
					      };
 | 
				
			||||||
      ).catch((error) => {
 | 
					
 | 
				
			||||||
        throw error;
 | 
					      let results: (any | null)[];
 | 
				
			||||||
      });
 | 
					      if (!config.input_preserve_order) {
 | 
				
			||||||
      setOutput("assets", assets);
 | 
					        results = await Promise.all(files.map(uploadFile));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        results = [];
 | 
				
			||||||
 | 
					        for (const path of files) {
 | 
				
			||||||
 | 
					          results.push(await uploadFile(path));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const assets = results.filter(Boolean);
 | 
				
			||||||
 | 
					      setOutput('assets', assets);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    console.log(`🎉 Release ready at ${rel.html_url}`);
 | 
					    console.log(`🎉 Release ready at ${rel.html_url}`);
 | 
				
			||||||
    setOutput("url", rel.html_url);
 | 
					    setOutput('url', rel.html_url);
 | 
				
			||||||
    setOutput("id", rel.id.toString());
 | 
					    setOutput('id', rel.id.toString());
 | 
				
			||||||
    setOutput("upload_url", rel.upload_url);
 | 
					    setOutput('upload_url', rel.upload_url);
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    setFailed(error.message);
 | 
					    setFailed(error.message);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										91
									
								
								src/util.ts
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								src/util.ts
									
									
									
									
									
								
							@@ -1,5 +1,6 @@
 | 
				
			|||||||
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;
 | 
				
			||||||
@@ -12,17 +13,21 @@ 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_draft?: boolean;
 | 
					  input_draft?: boolean;
 | 
				
			||||||
 | 
					  input_preserve_order?: boolean;
 | 
				
			||||||
  input_prerelease?: boolean;
 | 
					  input_prerelease?: boolean;
 | 
				
			||||||
  input_fail_on_unmatched_files?: boolean;
 | 
					  input_fail_on_unmatched_files?: boolean;
 | 
				
			||||||
  input_target_commitish?: string;
 | 
					  input_target_commitish?: string;
 | 
				
			||||||
  input_discussion_category_name?: string;
 | 
					  input_discussion_category_name?: string;
 | 
				
			||||||
  input_generate_release_notes?: boolean;
 | 
					  input_generate_release_notes?: boolean;
 | 
				
			||||||
  input_append_body?: boolean;
 | 
					  input_append_body?: boolean;
 | 
				
			||||||
 | 
					  input_make_latest: 'true' | 'false' | 'legacy' | undefined;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const uploadUrl = (url: string): string => {
 | 
					export const uploadUrl = (url: string): string => {
 | 
				
			||||||
  const templateMarkerPos = url.indexOf("{");
 | 
					  const templateMarkerPos = url.indexOf('{');
 | 
				
			||||||
  if (templateMarkerPos > -1) {
 | 
					  if (templateMarkerPos > -1) {
 | 
				
			||||||
    return url.substring(0, templateMarkerPos);
 | 
					    return url.substring(0, templateMarkerPos);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -31,8 +36,7 @@ export const uploadUrl = (url: string): string => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const releaseBody = (config: Config): string | undefined => {
 | 
					export const releaseBody = (config: Config): string | undefined => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    (config.input_body_path &&
 | 
					    (config.input_body_path && readFileSync(config.input_body_path).toString('utf8')) ||
 | 
				
			||||||
      readFileSync(config.input_body_path).toString("utf8")) ||
 | 
					 | 
				
			||||||
    config.input_body
 | 
					    config.input_body
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -43,54 +47,81 @@ export const parseInputFiles = (files: string): string[] => {
 | 
				
			|||||||
  return files.split(/\r?\n/).reduce<string[]>(
 | 
					  return files.split(/\r?\n/).reduce<string[]>(
 | 
				
			||||||
    (acc, line) =>
 | 
					    (acc, line) =>
 | 
				
			||||||
      acc
 | 
					      acc
 | 
				
			||||||
        .concat(line.split(","))
 | 
					        .concat(line.split(','))
 | 
				
			||||||
        .filter((pat) => pat)
 | 
					        .filter((pat) => pat)
 | 
				
			||||||
        .map((pat) => pat.trim()),
 | 
					        .map((pat) => pat.trim()),
 | 
				
			||||||
    []
 | 
					    [],
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const parseConfig = (env: Env): Config => {
 | 
					export const parseConfig = (env: Env): Config => {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    github_token: env.GITHUB_TOKEN || env.INPUT_TOKEN || "",
 | 
					    github_token: env.GITHUB_TOKEN || env.INPUT_TOKEN || '',
 | 
				
			||||||
    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: 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 || ''),
 | 
				
			||||||
    input_draft: env.INPUT_DRAFT ? env.INPUT_DRAFT === "true" : undefined,
 | 
					    input_working_directory: env.INPUT_WORKING_DIRECTORY || undefined,
 | 
				
			||||||
    input_prerelease: env.INPUT_PRERELEASE
 | 
					    input_overwrite_files: env.INPUT_OVERWRITE_FILES
 | 
				
			||||||
      ? env.INPUT_PRERELEASE == "true"
 | 
					      ? env.INPUT_OVERWRITE_FILES == 'true'
 | 
				
			||||||
      : undefined,
 | 
					      : undefined,
 | 
				
			||||||
    input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == "true",
 | 
					    input_draft: env.INPUT_DRAFT ? env.INPUT_DRAFT === 'true' : undefined,
 | 
				
			||||||
 | 
					    input_preserve_order: env.INPUT_PRESERVE_ORDER ? env.INPUT_PRESERVE_ORDER == 'true' : undefined,
 | 
				
			||||||
 | 
					    input_prerelease: env.INPUT_PRERELEASE ? env.INPUT_PRERELEASE == 'true' : undefined,
 | 
				
			||||||
 | 
					    input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == 'true',
 | 
				
			||||||
    input_target_commitish: env.INPUT_TARGET_COMMITISH || undefined,
 | 
					    input_target_commitish: env.INPUT_TARGET_COMMITISH || undefined,
 | 
				
			||||||
    input_discussion_category_name:
 | 
					    input_discussion_category_name: env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
 | 
				
			||||||
      env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
 | 
					    input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == 'true',
 | 
				
			||||||
    input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == "true",
 | 
					    input_append_body: env.INPUT_APPEND_BODY == 'true',
 | 
				
			||||||
    input_append_body: env.INPUT_APPEND_BODY == "true",
 | 
					    input_make_latest: parseMakeLatest(env.INPUT_MAKE_LATEST),
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const paths = (patterns: string[]): string[] => {
 | 
					const parseMakeLatest = (value: string | undefined): 'true' | 'false' | 'legacy' | undefined => {
 | 
				
			||||||
 | 
					  if (value === 'true' || value === 'false' || value === 'legacy') {
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return undefined;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const paths = (patterns: string[], cwd?: string): string[] => {
 | 
				
			||||||
  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
					  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
				
			||||||
    return acc.concat(
 | 
					    const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
 | 
				
			||||||
      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[]): string[] => {
 | 
					export const unmatchedPatterns = (patterns: string[], cwd?: string): string[] => {
 | 
				
			||||||
  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
					  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
				
			||||||
    return acc.concat(
 | 
					    const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
 | 
				
			||||||
      glob.sync(pattern).filter((path) => statSync(path).isFile()).length == 0
 | 
					    const files = matches.filter((p) => {
 | 
				
			||||||
        ? [pattern]
 | 
					      try {
 | 
				
			||||||
        : []
 | 
					        const full = cwd ? pathLib.join(cwd, p) : p;
 | 
				
			||||||
    );
 | 
					        return statSync(full).isFile();
 | 
				
			||||||
 | 
					      } catch {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return acc.concat(files.length == 0 ? [pattern] : []);
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const isTag = (ref: string): boolean => {
 | 
					export const isTag = (ref: string): boolean => {
 | 
				
			||||||
  return ref.startsWith("refs/tags/");
 | 
					  return ref.startsWith('refs/tags/');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const alignAssetName = (assetName: string): string => {
 | 
				
			||||||
 | 
					  return assetName.replace(/ /g, '.');
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,8 @@
 | 
				
			|||||||
    "useUnknownInCatchVariables": false,
 | 
					    "useUnknownInCatchVariables": false,
 | 
				
			||||||
    /* Basic Options */
 | 
					    /* Basic Options */
 | 
				
			||||||
    // "incremental": true,                   /* Enable incremental compilation */
 | 
					    // "incremental": true,                   /* Enable incremental compilation */
 | 
				
			||||||
    "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
 | 
					    "target": "es2022",
 | 
				
			||||||
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
 | 
					    "module": "NodeNext",
 | 
				
			||||||
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
 | 
					    // "allowJs": true,                       /* Allow javascript files to be compiled. */
 | 
				
			||||||
    // "checkJs": true,                       /* Report errors in .js files. */
 | 
					    // "checkJs": true,                       /* Report errors in .js files. */
 | 
				
			||||||
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
 | 
					    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
 | 
				
			||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
    /* Strict Type-Checking Options */
 | 
					    /* Strict Type-Checking Options */
 | 
				
			||||||
    "strict": true,                           /* Enable all strict type-checking options. */
 | 
					    "strict": true,                           /* Enable all strict type-checking options. */
 | 
				
			||||||
    "noImplicitAny": false,                 /* Raise error on expressions and declarations with an implied 'any' type. */
 | 
					    "noImplicitAny": false,                 /* Raise error on expressions and declarations with an implied 'any' type. */
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
    // "strictNullChecks": true,              /* Enable strict null checks. */
 | 
					    // "strictNullChecks": true,              /* Enable strict null checks. */
 | 
				
			||||||
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
 | 
					    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
 | 
				
			||||||
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
 | 
					    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
 | 
				
			||||||
@@ -44,7 +45,7 @@
 | 
				
			|||||||
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
 | 
					    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
 | 
				
			||||||
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
 | 
					    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
 | 
				
			||||||
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
 | 
					    // "typeRoots": [],                       /* List of folders to include type definitions from. */
 | 
				
			||||||
    // "types": [],                           /* Type declaration files to be included in compilation. */
 | 
					    "types": ["vitest/globals"],
 | 
				
			||||||
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
 | 
					    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
 | 
				
			||||||
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
 | 
					    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
 | 
				
			||||||
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
 | 
					    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
 | 
				
			||||||
@@ -60,5 +61,5 @@
 | 
				
			|||||||
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
 | 
					    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
 | 
				
			||||||
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
 | 
					    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "exclude": ["node_modules", "**/*.test.ts"]
 | 
					  "exclude": ["node_modules", "**/*.test.ts", "vitest.config.ts"]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								vitest.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vitest.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import { defineConfig } from 'vitest/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  test: {
 | 
				
			||||||
 | 
					    environment: 'node',
 | 
				
			||||||
 | 
					    coverage: {
 | 
				
			||||||
 | 
					      reporter: ['text', 'lcov'],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    include: ['__tests__/**/*.ts'],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Reference in New Issue
	
	Block a user