Skip to content

Commit 04bdf5a

Browse files
authored
cli/ci: avoid stdin hang and add weekly parity alert
2 parents 87c313e + ff0cdf1 commit 04bdf5a

9 files changed

Lines changed: 292 additions & 7 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: knope-release
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: write
8+
9+
jobs:
10+
release:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Check release token
14+
env:
15+
KNOPE_RELEASE_TOKEN: ${{ secrets.UNRAID_BOT_GITHUB_ADMIN_TOKEN }}
16+
run: |
17+
if [ -z "$KNOPE_RELEASE_TOKEN" ]; then
18+
echo "UNRAID_BOT_GITHUB_ADMIN_TOKEN is required to create a release that triggers workflows." >&2
19+
exit 1
20+
fi
21+
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
token: ${{ secrets.UNRAID_BOT_GITHUB_ADMIN_TOKEN }}
27+
28+
- name: Install Knope
29+
uses: knope-dev/action@v2.1.0
30+
with:
31+
version: 0.22.1
32+
github-token: ${{ secrets.UNRAID_BOT_GITHUB_ADMIN_TOKEN }}
33+
34+
- name: Create release
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.UNRAID_BOT_GITHUB_ADMIN_TOKEN }}
37+
run: knope release

.github/workflows/parity.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ on:
55
push:
66
branches:
77
- main
8+
schedule:
9+
- cron: "0 9 * * 1"
810

911
jobs:
1012
parity:
1113
runs-on: ubuntu-latest
14+
env:
15+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
1216
steps:
1317
- name: Checkout
1418
uses: actions/checkout@v4
@@ -28,6 +32,12 @@ jobs:
2832

2933
- name: Run parity tests
3034
run: bash scripts/ci/run_parity_tests.sh
35+
- name: Notify Discord on scheduled parity failure
36+
if: failure() && github.event_name == 'schedule' && env.DISCORD_WEBHOOK != ''
37+
run: |
38+
run_url="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
39+
payload=$(printf '{"content":"parity cron failed for %s: %s"}' "$GITHUB_REPOSITORY" "$run_url")
40+
curl -sS -X POST -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK"
3141
3242
build:
3343
runs-on: ubuntu-latest

.github/workflows/release.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: release
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
include:
18+
- goos: linux
19+
goarch: amd64
20+
- goos: linux
21+
goarch: arm64
22+
- goos: darwin
23+
goarch: amd64
24+
notarize: true
25+
- goos: darwin
26+
goarch: arm64
27+
notarize: true
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@34e1148
31+
32+
- name: Set up Go
33+
uses: actions/setup-go@40f1582
34+
with:
35+
go-version-file: go.mod
36+
37+
- name: Build binary
38+
env:
39+
GOOS: ${{ matrix.goos }}
40+
GOARCH: ${{ matrix.goarch }}
41+
CGO_ENABLED: "0"
42+
run: |
43+
mkdir -p dist
44+
go build -o "dist/apprise-go-${GOOS}-${GOARCH}" ./cmd/apprise
45+
46+
- name: Write signing certificate
47+
if: matrix.notarize
48+
env:
49+
APPLE_BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }}
50+
run: |
51+
printf '%s' "$APPLE_BUILD_CERTIFICATE_BASE64" | base64 --decode > apple_codesign.p12
52+
chmod 600 apple_codesign.p12
53+
54+
- name: Write App Store Connect API key
55+
if: matrix.notarize
56+
env:
57+
APP_STORE_CONNECT_KEY_JSON: ${{ secrets.APPLE_APP_STORE_CONNECT_KEY_JSON }}
58+
run: |
59+
printf '%s' "$APP_STORE_CONNECT_KEY_JSON" > app_store_connect_key.json
60+
chmod 600 app_store_connect_key.json
61+
62+
- name: Sign and notarize darwin binary
63+
if: matrix.notarize
64+
uses: indygreg/apple-code-sign-action@44d0985b
65+
with:
66+
input_path: dist/apprise-go-${{ matrix.goos }}-${{ matrix.goarch }}
67+
p12_file: apple_codesign.p12
68+
p12_password: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }}
69+
notarize: true
70+
app_store_connect_api_key_json_file: app_store_connect_key.json
71+
72+
- name: Cleanup signing materials
73+
if: always()
74+
run: rm -f apple_codesign.p12 app_store_connect_key.json
75+
76+
- name: Upload release asset
77+
if: github.event_name == 'release'
78+
uses: softprops/action-gh-release@a06a81a0
79+
with:
80+
files: dist/apprise-go-${{ matrix.goos }}-${{ matrix.goarch }}
81+
82+
- name: Upload artifact
83+
if: github.event_name != 'release'
84+
uses: actions/upload-artifact@ea165f8d
85+
with:
86+
name: apprise-go-${{ matrix.goos }}-${{ matrix.goarch }}
87+
path: dist/apprise-go-${{ matrix.goos }}-${{ matrix.goarch }}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: sync-upstream-version
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
allow_sync:
7+
description: Allow updating UpstreamVersion
8+
type: boolean
9+
required: false
10+
default: false
11+
schedule:
12+
- cron: "0 12 * * 1"
13+
14+
permissions:
15+
contents: write
16+
pull-requests: write
17+
18+
jobs:
19+
sync:
20+
if: vars.ALLOW_UPSTREAM_VERSION_SYNC == 'true' || inputs.allow_sync == 'true'
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Fetch latest upstream release
27+
id: upstream
28+
run: |
29+
set -euo pipefail
30+
api="https://api.github.com/repos/caronc/apprise/releases/latest"
31+
tag="$(curl -sSL "$api" | jq -r '.tag_name')"
32+
if [ -z "$tag" ] || [ "$tag" = "null" ]; then
33+
echo "Failed to read latest upstream release tag." >&2
34+
exit 1
35+
fi
36+
version="${tag#v}"
37+
echo "tag=$tag" >> "$GITHUB_OUTPUT"
38+
echo "version=$version" >> "$GITHUB_OUTPUT"
39+
40+
- name: Update UpstreamVersion
41+
env:
42+
UPSTREAM_VERSION: ${{ steps.upstream.outputs.version }}
43+
run: |
44+
python - <<'PY'
45+
import os
46+
import re
47+
from pathlib import Path
48+
49+
path = Path("internal/version/version.go")
50+
data = path.read_text()
51+
version = os.environ["UPSTREAM_VERSION"]
52+
pattern = r'(var\s+UpstreamVersion\s*=\s*")([^"]+)(")'
53+
updated, count = re.subn(pattern, r'\g<1>' + version + r'\g<3>', data)
54+
if count == 0:
55+
raise SystemExit("UpstreamVersion not found in version.go")
56+
if updated != data:
57+
path.write_text(updated)
58+
PY
59+
60+
- name: Create pull request
61+
uses: peter-evans/create-pull-request@v7
62+
with:
63+
branch: chore/sync-upstream-version
64+
delete-branch: true
65+
commit-message: "chore: sync upstream apprise version to ${{ steps.upstream.outputs.tag }}"
66+
title: "chore: sync upstream apprise version to ${{ steps.upstream.outputs.tag }}"
67+
body: |
68+
Syncs `internal/version.UpstreamVersion` to the latest upstream release.
69+
70+
Upstream release: `${{ steps.upstream.outputs.tag }}`

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog for apprise-go
2+
3+
This project maintains its own release version. Compatibility with upstream
4+
`caronc/apprise` releases is tracked separately via
5+
`internal/version.UpstreamVersion`.

