mirror of
				https://github.com/softprops/action-gh-release.git
				synced 2025-11-03 13:19:25 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			v2.0.4
			...
			ncc-packag
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e6a400341a | ||
| 
						 | 
					5733db0089 | ||
| 
						 | 
					7060560593 | ||
| 
						 | 
					7b2fd2c223 | ||
| 
						 | 
					e7bba17971 | ||
| 
						 | 
					03caddd29a | 
							
								
								
									
										14
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,14 +0,0 @@
 | 
			
		||||
version: 2
 | 
			
		||||
updates:
 | 
			
		||||
- package-ecosystem: npm
 | 
			
		||||
  directory: "/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: weekly
 | 
			
		||||
  ignore:
 | 
			
		||||
  - dependency-name: node-fetch
 | 
			
		||||
    versions:
 | 
			
		||||
    - ">=3.0.0"
 | 
			
		||||
- package-ecosystem: github-actions
 | 
			
		||||
  directory: "/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: weekly
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/main.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ jobs:
 | 
			
		||||
    steps:
 | 
			
		||||
      # https://github.com/actions/checkout
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
      - name: Install
 | 
			
		||||
        run: npm ci
 | 
			
		||||
      - name: Build
 | 
			
		||||
@@ -23,4 +23,4 @@ jobs:
 | 
			
		||||
      #     git diff --exit-code --stat -- . ':!node_modules' \
 | 
			
		||||
      #     || (echo "##[error] found changed files after build. please 'npm run build && npm run fmt'" \
 | 
			
		||||
      #             "and check in all changes" \
 | 
			
		||||
      #         && exit 1)
 | 
			
		||||
      #         && exit 1)
 | 
			
		||||
							
								
								
									
										120
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,127 +1,43 @@
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
- Upgrade to action.yml declaration to node16 to address deprecations
 | 
			
		||||
- Upgrade dependencies
 | 
			
		||||
- Add `asset` output as a JSON array containing information about the uploaded assets
 | 
			
		||||
 | 
			
		||||
## 0.1.14
 | 
			
		||||
 | 
			
		||||
