Skip to content

Uploading assets to draft releases

If you need to upload assets to a release, you likely want to create that release as a draft and only publish it once you’ve uploaded the assets.

This recipe will show you how to configure Knope Bot to create draft releases and provide a sample GitHub Actions workflow to upload and publish.

First, indicate to Knope Bot that there are assets to upload by adding the assets config option to your knope.toml file:

knope.toml
[package]
# versioned_files and changelog config here
assets = "marker"
[bot.releases]
enabled = true

When you merge the release pull request from Knope Bot, it will create the release as a draft instead of a published release.

Here’s a complete example workflow, which is broken down step-by-step below:

.github/workflows/release.yml
on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
jobs:
get-tag:
if: (github.head_ref == 'knope/release' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- run: echo "tag_name=$(gh release list --json 'isDraft,tagName' --jq '.[] | select(.isDraft) | .tagName')" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ github.token }}
id: get-tag
outputs:
tag_name: ${{ steps.get-tag.outputs.tag_name }}
build-artifacts:
needs: [get-tag]
if: needs.get-tag.outputs.tag_name != ''
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- name: Replace Me with actual artifact creation
run: echo "example artifact" >> artifact.txt
- name: Upload Artifact
uses: actions/[email protected]
with:
name: Example
path: artifact.txt
if-no-files-found: error
release:
needs: [build-artifacts, get-tag]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/[email protected]
- uses: actions/[email protected]
with:
path: artifacts
merge-multiple: true
- name: Upload artifacts to release
run: |
cd artifacts
gh release upload ${{ needs.get-tag.outputs.tag_name }} *
gh release edit ${{ needs.get-tag.outputs.tag_name }} --draft=false --latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

The whole workflow is triggered either manually (in case something fails and needs to be retried) or when the release pull request merges. You can’t detect a draft release with the on.release event.

on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:

The first job “get-tag” then determines what the GitHub release is that needs to be edited. This job only runs if the pull request was a release pull request, and only if the pull request merged (not just closed).

get-tag:
if: (github.head_ref == 'knope/release' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- run: echo "tag_name=$(gh release list --json 'isDraft,tagName' --jq '.[] | select(.isDraft) | .tagName')" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ github.token }}
id: get-tag
outputs:
tag_name: ${{ steps.get-tag.outputs.tag_name }}

Next is a placeholder job for actually building the artifacts, which you’ll need to replace with your own logic. This is a separate job so you can “fan out” with a matrix and build multiple artifacts in parallel.

build-artifacts:
needs: [get-tag]
if: needs.get-tag.outputs.tag_name != ''
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- name: Replace Me with actual artifact creation
run: echo "example artifact" >> artifact.txt
- name: Upload Artifact
uses: actions/[email protected]
with:
name: Example
path: artifact.txt
if-no-files-found: error

The final job downloads all artifacts uploaded in previous jobs and uploads them to the release. It then sets the release as a non-draft and as the latest release.

release:
needs: [build-artifacts, get-tag]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/[email protected]
- uses: actions/[email protected]
with:
path: artifacts
merge-multiple: true
- name: Upload artifacts to release
run: |
cd artifacts
gh release upload ${{ needs.get-tag.outputs.tag_name }} *
gh release edit ${{ needs.get-tag.outputs.tag_name }} --draft=false --latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}