Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package semaphore for openSUSE:Factory 
checked in at 2026-03-23 17:14:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/semaphore (Old)
 and      /work/SRC/openSUSE:Factory/.semaphore.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "semaphore"

Mon Mar 23 17:14:28 2026 rev:36 rq:1341962 version:2.17.28

Changes:
--------
--- /work/SRC/openSUSE:Factory/semaphore/semaphore.changes      2026-03-20 
21:26:01.885037437 +0100
+++ /work/SRC/openSUSE:Factory/.semaphore.new.8177/semaphore.changes    
2026-03-23 17:16:18.533012600 +0100
@@ -1,0 +2,23 @@
+Mon Mar 23 06:22:01 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 2.17.28:
+  This release improves runner-to-task tracking and fixes task
+  status handling in the runner update flow.
+  A new runner_id field was added to tasks in the database, which
+  makes it possible to persist the association between a task and
+  the runner executing it. This improves internal task tracking and
+  lays the groundwork for more reliable runner state handling.
+  This release also fixes a bug in the runner update logic where
+  the current task state was checked using the wrong field. In
+  api/runners/runners.go, the status check was corrected from
+  job.Status.IsFinished() to tsk.Task.Status.IsFinished(), ensuring
+  the system evaluates the actual stored task state before applying
+  runner updates. This makes task state transitions more accurate
+  during runner execution.
+  * What's changed
+    - Added runner_id to the task record in the database for better
+      runner-to-task association. (#3712)
+    - Fixed runner task status validation to use the actual task
+      status field instead of the job status field.
+
+-------------------------------------------------------------------

Old:
----
  semaphore-2.17.27.obscpio
  web-2.17.27.tar.gz

New:
----
  semaphore-2.17.28.obscpio
  web-2.17.28.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ semaphore.spec ++++++
--- /var/tmp/diff_new_pack.dVMDRL/_old  2026-03-23 17:16:22.729187118 +0100
+++ /var/tmp/diff_new_pack.dVMDRL/_new  2026-03-23 17:16:22.733187284 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           semaphore
-Version:        2.17.27
+Version:        2.17.28
 Release:        0
 Summary:        Modern UI for Ansible
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.dVMDRL/_old  2026-03-23 17:16:22.833191443 +0100
+++ /var/tmp/diff_new_pack.dVMDRL/_new  2026-03-23 17:16:22.837191610 +0100
@@ -3,8 +3,8 @@
     <param name="url">https://github.com/ansible-semaphore/semaphore</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v2.17.27</param>
-    <param name="match-tag">v2.17.27</param>
+    <param name="revision">v2.17.28</param>
+    <param name="match-tag">v2.17.28</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.dVMDRL/_old  2026-03-23 17:16:22.913194771 +0100
+++ /var/tmp/diff_new_pack.dVMDRL/_new  2026-03-23 17:16:22.921195103 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/ansible-semaphore/semaphore</param>
-              <param 
name="changesrevision">9c5ed3b01d0266cc61f43dfca99bf23fa6f78252</param></service></servicedata>
+              <param 
name="changesrevision">0d961bf3d0106d7f1fd7bf674e824740ee98801e</param></service></servicedata>
 (No newline at EOF)
 

++++++ semaphore-2.17.27.obscpio -> semaphore-2.17.28.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/api/projects/tasks.go 
new/semaphore-2.17.28/api/projects/tasks.go
--- old/semaphore-2.17.27/api/projects/tasks.go 2026-03-19 17:07:32.000000000 
+0100
+++ new/semaphore-2.17.28/api/projects/tasks.go 2026-03-22 14:56:57.000000000 
+0100
@@ -365,7 +365,12 @@
        editor := helpers.GetFromContext(r, "user").(*db.User)
        project := helpers.GetFromContext(r, "project").(db.Project)
 
-       activeTask := taskPool(r).GetTask(targetTask.ID)
+       activeTask, err := taskPool(r).GetTask(targetTask.ID)
+
+       if err != nil {
+               helpers.WriteError(w, err)
+               return
+       }
 
        if activeTask != nil {
                // can't delete task in queue or running
@@ -380,7 +385,7 @@
                return
        }
 
-       err := helpers.Store(r).DeleteTaskWithOutputs(project.ID, targetTask.ID)
+       err = helpers.Store(r).DeleteTaskWithOutputs(project.ID, targetTask.ID)
        if err != nil {
                util.LogErrorF(err, log.Fields{"error": "Bad request. Cannot 
delete task from database"})
                w.WriteHeader(http.StatusBadRequest)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/api/runners/runners.go 
new/semaphore-2.17.28/api/runners/runners.go
--- old/semaphore-2.17.27/api/runners/runners.go        2026-03-19 
17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/api/runners/runners.go        2026-03-22 
14:56:57.000000000 +0100
@@ -258,9 +258,14 @@
        }
 
        for _, job := range body.Jobs {
-               tsk := taskPool.GetTask(job.ID)
+               tsk, err := taskPool.GetTask(job.ID)
 
-               if tsk == nil {
+               if err != nil {
+                       log.WithError(err).WithFields(log.Fields{
+                               "task_id":   job.ID,
+                               "runner_id": runner.ID,
+                               "context":   "runner",
+                       }).Warn("runner progress: task not in local pool and 
could not be loaded from database")
                        continue
                }
 
@@ -278,10 +283,12 @@
                        return
                }
 
-               tsk.SetStatus(job.Status)
+               if !tsk.Task.Status.IsFinished() {
+                       tsk.SetStatus(job.Status)
 
-               if job.Commit != nil {
-                       tsk.SetCommit(job.Commit.Hash, job.Commit.Message)
+                       if job.Commit != nil {
+                               tsk.SetCommit(job.Commit.Hash, 
job.Commit.Message)
+                       }
                }
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/cli/cmd/root.go 
new/semaphore-2.17.28/cli/cmd/root.go
--- old/semaphore-2.17.27/cli/cmd/root.go       2026-03-19 17:07:32.000000000 
+0100
+++ new/semaphore-2.17.28/cli/cmd/root.go       2026-03-22 14:56:57.000000000 
+0100
@@ -6,6 +6,7 @@
        "net/url"
        "os"
        "strings"
+       "time"
 
        "github.com/gorilla/handlers"
        "github.com/semaphoreui/semaphore/api"
@@ -137,6 +138,20 @@
                schedulePool.SetDeduplicator(dedup)
        }
 
+       // Each process holds its own in-memory cron table. Schedule CRUD 
handlers only
+       // call Refresh on the node that served the HTTP request, so other HA 
nodes
+       // would keep stale jobs until restart. Reload from the shared DB on an 
interval.
+       if util.HAEnabled() {
+               const haSchedulePoolSyncInterval = 60 * time.Second
+               go func() {
+                       ticker := time.NewTicker(haSchedulePoolSyncInterval)
+                       defer ticker.Stop()
+                       for range ticker.C {
+                               schedulePool.Refresh()
+                       }
+               }()
+       }
+
        if orphanCleaner := proHA.NewOrphanCleaner(store); orphanCleaner != nil 
{
                orphanCleaner.Start()
                defer orphanCleaner.Stop()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/Migration.go 
new/semaphore-2.17.28/db/Migration.go
--- old/semaphore-2.17.27/db/Migration.go       2026-03-19 17:07:32.000000000 
+0100
+++ new/semaphore-2.17.28/db/Migration.go       2026-03-22 14:56:57.000000000 
+0100
@@ -120,6 +120,7 @@
                {Version: "2.17.1"},
                {Version: "2.17.2"},
                {Version: "2.17.15"},
+               {Version: "2.17.16"},
        }
 
        return append(initScripts, commonScripts...)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/Store.go 
new/semaphore-2.17.28/db/Store.go
--- old/semaphore-2.17.27/db/Store.go   2026-03-19 17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/db/Store.go   2026-03-22 14:56:57.000000000 +0100
@@ -399,6 +399,7 @@
        GetTemplateTasks(projectID int, templateID int, params 
RetrieveQueryParams) ([]TaskWithTpl, error)
        GetProjectTasks(projectID int, params RetrieveQueryParams) 
([]TaskWithTpl, error)
        GetTask(projectID int, taskID int) (Task, error)
+       GetTaskByID(taskID int) (Task, error)
        DeleteTaskWithOutputs(projectID int, taskID int) error
        GetTaskOutputs(projectID int, taskID int, params RetrieveQueryParams) 
([]TaskOutput, error)
        CreateTaskOutput(output TaskOutput) (TaskOutput, error)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/Task.go 
new/semaphore-2.17.28/db/Task.go
--- old/semaphore-2.17.27/db/Task.go    2026-03-19 17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/db/Task.go    2026-03-22 14:56:57.000000000 +0100
@@ -54,6 +54,9 @@
        UserID        *int `db:"user_id" json:"user_id,omitempty"`
        IntegrationID *int `db:"integration_id" json:"integration_id,omitempty"`
        ScheduleID    *int `db:"schedule_id" json:"schedule_id,omitempty"`
+       // RunnerID is set while a task is assigned to a remote runner (cleared 
when the task finishes).
+       // Used so runner progress API can authorize updates on any HA node.
+       RunnerID *int `db:"runner_id" json:"-"`
 
        Created time.Time  `db:"created" json:"created"`
        Start   *time.Time `db:"start" json:"start,omitempty"`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/bolt/task.go 
new/semaphore-2.17.28/db/bolt/task.go
--- old/semaphore-2.17.27/db/bolt/task.go       2026-03-19 17:07:32.000000000 
+0100
+++ new/semaphore-2.17.28/db/bolt/task.go       2026-03-22 14:56:57.000000000 
+0100
@@ -229,6 +229,11 @@
        return
 }
 
+func (d *BoltDb) GetTaskByID(taskID int) (task db.Task, err error) {
+       err = d.getObject(0, db.TaskProps, intObjectID(taskID), &task)
+       return
+}
+
 func (d *BoltDb) GetTemplateTasks(projectID int, templateID int, params 
db.RetrieveQueryParams) ([]db.TaskWithTpl, error) {
        return d.getTasks(projectID, &templateID, params)
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/sql/migrations/v2.17.16.err.sql 
new/semaphore-2.17.28/db/sql/migrations/v2.17.16.err.sql
--- old/semaphore-2.17.27/db/sql/migrations/v2.17.16.err.sql    1970-01-01 
01:00:00.000000000 +0100
+++ new/semaphore-2.17.28/db/sql/migrations/v2.17.16.err.sql    2026-03-22 
14:56:57.000000000 +0100
@@ -0,0 +1 @@
+alter table `task` drop column `runner_id`;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/sql/migrations/v2.17.16.sql 
new/semaphore-2.17.28/db/sql/migrations/v2.17.16.sql
--- old/semaphore-2.17.27/db/sql/migrations/v2.17.16.sql        1970-01-01 
01:00:00.000000000 +0100
+++ new/semaphore-2.17.28/db/sql/migrations/v2.17.16.sql        2026-03-22 
14:56:57.000000000 +0100
@@ -0,0 +1 @@
+alter table `task` add `runner_id` int null references `runner`(`id`) on 
delete set null;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/db/sql/task.go 
new/semaphore-2.17.28/db/sql/task.go
--- old/semaphore-2.17.27/db/sql/task.go        2026-03-19 17:07:32.000000000 
+0100
+++ new/semaphore-2.17.28/db/sql/task.go        2026-03-22 14:56:57.000000000 
+0100
@@ -196,19 +196,21 @@
 
        if task.CommitHash != nil {
                _, err = d.exec(
-                       "update task set status=?, start=?, `end`=?, 
commit_hash=?, commit_message=? where id=?",
+                       "update task set status=?, start=?, `end`=?, 
commit_hash=?, commit_message=?, runner_id=? where id=?",
                        task.Status,
                        task.Start,
                        task.End,
                        task.CommitHash,
                        task.CommitMessage,
+                       task.RunnerID,
                        task.ID)
        } else {
                _, err = d.exec(
-                       "update task set status=?, start=?, `end`=? where id=?",
+                       "update task set status=?, start=?, `end`=?, 
runner_id=? where id=?",
                        task.Status,
                        task.Start,
                        task.End,
+                       task.RunnerID,
                        task.ID)
        }
 
@@ -321,6 +323,11 @@
        return
 }
 
+func (d *SqlDb) GetTaskByID(taskID int) (task db.Task, err error) {
+       err = d.selectOne(&task, d.PrepareQuery("select * from task where 
id=?"), taskID)
+       return
+}
+
 func (d *SqlDb) GetTemplateTasks(projectID int, templateID int, params 
db.RetrieveQueryParams) (tasks []db.TaskWithTpl, err error) {
        err = d.getTasks(projectID, &templateID, nil, params, &tasks)
        return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/pkg/task_logger/task_logger.go 
new/semaphore-2.17.28/pkg/task_logger/task_logger.go
--- old/semaphore-2.17.27/pkg/task_logger/task_logger.go        2026-03-19 
17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/pkg/task_logger/task_logger.go        2026-03-22 
14:56:57.000000000 +0100
@@ -100,6 +100,30 @@
        return s == TaskStoppedStatus || s == TaskSuccessStatus || s == 
TaskFailStatus
 }
 
+// TaskStatusProgressRank orders statuses for comparing how far execution has 
progressed
+// (higher = further). Used in HA / remote-runner paths to avoid regressing 
status when
+// merging DB state with stale runtime-store snapshots.
+func TaskStatusProgressRank(s TaskStatus) int {
+       switch s {
+       case TaskWaitingStatus:
+               return 10
+       case TaskStartingStatus:
+               return 20
+       case TaskWaitingConfirmation:
+               return 25
+       case TaskConfirmed, TaskRejected:
+               return 26
+       case TaskRunningStatus:
+               return 40
+       case TaskStoppingStatus:
+               return 50
+       case TaskStoppedStatus, TaskSuccessStatus, TaskFailStatus:
+               return 100
+       default:
+               return 0
+       }
+}
+
 type StatusListener func(status TaskStatus)
 type LogListener func(new time.Time, msg string)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/services/tasks/RemoteJob.go 
new/semaphore-2.17.28/services/tasks/RemoteJob.go
--- old/semaphore-2.17.27/services/tasks/RemoteJob.go   2026-03-19 
17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/services/tasks/RemoteJob.go   2026-03-22 
14:56:57.000000000 +0100
@@ -93,7 +93,11 @@
 
 func (t *RemoteJob) Run(username string, incomingVersion *string, alias 
string) (err error) {
 
-       tsk := t.taskPool.GetTask(t.Task.ID)
+       tsk, err := t.taskPool.GetTask(t.Task.ID)
+
+       if err != nil {
+               return
+       }
 
        if tsk == nil {
                return fmt.Errorf("task not found")
@@ -151,6 +155,15 @@
        }
 
        tsk.RunnerID = runner.ID
+       tsk.Task.RunnerID = &runner.ID
+       db.StoreSession(t.taskPool.store, "remote job assign runner", func() {
+               err = t.taskPool.store.UpdateTask(tsk.Task)
+       })
+
+       if err != nil {
+               return
+       }
+
        if t.taskPool != nil && t.taskPool.state != nil {
                t.taskPool.state.UpdateRuntimeFields(tsk)
        }
@@ -166,13 +179,36 @@
                }
 
                time.Sleep(1_000_000_000)
-               tsk = t.taskPool.GetTask(t.Task.ID)
+               tsk, err = t.taskPool.GetTask(t.Task.ID)
+
+               if err != nil {
+                       return
+               }
 
                if tsk == nil {
                        err = fmt.Errorf("task %d not found", t.Task.ID)
                        return
                }
 
+               if util.HAEnabled() {
+                       var row db.Task
+                       var rowErr error
+                       db.StoreSession(t.taskPool.store, "remote job status 
sync", func() {
+                               row, rowErr = 
t.taskPool.store.GetTask(tsk.Task.ProjectID, t.Task.ID)
+                       })
+                       if rowErr == nil {
+                               // Never regress (e.g. running → starting) if 
the DB read is briefly stale.
+                               if 
task_logger.TaskStatusProgressRank(row.Status) >= 
task_logger.TaskStatusProgressRank(tsk.Task.Status) {
+                                       tsk.Task.Status = row.Status
+                                       tsk.Task.Start = row.Start
+                                       tsk.Task.End = row.End
+                               }
+                               if row.RunnerID != nil {
+                                       tsk.Task.RunnerID = row.RunnerID
+                               }
+                       }
+               }
+
                if tsk.Task.Status == task_logger.TaskSuccessStatus ||
                        tsk.Task.Status == task_logger.TaskStoppedStatus ||
                        tsk.Task.Status == task_logger.TaskFailStatus {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.17.27/services/tasks/TaskPool.go 
new/semaphore-2.17.28/services/tasks/TaskPool.go
--- old/semaphore-2.17.27/services/tasks/TaskPool.go    2026-03-19 
17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/services/tasks/TaskPool.go    2026-03-22 
14:56:57.000000000 +0100
@@ -132,7 +132,7 @@
        return p.state.RunningRange()
 }
 
-func (p *TaskPool) GetTask(id int) (task *TaskRunner) {
+func (p *TaskPool) GetTask(id int) (task *TaskRunner, err error) {
        for _, t := range p.state.QueueRange() {
                if t.Task.ID == id {
                        task = t
@@ -149,6 +149,12 @@
                }
        }
 
+       if util.HAEnabled() {
+               if task == nil {
+                       task, err = p.HydrateTaskRunnerFromDB(id)
+               }
+       }
+
        return
 }
 
@@ -170,12 +176,11 @@
                case task := <-p.register: // new task created by API or 
schedule
 
                        db.StoreSession(p.store, "new task", func() {
-                               //p.Queue = append(p.Queue, task)
-                               msg := "Task " + task.Template.Name + " added 
to queue"
-                               task.Log(msg)
+                               task.Log("Task " + task.Template.Name + " added 
to queue")
                                log.WithFields(log.Fields{
-                                       "task_id": task.Task.ID,
-                               }).Info(msg)
+                                       "task_id":   task.Task.ID,
+                                       "task_name": task.Template.Name,
+                               }).Info("Task added to queue")
                                task.saveStatus()
                        })
                        p.queueEvents <- PoolEvent{EventTypeNew, task}
@@ -188,7 +193,7 @@
 }
 
 func getTaskName(t *TaskRunner) string {
-       return t.Template.Name + " " + strconv.Itoa(t.Task.ID)
+       return t.Template.Name + " (" + strconv.Itoa(t.Task.ID) + ")"
 }
 
 func (p *TaskPool) handleQueue() {
@@ -340,10 +345,18 @@
 }
 
 func runTask(task *TaskRunner, p *TaskPool) {
-       log.Info("Set resource locker with TaskRunner " + getTaskName(task))
+       log.WithFields(log.Fields{
+               "context":   "task_pool",
+               "task_id":   task.Task.ID,
+               "task_name": task.Template.Name,
+       }).Info("Set resource locker")
        p.onTaskRun(task)
 
-       log.Info("Task " + getTaskName(task) + " started")
+       log.WithFields(log.Fields{
+               "context":   "task_pool",
+               "task_id":   task.Task.ID,
+               "task_name": task.Template.Name,
+       }).Info("Task started")
        go func() {
                time.Sleep(1 * time.Second)
                task.run()
@@ -367,6 +380,15 @@
        }
 }
 
+func applyDBPersistedTaskSnapshot(dst *db.Task, src db.Task) {
+       dst.Status = src.Status
+       dst.Start = src.Start
+       dst.End = src.End
+       dst.RunnerID = src.RunnerID
+       dst.CommitHash = src.CommitHash
+       dst.CommitMessage = src.CommitMessage
+}
+
 // hydrateTaskRunner builds a TaskRunner for an existing task from DB without 
starting it
 func (p *TaskPool) hydrateTaskRunner(taskID int, projectID int) (*TaskRunner, 
error) {
        task, err := p.store.GetTask(projectID, taskID)
@@ -381,6 +403,9 @@
        if p.state != nil {
                p.state.LoadRuntimeFields(tr)
        }
+       // Persisted row from DB must win over runtime-store fields: Redis may 
still hold a
+       // snapshot from enqueue time (e.g. status "starting") after the runner 
updated the DB.
+       //applyDBPersistedTaskSnapshot(&tr.Task, task)
        // set appropriate job handler for consistency (not run)
        var job Job
        if util.Config.UseRemoteRunner || tr.Template.RunnerTag != nil || 
tr.Inventory.RunnerTag != nil {
@@ -407,6 +432,23 @@
        return tr, nil
 }
 
+// HydrateTaskRunnerFromDB loads a task row by ID and builds a TaskRunner for 
API-side updates
+// (e.g. runner progress on an HA node that did not enqueue the task).
+func (p *TaskPool) HydrateTaskRunnerFromDB(taskID int) (*TaskRunner, error) {
+       row, err := p.store.GetTaskByID(taskID)
+       if err != nil {
+               return nil, err
+       }
+       tr, err := p.hydrateTaskRunner(taskID, row.ProjectID)
+       if err != nil {
+               return nil, err
+       }
+       if row.RunnerID != nil {
+               tr.RunnerID = *row.RunnerID
+       }
+       return tr, nil
+}
+
 func (p *TaskPool) blocks(t *TaskRunner) bool {
 
        if util.Config.MaxParallelTasks > 0 && p.state.RunningCount() >= 
util.Config.MaxParallelTasks {
@@ -443,7 +485,11 @@
 }
 
 func (p *TaskPool) ConfirmTask(targetTask db.Task) error {
-       tsk := p.GetTask(targetTask.ID)
+       tsk, err := p.GetTask(targetTask.ID)
+
+       if err != nil {
+               return err
+       }
 
        if tsk == nil { // task not active, but exists in database
                return fmt.Errorf("task is not active")
@@ -455,7 +501,11 @@
 }
 
 func (p *TaskPool) RejectTask(targetTask db.Task) error {
-       tsk := p.GetTask(targetTask.ID)
+       tsk, err := p.GetTask(targetTask.ID)
+
+       if err != nil {
+               return err
+       }
 
        if tsk == nil { // task not active, but exists in database
                return fmt.Errorf("task is not active")
@@ -467,7 +517,11 @@
 }
 
 func (p *TaskPool) StopTask(targetTask db.Task, forceStop bool) error {
-       tsk := p.GetTask(targetTask.ID)
+       tsk, err := p.GetTask(targetTask.ID)
+       if err != nil {
+               return err
+       }
+
        if tsk == nil { // task not active, but exists in database
 
                tsk = NewTaskRunner(targetTask, p, "", p.keyInstallationService)
@@ -551,7 +605,16 @@
                for _, twt := range tasks {
 
                        // if task is managed locally (queued/running), it was 
handled above
-                       if p.GetTask(twt.Task.ID) != nil {
+                       tsk, taskErr := p.GetTask(twt.ID)
+                       if taskErr != nil {
+                               log.WithError(err).WithFields(log.Fields{
+                                       "task_id": twt.ID,
+                                       "context": "task_pool",
+                               }).Warn("can't get task")
+
+                               continue
+                       }
+                       if tsk != nil {
                                continue
                        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/semaphore-2.17.27/services/tasks/TaskRunner_logging.go 
new/semaphore-2.17.28/services/tasks/TaskRunner_logging.go
--- old/semaphore-2.17.27/services/tasks/TaskRunner_logging.go  2026-03-19 
17:07:32.000000000 +0100
+++ new/semaphore-2.17.28/services/tasks/TaskRunner_logging.go  2026-03-22 
14:56:57.000000000 +0100
@@ -133,6 +133,12 @@
        for _, l := range t.statusListeners {
                l(status)
        }
+
+       log.WithFields(log.Fields{
+               "task_id": t.Task.ID,
+               "context": "task_logger",
+               "status":  status,
+       }).Info("Task status updated")
 }
 
 func (t *TaskRunner) panicOnError(err error, msg string) {

++++++ semaphore.obsinfo ++++++
--- /var/tmp/diff_new_pack.dVMDRL/_old  2026-03-23 17:16:24.849275292 +0100
+++ /var/tmp/diff_new_pack.dVMDRL/_new  2026-03-23 17:16:24.857275624 +0100
@@ -1,5 +1,5 @@
 name: semaphore
-version: 2.17.27
-mtime: 1773936452
-commit: 9c5ed3b01d0266cc61f43dfca99bf23fa6f78252
+version: 2.17.28
+mtime: 1774187817
+commit: 0d961bf3d0106d7f1fd7bf674e824740ee98801e
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/semaphore/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.semaphore.new.8177/vendor.tar.gz differ: char 151, 
line 2

++++++ web-2.17.27.tar.gz -> web-2.17.28.tar.gz ++++++
/work/SRC/openSUSE:Factory/semaphore/web-2.17.27.tar.gz 
/work/SRC/openSUSE:Factory/.semaphore.new.8177/web-2.17.28.tar.gz differ: char 
30, line 1

Reply via email to