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-08-28 19:53:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/semaphore (Old)
 and      /work/SRC/openSUSE:Factory/.semaphore.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "semaphore"

Fri Aug 28 19:53:41 2026 rev:56 rq:1374302 version:2.19.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/semaphore/semaphore.changes      2026-08-12 
16:14:28.215446158 +0200
+++ /work/SRC/openSUSE:Factory/.semaphore.new.1265/semaphore.changes    
2026-08-28 19:56:03.829184030 +0200
@@ -1,0 +2,9 @@
+Fri Aug 28 08:28:17 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 2.19.11 (.9 and .10 were not released):
+  * 0c3f373 test(db): add tests for db migration
+- Update to version 2.19.8:
+  * Bugfixes
+    - Fixed SQLite migration
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ semaphore.spec ++++++
--- /var/tmp/diff_new_pack.b1pZl5/_old  2026-08-28 19:56:14.523557924 +0200
+++ /var/tmp/diff_new_pack.b1pZl5/_new  2026-08-28 19:56:14.529558133 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           semaphore
-Version:        2.19.7
+Version:        2.19.11
 Release:        0
 Summary:        Modern UI for Ansible
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.b1pZl5/_old  2026-08-28 19:56:14.685563588 +0200
+++ /var/tmp/diff_new_pack.b1pZl5/_new  2026-08-28 19:56:14.699564077 +0200
@@ -4,8 +4,8 @@
     <param name="scm">git</param>
     <param name="submodules">disable</param>
     <param name="exclude">.git</param>
-    <param name="revision">refs/tags/v2.19.7</param>
-    <param name="match-tag">v2.19.7</param>
+    <param name="revision">refs/tags/v2.19.11</param>
+    <param name="match-tag">v2.19.11</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.b1pZl5/_old  2026-08-28 19:56:14.741565545 +0200
+++ /var/tmp/diff_new_pack.b1pZl5/_new  2026-08-28 19:56:14.748565790 +0200
@@ -3,6 +3,6 @@
                 <param 
name="url">https://github.com/ansible-semaphore/semaphore</param>
               <param 
name="changesrevision">8a4dcf0868af718aaa5871368a3247dd622521f4</param></service><service
 name="tar_scm">
                 <param 
name="url">https://github.com/ansible-semaphore/semaphore.git</param>
-              <param 
name="changesrevision">e9dc41a1de8a747569334f7a2b76c320b945d4f0</param></service></servicedata>
+              <param 
name="changesrevision">0c3f3738ea5ed988165afe499d896ff78b428c44</param></service></servicedata>
 (No newline at EOF)
 

++++++ semaphore-2.19.7.obscpio -> semaphore-2.19.11.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/Migration.go 
new/semaphore-2.19.11/db/Migration.go
--- old/semaphore-2.19.7/db/Migration.go        2026-07-30 19:15:03.000000000 
+0200
+++ new/semaphore-2.19.11/db/Migration.go       2026-08-26 15:30:53.000000000 
+0200
@@ -132,6 +132,7 @@
                {Version: "2.19.2"},
                {Version: "2.19.11"},
                {Version: "2.19.12"},
+               {Version: "2.19.14"},
        }
 
        return append(initScripts, commonScripts...)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/SqlDb.go 
new/semaphore-2.19.11/db/sql/SqlDb.go
--- old/semaphore-2.19.7/db/sql/SqlDb.go        2026-07-30 19:15:03.000000000 
+0200
+++ new/semaphore-2.19.11/db/sql/SqlDb.go       2026-08-26 15:30:53.000000000 
+0200
@@ -121,6 +121,42 @@
        }
 }
 