- provides an new workflow input option `generate_release_notes` which when set to true will automatically generate release notes for you based on GitHub activity [#179](https://github.com/softprops/action-gh-release/pull/179). Please see the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information
 | 
			
		||||
 | 
			
		||||
## 0.1.13
 | 
			
		||||
 | 
			
		||||
- fix issue with multiple runs concatenating release bodies [#145](https://github.com/softprops/action-gh-release/pull/145)
 | 
			
		||||
 | 
			
		||||
## 0.1.12
 | 
			
		||||
 | 
			
		||||
- fix bug leading to empty strings subsituted for inputs users don't provide breaking api calls [#144](https://github.com/softprops/action-gh-release/pull/144)
 | 
			
		||||
 | 
			
		||||
## 0.1.11
 | 
			
		||||
 | 
			
		||||
- better error message on release create failed [#143](https://github.com/softprops/action-gh-release/pull/143)
 | 
			
		||||
 | 
			
		||||
## 0.1.10
 | 
			
		||||
 | 
			
		||||
- fixed error message formatting for file uploads
 | 
			
		||||
 | 
			
		||||
## 0.1.9
 | 
			
		||||
 | 
			
		||||
- add support for linking release to GitHub discussion [#136](https://github.com/softprops/action-gh-release/pull/136)
 | 
			
		||||
 | 
			
		||||
## 0.1.8
 | 
			
		||||
 | 
			
		||||
- address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134)
 | 
			
		||||
- fix backwards compatibility with `GITHUB_TOKEN` resolution. `GITHUB_TOKEN` is no resolved first from an env varibale and then from and input [#133](https://github.com/softprops/action-gh-release/pull/133)
 | 
			
		||||
- trim white space in provided `tag_name` [#130](https://github.com/softprops/action-gh-release/pull/130)
 | 
			
		||||
 | 
			
		||||
## 0.1.7
 | 
			
		||||
 | 
			
		||||
- allow creating draft releases without a tag [#95](https://github.com/softprops/action-gh-release/pull/95)
 | 
			
		||||
- Set default token for simpler setup [#83](https://github.com/softprops/action-gh-release/pull/83)
 | 
			
		||||
- fix regression with action yml [#126](https://github.com/softprops/action-gh-release/pull/126)
 | 
			
		||||
 | 
			
		||||
## 0.1.6
 | 
			
		||||
 | 
			
		||||
This is a release catch up have a hiatus. Future releases will happen more frequently
 | 
			
		||||
 | 
			
		||||
- Add 'fail_on_unmatched_files' input, useful for catching cases were your `files` input does not actually match what you expect [#55](https://github.com/softprops/action-gh-release/pull/55)
 | 
			
		||||
- Add `repository` input, useful for creating a release in an external repository [#61](https://github.com/softprops/action-gh-release/pull/61)
 | 
			
		||||
- Add release `id` to outputs, useful for refering to release in workflow steps following the step that uses this action [#60](https://github.com/softprops/action-gh-release/pull/60)
 | 
			
		||||
- Add `upload_url` as action output, useful for managing uploads separately [#75](https://github.com/softprops/action-gh-release/pull/75)
 | 
			
		||||
- Support custom `target_commitish` value, useful to customize the default [#76](https://github.com/softprops/action-gh-release/pull/76)
 | 
			
		||||
- fix `body_path` input first then fall back on `body` input. this was the originally documented precedence but was implemened the the opposite order! [#85](https://github.com/softprops/action-gh-release/pull/85)
 | 
			
		||||
- Retain original release info if the keys are not set, useful for filling in blanks for a release you've already started separately [#109](https://github.com/softprops/action-gh-release/pull/109)
 | 
			
		||||
- Limit number of times github api request to create a release is retried, useful for avoiding eating up your rate limit and action minutes do to either an invalid token or other circumstance causing the api call to fail [#111](https://github.com/softprops/action-gh-release/pull/111)
 | 
			
		||||
 | 
			
		||||
## 0.1.5
 | 
			
		||||
 | 
			
		||||
- Added support for specifying tag name [#39](https://github.com/softprops/action-gh-release/pull/39)
 | 
			
		||||
 | 
			
		||||
## 0.1.4
 | 
			
		||||
 | 
			
		||||
- Added support for updating releases body [#36](https://github.com/softprops/action-gh-release/pull/36)
 | 
			
		||||
- Steps can now access the url of releases with the `url` output of this Action [#28](https://github.com/softprops/action-gh-release/pull/28)
 | 
			
		||||
- Added basic GitHub API retry support to manage API turbulance [#26](https://github.com/softprops/action-gh-release/pull/26)
 | 
			
		||||
* Steps can now access the url of releases with the `url` output of this Action [#28](https://github.com/softprops/action-gh-release/pull/28)
 | 
			
		||||
* Added basic GitHub API retry support to manage API turbulance [#26](https://github.com/softprops/action-gh-release/pull/26)
 | 
			
		||||
 | 
			
		||||
## 0.1.3
 | 
			
		||||
 | 
			
		||||
- Fixed where `with: body_path` was not being used in generated GitHub releases
 | 
			
		||||
* Fixed where `with: body_path` was not being used in generated GitHub releases
 | 
			
		||||
 | 
			
		||||
## 0.1.2
 | 
			
		||||
 | 
			
		||||
- Add support for merging draft releases [#16](https://github.com/softprops/action-gh-release/pull/16)
 | 
			
		||||
* Add support for merging draft releases [#16](https://github.com/softprops/action-gh-release/pull/16)
 | 
			
		||||
 | 
			
		||||
GitHub's api doesn't explicitly have a way of fetching a draft release by tag name which caused draft releases to appear as separate releases when used in a build matrix.
 | 
			
		||||
This is now fixed.
 | 
			
		||||
 | 
			
		||||
- Add support for newline-delimited asset list [#18](https://github.com/softprops/action-gh-release/pull/18)
 | 
			
		||||
* Add support for newline-delimited asset list [#18](https://github.com/softprops/action-gh-release/pull/18)
 | 
			
		||||
 | 
			
		||||
GitHub actions inputs don't inherently support lists of things and one might like to append a list of files to include in a release. Previously this was possible using a comma-delimited list of asset path patterns to upload. You can now provide these as a newline delimieted list for better readability
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
- name: Release
 | 
			
		||||
  uses: softprops/action-gh-release@v1
 | 
			
		||||
  if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
  with:
 | 
			
		||||
    files: |
 | 
			
		||||
      filea.txt
 | 
			
		||||
      fileb.txt
 | 
			
		||||
      filec.txt
 | 
			
		||||
  env:
 | 
			
		||||
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
  - name: Release
 | 
			
		||||
    uses: softprops/action-gh-release@v1
 | 
			
		||||
    if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
    with:
 | 
			
		||||
      files: |
 | 
			
		||||
        filea.txt
 | 
			
		||||
        fileb.txt
 | 
			
		||||
        filec.txt
 | 
			
		||||
    env:
 | 
			
		||||
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Add support for prerelease annotated GitHub releases with the new input field `with.prerelease: true` [#19](https://github.com/softprops/action-gh-release/pull/19)
 | 
			
		||||
* Add support for prerelease annotated GitHub releases with the new input field `with.prerelease: true` [#19](https://github.com/softprops/action-gh-release/pull/19)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 0.1.1
 | 
			
		||||
 | 
			
		||||
- Add support for publishing releases on all supported virtual hosts
 | 
			
		||||
* Add support for publishing releases on all supported virtual hosts
 | 
			
		||||
 | 
			
		||||
You'll need to remove `docker://` prefix and use the `@v1` action tag
 | 
			
		||||
 | 
			
		||||
@@ -129,4 +45,4 @@ You'll need to remove `docker://` prefix and use the `@v1` action tag
 | 
			
		||||
 | 
			
		||||
## 0.1.0
 | 
			
		||||
 | 
			
		||||
- Initial release
 | 
			
		||||
* Initial release
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
## bootstrapping
 | 
			
		||||
 | 
			
		||||
This a [JavaScript](https://help.github.com/en/articles/about-actions#types-of-actions) action but uses [TypeScript](https://www.typescriptlang.org/docs/home.html) to generate that JavaScript.
 | 
			
		||||
This a [JavaScript](https://help.github.com/en/articles/about-actions#types-of-actions)  action but uses [TypeScript](https://www.typescriptlang.org/docs/home.html) to generate that JavaScript.
 | 
			
		||||
 | 
			
		||||
You can bootstrap your environment with a modern version of npm and by running `npm i` at the root of this repo.
 | 
			
		||||
You can bootstrap your envrinment with a modern version of npm and by running `npm i` at the root of this repo.
 | 
			
		||||
 | 
			
		||||
## testing
 | 
			
		||||
 | 
			
		||||
Tests can be found under under `__tests__` directory and are runnable with the `npm t` command.
 | 
			
		||||
Tests can be found under under `__tests__` directory and are runnable with the `npm t` command
 | 
			
		||||
 | 
			
		||||
## source code
 | 
			
		||||
 | 
			
		||||
@@ -14,4 +14,5 @@ Source code can be found under the `src` directory. Running `npm run build` will
 | 
			
		||||
 | 
			
		||||
## formatting
 | 
			
		||||
 | 
			
		||||
A minimal attempt at keeping a consistent code style is can be applied by running `npm run fmt`.
 | 
			
		||||
A minimal attempt at keeping a consistent code style is can be applied by running `npm run fmt`
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
Copyright (c) 2019-current Doug Tangren
 | 
			
		||||
Copyright (c) 2019 Doug Tangren
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
a copy of this software and associated documentation files (the
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										127
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								README.md
									
									
									
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
 | 
			
		||||
<div align="center">
 | 
			
		||||
  📦 :octocat:
 | 
			
		||||
</div>
 | 
			
		||||
@@ -6,7 +7,7 @@
 | 
			
		||||
</h1>
 | 
			
		||||
 | 
			
		||||
<p align="center">
 | 
			
		||||
   A GitHub Action for creating GitHub Releases on Linux, Windows, and macOS virtual environments
 | 
			
		||||
   A GitHub Action for creating GitHub Releases on Linux, Windows, and OSX virtual environments
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
<div align="center">
 | 
			
		||||
@@ -19,6 +20,7 @@
 | 
			
		||||
	</a>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<br />
 | 
			
		||||
 | 
			
		||||
## 🤸 Usage
 | 
			
		||||
@@ -27,7 +29,7 @@
 | 
			
		||||
 | 
			
		||||
Typically usage of this action involves adding a step to a build that
 | 
			
		||||
is gated pushes to git tags. You may find `step.if` field helpful in accomplishing this
 | 
			
		||||
as it maximizes the reuse value of your workflow for non-tag pushes.
 | 
			
		||||
as it maximizes the resuse value of your workflow for non-tag pushes.
 | 
			
		||||
 | 
			
		||||
Below is a simple example of `step.if` tag gating
 | 
			
		||||
 | 
			
		||||
@@ -41,10 +43,12 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v1
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You can also use push config tag filter
 | 
			
		||||
@@ -55,21 +59,23 @@ name: Main
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    tags:
 | 
			
		||||
      - "v*.*.*"
 | 
			
		||||
      - 'v*.*.*'
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v1
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### ⬆️ Uploading release assets
 | 
			
		||||
 | 
			
		||||
You can configure a number of options for your
 | 
			
		||||
You can can configure a number of options for your
 | 
			
		||||
GitHub release and all are optional.
 | 
			
		||||
 | 
			
		||||
A common case for GitHub releases is to upload your binary after its been validated and packaged.
 | 
			
		||||
@@ -88,16 +94,18 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v1
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: echo ${{ github.sha }} > Release.txt
 | 
			
		||||
      - name: Test
 | 
			
		||||
        run: cat Release.txt
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
        with:
 | 
			
		||||
          files: Release.txt
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Below is an example of uploading more than one asset with a GitHub release
 | 
			
		||||
@@ -112,23 +120,23 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v1
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: echo ${{ github.sha }} > Release.txt
 | 
			
		||||
      - name: Test
 | 
			
		||||
        run: cat Release.txt
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
        with:
 | 
			
		||||
          files: |
 | 
			
		||||
            Release.txt
 | 
			
		||||
            LICENSE
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> **⚠️ 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 '\\','/'`
 | 
			
		||||
> **⚠️ 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)
 | 
			
		||||
 | 
			
		||||
### 📝 External release notes
 | 
			
		||||
 | 
			
		||||
@@ -146,19 +154,16 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v1
 | 
			
		||||
      - name: Generate Changelog
 | 
			
		||||
        run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
 | 
			
		||||
        run: echo "# Good things have arrived" > ${{ github.workflow }}-CHANGELOG.txt
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
        with:
 | 
			
		||||
          body_path: ${{ github.workspace }}-CHANGELOG.txt
 | 
			
		||||
          # note you'll typically need to create a personal access token
 | 
			
		||||
          # with permissions to create releases in the other repo
 | 
			
		||||
          token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
 | 
			
		||||
          body_path: ${{ github.workflow }}-CHANGELOG.txt
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_REPOSITORY: my_gh_org/my_gh_repo
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 💅 Customizing
 | 
			
		||||
@@ -167,75 +172,37 @@ jobs:
 | 
			
		||||
 | 
			
		||||
The following are optional as `step.with` keys
 | 
			
		||||
 | 
			
		||||
| Name                       | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                     |
 | 
			
		||||
| -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| `body`                     | String  | 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                                                                                                                                                                                                                                                                                                                                                                                             |
 | 
			
		||||
| `prerelease`               | Boolean | Indicator of whether or not is a prerelease                                                                                                                                                                                                                                                                                                                                                                                                     |
 | 
			
		||||
| `files`                    | String  | Newline-delimited globs of paths to assets to upload for release                                                                                                                                                                                                                                                                                                                                                                                |
 | 
			
		||||
| `name`                     | String  | Name of the release. defaults to tag name                                                                                                                                                                                                                                                                                                                                                                                                       |
 | 
			
		||||
| `tag_name`                 | String  | Name of a tag. defaults to `github.ref`                                                                                                                                                                                                                                                                                                                                                                                                         |
 | 
			
		||||
| `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                                                                                                                                                                                                                                                                                                                                              |
 | 
			
		||||
| `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.                                                                                                                                                                                                                                                                                                      |
 | 
			
		||||
| `token`                    | String  | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}`                                                                                                                                                                                                                                                                                                                                                                          |
 | 
			
		||||
| `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 |
 | 
			
		||||
| `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                                                                                                                                                                                                                            |
 | 
			
		||||
| Name        | Type    | Description                                                     |
 | 
			
		||||
|-------------|---------|-----------------------------------------------------------------|
 | 
			
		||||
| `body`      | String  | 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             |
 | 
			
		||||
| `prerelease`| Boolean | Indicator of whether or not is a prerelease                     |
 | 
			
		||||
| `files`     | String  | Newline-delimited globs of paths to assets to upload for release|
 | 
			
		||||
| `name`      | String  | Name of the release. defaults to tag name                       |
 | 
			
		||||
 | 
			
		||||
💡 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.
 | 
			
		||||
 | 
			
		||||
💡 When the release info keys (such as `name`, `body`, `draft`, `prerelease`, etc.)
 | 
			
		||||
are not explicitly set and there is already an existing release for the tag, the
 | 
			
		||||
release will retain its original info.
 | 
			
		||||
💡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.
 | 
			
		||||
 | 
			
		||||
#### outputs
 | 
			
		||||
 | 
			
		||||
The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
 | 
			
		||||
 | 
			
		||||
| Name         | Type   | Description                                                                                                                                                                               |
 | 
			
		||||
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| `url`        | String | Github.com URL for the release                                                                                                                                                            |
 | 
			
		||||
| `id`         | String | Release ID                                                                                                                                                                                |
 | 
			
		||||
| `upload_url` | String | URL for uploading assets to the release                                                                                                                                                   |
 | 
			
		||||
| `assets`     | String | JSON array containing information about each uploaded asset, in the format given [here](https://docs.github.com/en/rest/releases/assets#get-a-release-asset) (minus the `uploader` field) |
 | 
			
		||||
| Name        | Type    | Description                                                     |
 | 
			
		||||
|-------------|---------|-----------------------------------------------------------------|
 | 
			
		||||
| `url`       | String  | Github.com URL for the release                                  |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
As an example, you can use `${{ fromJSON(steps.<step-id>.outputs.assets)[0].browser_download_url }}` to get the download URL of the first asset.
 | 
			
		||||
 | 
			
		||||
#### environment variables
 | 
			
		||||
 | 
			
		||||
The following `step.env` keys are allowed as a fallback but deprecated in favor of using inputs.
 | 
			
		||||
The following are *required* as `step.env` keys
 | 
			
		||||
 | 
			
		||||
| Name                | Description                                                                                |
 | 
			
		||||
| ------------------- | ------------------------------------------------------------------------------------------ |
 | 
			
		||||
| `GITHUB_TOKEN`      | GITHUB_TOKEN as provided by `secrets`                                                      |
 | 
			
		||||
| `GITHUB_REPOSITORY` | Name of a target repository in `<owner>/<repo>` format. defaults to the current repository |
 | 
			
		||||
| Name           | Description                          |
 | 
			
		||||
|----------------|--------------------------------------|
 | 
			
		||||
| `GITHUB_TOKEN` | GITHUB_TOKEN as provided by `secrets`|
 | 
			
		||||
 | 
			
		||||
> **⚠️ Note:** This action was previously implemented as a Docker container, limiting its use to GitHub Actions Linux virtual environments only. With recent releases, we now support cross platform usage. You'll need to remove the `docker://` prefix in these versions
 | 
			
		||||
 | 
			
		||||
### Permissions
 | 
			
		||||
 | 
			
		||||
This Action requires the following permissions on the GitHub integration token:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When used with `discussion_category_name`, additional permission is needed:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: write
 | 
			
		||||
  discussions: write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[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).
 | 
			
		||||
> **⚠️ Note:** This action was previously implemented as a docker container, limiting its use to GitHub Actions Linux virtual environments only. With recent releases, we now support cross platform usage. You'll need to remove the `docker://` prefix in these versions
 | 
			
		||||
 | 
			
		||||
Doug Tangren (softprops) 2019
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,11 @@ describe("github", () => {
 | 
			
		||||
 | 
			
		||||
  describe("asset", () => {
 | 
			
		||||
    it("derives asset info from a path", async () => {
 | 
			
		||||
      const { name, mime, size, data } = asset("tests/data/foo/bar.txt");
 | 
			
		||||
      const { name, mime, size, file } = asset("tests/data/foo/bar.txt");
 | 
			
		||||
      assert.equal(name, "bar.txt");
 | 
			
		||||
      assert.equal(mime, "text/plain");
 | 
			
		||||
      assert.equal(size, 10);
 | 
			
		||||
      assert.equal(data.toString(), "release me");
 | 
			
		||||
      assert.equal(file.toString(), "release me");
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -3,23 +3,11 @@ import {
 | 
			
		||||
  isTag,
 | 
			
		||||
  paths,
 | 
			
		||||
  parseConfig,
 | 
			
		||||
  parseInputFiles,
 | 
			
		||||
  unmatchedPatterns,
 | 
			
		||||
  uploadUrl,
 | 
			
		||||
  parseInputFiles
 | 
			
		||||
} from "../src/util";
 | 
			
		||||
import * as assert from "assert";
 | 
			
		||||
 | 
			
		||||
describe("util", () => {
 | 
			
		||||
  describe("uploadUrl", () => {
 | 
			
		||||
    it("strips template", () => {
 | 
			
		||||
      assert.equal(
 | 
			
		||||
        uploadUrl(
 | 
			
		||||
          "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}"
 | 
			
		||||
        ),
 | 
			
		||||
        "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets"
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe("parseInputFiles", () => {
 | 
			
		||||
    it("parses empty strings", () => {
 | 
			
		||||
      assert.deepStrictEqual(parseInputFiles(""), []);
 | 
			
		||||
@@ -47,12 +35,7 @@ describe("util", () => {
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: false,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
          input_name: undefined
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
@@ -68,18 +51,13 @@ describe("util", () => {
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: false,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
          input_name: undefined
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("defaults to body path when both body and body path are provided", () => {
 | 
			
		||||
    it("defaults to body when both body and body path are provided", () => {
 | 
			
		||||
      assert.equal(
 | 
			
		||||
        "bar",
 | 
			
		||||
        "foo",
 | 
			
		||||
        releaseBody({
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
@@ -89,257 +67,24 @@ describe("util", () => {
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: false,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
          input_name: undefined
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe("parseConfig", () => {
 | 
			
		||||
    it("parses basic config", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          // note: inputs declared in actions.yml, even when declared not required,
 | 
			
		||||
          // are still provided by the actions runtime env as empty strings instead of
 | 
			
		||||
          // the normal absent env value one would expect. this breaks things
 | 
			
		||||
          // as an empty string !== undefined in terms of what we pass to the api
 | 
			
		||||
          // so we cover that in a test case here to ensure undefined values are actually
 | 
			
		||||
          // resolved as undefined and not empty strings
 | 
			
		||||
          INPUT_TARGET_COMMITISH: "",
 | 
			
		||||
          INPUT_DISCUSSION_CATEGORY_NAME: "",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("parses basic config with commitish", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_TARGET_COMMITISH: "affa18ef97bc9db20076945705aba8c516139abd",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("supports discussion category names", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_DISCUSSION_CATEGORY_NAME: "releases",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: "releases",
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("supports generating release notes", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_GENERATE_RELEASE_NOTES: "true",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: true,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("prefers GITHUB_TOKEN over token input for backwards compatibility", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_DRAFT: "false",
 | 
			
		||||
          INPUT_PRERELEASE: "true",
 | 
			
		||||
          GITHUB_TOKEN: "env-token",
 | 
			
		||||
          INPUT_TOKEN: "input-token",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "env-token",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: true,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("uses input token as the source of GITHUB_TOKEN by default", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_DRAFT: "false",
 | 
			
		||||
          INPUT_PRERELEASE: "true",
 | 
			
		||||
          INPUT_TOKEN: "input-token",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "input-token",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: true,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("parses basic config with draft and prerelease", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_DRAFT: "false",
 | 
			
		||||
          INPUT_PRERELEASE: "true",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: false,
 | 
			
		||||
          input_prerelease: true,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("parses basic config where make_latest is passed", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_MAKE_LATEST: "false",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: false,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: "false",
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    it("parses basic config with append_body", () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        parseConfig({
 | 
			
		||||
          INPUT_APPEND_BODY: "true",
 | 
			
		||||
        }),
 | 
			
		||||
        {
 | 
			
		||||
          github_ref: "",
 | 
			
		||||
          github_repository: "",
 | 
			
		||||
          github_token: "",
 | 
			
		||||
          input_append_body: true,
 | 
			
		||||
          input_body: undefined,
 | 
			
		||||
          input_body_path: undefined,
 | 
			
		||||
          input_draft: undefined,
 | 
			
		||||
          input_prerelease: undefined,
 | 
			
		||||
          input_files: [],
 | 
			
		||||
          input_name: undefined,
 | 
			
		||||
          input_tag_name: undefined,
 | 
			
		||||
          input_fail_on_unmatched_files: false,
 | 
			
		||||
          input_target_commitish: undefined,
 | 
			
		||||
          input_discussion_category_name: undefined,
 | 
			
		||||
          input_generate_release_notes: false,
 | 
			
		||||
          input_make_latest: undefined,
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
      assert.deepStrictEqual(parseConfig({}), {
 | 
			
		||||
        github_ref: "",
 | 
			
		||||
        github_repository: "",
 | 
			
		||||
        github_token: "",
 | 
			
		||||
        input_body: undefined,
 | 
			
		||||
        input_body_path: undefined,
 | 
			
		||||
        input_draft: false,
 | 
			
		||||
        input_prerelease: false,
 | 
			
		||||
        input_files: [],
 | 
			
		||||
        input_name: undefined
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe("isTag", () => {
 | 
			
		||||
@@ -353,19 +98,9 @@ describe("util", () => {
 | 
			
		||||
 | 
			
		||||
  describe("paths", () => {
 | 
			
		||||
    it("resolves files given a set of paths", async () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        paths(["tests/data/**/*", "tests/data/does/not/exist/*"]),
 | 
			
		||||
        ["tests/data/foo/bar.txt"]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe("unmatchedPatterns", () => {
 | 
			
		||||
    it("returns the patterns that don't match any files", async () => {
 | 
			
		||||
      assert.deepStrictEqual(
 | 
			
		||||
        unmatchedPatterns(["tests/data/**/*", "tests/data/does/not/exist/*"]),
 | 
			
		||||
        ["tests/data/does/not/exist/*"]
 | 
			
		||||
      );
 | 
			
		||||
      assert.deepStrictEqual(paths(["tests/data/**/*"]), [
 | 
			
		||||
        "tests/data/foo/bar.txt"
 | 
			
		||||
      ]);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								action.yml
									
									
									
									
									
								
							@@ -1,68 +1,34 @@
 | 
			
		||||
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
 | 
			
		||||
name: "GH Release"
 | 
			
		||||
description: "Github Action for creating Github Releases"
 | 
			
		||||
author: "softprops"
 | 
			
		||||
name: 'GH Release'
 | 
			
		||||
description: 'Github Action for creating Github Releases'
 | 
			
		||||
author: 'softprops'
 | 
			
		||||
inputs:
 | 
			
		||||
  body:
 | 
			
		||||
    description: "Note-worthy description of changes in release"
 | 
			
		||||
    description: 'Note-worthy description of changes in release'
 | 
			
		||||
    required: false
 | 
			
		||||
  body_path:
 | 
			
		||||
    description: "Path to load note-worthy description of changes in release from"
 | 
			
		||||
    description: 'Path to load note-worthy description of changes in release from'
 | 
			
		||||
    required: false
 | 
			
		||||
  name:
 | 
			
		||||
    description: "Gives the release a custom name. Defaults to tag name"
 | 
			
		||||
    required: false
 | 
			
		||||
  tag_name:
 | 
			
		||||
    description: "Gives a tag name. Defaults to github.GITHUB_REF"
 | 
			
		||||
    description: 'Gives the release a custom name. Defaults to tag name'
 | 
			
		||||
    required: false
 | 
			
		||||
  draft:
 | 
			
		||||
    description: "Creates a draft release. Defaults to false"
 | 
			
		||||
    description: 'Creates a draft release. Defaults to false'
 | 
			
		||||
    required: false
 | 
			
		||||
  prerelease:
 | 
			
		||||
    description: "Identify the release as a prerelease. Defaults to false"
 | 
			
		||||
    description: 'Identify the release as a prerelease. Defaults to false'
 | 
			
		||||
    required: false
 | 
			
		||||
  files:
 | 
			
		||||
    description: "Newline-delimited list of path globs for asset files to upload"
 | 
			
		||||
    required: false
 | 
			
		||||
  fail_on_unmatched_files:
 | 
			
		||||
    description: "Fails if any of the `files` globs match nothing. Defaults to false"
 | 
			
		||||
    required: false
 | 
			
		||||
  repository:
 | 
			
		||||
    description: "Repository to make releases against, in <owner>/<repo> format"
 | 
			
		||||
    required: false
 | 
			
		||||
  token:
 | 
			
		||||
    description: "Authorized secret GitHub Personal Access Token. Defaults to github.token"
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ${{ github.token }}
 | 
			
		||||
  target_commitish:
 | 
			
		||||
    description: "Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA."
 | 
			
		||||
    required: false
 | 
			
		||||
  discussion_category_name:
 | 
			
		||||
    description: "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. If there is already a discussion linked to the release, this parameter is ignored."
 | 
			
		||||
    required: false
 | 
			
		||||
  generate_release_notes:
 | 
			
		||||
    description: "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."
 | 
			
		||||
    required: false
 | 
			
		||||
  append_body:
 | 
			
		||||
    description: "Append to existing body instead of overwriting it. Default is 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"
 | 
			
		||||
    description: 'Newline-delimited list of path globs for asset files to upload'
 | 
			
		||||
    required: false
 | 
			
		||||
env:
 | 
			
		||||
  "GITHUB_TOKEN": "As provided by Github Actions"
 | 
			
		||||
  'GITHUB_TOKEN': 'As provided by Github Actions'
 | 
			
		||||
outputs:
 | 
			
		||||
  url:
 | 
			
		||||
    description: "URL to the Release HTML Page"
 | 
			
		||||
  id:
 | 
			
		||||
    description: "Release ID"
 | 
			
		||||
  upload_url:
 | 
			
		||||
    description: "URL for uploading assets to the release"
 | 
			
		||||
  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: 'URL to the Release HTML Page'
 | 
			
		||||
runs:
 | 
			
		||||
  using: "node20"
 | 
			
		||||
  main: "dist/index.js"
 | 
			
		||||
  using: 'node12'
 | 
			
		||||
  main: 'dist/index.js'
 | 
			
		||||
branding:
 | 
			
		||||
  color: "green"
 | 
			
		||||
  icon: "package"
 | 
			
		||||
  color: 'green'
 | 
			
		||||
  icon: 'package'
 | 
			
		||||
							
								
								
									
										8
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										10501
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10501
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										41
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								package.json
									
									
									
									
									
								
							@@ -1,43 +1,42 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "action-gh-release",
 | 
			
		||||
  "version": "2.0.3",
 | 
			
		||||
  "version": "0.1.4",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "description": "GitHub Action for creating GitHub Releases",
 | 
			
		||||
  "main": "lib/main.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "build": "ncc build src/main.ts --minify",
 | 
			
		||||
    "test": "jest",
 | 
			
		||||
    "fmt": "prettier --write \"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"
 | 
			
		||||
    "fmt": "prettier --write 'src/**/*.ts' '__tests__/**/*.ts'",
 | 
			
		||||
    "fmtcheck": "prettier --check 'src/**/*.ts' '__tests__/**/*.ts'"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/softprops/action-gh-release.git"
 | 
			
		||||
    "url": "git+https://github.com/softprops/action-gh-template.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "actions"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "softprops",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@actions/core": "^1.10.0",
 | 
			
		||||
    "@actions/github": "^5.1.1",
 | 
			
		||||
    "@octokit/plugin-retry": "^4.0.3",
 | 
			
		||||
    "@octokit/plugin-throttling": "^4.3.2",
 | 
			
		||||
    "glob": "^8.0.3",
 | 
			
		||||
    "mime": "^3.0.0"
 | 
			
		||||
    "@actions/core": "^1.2.0",
 | 
			
		||||
    "@actions/github": "^2.0.0",
 | 
			
		||||
    "@octokit/plugin-throttling": "^2.7.1",
 | 
			
		||||
    "glob": "^7.1.6",
 | 
			
		||||
    "mime": "^2.4.4"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/glob": "^8.0.0",
 | 
			
		||||
    "@types/jest": "^29.2.3",
 | 
			
		||||
    "@types/mime": "^3.0.1",
 | 
			
		||||
    "@types/node": "^18.11.9",
 | 
			
		||||
    "@vercel/ncc": "^0.34.0",
 | 
			
		||||
    "jest": "^29.3.1",
 | 
			
		||||
    "jest-circus": "^29.3.1",
 | 
			
		||||
    "prettier": "2.8.0",
 | 
			
		||||
    "ts-jest": "^29.0.3",
 | 
			
		||||
    "typescript": "^4.9.3",
 | 
			
		||||
    "@types/glob": "^7.1.1",
 | 
			
		||||
    "@types/jest": "^24.0.25",
 | 
			
		||||
    "@types/mime": "^2.0.1",
 | 
			
		||||
    "@types/node": "^12.12.24",
 | 
			
		||||
    "@zeit/ncc": "^0.21.0",
 | 
			
		||||
    "jest": "^24.9.0",
 | 
			
		||||
    "jest-circus": "^24.9.0",
 | 
			
		||||
    "prettier": "1.19.1",
 | 
			
		||||
    "ts-jest": "^24.2.0",
 | 
			
		||||
    "typescript": "^3.7.4",
 | 
			
		||||
    "typescript-formatter": "^7.2.2"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								release.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								release.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#!/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
 | 
			
		||||
							
								
								
									
										180
									
								
								src/github.ts
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								src/github.ts
									
									
									
									
									
								
							@@ -1,16 +1,14 @@
 | 
			
		||||
import { GitHub } from "@actions/github/lib/utils";
 | 
			
		||||
import { Config, isTag, releaseBody } from "./util";
 | 
			
		||||
import { statSync, readFileSync } from "fs";
 | 
			
		||||
import { GitHub } from "@actions/github";
 | 
			
		||||
import { Config, releaseBody } from "./util";
 | 
			
		||||
import { lstatSync, readFileSync } from "fs";
 | 
			
		||||
import { getType } from "mime";
 | 
			
		||||
import { basename } from "path";
 | 
			
		||||
 | 
			
		||||
type GitHub = InstanceType<typeof GitHub>;
 | 
			
		||||
 | 
			
		||||
export interface ReleaseAsset {
 | 
			
		||||
  name: string;
 | 
			
		||||
  mime: string;
 | 
			
		||||
  size: number;
 | 
			
		||||
  data: Buffer;
 | 
			
		||||
  file: Buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Release {
 | 
			
		||||
@@ -18,12 +16,8 @@ export interface Release {
 | 
			
		||||
  upload_url: string;
 | 
			
		||||
  html_url: string;
 | 
			
		||||
  tag_name: string;
 | 
			
		||||
  name: string | null;
 | 
			
		||||
  body?: string | null | undefined;
 | 
			
		||||
  body: string;
 | 
			
		||||
  target_commitish: string;
 | 
			
		||||
  draft: boolean;
 | 
			
		||||
  prerelease: boolean;
 | 
			
		||||
  assets: Array<{ id: number; name: string }>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Releaser {
 | 
			
		||||
@@ -41,10 +35,6 @@ export interface Releaser {
 | 
			
		||||
    body: string | undefined;
 | 
			
		||||
    draft: boolean | undefined;
 | 
			
		||||
    prerelease: boolean | undefined;
 | 
			
		||||
    target_commitish: string | undefined;
 | 
			
		||||
    discussion_category_name: string | undefined;
 | 
			
		||||
    generate_release_notes: boolean | undefined;
 | 
			
		||||
    make_latest: string | undefined;
 | 
			
		||||
  }): Promise<{ data: Release }>;
 | 
			
		||||
 | 
			
		||||
  updateRelease(params: {
 | 
			
		||||
@@ -57,9 +47,6 @@ export interface Releaser {
 | 
			
		||||
    body: string | undefined;
 | 
			
		||||
    draft: boolean | undefined;
 | 
			
		||||
    prerelease: boolean | undefined;
 | 
			
		||||
    discussion_category_name: string | undefined;
 | 
			
		||||
    generate_release_notes: boolean | undefined;
 | 
			
		||||
    make_latest: string | undefined;
 | 
			
		||||
  }): Promise<{ data: Release }>;
 | 
			
		||||
 | 
			
		||||
  allReleases(params: {
 | 
			
		||||
@@ -79,7 +66,7 @@ export class GitHubReleaser implements Releaser {
 | 
			
		||||
    repo: string;
 | 
			
		||||
    tag: string;
 | 
			
		||||
  }): Promise<{ data: Release }> {
 | 
			
		||||
    return this.github.rest.repos.getReleaseByTag(params);
 | 
			
		||||
    return this.github.repos.getReleaseByTag(params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createRelease(params: {
 | 
			
		||||
@@ -90,12 +77,8 @@ export class GitHubReleaser implements Releaser {
 | 
			
		||||
    body: string | undefined;
 | 
			
		||||
    draft: boolean | undefined;
 | 
			
		||||
    prerelease: boolean | undefined;
 | 
			
		||||
    target_commitish: string | undefined;
 | 
			
		||||
    discussion_category_name: string | undefined;
 | 
			
		||||
    generate_release_notes: boolean | undefined;
 | 
			
		||||
    make_latest: string | undefined;
 | 
			
		||||
  }): Promise<{ data: Release }> {
 | 
			
		||||
    return this.github.rest.repos.createRelease(params);
 | 
			
		||||
    return this.github.repos.createRelease(params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateRelease(params: {
 | 
			
		||||
@@ -108,11 +91,8 @@ export class GitHubReleaser implements Releaser {
 | 
			
		||||
    body: string | undefined;
 | 
			
		||||
    draft: boolean | undefined;
 | 
			
		||||
    prerelease: boolean | undefined;
 | 
			
		||||
    discussion_category_name: string | undefined;
 | 
			
		||||
    generate_release_notes: boolean | undefined;
 | 
			
		||||
    make_latest: string | undefined;
 | 
			
		||||
  }): Promise<{ data: Release }> {
 | 
			
		||||
    return this.github.rest.repos.updateRelease(params);
 | 
			
		||||
    return this.github.repos.updateRelease(params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  allReleases(params: {
 | 
			
		||||
@@ -121,7 +101,7 @@ export class GitHubReleaser implements Releaser {
 | 
			
		||||
  }): AsyncIterableIterator<{ data: Release[] }> {
 | 
			
		||||
    const updatedParams = { per_page: 100, ...params };
 | 
			
		||||
    return this.github.paginate.iterator(
 | 
			
		||||
      this.github.rest.repos.listReleases.endpoint.merge(updatedParams)
 | 
			
		||||
      this.github.repos.listReleases.endpoint.merge(updatedParams)
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -130,8 +110,8 @@ export const asset = (path: string): ReleaseAsset => {
 | 
			
		||||
  return {
 | 
			
		||||
    name: basename(path),
 | 
			
		||||
    mime: mimeOrDefault(path),
 | 
			
		||||
    size: statSync(path).size,
 | 
			
		||||
    data: readFileSync(path),
 | 
			
		||||
    size: lstatSync(path).size,
 | 
			
		||||
    file: readFileSync(path)
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -140,77 +120,38 @@ export const mimeOrDefault = (path: string): string => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const upload = async (
 | 
			
		||||
  config: Config,
 | 
			
		||||
  github: GitHub,
 | 
			
		||||
  gh: GitHub,
 | 
			
		||||
  url: string,
 | 
			
		||||
  path: string,
 | 
			
		||||
  currentAssets: Array<{ id: number; name: string }>
 | 
			
		||||
  path: string
 | 
			
		||||
): Promise<any> => {
 | 
			
		||||
  const [owner, repo] = config.github_repository.split("/");
 | 
			
		||||
  const { name, size, mime, data: body } = asset(path);
 | 
			
		||||
  const currentAsset = currentAssets.find(
 | 
			
		||||
    ({ name: currentName }) => currentName == name
 | 
			
		||||
  );
 | 
			
		||||
  if (currentAsset) {
 | 
			
		||||
    console.log(`♻️ Deleting previously uploaded asset ${name}...`);
 | 
			
		||||
    await github.rest.repos.deleteReleaseAsset({
 | 
			
		||||
      asset_id: currentAsset.id || 1,
 | 
			
		||||
      owner,
 | 
			
		||||
      repo,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  let { name, size, mime, file } = asset(path);
 | 
			
		||||
  console.log(`⬆️ Uploading ${name}...`);
 | 
			
		||||
  const endpoint = new URL(url);
 | 
			
		||||
  endpoint.searchParams.append("name", name);
 | 
			
		||||
  const resp = await github.request({
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    url: endpoint.toString(),
 | 
			
		||||
  return await gh.repos.uploadReleaseAsset({
 | 
			
		||||
    url,
 | 
			
		||||
    headers: {
 | 
			
		||||
      "content-length": `${size}`,
 | 
			
		||||
      "content-type": mime,
 | 
			
		||||
      authorization: `token ${config.github_token}`,
 | 
			
		||||
      "content-length": size,
 | 
			
		||||
      "content-type": mime
 | 
			
		||||
    },
 | 
			
		||||
    data: body,
 | 
			
		||||
    name,
 | 
			
		||||
    file
 | 
			
		||||
  });
 | 
			
		||||
  const json = resp.data;
 | 
			
		||||
  if (resp.status !== 201) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `Failed to upload release asset ${name}. received status code ${
 | 
			
		||||
        resp.status
 | 
			
		||||
      }\n${json.message}\n${JSON.stringify(json.errors)}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  return json;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const release = async (
 | 
			
		||||
  config: Config,
 | 
			
		||||
  releaser: Releaser,
 | 
			
		||||
  maxRetries: number = 3
 | 
			
		||||
  releaser: Releaser
 | 
			
		||||
): Promise<Release> => {
 | 
			
		||||
  if (maxRetries <= 0) {
 | 
			
		||||
    console.log(`❌ Too many retries. Aborting...`);
 | 
			
		||||
    throw new Error("Too many retries.");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const [owner, repo] = config.github_repository.split("/");
 | 
			
		||||
  const tag =
 | 
			
		||||
    config.input_tag_name ||
 | 
			
		||||
    (isTag(config.github_ref)
 | 
			
		||||
      ? config.github_ref.replace("refs/tags/", "")
 | 
			
		||||
      : "");
 | 
			
		||||
 | 
			
		||||
  const discussion_category_name = config.input_discussion_category_name;
 | 
			
		||||
  const generate_release_notes = config.input_generate_release_notes;
 | 
			
		||||
  const tag = config.github_ref.replace("refs/tags/", "");
 | 
			
		||||
  try {
 | 
			
		||||
    // you can't get a an existing draft by 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,
 | 
			
		||||
        repo
 | 
			
		||||
      })) {
 | 
			
		||||
        let release = response.data.find((release) => release.tag_name === tag);
 | 
			
		||||
        let release = response.data.find(release => release.tag_name === tag);
 | 
			
		||||
        if (release) {
 | 
			
		||||
          return release;
 | 
			
		||||
        }
 | 
			
		||||
@@ -219,48 +160,16 @@ export const release = async (
 | 
			
		||||
    let existingRelease = await releaser.getReleaseByTag({
 | 
			
		||||
      owner,
 | 
			
		||||
      repo,
 | 
			
		||||
      tag,
 | 
			
		||||
      tag
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const release_id = existingRelease.data.id;
 | 
			
		||||
    let target_commitish: string;
 | 
			
		||||
    if (
 | 
			
		||||
      config.input_target_commitish &&
 | 
			
		||||
      config.input_target_commitish !== existingRelease.data.target_commitish
 | 
			
		||||
    ) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        `Updating commit from "${existingRelease.data.target_commitish}" to "${config.input_target_commitish}"`
 | 
			
		||||
      );
 | 
			
		||||
      target_commitish = config.input_target_commitish;
 | 
			
		||||
    } else {
 | 
			
		||||
      target_commitish = existingRelease.data.target_commitish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const target_commitish = existingRelease.data.target_commitish;
 | 
			
		||||
    const tag_name = tag;
 | 
			
		||||
    const name = config.input_name || existingRelease.data.name || tag;
 | 
			
		||||
    // revisit: support a new body-concat-strategy input for accumulating
 | 
			
		||||
    // 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
 | 
			
		||||
    // no one wants
 | 
			
		||||
    const workflowBody = releaseBody(config) || "";
 | 
			
		||||
    const existingReleaseBody = existingRelease.data.body || "";
 | 
			
		||||
    let body: string;
 | 
			
		||||
    if (config.input_append_body && workflowBody && existingReleaseBody) {
 | 
			
		||||
      body = existingReleaseBody + "\n" + workflowBody;
 | 
			
		||||
    } else {
 | 
			
		||||
      body = workflowBody || existingReleaseBody;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const draft =
 | 
			
		||||
      config.input_draft !== undefined
 | 
			
		||||
        ? config.input_draft
 | 
			
		||||
        : existingRelease.data.draft;
 | 
			
		||||
    const prerelease =
 | 
			
		||||
      config.input_prerelease !== undefined
 | 
			
		||||
        ? config.input_prerelease
 | 
			
		||||
        : existingRelease.data.prerelease;
 | 
			
		||||
 | 
			
		||||
    const make_latest = config.input_make_latest;
 | 
			
		||||
    const name = config.input_name || tag;
 | 
			
		||||
    const body = `${existingRelease.data.body}\n${releaseBody(config)}`;
 | 
			
		||||
    const draft = config.input_draft;
 | 
			
		||||
    const prerelease = config.input_prerelease;
 | 
			
		||||
 | 
			
		||||
    const release = await releaser.updateRelease({
 | 
			
		||||
      owner,
 | 
			
		||||
@@ -271,10 +180,7 @@ export const release = async (
 | 
			
		||||
      name,
 | 
			
		||||
      body,
 | 
			
		||||
      draft,
 | 
			
		||||
      prerelease,
 | 
			
		||||
      discussion_category_name,
 | 
			
		||||
      generate_release_notes,
 | 
			
		||||
      make_latest,
 | 
			
		||||
      prerelease
 | 
			
		||||
    });
 | 
			
		||||
    return release.data;
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
@@ -284,15 +190,7 @@ export const release = async (
 | 
			
		||||
      const body = releaseBody(config);
 | 
			
		||||
      const draft = config.input_draft;
 | 
			
		||||
      const prerelease = config.input_prerelease;
 | 
			
		||||
      const target_commitish = config.input_target_commitish;
 | 
			
		||||
      const make_latest = config.input_make_latest;
 | 
			
		||||
      let commitMessage: string = "";
 | 
			
		||||
      if (target_commitish) {
 | 
			
		||||
        commitMessage = ` using commit "${target_commitish}"`;
 | 
			
		||||
      }
 | 
			
		||||
      console.log(
 | 
			
		||||
        `👩🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`
 | 
			
		||||
      );
 | 
			
		||||
      console.log(`👩🏭 Creating new GitHub release for tag ${tag_name}...`);
 | 
			
		||||
      try {
 | 
			
		||||
        let release = await releaser.createRelease({
 | 
			
		||||
          owner,
 | 
			
		||||
@@ -301,23 +199,15 @@ export const release = async (
 | 
			
		||||
          name,
 | 
			
		||||
          body,
 | 
			
		||||
          draft,
 | 
			
		||||
          prerelease,
 | 
			
		||||
          target_commitish,
 | 
			
		||||
          discussion_category_name,
 | 
			
		||||
          generate_release_notes,
 | 
			
		||||
          make_latest,
 | 
			
		||||
          prerelease
 | 
			
		||||
        });
 | 
			
		||||
        return release.data;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        // presume a race with competing metrix runs
 | 
			
		||||
        console.log(
 | 
			
		||||
          `⚠️ GitHub release failed with status: ${
 | 
			
		||||
            error.status
 | 
			
		||||
          }\n${JSON.stringify(error.response.data.errors)}\nretrying... (${
 | 
			
		||||
            maxRetries - 1
 | 
			
		||||
          } retries remaining)`
 | 
			
		||||
          `⚠️ GitHub release failed with status: ${error.status}, retrying...`
 | 
			
		||||
        );
 | 
			
		||||
        return release(config, releaser, maxRetries - 1);
 | 
			
		||||
        return release(config, releaser);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      console.log(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/main.ts
									
									
									
									
									
								
							@@ -1,100 +1,46 @@
 | 
			
		||||
import {
 | 
			
		||||
  paths,
 | 
			
		||||
  parseConfig,
 | 
			
		||||
  isTag,
 | 
			
		||||
  unmatchedPatterns,
 | 
			
		||||
  uploadUrl,
 | 
			
		||||
} from "./util";
 | 
			
		||||
import { paths, parseConfig, isTag } 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 { GitHub } from "@actions/github";
 | 
			
		||||
import { env } from "process";
 | 
			
		||||
 | 
			
		||||
async function run() {
 | 
			
		||||
  try {
 | 
			
		||||
    const config = parseConfig(env);
 | 
			
		||||
    if (
 | 
			
		||||
      !config.input_tag_name &&
 | 
			
		||||
      !isTag(config.github_ref) &&
 | 
			
		||||
      !config.input_draft
 | 
			
		||||
    ) {
 | 
			
		||||
    if (!isTag(config.github_ref)) {
 | 
			
		||||
      throw new Error(`⚠️ GitHub Releases requires a tag`);
 | 
			
		||||
    }
 | 
			
		||||
    if (config.input_files) {
 | 
			
		||||
      const patterns = unmatchedPatterns(config.input_files);
 | 
			
		||||
      patterns.forEach((pattern) => {
 | 
			
		||||
        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.`);
 | 
			
		||||
    GitHub.plugin(require("@octokit/plugin-throttling"));
 | 
			
		||||
    const gh = new GitHub(config.github_token, {
 | 
			
		||||
      onRateLimit: (retryAfter, options) => {
 | 
			
		||||
        console.warn(
 | 
			
		||||
          `Request quota exhausted for request ${options.method} ${options.url}`
 | 
			
		||||
        );
 | 
			
		||||
        if (options.request.retryCount === 0) {
 | 
			
		||||
          // only retries once
 | 
			
		||||
          console.log(`Retrying after ${retryAfter} seconds!`);
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      if (patterns.length > 0 && config.input_fail_on_unmatched_files) {
 | 
			
		||||
        throw new Error(`⚠️ There were unmatched files`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // const oktokit = GitHub.plugin(
 | 
			
		||||
    //   require("@octokit/plugin-throttling"),
 | 
			
		||||
    //   require("@octokit/plugin-retry")
 | 
			
		||||
    // );
 | 
			
		||||
 | 
			
		||||
    const gh = getOctokit(config.github_token, {
 | 
			
		||||
      //new oktokit(
 | 
			
		||||
      throttle: {
 | 
			
		||||
        onRateLimit: (retryAfter, options) => {
 | 
			
		||||
          console.warn(
 | 
			
		||||
            `Request quota exhausted for request ${options.method} ${options.url}`
 | 
			
		||||
          );
 | 
			
		||||
          if (options.request.retryCount === 0) {
 | 
			
		||||
            // only retries once
 | 
			
		||||
            console.log(`Retrying after ${retryAfter} seconds!`);
 | 
			
		||||
            return true;
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        onAbuseLimit: (retryAfter, options) => {
 | 
			
		||||
          // does not retry, only logs a warning
 | 
			
		||||
          console.warn(
 | 
			
		||||
            `Abuse detected for request ${options.method} ${options.url}`
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      onAbuseLimit: (retryAfter, options) => {
 | 
			
		||||
        // does not retry, only logs a warning
 | 
			
		||||
        console.warn(
 | 
			
		||||
          `Abuse detected for request ${options.method} ${options.url}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    //);
 | 
			
		||||
    const rel = await release(config, new GitHubReleaser(gh));
 | 
			
		||||
    if (config.input_files && config.input_files.length > 0) {
 | 
			
		||||
    let rel = await release(config, new GitHubReleaser(gh));
 | 
			
		||||
    if (config.input_files) {
 | 
			
		||||
      const files = paths(config.input_files);
 | 
			
		||||
      if (files.length == 0) {
 | 
			
		||||
        if (config.input_fail_on_unmatched_files) {
 | 
			
		||||
          throw new Error(`⚠️ ${config.input_files} not include valid file.`);
 | 
			
		||||
        } else {
 | 
			
		||||
          console.warn(`🤔 ${config.input_files} not include valid file.`);
 | 
			
		||||
        }
 | 
			
		||||
        console.warn(`🤔 ${config.input_files} not include valid file.`);
 | 
			
		||||
      }
 | 
			
		||||
      const currentAssets = rel.assets;
 | 
			
		||||
      const assets = await Promise.all(
 | 
			
		||||
        files.map(async (path) => {
 | 
			
		||||
          const json = await upload(
 | 
			
		||||
            config,
 | 
			
		||||
            gh,
 | 
			
		||||
            uploadUrl(rel.upload_url),
 | 
			
		||||
            path,
 | 
			
		||||
            currentAssets
 | 
			
		||||
          );
 | 
			
		||||
          delete json.uploader;
 | 
			
		||||
          return json;
 | 
			
		||||
        })
 | 
			
		||||
      ).catch((error) => {
 | 
			
		||||
        throw error;
 | 
			
		||||
      files.forEach(async path => {
 | 
			
		||||
        await upload(gh, rel.upload_url, path);
 | 
			
		||||
      });
 | 
			
		||||
      setOutput("assets", assets);
 | 
			
		||||
    }
 | 
			
		||||
    console.log(`🎉 Release ready at ${rel.html_url}`);
 | 
			
		||||
    setOutput("url", rel.html_url);
 | 
			
		||||
    setOutput("id", rel.id.toString());
 | 
			
		||||
    setOutput("upload_url", rel.upload_url);
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    setFailed(error.message);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								src/util.ts
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								src/util.ts
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
import * as glob from "glob";
 | 
			
		||||
import { statSync, readFileSync } from "fs";
 | 
			
		||||
import { lstatSync, readFileSync } from "fs";
 | 
			
		||||
 | 
			
		||||
export interface Config {
 | 
			
		||||
  github_token: string;
 | 
			
		||||
@@ -7,34 +7,18 @@ export interface Config {
 | 
			
		||||
  github_repository: string;
 | 
			
		||||
  // user provided
 | 
			
		||||
  input_name?: string;
 | 
			
		||||
  input_tag_name?: string;
 | 
			
		||||
  input_repository?: string;
 | 
			
		||||
  input_body?: string;
 | 
			
		||||
  input_body_path?: string;
 | 
			
		||||
  input_files?: string[];
 | 
			
		||||
  input_draft?: boolean;
 | 
			
		||||
  input_prerelease?: boolean;
 | 
			
		||||
  input_fail_on_unmatched_files?: boolean;
 | 
			
		||||
  input_target_commitish?: string;
 | 
			
		||||
  input_discussion_category_name?: string;
 | 
			
		||||
  input_generate_release_notes?: boolean;
 | 
			
		||||
  input_append_body?: boolean;
 | 
			
		||||
  input_make_latest: string | undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const uploadUrl = (url: string): string => {
 | 
			
		||||
  const templateMarkerPos = url.indexOf("{");
 | 
			
		||||
  if (templateMarkerPos > -1) {
 | 
			
		||||
    return url.substring(0, templateMarkerPos);
 | 
			
		||||
  }
 | 
			
		||||
  return url;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const releaseBody = (config: Config): string | undefined => {
 | 
			
		||||
  return (
 | 
			
		||||
    config.input_body ||
 | 
			
		||||
    (config.input_body_path &&
 | 
			
		||||
      readFileSync(config.input_body_path).toString("utf8")) ||
 | 
			
		||||
    config.input_body
 | 
			
		||||
      readFileSync(config.input_body_path).toString("utf8"))
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -45,52 +29,30 @@ export const parseInputFiles = (files: string): string[] => {
 | 
			
		||||
    (acc, line) =>
 | 
			
		||||
      acc
 | 
			
		||||
        .concat(line.split(","))
 | 
			
		||||
        .filter((pat) => pat)
 | 
			
		||||
        .map((pat) => pat.trim()),
 | 
			
		||||
        .filter(pat => pat)
 | 
			
		||||
        .map(pat => pat.trim()),
 | 
			
		||||
    []
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const parseConfig = (env: Env): Config => {
 | 
			
		||||
  return {
 | 
			
		||||
    github_token: env.GITHUB_TOKEN || env.INPUT_TOKEN || "",
 | 
			
		||||
    github_token: env.GITHUB_TOKEN || "",
 | 
			
		||||
    github_ref: env.GITHUB_REF || "",
 | 
			
		||||
    github_repository: env.INPUT_REPOSITORY || env.GITHUB_REPOSITORY || "",
 | 
			
		||||
    github_repository: env.GITHUB_REPOSITORY || "",
 | 
			
		||||
    input_name: env.INPUT_NAME,
 | 
			
		||||
    input_tag_name: env.INPUT_TAG_NAME?.trim(),
 | 
			
		||||
    input_body: env.INPUT_BODY,
 | 
			
		||||
    input_body_path: env.INPUT_BODY_PATH,
 | 
			
		||||
    input_files: parseInputFiles(env.INPUT_FILES || ""),
 | 
			
		||||
    input_draft: env.INPUT_DRAFT ? env.INPUT_DRAFT === "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_discussion_category_name:
 | 
			
		||||
      env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
 | 
			
		||||
    input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == "true",
 | 
			
		||||
    input_append_body: env.INPUT_APPEND_BODY == "true",
 | 
			
		||||
    input_make_latest: env.INPUT_MAKE_LATEST
 | 
			
		||||
      ? env.INPUT_MAKE_LATEST
 | 
			
		||||
      : undefined,
 | 
			
		||||
    input_draft: env.INPUT_DRAFT === "true",
 | 
			
		||||
    input_prerelease: env.INPUT_PRERELEASE == "true"
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const paths = (patterns: string[]): string[] => {
 | 
			
		||||
  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
			
		||||
    return acc.concat(
 | 
			
		||||
      glob.sync(pattern).filter((path) => statSync(path).isFile())
 | 
			
		||||
    );
 | 
			
		||||
  }, []);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const unmatchedPatterns = (patterns: string[]): string[] => {
 | 
			
		||||
  return patterns.reduce((acc: string[], pattern: string): string[] => {
 | 
			
		||||
    return acc.concat(
 | 
			
		||||
      glob.sync(pattern).filter((path) => statSync(path).isFile()).length == 0
 | 
			
		||||
        ? [pattern]
 | 
			
		||||
        : []
 | 
			
		||||
      glob.sync(pattern).filter(path => lstatSync(path).isFile())
 | 
			
		||||
    );
 | 
			
		||||
  }, []);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "useUnknownInCatchVariables": false,
 | 
			
		||||
    /* Basic Options */
 | 
			
		||||
    // "incremental": true,                   /* Enable incremental compilation */
 | 
			
		||||
    "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user