diff --git a/.forgejo/workflows/integration.yml b/.forgejo/workflows/integration.yml
index ced0ae6..c1ca93c 100644
--- a/.forgejo/workflows/integration.yml
+++ b/.forgejo/workflows/integration.yml
@@ -3,10 +3,10 @@ jobs:
integration:
runs-on: self-hosted
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- id: forgejo
- uses: https://code.forgejo.org/actions/setup-forgejo@v2.0.4
+ uses: https://code.forgejo.org/actions/setup-forgejo@v2.0.11
with:
user: testuser
password: admin1234
diff --git a/.forgejo/workflows/tests.yml b/.forgejo/workflows/tests.yml
index 70a5f87..5eba0cc 100644
--- a/.forgejo/workflows/tests.yml
+++ b/.forgejo/workflows/tests.yml
@@ -3,7 +3,7 @@ jobs:
integration:
runs-on: docker
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Unit tests of the supporting script forgejo-release.sh
run: |
diff --git a/README.md b/README.md
index eb93cf2..f532c6b 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,12 @@ Upload or download the assets of a release to a Forgejo instance.
| name | description | required | default |
| --- | --- | --- | --- |
-| `url` |
URL of the Forgejo instance
| `false` | `""` |
-| `repo` | owner/project relative to the URL
| `false` | `""` |
-| `tag` | Tag of the release
| `false` | `""` |
+| `url` | URL of the Forgejo instance
| `false` | `${{ env.GITHUB_SERVER_URL }}` |
+| `repo` | owner/project relative to the URL
| `false` | `${{ github.repository }}` |
+| `tag` | Tag of the release
| `false` | `${{ github.ref_name }}` |
| `title` | Title of the release (defaults to tag)
| `false` | `""` |
-| `sha` | SHA of the release
| `false` | `""` |
-| `token` | Forgejo application token
| `true` | `""` |
+| `sha` | SHA of the release
| `false` | `${{ github.sha }}` |
+| `token` | Forgejo application token
| `false` | `${{ secrets.GITHUB_TOKEN }}` |
| `release-dir` | Directory in whichs release assets are uploaded or downloaded
| `true` | `""` |
| `release-notes` | Release notes
| `false` | `""` |
| `direction` | Can either be download or upload
| `true` | `""` |
@@ -37,16 +37,18 @@ Upload or download the assets of a release to a Forgejo instance.
Upload the release located in `release-dir` to the release section of a repository (`url` and `repo`):
```yaml
-on: [tag]
jobs:
upload-release:
- runs-on: ubuntu-latest
+ runs-on: docker
steps:
- - uses: actions/checkout@v3
- - uses: actions/forgejo-release@v2
+ - uses: actions/checkout@v4
+ - uses: actions/forgejo-release@v2.6.0
with:
direction: upload
- url: https://code.forgejo.org
+ url: https://my-forgejo-instance.net
+ repo: myuser/myrepo
+ token: ${{ secrets.WRITE_TOKEN_TO_MYREPO }}
+ tag: v1.0.0
release-dir: dist/release
release-notes: "MY RELEASE NOTES"
```
@@ -56,24 +58,24 @@ jobs:
Example downloading the forgejo release v1.21.4-0 into the working directory:
```yaml
-on: [tag]
jobs:
download-release:
- runs-on: ubuntu-latest
+ runs-on: docker
steps:
- - uses: actions/checkout@v3
- - uses: actions/forgejo-release@v2
+ - uses: actions/checkout@v4
+ - uses: actions/forgejo-release@v2.6.0
with:
direction: download
- url: https://code.forgejo.org
- repo: forgejo/forgejo
- tag: v1.21.4-0
+ url: https://my-forgejo-instance.net
+ repo: myuser/myrepo
+ token: ${{ secrets.READ_TOKEN_TO_MYREPO }}
+ tag: v1.0.0
release-dir: ./ # by default, files are downloaded into dist/release
```
### Real world example
-This action is used to [publish](https://code.forgejo.org/forgejo/release-notes-assistant/src/branch/main/.forgejo/workflows/release.yml) the release notes assistant assets.
+This action is used to [publish](https://code.forgejo.org/forgejo/release-notes-assistant/src/commit/09f2c22d80d5ee655783cfeb2c1d4bab4afec3e4/.forgejo/workflows/release.yml) the release notes assistant assets.
## Update the `input` section of the README
diff --git a/action.yml b/action.yml
index 847c886..7e09788 100644
--- a/action.yml
+++ b/action.yml
@@ -6,17 +6,21 @@ description: |
inputs:
url:
description: 'URL of the Forgejo instance'
+ default: '${{ env.GITHUB_SERVER_URL }}'
repo:
description: 'owner/project relative to the URL'
+ default: '${{ github.repository }}'
tag:
description: 'Tag of the release'
+ default: '${{ github.ref_name }}'
title:
description: 'Title of the release (defaults to tag)'
sha:
description: 'SHA of the release'
+ default: '${{ github.sha }}'
token:
description: 'Forgejo application token'
- required: true
+ default: '${{ secrets.GITHUB_TOKEN }}'
release-dir:
description: 'Directory in whichs release assets are uploaded or downloaded'
required: true
@@ -57,9 +61,6 @@ runs:
shell: bash
- run: |
export FORGEJO="${{ inputs.url }}"
- if test -z "$FORGEJO"; then
- export FORGEJO="${{ env.GITHUB_SERVER_URL }}"
- fi
# A trailing / will mean http://forgejo//api/v1 is used
# and it always 401 as of v1.19, because of the double slash
FORGEJO=${FORGEJO%%/}
@@ -67,17 +68,8 @@ runs:
export HOST=${FORGEJO#*://}
export REPO="${{ inputs.repo }}"
- if test -z "$REPO"; then
- export REPO="${{ github.repository }}"
- fi
export TAG="${{ inputs.tag }}"
- if test -z "$TAG"; then
- export TAG="${{ github.ref_name }}"
- # until https://code.forgejo.org/forgejo/runner/issues/9 is fixed
- # trim refs/tags/
- TAG=${TAG##refs/tags/}
- fi
export TITLE="${{ inputs.title }}"
@@ -99,9 +91,6 @@ runs:
)
export SHA="${{ inputs.sha }}"
- if test -z "$SHA"; then
- export SHA="${{ github.sha }}"
- fi
export OVERRIDE="${{ inputs.override }}"
diff --git a/forgejo-release.sh b/forgejo-release.sh
index 8abb54e..38aa100 100755
--- a/forgejo-release.sh
+++ b/forgejo-release.sh
@@ -19,26 +19,58 @@ if ${VERBOSE:-false}; then set -x; fi
: ${RETRY:=1}
: ${DELAY:=10}
+TAG_FILE="$TMP_DIR/tag$$.json"
+
export GNUPGHOME
setup_tea() {
- if ! test -f "$BIN_DIR"/tea ; then
- ARCH=$(dpkg --print-architecture)
- curl -sL https://dl.gitea.io/tea/$TEA_VERSION/tea-$TEA_VERSION-linux-"$ARCH" > "$BIN_DIR"/tea
- chmod +x "$BIN_DIR"/tea
+ if ! test -f "$BIN_DIR"/tea; then
+ ARCH=$(dpkg --print-architecture)
+ curl -sL https://dl.gitea.io/tea/$TEA_VERSION/tea-$TEA_VERSION-linux-"$ARCH" >"$BIN_DIR"/tea
+ chmod +x "$BIN_DIR"/tea
+ fi
+}
+
+get_tag() {
+ if ! test -f "$TAG_FILE"; then
+ if api GET repos/$REPO/tags/"$TAG" >"$TAG_FILE"; then
+ echo "tag $TAG exists"
+ else
+ echo "tag $TAG does not exists"
+ fi
+ fi
+ test -s "$TAG_FILE"
+}
+
+matched_tag() {
+ if get_tag; then
+ local sha=$(jq --raw-output .commit.sha <"$TAG_FILE")
+ test "$sha" = "$SHA"
+ else
+ return 1
fi
}
ensure_tag() {
- if api GET repos/$REPO/tags/"$TAG" > "$TMP_DIR"/tag.json ; then
- local sha=$(jq --raw-output .commit.sha < "$TMP_DIR"/tag.json)
- if test "$sha" != "$SHA" ; then
- cat "$TMP_DIR"/tag.json
- echo "the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA"
- false
- fi
+ if get_tag; then
+ if ! matched_tag; then
+ cat "$TAG_FILE"
+ echo "the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA"
+ return 1
+ fi
else
- api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}'
+ create_tag
+ fi
+}
+
+create_tag() {
+ api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}' >"$TAG_FILE"
+}
+
+delete_tag() {
+ if get_tag; then
+ api DELETE repos/$REPO/tags/$TAG
+ rm -f "$TAG_FILE"
fi
}
@@ -50,15 +82,15 @@ upload_release() {
for file in "$RELEASE_DIR"/*; do
assets=("${assets[@]}" -a "$file")
done
- if $PRERELEASE || echo "${TAG}" | grep -qi '\-rc' ; then
+ if $PRERELEASE || echo "${TAG}" | grep -qi '\-rc'; then
releaseType="--prerelease"
echo "Uploading as Pre-Release"
else
echo "Uploading as Stable"
fi
ensure_tag
- if ! "$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType} >& "$TMP_DIR"/tea.log ; then
- if grep --quiet 'Unknown API Error: 500' "$TMP_DIR"/tea.log && grep --quiet services/release/release.go:194 "$TMP_DIR"/tea.log ; then
+ if ! "$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType} >&"$TMP_DIR"/tea.log; then
+ if grep --quiet 'Unknown API Error: 500' "$TMP_DIR"/tea.log && grep --quiet services/release/release.go:194 "$TMP_DIR"/tea.log; then
echo "workaround v1.20 race condition https://codeberg.org/forgejo/forgejo/issues/1370"
sleep 10
"$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType}
@@ -90,29 +122,31 @@ maybe_use_release_note_assistant() {
sign_release() {
local passphrase
if test -s "$GPG_PASSPHRASE"; then
- passphrase="--passphrase-file $GPG_PASSPHRASE"
+ passphrase="--passphrase-file $GPG_PASSPHRASE"
fi
gpg --import --no-tty --pinentry-mode loopback $passphrase "$GPG_PRIVATE_KEY"
- for asset in "$RELEASE_DIR"/* ; do
- if [[ $asset =~ .sha256$ ]] ; then
- continue
- fi
- gpg --armor --detach-sign --no-tty --pinentry-mode loopback $passphrase < "$asset" > "$asset".asc
+ for asset in "$RELEASE_DIR"/*; do
+ if [[ $asset =~ .sha256$ ]]; then
+ continue
+ fi
+ gpg --armor --detach-sign --no-tty --pinentry-mode loopback $passphrase <"$asset" >"$asset".asc
done
}
maybe_sign_release() {
if test -s "$GPG_PRIVATE_KEY"; then
- sign_release
+ sign_release
fi
}
maybe_override() {
if test "$OVERRIDE" = "false"; then
- return
+ return
+ fi
+ api DELETE repos/$REPO/releases/tags/"$TAG" >&/dev/null || true
+ if get_tag && ! matched_tag; then
+ delete_tag
fi
- api DELETE repos/$REPO/releases/tags/"$TAG" >& /dev/null || true
- api DELETE repos/$REPO/tags/"$TAG" >& /dev/null || true
}
upload() {
@@ -126,9 +160,9 @@ upload() {
}
setup_api() {
- if ! which jq curl ; then
- apt-get -qq update
- apt-get install -y -qq jq curl
+ if ! which jq curl; then
+ apt-get -qq update
+ apt-get install -y -qq jq curl
fi
}
@@ -144,40 +178,40 @@ api() {
wait_release() {
local ready=false
for i in $(seq $RETRY); do
- if api GET repos/$REPO/releases/tags/"$TAG" | jq --raw-output .draft > "$TMP_DIR"/draft; then
- if test "$(cat "$TMP_DIR"/draft)" = "false"; then
- ready=true
- break
+ if api GET repos/$REPO/releases/tags/"$TAG" | jq --raw-output .draft >"$TMP_DIR"/draft; then
+ if test "$(cat "$TMP_DIR"/draft)" = "false"; then
+ ready=true
+ break
+ fi
+ echo "release $TAG is still a draft"
+ else
+ echo "release $TAG does not exist yet"
fi
- echo "release $TAG is still a draft"
- else
- echo "release $TAG does not exist yet"
- fi
- echo "waiting $DELAY seconds"
- sleep $DELAY
+ echo "waiting $DELAY seconds"
+ sleep $DELAY
done
- if ! $ready ; then
- echo "no release for $TAG"
- return 1
+ if ! $ready; then
+ echo "no release for $TAG"
+ return 1
fi
}
download() {
setup_api
(
- mkdir -p $RELEASE_DIR
- cd $RELEASE_DIR
- if [[ ${DOWNLOAD_LATEST} == "true" ]] ; then
- echo "Downloading the latest release"
- api GET repos/$REPO/releases/latest > "$TMP_DIR"/assets.json
- elif [[ ${DOWNLOAD_LATEST} == "false" ]] ; then
- wait_release
- echo "Downloading tagged release ${TAG}"
- api GET repos/$REPO/releases/tags/"$TAG" > "$TMP_DIR"/assets.json
- fi
- jq --raw-output '.assets[] | "\(.browser_download_url) \(.name)"' < "$TMP_DIR"/assets.json | while read url name ; do # `name` may contain whitespace, therefore, it must be last
- curl --fail -H "Authorization: token $TOKEN" -o "$name" -L "$url"
- done
+ mkdir -p $RELEASE_DIR
+ cd $RELEASE_DIR
+ if [[ ${DOWNLOAD_LATEST} == "true" ]]; then
+ echo "Downloading the latest release"
+ api GET repos/$REPO/releases/latest >"$TMP_DIR"/assets.json
+ elif [[ ${DOWNLOAD_LATEST} == "false" ]]; then
+ wait_release
+ echo "Downloading tagged release ${TAG}"
+ api GET repos/$REPO/releases/tags/"$TAG" >"$TMP_DIR"/assets.json
+ fi
+ jq --raw-output '.assets[] | "\(.browser_download_url) \(.name)"' <"$TMP_DIR"/assets.json | while read url name; do # `name` may contain whitespace, therefore, it must be last
+ curl --fail -H "Authorization: token $TOKEN" -o "$name" -L "$url"
+ done
)
}
diff --git a/renovate.json b/renovate.json
index e95bd65..1fd35ff 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,6 +1,22 @@
{
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
- "extends": [
- "local>actions/renovate-config"
- ]
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ "local>actions/renovate-config"
+ ],
+ "customManagers": [
+ {
+ "customType": "regex",
+ "description": "update example in README.md",
+ "managerFilePatterns": [
+ "/^README.md$/"
+ ],
+ "matchStrings": [
+ "uses: actions/forgejo-release@(?v\\d+\\.\\d+\\.\\d+)"
+ ],
+ "datasourceTemplate": "gitea-tags",
+ "depNameTemplate": "actions/forgejo-release",
+ "versioningTemplate": "semver",
+ "registryUrlTemplate": "https://code.forgejo.org"
+ }
+ ]
}
diff --git a/testdata/forgejo-release-test.sh b/testdata/forgejo-release-test.sh
index 4e84498..156fb6b 100755
--- a/testdata/forgejo-release-test.sh
+++ b/testdata/forgejo-release-test.sh
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
set -ex
+PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: '
test_teardown() {
setup_api
@@ -38,24 +39,37 @@ test_wait_release() {
! wait_release
}
+test_create_delete_tag() {
+ delete_tag
+
+ ! get_tag
+ create_tag
+ get_tag
+ delete_tag
+ ! get_tag
+}
+
test_ensure_tag() {
- api DELETE repos/$REPO/tags/$TAG || true
+ delete_tag
#
# idempotent
#
ensure_tag
- api GET repos/$REPO/tags/$TAG > $TMP_DIR/tag1.json
+ mv $TAG_FILE $TMP_DIR/tag1.json
+
ensure_tag
- api GET repos/$REPO/tags/$TAG > $TMP_DIR/tag2.json
+ mv $TAG_FILE $TMP_DIR/tag2.json
+
diff -u $TMP_DIR/tag[12].json
#
# sanity check on the SHA of an existing tag
#
(
- SHA=12345
- ! ensure_tag
+ SHA=12345
+ ! matched_tag
+ ! ensure_tag
)
- api DELETE repos/$REPO/tags/$TAG
+ delete_tag
}
test_maybe_sign_release_no_gpg() {
@@ -94,8 +108,8 @@ test_maybe_sign_release_skipped() {
}
test_maybe_sign_release_verify() {
- for file in $RELEASE_DIR/file-one.txt $RELEASE_DIR/file-two.txt; do
- gpg --verify $file.asc $file
+ for file in $RELEASE_DIR/file-one.txt $RELEASE_DIR/file-two.txt; do
+ gpg --verify $file.asc $file
done
}
@@ -129,6 +143,7 @@ test_run() {
REPO=$user/$project
test_setup $project
test_ensure_tag
+ test_create_delete_tag
DELAY=0
test_wait_release_fail
echo "================================ TEST BEGIN"
diff --git a/testdata/nested-upload-download/.forgejo/workflows/test.yml b/testdata/nested-upload-download/.forgejo/workflows/test.yml
index 4c6bd91..dffd1ea 100644
--- a/testdata/nested-upload-download/.forgejo/workflows/test.yml
+++ b/testdata/nested-upload-download/.forgejo/workflows/test.yml
@@ -10,9 +10,9 @@ jobs:
setup-forgejo:
runs-on: self-hosted
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- id: forgejo
- uses: https://code.forgejo.org/actions/setup-forgejo@v1
+ uses: https://code.forgejo.org/actions/setup-forgejo@v2.0.11
with:
user: testuser
password: admin1234
diff --git a/testdata/upload-download/.forgejo/workflows/gpg-no-passphrase.yml b/testdata/upload-download/.forgejo/workflows/gpg-no-passphrase.yml
index 8679fc5..db74ade 100644
--- a/testdata/upload-download/.forgejo/workflows/gpg-no-passphrase.yml
+++ b/testdata/upload-download/.forgejo/workflows/gpg-no-passphrase.yml
@@ -90,7 +90,7 @@ jobs:
upload-gpg-no-passphrase:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
id: release-upload
uses: SELF@vTest
diff --git a/testdata/upload-download/.forgejo/workflows/gpg.yml b/testdata/upload-download/.forgejo/workflows/gpg.yml
index 8eb043e..49475d1 100644
--- a/testdata/upload-download/.forgejo/workflows/gpg.yml
+++ b/testdata/upload-download/.forgejo/workflows/gpg.yml
@@ -93,7 +93,7 @@ jobs:
upload-gpg:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
id: release-upload
uses: SELF@vTest
diff --git a/testdata/upload-download/.forgejo/workflows/test.yml b/testdata/upload-download/.forgejo/workflows/test.yml
index a88867a..f2bbe6f 100644
--- a/testdata/upload-download/.forgejo/workflows/test.yml
+++ b/testdata/upload-download/.forgejo/workflows/test.yml
@@ -6,7 +6,7 @@ jobs:
upload-download:
runs-on: self-hosted
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
id: release-upload
uses: SELF@vTest