internal/cli/cli.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,6 @@ func Run(args []string, stdout, stderr io.Writer) int {
6666
return 0
6767
}
6868

69-
if body == "" {
70-
data, err := io.ReadAll(os.Stdin)
71-
if err == nil {
72-
body = string(data)
73-
}
74-
}
75-
7669
nt, ok := notify.ParseNotifyType(notificationType)
7770
if !ok {
7871
fmt.Fprintf(stderr, "unsupported notification type: %s\n", notificationType)
@@ -85,6 +78,13 @@ func Run(args []string, stdout, stderr io.Writer) int {
8578
return 1
8679
}
8780

81+
if body == "" {
82+
data, err := io.ReadAll(os.Stdin)
83+
if err == nil {
84+
body = string(data)
85+
}
86+
}
87+
8888
_ = inputFormat
8989
_ = disableAsync
9090

internal/cli/cli_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cli
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"testing"
7+
"time"
8+
)
9+
10+
func TestRunNoArgsDoesNotReadStdin(t *testing.T) {
11+
oldStdin := os.Stdin
12+
reader, writer, err := os.Pipe()
13+
if err != nil {
14+
t.Fatalf("pipe: %v", err)
15+
}
16+
os.Stdin = reader
17+
defer func() {
18+
os.Stdin = oldStdin
19+
_ = reader.Close()
20+
_ = writer.Close()
21+
}()
22+
23+
stdout := &bytes.Buffer{}
24+
stderr := &bytes.Buffer{}
25+
done := make(chan int, 1)
26+
go func() {
27+
done <- Run([]string{}, stdout, stderr)
28+
}()
29+
30+
select {
31+
case code := <-done:
32+
if code != 1 {
33+
t.Fatalf("expected exit code 1, got %d", code)
34+
}
35+
case <-time.After(500 * time.Millisecond):
36+
_ = writer.Close()
37+
select {
38+
case code := <-done:
39+
t.Fatalf("Run blocked on stdin (exit code %d)", code)
40+
case <-time.After(500 * time.Millisecond):
41+
t.Fatalf("Run blocked on stdin after closing pipe")
42+
}
43+
}
44+
}

internal/version/version.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ const (
1212
// Override at build time with: -ldflags "-X github.com/unraid/apprise-go/internal/version.Version=1.2.3"
1313
var Version = "1.9.7"
1414

15+
// UpstreamVersion tracks the caronc/apprise release version we are compatible with.
16+
// Override at build time with: -ldflags "-X github.com/unraid/apprise-go/internal/version.UpstreamVersion=1.2.3"
17+
var UpstreamVersion = "1.9.7"
18+
1519
func Message() string {
1620
return fmt.Sprintf("%s v%s\n%s\nThis code is licensed under the %s License.", Title, Version, Copyright, License)
1721
}

knope.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "apprise-go"
3+
changelog = "CHANGELOG.md"
4+
versioned_files = [
5+
{ path = "internal/version/version.go", regex = "var\\s+Version\\s*=\\s*\\\"(?<version>[^\\\"]+)\\\"" }
6+
]
7+
8+
[[workflows]]
9+
name = "release"
10+
11+
[[workflows.steps]]
12+
type = "PrepareRelease"
13+
14+
[[workflows.steps]]
15+
type = "Release"
16+
17+
[[workflows]]
18+
name = "document-change"
19+
20+
[[workflows.steps]]
21+
type = "CreateChangeFile"
22+
23+
[bot.releases]
24+
enabled = true
25+
26+
[github]
27+
owner = "unraid"
28+
repo = "apprise-go"

0 commit comments

Comments
 (0)