Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: Release

on:
push:
branches:
- main
tags:
- "v*"

Expand All @@ -22,6 +20,14 @@ jobs:
with:
fetch-depth: 0 # Full history required for changelog generation

- name: Verify tag is on main
run: |
git fetch origin main
if ! git merge-base --is-ancestor HEAD origin/main; then
echo "Tag v${{ github.ref_name }} is not an ancestor of main — refusing release."
exit 1
fi

- name: Set up Go
uses: actions/setup-go@v5
with:
Expand Down
3 changes: 3 additions & 0 deletions internal/plugins/runcommand/runcommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type RunCommandPlugin struct {
Commands map[string]string
CommandsPerDevice map[string]map[string]string // keyed by device ID
logger *zap.Logger
wg sync.WaitGroup // exported for tests to synchronize with background goroutines
}

func NewRunCommandPlugin(commands map[string]string, commandsPerDevice map[string]map[string]string, logger *zap.Logger) *RunCommandPlugin {
Expand Down Expand Up @@ -110,7 +111,9 @@ func (p *RunCommandPlugin) Handle(ctx context.Context, dev device.Sender, pkt *p

// Handlers must not block. Spawning goroutine to run the command
// and optionally send a notification with the output.
p.wg.Add(1)
go func() {
defer p.wg.Done()
execCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

Expand Down
3 changes: 3 additions & 0 deletions internal/plugins/runcommand/runcommand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestRunCommandPlugin_Handle_GlobalCommand(t *testing.T) {
if err := p.Handle(context.Background(), dev, pkt); err != nil {
t.Fatalf("Handle failed: %v", err)
}
p.wg.Wait()
}

func TestRunCommandPlugin_Handle_PerDeviceOverrides(t *testing.T) {
Expand All @@ -41,13 +42,15 @@ func TestRunCommandPlugin_Handle_PerDeviceOverrides(t *testing.T) {
if err := p.Handle(context.Background(), dev1, pkt); err != nil {
t.Fatalf("Handle for dev1 failed: %v", err)
}
p.wg.Wait()

// Device dev2 should fall back to the global command.
dev2 := device.NewDevice("dev2", "Phone 2", "phone", logger)
pkt, _ = protocol.NewPacket("kdeconnect.runcommand.request", RequestBody{Key: "cmd"})
if err := p.Handle(context.Background(), dev2, pkt); err != nil {
t.Fatalf("Handle for dev2 failed: %v", err)
}
p.wg.Wait()
}

func TestRunCommandPlugin_Handle_RequestCommandList(t *testing.T) {
Expand Down
Loading