+func InitConfigCreateTestStore() *SqlDb {
+       return InitConfigCreateTestStoreAt(nil)
+}
+
+// InitConfigCreateTestStoreAt creates a test store migrated up to
+// targetVersion (or fully when nil), so tests can seed data on an older
+// schema and then apply the remaining migrations with db.Migrate.
+func InitConfigCreateTestStoreAt(targetVersion *string) *SqlDb {
+       util.Config = &util.ConfigType{
+               SQLite: &util.DbConfig{
+                       Hostname: ":memory:",
+               },
+               Dialect: "sqlite",
+               Log: &util.ConfigLog{
+                       Events: &util.EventLogType{},
+                       Tasks:  &util.TaskLogType{},
+               },
+               Process: &util.ConfigProcess{},
+               Runners: &util.RunnersConfig{},
+               Apps: map[string]util.App{
+                       "ansible": {},
+                       "bash":    {},
+               },
+       }
+       store := CreateDb(util.DbDriverSQLite)
+
+       store.Connect()
+
+       err := db.Migrate(store, targetVersion)
+       if err != nil {
+               panic(err)
+       }
+
+       return store
+}
+
 func CreateTestStore() *SqlDb {
        util.Config = &util.ConfigType{
                SQLite: &util.DbConfig{
@@ -410,7 +446,7 @@
 // validateMutationResult checks the success of the update query
 func validateMutationResult(res sql.Result, err error) error {
        if err != nil {
-               if strings.Contains(err.Error(), "foreign key") {
+               if strings.Contains(strings.ToLower(err.Error()), "foreign 
key") {
                        err = db.ErrInvalidOperation
                }
                return err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/migration.go 
new/semaphore-2.19.11/db/sql/migration.go
--- old/semaphore-2.19.7/db/sql/migration.go    2026-07-30 19:15:03.000000000 
+0200
+++ new/semaphore-2.19.11/db/sql/migration.go   2026-08-26 15:30:53.000000000 
+0200
@@ -211,6 +211,25 @@
                }
        }
 
+       // Rebuilding a table that other tables reference by foreign key must 
run
+       // with foreign_keys=OFF: with FK enforcement enabled, renaming rewrites
+       // child FK definitions and dropping cascade-deletes child rows. The 
pragma
+       // is a no-op inside a transaction, so toggle it on the connection 
itself
+       // (the pool is limited to a single connection for SQLite).
+       if sqliteNeedsFkOff(d.GetDialect(), migration.Version) {
+               if _, err = d.exec("PRAGMA foreign_keys = OFF"); err != nil {
+                       return err
+               }
+               defer func() {
+                       if _, fkErr := d.exec("PRAGMA foreign_keys = ON"); 
fkErr != nil {
+                               log.WithFields(log.Fields{
+                                       "context": "migration",
+                                       "version": migration.Version,
+                               }).WithError(fkErr).Fatal("failed to re-enable 
foreign_keys pragma after migration")
+                       }
+               }()
+       }
+
        tx, err := d.Sql().Begin()
        if err != nil {
                return err
@@ -279,10 +298,35 @@
        return tx.Commit()
 }
 
+// sqliteNeedsFkOff reports whether the migration rebuilds SQLite tables that
+// are referenced by other tables' foreign keys and therefore must be applied
+// (and rolled back) with FK enforcement disabled on the connection.
+func sqliteNeedsFkOff(dialect string, version string) bool {
+       return dialect == util.DbDriverSQLite && version == "2.19.14"
+}
+
 // TryRollbackMigration attempts to rollback the database to an earlier 
version if a rollback exists
 func (d *SqlDb) TryRollbackMigration(version db.Migration) {
        var err error
 
+       if sqliteNeedsFkOff(d.GetDialect(), version.Version) {
+               if _, err = d.exec("PRAGMA foreign_keys = OFF"); err != nil {
+                       log.WithFields(log.Fields{
+                               "context": "migration",
+                               "version": version.Version,
+                       }).WithError(err).Fatal("failed to disable foreign_keys 
pragma before migration")
+                       return
+               }
+               defer func() {
+                       if _, fkErr := d.exec("PRAGMA foreign_keys = ON"); 
fkErr != nil {
+                               log.WithFields(log.Fields{
+                                       "context": "migration",
+                                       "version": version.Version,
+                               }).WithError(fkErr).Fatal("failed to re-enable 
foreign_keys pragma after rollback")
+                       }
+               }()
+       }
+
        tx, err := d.Sql().Begin()
        if err != nil {
                panic(err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/migration_2_19_14_test.go 
new/semaphore-2.19.11/db/sql/migration_2_19_14_test.go
--- old/semaphore-2.19.7/db/sql/migration_2_19_14_test.go       1970-01-01 
01:00:00.000000000 +0100
+++ new/semaphore-2.19.11/db/sql/migration_2_19_14_test.go      2026-08-26 
15:30:53.000000000 +0200
@@ -0,0 +1,113 @@
+package sql
+
+import (
+       "testing"
+       "time"
+
+       "github.com/semaphoreui/semaphore/db"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+// TestMigration_2_19_14_DataSurvivesRebuild seeds data on the 2.19.12 schema
+// and then applies 2.19.14 to ensure the session/task rebuild keeps existing
+// rows intact — in particular dropping the old task table must not trigger
+// ON DELETE CASCADE into task__output.
+func TestMigration_2_19_14_DataSurvivesRebuild(t *testing.T) {
+       preRebuild := "2.19.12"
+       store := InitConfigCreateTestStoreAt(&preRebuild)
+
+       user, err := store.CreateUserWithoutPassword(db.User{
+               Username: "jdoe", Name: "John Doe", Email: "[email protected]",
+       })
+       require.NoError(t, err)
+
+       now := time.Now()
+       session, err := store.CreateSession(db.Session{
+               UserID:     user.ID,
+               Created:    now,
+               LastActive: now,
+               UserAgent:  "test",
+       })
+       require.NoError(t, err)
+
+       // newTemplateTestProject is unusable here: its CreateAccessKey call
+       // writes the task_id/expire_at columns which appear only in 2.20.1,
+       // so seed the access key with SQL matching the 2.19.12 schema.
+       project, err := store.CreateProject(db.Project{Name: "proj"})
+       require.NoError(t, err)
+       projectID := project.ID
+
+       keyID, err := store.insert("id",
+               "insert into access_key (name, type, project_id) values ('key', 
'none', ?)", projectID)
+       require.NoError(t, err)
+
+       repo, err := store.CreateRepository(db.Repository{
+               ProjectID: projectID,
+               Name:      "repo",
+               GitURL:    "https://example.com/repo.git";,
+               GitBranch: "main",
+               SSHKeyID:  keyID,
+       })
+       require.NoError(t, err)
+
+       template, err := store.CreateTemplate(db.Template{
+               ProjectID:    projectID,
+               RepositoryID: repo.ID,
+               Name:         "tpl",
+               Playbook:     "site.yml",
+       })
+       require.NoError(t, err)
+
+       task, err := store.CreateTask(db.Task{
+               TemplateID: template.ID,
+               ProjectID:  projectID,
+               Status:     "success",
+               Playbook:   "site.yml",
+               UserID:     &user.ID,
+               Created:    now,
+       }, 0)
+       require.NoError(t, err)
+
+       _, err = store.CreateTaskOutput(db.TaskOutput{
+               TaskID: task.ID,
+               Time:   now,
+               Output: "ok",
+       })
+       require.NoError(t, err)
+
+       // Apply the remaining migrations (2.19.14 rebuilds session and task).
+       require.NoError(t, db.Migrate(store, nil))
+
+       // The rebuild runs with foreign_keys=OFF, so make sure it left no
+       // dangling references behind.
+       violations, err := store.Sql().SelectInt("select count(1) from 
pragma_foreign_key_check")
+       require.NoError(t, err)
+       assert.Zero(t, violations)
+
+       // Existing rows survived the rebuild.
+       survivedSession, err := store.GetSession(user.ID, session.ID)
+       require.NoError(t, err)
+       assert.Equal(t, user.ID, survivedSession.UserID)
+
+       survivedTask, err := store.GetTask(projectID, task.ID)
+       require.NoError(t, err)
+       require.NotNil(t, survivedTask.UserID)
+       assert.Equal(t, user.ID, *survivedTask.UserID)
+
+       outputs, err := store.GetTaskOutputs(projectID, task.ID, 
db.RetrieveQueryParams{})
+       require.NoError(t, err)
+       assert.Len(t, outputs, 1)
+
+       // And the rebuilt FKs are in effect: a bare user delete cascades the
+       // session and nulls task.user_id.
+       _, err = store.exec("delete from `user` where id=?", user.ID)
+       require.NoError(t, err)
+
+       _, err = store.GetSession(user.ID, session.ID)
+       assert.ErrorIs(t, err, db.ErrNotFound)
+
+       survivedTask, err = store.GetTask(projectID, task.ID)
+       require.NoError(t, err)
+       assert.Nil(t, survivedTask.UserID)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/migrations/v2.19.14.err.sql 
new/semaphore-2.19.11/db/sql/migrations/v2.19.14.err.sql
--- old/semaphore-2.19.7/db/sql/migrations/v2.19.14.err.sql     1970-01-01 
01:00:00.000000000 +0100
+++ new/semaphore-2.19.11/db/sql/migrations/v2.19.14.err.sql    2026-08-26 
15:30:53.000000000 +0200
@@ -0,0 +1,75 @@
+{{if .Sqlite}}
+create table session_old_2_19_14 (
+    id                  INTEGER PRIMARY KEY AUTOINCREMENT,
+    user_id             INTEGER NOT NULL,
+    created             DATETIME NOT NULL,
+    last_active         DATETIME NOT NULL,
+    ip                  VARCHAR(39) NOT NULL DEFAULT '',
+    user_agent          TEXT NOT NULL,
+    expired             INTEGER NOT NULL DEFAULT 0,
+    verification_method INTEGER NOT NULL DEFAULT 0,
+    verified            INTEGER NOT NULL DEFAULT 0,
+    FOREIGN KEY(user_id) REFERENCES user(id)
+);
+
+insert into session_old_2_19_14 (id, user_id, created, last_active, ip, 
user_agent, expired, verification_method, verified)
+    select id, user_id, created, last_active, ip, user_agent, expired, 
verification_method, verified from session;
+
+drop table session;
+
+alter table session_old_2_19_14 rename to session;
+
+create index session__session__expired on session(expired);
+
+create index session__session__user_id on session(user_id);
+
+create table task_old_2_20_2 (
+    id               INTEGER PRIMARY KEY AUTOINCREMENT,
+    template_id      INTEGER NOT NULL REFERENCES project__template(id) ON 
DELETE CASCADE,
+    status           VARCHAR(255) NOT NULL,
+    playbook         VARCHAR(255) NOT NULL,
+    environment      TEXT NULL,
+    created          DATETIME NULL,
+    start            DATETIME NULL,
+    end              DATETIME NULL,
+    user_id          INTEGER REFERENCES user(id),
+    project_id       INTEGER REFERENCES project(id),
+    message          VARCHAR(250) NOT NULL DEFAULT '',
+    version          VARCHAR(20) NULL,
+    commit_hash      VARCHAR(64) NULL,
+    commit_message   VARCHAR(100) NOT NULL DEFAULT '',
+    build_task_id    INTEGER REFERENCES task(id) ON DELETE SET NULL,
+    arguments        TEXT NULL,
+    inventory_id     INTEGER REFERENCES project__inventory(id) ON DELETE SET 
NULL,
+    integration_id   INTEGER REFERENCES project__integration(id) ON DELETE SET 
NULL,
+    schedule_id      INTEGER REFERENCES project__schedule(id) ON DELETE SET 
NULL,
+    git_branch       VARCHAR(255) NULL,
+    params           TEXT NULL,
+    runner_id        INTEGER NULL REFERENCES runner(id) ON DELETE SET NULL,
+    workflow_run_id  INTEGER NULL,
+    workflow_node_id INTEGER NULL,
+    artifacts        TEXT NULL
+);
+
+insert into task_old_2_20_2 (id, template_id, status, playbook, environment, 
created, start, `end`, user_id, project_id, message, version, commit_hash, 
commit_message, build_task_id, arguments, inventory_id, integration_id, 
schedule_id, git_branch, params, runner_id, workflow_run_id, workflow_node_id, 
artifacts)
+    select id, template_id, status, playbook, environment, created, start, 
`end`, user_id, project_id, message, version, commit_hash, commit_message, 
build_task_id, arguments, inventory_id, integration_id, schedule_id, 
git_branch, params, runner_id, workflow_run_id, workflow_node_id, artifacts
+    from task;
+
+drop table task;
+
+alter table task_old_2_20_2 rename to task;
+
+create index task__integration_id on task(integration_id);
+
+create index task__inventory_id on task(inventory_id);
+
+create index task__project_id on task(project_id);
+
+create index task__schedule_id on task(schedule_id);
+
+create index task__template_id on task(template_id);
+
+create index task__workflow_run_id on task(workflow_run_id);
+
+create index task__workflow_node_id on task(workflow_node_id);
+{{end}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/migrations/v2.19.14.sql 
new/semaphore-2.19.11/db/sql/migrations/v2.19.14.sql
--- old/semaphore-2.19.7/db/sql/migrations/v2.19.14.sql 1970-01-01 
01:00:00.000000000 +0100
+++ new/semaphore-2.19.11/db/sql/migrations/v2.19.14.sql        2026-08-26 
15:30:53.000000000 +0200
@@ -0,0 +1,79 @@
+{{if .Sqlite}}
+delete from session where user_id not in (select id from `user`);
+
+update task set user_id = null where user_id is not null and user_id not in 
(select id from `user`);
+
+create table session_new_2_20_2 (
+    id                  INTEGER PRIMARY KEY AUTOINCREMENT,
+    user_id             INTEGER NOT NULL,
+    created             DATETIME NOT NULL,
+    last_active         DATETIME NOT NULL,
+    ip                  VARCHAR(39) NOT NULL DEFAULT '',
+    user_agent          TEXT NOT NULL,
+    expired             INTEGER NOT NULL DEFAULT 0,
+    verification_method INTEGER NOT NULL DEFAULT 0,
+    verified            INTEGER NOT NULL DEFAULT 0,
+    FOREIGN KEY(user_id) REFERENCES user(id) ON DELETE CASCADE
+);
+
+insert into session_new_2_20_2 (id, user_id, created, last_active, ip, 
user_agent, expired, verification_method, verified)
+    select id, user_id, created, last_active, ip, user_agent, expired, 
verification_method, verified from session;
+
+drop table session;
+
+alter table session_new_2_20_2 rename to session;
+
+create index session__session__expired on session(expired);
+
+create index session__session__user_id on session(user_id);
+
+create table task_new_2_20_2 (
+    id               INTEGER PRIMARY KEY AUTOINCREMENT,
+    template_id      INTEGER NOT NULL REFERENCES project__template(id) ON 
DELETE CASCADE,
+    status           VARCHAR(255) NOT NULL,
+    playbook         VARCHAR(255) NOT NULL,
+    environment      TEXT NULL,
+    created          DATETIME NULL,
+    start            DATETIME NULL,
+    end              DATETIME NULL,
+    user_id          INTEGER REFERENCES user(id) ON DELETE SET NULL,
+    project_id       INTEGER REFERENCES project(id) ON DELETE CASCADE,
+    message          VARCHAR(250) NOT NULL DEFAULT '',
+    version          VARCHAR(20) NULL,
+    commit_hash      VARCHAR(64) NULL,
+    commit_message   VARCHAR(100) NOT NULL DEFAULT '',
+    build_task_id    INTEGER REFERENCES task(id) ON DELETE SET NULL,
+    arguments        TEXT NULL,
+    inventory_id     INTEGER REFERENCES project__inventory(id) ON DELETE SET 
NULL,
+    integration_id   INTEGER REFERENCES project__integration(id) ON DELETE SET 
NULL,
+    schedule_id      INTEGER REFERENCES project__schedule(id) ON DELETE SET 
NULL,
+    git_branch       VARCHAR(255) NULL,
+    params           TEXT NULL,
+    runner_id        INTEGER NULL REFERENCES runner(id) ON DELETE SET NULL,
+    workflow_run_id  INTEGER NULL,
+    workflow_node_id INTEGER NULL,
+    artifacts        TEXT NULL
+);
+
+insert into task_new_2_20_2 (id, template_id, status, playbook, environment, 
created, start, `end`, user_id, project_id, message, version, commit_hash, 
commit_message, build_task_id, arguments, inventory_id, integration_id, 
schedule_id, git_branch, params, runner_id, workflow_run_id, workflow_node_id, 
artifacts)
+    select id, template_id, status, playbook, environment, created, start, 
`end`, user_id, project_id, message, version, commit_hash, commit_message, 
build_task_id, arguments, inventory_id, integration_id, schedule_id, 
git_branch, params, runner_id, workflow_run_id, workflow_node_id, artifacts
+    from task;
+
+drop table task;
+
+alter table task_new_2_20_2 rename to task;
+
+create index task__integration_id on task(integration_id);
+
+create index task__inventory_id on task(inventory_id);
+
+create index task__project_id on task(project_id);
+
+create index task__schedule_id on task(schedule_id);
+
+create index task__template_id on task(template_id);
+
+create index task__workflow_run_id on task(workflow_run_id);
+
+create index task__workflow_node_id on task(workflow_node_id);
+{{end}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db/sql/user_test.go 
new/semaphore-2.19.11/db/sql/user_test.go
--- old/semaphore-2.19.7/db/sql/user_test.go    1970-01-01 01:00:00.000000000 
+0100
+++ new/semaphore-2.19.11/db/sql/user_test.go   2026-08-26 15:30:53.000000000 
+0200
@@ -0,0 +1,82 @@
+package sql
+
+import (
+       "testing"
+       "time"
+
+       "github.com/semaphoreui/semaphore/db"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+// Reproduces "Failed to delete user ... constraint failed: FOREIGN KEY
+// constraint failed (787)": on SQLite session.user_id references user(id)
+// without an ON DELETE action, so deleting any user who has ever logged in
+// (session rows are only flagged expired, never removed) fails.
+func TestDeleteUser_WithSession(t *testing.T) {
+       store := InitConfigCreateTestStore()
+
+       user, err := store.CreateUserWithoutPassword(db.User{
+               Username: "jdoe",
+               Name:     "John Doe",
+               Email:    "[email protected]",
+       })
+       require.NoError(t, err)
+
+       now := time.Now()
+       _, err = store.CreateSession(db.Session{
+               UserID:     user.ID,
+               Created:    now,
+               LastActive: now,
+               IP:         "127.0.0.1",
+               UserAgent:  "test",
+       })
+       require.NoError(t, err)
+
+       require.NoError(t, store.DeleteUser(user.ID))
+
+       _, err = store.GetUser(user.ID)
+       assert.ErrorIs(t, err, db.ErrNotFound)
+}
+
+// Same failure via task.user_id: the SQLite schema declares
+// task.user_id REFERENCES user(id) with no ON DELETE action, so a user who
+// has ever run a task cannot be deleted.
+func TestDeleteUser_WithTask(t *testing.T) {
+       store := InitConfigCreateTestStore()
+
+       user, err := store.CreateUserWithoutPassword(db.User{
+               Username: "jdoe",
+               Name:     "John Doe",
+               Email:    "[email protected]",
+       })
+       require.NoError(t, err)
+
+       projectID, repositoryID := newTemplateTestProject(t, store)
+       template, err := store.CreateTemplate(db.Template{
+               ProjectID:    projectID,
+               RepositoryID: repositoryID,
+               Name:         "tpl",
+               Playbook:     "site.yml",
+       })
+       require.NoError(t, err)
+
+       task, err := store.CreateTask(db.Task{
+               TemplateID: template.ID,
+               ProjectID:  projectID,
+               Status:     "success",
+               Playbook:   "site.yml",
+               UserID:     &user.ID,
+               Created:    time.Now(),
+       }, 0)
+       require.NoError(t, err)
+
+       require.NoError(t, store.DeleteUser(user.ID))
+
+       _, err = store.GetUser(user.ID)
+       assert.ErrorIs(t, err, db.ErrNotFound)
+
+       // The task itself must survive the deletion of its author.
+       _, err = store.GetTask(projectID, task.ID)
+       assert.NoError(t, err)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/db_lib/TerraformApp.go 
new/semaphore-2.19.11/db_lib/TerraformApp.go
--- old/semaphore-2.19.7/db_lib/TerraformApp.go 2026-07-30 19:15:03.000000000 
+0200
+++ new/semaphore-2.19.11/db_lib/TerraformApp.go        2026-08-26 
15:30:53.000000000 +0200
@@ -287,9 +287,11 @@
        }
 
        if !t.isWorkspacesSupported(args.EnvironmentVars) {
+               t.Logger.Log("Workspaces are not supported, skipping workspace 
selection")
                return
        }
 
+       t.Logger.Logf("Selecting workspace \"%s\"", workspace)
        err = t.selectWorkspace(workspace, args.EnvironmentVars)
        return
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/semaphore-2.19.7/util/config.go 
new/semaphore-2.19.11/util/config.go
--- old/semaphore-2.19.7/util/config.go 2026-07-30 19:15:03.000000000 +0200
+++ new/semaphore-2.19.11/util/config.go        2026-08-26 15:30:53.000000000 
+0200
@@ -140,9 +140,9 @@
 )
 
 type ExecutorConfig struct {
-       Type   ExecutorType       `json:"type" default:"local"`
-       K8s    RunnerK8sConfig    `json:"k8s,omitempty"`
-       Docker RunnerDockerConfig `json:"docker,omitempty"`
+       Type   ExecutorType       `json:"type" default:"local" 
env:"SEMAPHORE_RUNNER_EXECUTOR_TYPE"`
+       K8s    RunnerK8sConfig    `json:"k8s"`
+       Docker RunnerDockerConfig `json:"docker"`
 }
 
 type RunnerConfig struct {
@@ -169,7 +169,7 @@
 
        Connection *RunnerConnectionConfig `json:"connection,omitempty"`
 
-       Executor *ExecutorConfig `json:"executor,omitempty"`
+       Executor *ExecutorConfig `json:"executor,omitempty" 
env:"SEMAPHORE_RUNNER_EXECUTOR"`
 }
 
 // RunnerK8sConfig holds runner-side configuration for the Kubernetes 
executor. Field

++++++ semaphore.obsinfo ++++++
--- /var/tmp/diff_new_pack.b1pZl5/_old  2026-08-28 19:56:16.267618899 +0200
+++ /var/tmp/diff_new_pack.b1pZl5/_new  2026-08-28 19:56:16.274619144 +0200
@@ -1,5 +1,5 @@
 name: semaphore
-version: 2.19.7
-mtime: 1785431703
-commit: e9dc41a1de8a747569334f7a2b76c320b945d4f0
+version: 2.19.11
+mtime: 1787751053
+commit: 0c3f3738ea5ed988165afe499d896ff78b428c44
 

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

++++++ web-2.19.7.tar.gz -> web-2.19.11.tar.gz ++++++
/work/SRC/openSUSE:Factory/semaphore/web-2.19.7.tar.gz 
/work/SRC/openSUSE:Factory/.semaphore.new.1265/web-2.19.11.tar.gz differ: char 
13, line 1

Reply via email to