This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new d4b31f1ed build(deps): maintain Go dependencies and migrate 
mapstructure v2 (#9061)
d4b31f1ed is described below

commit d4b31f1ede5bc326d8ae4893e1a79b0599c51f05
Author: Dirk <[email protected]>
AuthorDate: Wed Aug 26 05:54:15 2026 +0200

    build(deps): maintain Go dependencies and migrate mapstructure v2 (#9061)
    
    * build(deps): bump x/mod to v0.40.0
    
    * build(deps): update gorm postgres driver
    
    * build(deps): update go-oidc
    
    * refactor(deps): replace mapstructure with go-viper v2
    
    * fix(db): keep postgres index drops compatible with updated GORM
    
    * fix: make mysql schema migrations idempotent
    
    Signed-off-by: DoDiODev <[email protected]>
    
    * fix(db): keep AutoMigrate from redefining the mysql primary key
    
    gorm.io/driver/mysql v1.6.0 appends 'ADD PRIMARY KEY' to every column added 
by
    AutoMigrate that carries the primaryKey tag. DevLake migration scripts add 
such
    columns to tables that already own a primary key, so MySQL rejected them 
with
    'Error 1068: Multiple primary key defined'.
    Wrap the MySQL dialector so AddColumn keeps the pre-v1.6.0 behaviour: the
    primary key is only created for AUTO_INCREMENT columns on tables without 
one,
    every other primary key change stays with the migration scripts.
    
    Signed-off-by: DoDiODev <[email protected]>
    
    ---------
    
    Signed-off-by: DoDiODev <[email protected]>
---
 backend/core/runner/db.go                          |   6 +-
 backend/core/runner/mysql_dialector.go             | 111 +++++++++++++++++++++
 backend/go.mod                                     |  20 ++--
 backend/go.sum                                     |  47 +++++----
 backend/helpers/migrationhelper/migrationhelper.go |  37 +++++++
 backend/helpers/pluginhelper/api/mapstructure.go   |   2 +-
 backend/helpers/utils/mapstructure.go              |   2 +-
 backend/impls/dalgorm/dalgorm.go                   |   9 +-
 backend/plugins/customize/impl/impl.go             |   2 +-
 backend/plugins/github/api/connection_api.go       |   2 +-
 backend/plugins/issue_trace/impl/enricher.go       |   2 +-
 backend/plugins/jira/api/connection_api.go         |   2 +-
 .../e2e/issue_code_block_long_component_test.go    |   4 +-
 backend/plugins/zentao/tasks/task_data.go          |   2 +-
 backend/server/services/remote/plugin/scope_api.go |   2 +-
 15 files changed, 205 insertions(+), 45 deletions(-)

diff --git a/backend/core/runner/db.go b/backend/core/runner/db.go
index 0e3925942..8b1f6fcf1 100644
--- a/backend/core/runner/db.go
+++ b/backend/core/runner/db.go
@@ -145,13 +145,13 @@ func MakeDbConnection(dbUrl string, conf *gorm.Config) 
(*gorm.DB, error) {
                        if err != nil {
                                return nil, err
                        }
-                       gormDB, err := gorm.Open(mysql.New(mysql.Config{
+                       gormDB, err := 
gorm.Open(wrapMysqlDialector(mysql.New(mysql.Config{
                                Conn: db,
-                       }), &gorm.Config{})
+                       })), &gorm.Config{})
 
                        return gormDB, err
                }
-               return gorm.Open(mysql.Open(dbUrl), conf)
+               return gorm.Open(wrapMysqlDialector(mysql.Open(dbUrl)), conf)
        case "postgresql", "postgres", "pg":
                return gorm.Open(postgres.Open(dbUrl), conf)
        default:
diff --git a/backend/core/runner/mysql_dialector.go 
b/backend/core/runner/mysql_dialector.go
new file mode 100644
index 000000000..49fb9843a
--- /dev/null
+++ b/backend/core/runner/mysql_dialector.go
@@ -0,0 +1,111 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package runner
+
+import (
+       "fmt"
+       "strings"
+
+       "gorm.io/driver/mysql"
+       "gorm.io/gorm"
+       "gorm.io/gorm/clause"
+       gormmigrator "gorm.io/gorm/migrator"
+       "gorm.io/gorm/schema"
+)
+
+// primaryKeyIndexName is the fixed name MySQL gives to the primary key index
+const primaryKeyIndexName = "PRIMARY"
+
+// wrapMysqlDialector decorates the GORM MySQL dialector so that AutoMigrate 
keeps
+// working for DevLake's migration scripts.
+//
+// Since gorm.io/driver/mysql v1.6.0, `AddColumn` appends `ADD PRIMARY KEY 
(<col>)`
+// whenever the added field carries the `primaryKey` tag. DevLake migration 
scripts
+// regularly add such a column to a table that already owns a primary key, 
which
+// makes MySQL fail with `Error 1068: Multiple primary key defined`. Primary 
key
+// changes are always performed explicitly by the migration scripts (see
+// migrationhelper.ChangePrimaryKeyColumnsType), so the column is added 
without the
+// implicit clause, matching the behaviour of the previous driver release. The 
only
+// exception is an `AUTO_INCREMENT` column, which MySQL requires to be a key.
+func wrapMysqlDialector(dialector gorm.Dialector) gorm.Dialector {
+       if mysqlDialector, ok := dialector.(*mysql.Dialector); ok {
+               return safeMysqlDialector{Dialector: *mysqlDialector}
+       }
+       return dialector
+}
+
+type safeMysqlDialector struct {
+       mysql.Dialector
+}
+
+// Migrator returns the MySQL migrator with the AddColumn workaround applied
+func (d safeMysqlDialector) Migrator(db *gorm.DB) gorm.Migrator {
+       return safeMysqlMigrator{Migrator: d.Dialector.Migrator(db), db: db}
+}
+
+type safeMysqlMigrator struct {
+       gorm.Migrator
+       db *gorm.DB
+}
+
+// mysqlMigratorInternals exposes the helpers of the embedded GORM migrator 
that
+// are needed to rebuild the `ALTER TABLE ... ADD ...` statement
+type mysqlMigratorInternals interface {
+       RunWithValue(value interface{}, fc func(*gorm.Statement) error) error
+       FullDataTypeOf(field *schema.Field) clause.Expr
+       CurrentTable(stmt *gorm.Statement) interface{}
+}
+
+// AddColumn adds a column without implicitly promoting it to the primary key 
of
+// the table, see wrapMysqlDialector for the rationale
+func (m safeMysqlMigrator) AddColumn(value interface{}, name string) error {
+       base, ok := m.Migrator.(mysqlMigratorInternals)
+       if !ok {
+               return m.Migrator.AddColumn(value, name)
+       }
+       return base.RunWithValue(value, func(stmt *gorm.Statement) error {
+               field := stmt.Schema.LookUpField(name)
+               if field == nil {
+                       return fmt.Errorf("failed to look up field with name: 
%s", name)
+               }
+               if field.IgnoreMigration {
+                       return nil
+               }
+               fieldType := base.FullDataTypeOf(field)
+               columnName := clause.Column{Name: field.DBName}
+               values := []interface{}{base.CurrentTable(stmt), columnName, 
fieldType}
+               alterSql := "ALTER TABLE ? ADD ? ?"
+               // MySQL requires an AUTO_INCREMENT column to be a key, every 
other primary
+               // key is managed explicitly by the migration scripts
+               if strings.Contains(strings.ToLower(fieldType.SQL), 
"auto_increment") &&
+                       !m.Migrator.HasIndex(value, primaryKeyIndexName) {
+                       alterSql += ", ADD PRIMARY KEY (?)"
+                       values = append(values, columnName)
+               }
+               return m.db.Exec(alterSql, values...).Error
+       })
+}
+
+// BuildIndexOptions forwards to the embedded migrator, GORM requires every
+// migrator to implement migrator.BuildIndexOptionsInterface while creating 
tables
+func (m safeMysqlMigrator) BuildIndexOptions(opts []schema.IndexOption, stmt 
*gorm.Statement) []interface{} {
+       if builder, ok := m.Migrator.(gormmigrator.BuildIndexOptionsInterface); 
ok {
+               return builder.BuildIndexOptions(opts, stmt)
+       }
+       return nil
+}
diff --git a/backend/go.mod b/backend/go.mod
index 9e92f0890..6b46bc04a 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -10,12 +10,12 @@ require (
        github.com/go-errors/errors v1.4.2 // indirect
        github.com/go-git/go-git/v5 v5.19.2
        github.com/go-playground/validator/v10 v10.19.0
+       github.com/go-viper/mapstructure/v2 v2.5.0
        github.com/gocarina/gocsv v0.0.0-20220707092902-b9da1f06c77e
        github.com/google/uuid v1.3.0
        github.com/jackc/pgx/v5 v5.10.0
        github.com/libgit2/git2go/v34 v34.0.0
        github.com/magiconair/properties v1.8.5
-       github.com/mitchellh/mapstructure v1.5.0
        github.com/panjf2000/ants/v2 v2.4.6
        github.com/robfig/cron/v3 v3.0.0
        github.com/sirupsen/logrus v1.10.0
@@ -34,23 +34,24 @@ require (
        golang.org/x/oauth2 v0.36.0
        golang.org/x/sync v0.22.0
        gorm.io/datatypes v1.0.1
-       gorm.io/driver/mysql v1.5.1
-       gorm.io/driver/postgres v1.5.2
-       gorm.io/gorm v1.25.5
+       gorm.io/driver/mysql v1.6.0
+       gorm.io/driver/postgres v1.6.2
+       gorm.io/gorm v1.31.2
 )
 
 require (
        github.com/chainguard-dev/git-urls v1.0.2
-       github.com/coreos/go-oidc/v3 v3.9.0
-       github.com/go-sql-driver/mysql v1.7.1
+       github.com/coreos/go-oidc/v3 v3.20.0
+       github.com/go-sql-driver/mysql v1.8.1
        github.com/golang-jwt/jwt/v5 v5.3.1
        github.com/merico-ai/graphql v0.0.0-20260206020408-b7fd267bcfac
        github.com/rogpeppe/go-internal v1.14.1
-       golang.org/x/mod v0.38.0
+       golang.org/x/mod v0.40.0
 )
 
 require (
        dario.cat/mergo v1.0.0 // indirect
+       filippo.io/edwards25519 v1.1.0 // indirect
        github.com/KyleBanks/depth v1.2.1 // indirect
        github.com/Microsoft/go-winio v0.6.2 // indirect
        github.com/ProtonMail/go-crypto v1.1.6 // indirect
@@ -70,7 +71,7 @@ require (
        github.com/gin-contrib/sse v0.1.0 // indirect
        github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
        github.com/go-git/go-billy/v5 v5.9.0 // indirect
-       github.com/go-jose/go-jose/v3 v3.0.1 // indirect
+       github.com/go-jose/go-jose/v4 v4.1.4 // indirect
        github.com/go-openapi/jsonpointer v0.19.5 // indirect
        github.com/go-openapi/jsonreference v0.19.6 // indirect
        github.com/go-openapi/spec v0.20.4 // indirect
@@ -98,6 +99,7 @@ require (
        github.com/leodido/go-urn v1.4.0 // indirect
        github.com/mailru/easyjson v0.7.7 // indirect
        github.com/mattn/go-isatty v0.0.19 // indirect
+       github.com/mitchellh/mapstructure v1.4.1 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // 
indirect
        github.com/modern-go/reflect2 v1.0.2 // indirect
        github.com/pelletier/go-toml v1.9.3 // indirect
@@ -120,7 +122,7 @@ require (
        golang.org/x/net v0.58.0 // indirect
        golang.org/x/sys v0.47.0 // indirect
        golang.org/x/text v0.41.0 // indirect
-       golang.org/x/tools v0.48.0 // indirect
+       golang.org/x/tools v0.49.0 // indirect
        google.golang.org/protobuf v1.36.12 // indirect
        gopkg.in/ini.v1 v1.67.0 // indirect
        gopkg.in/warnings.v0 v0.1.2 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index 91c719303..bb0abbcb1 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -39,6 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod 
h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod 
h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod 
h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
 github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod 
h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/KyleBanks/depth v1.2.1 
h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
@@ -89,8 +91,8 @@ github.com/cockroachdb/logtags 
v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe
 github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod 
h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
 github.com/cockroachdb/redact v1.1.5 
h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
 github.com/cockroachdb/redact v1.1.5/go.mod 
h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
-github.com/coreos/go-oidc/v3 v3.9.0 
h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo=
-github.com/coreos/go-oidc/v3 v3.9.0/go.mod 
h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4=
+github.com/coreos/go-oidc/v3 v3.20.0 
h1:EtE0WIBHk03N+DqGkY4+UONzzZHk7amKt6IyNd7OsZE=
+github.com/coreos/go-oidc/v3 v3.20.0/go.mod 
h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4=
 github.com/coreos/go-semver v0.3.0/go.mod 
h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod 
h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod 
h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -147,8 +149,8 @@ github.com/go-git/go-git/v5 v5.19.2/go.mod 
h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuw
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod 
h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod 
h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-jose/go-jose/v3 v3.0.1 
h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
-github.com/go-jose/go-jose/v3 v3.0.1/go.mod 
h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
+github.com/go-jose/go-jose/v4 v4.1.4 
h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
+github.com/go-jose/go-jose/v4 v4.1.4/go.mod 
h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod 
h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonpointer v0.19.5 
h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
 github.com/go-openapi/jsonpointer v0.19.5/go.mod 
h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -168,10 +170,11 @@ github.com/go-playground/universal-translator 
v0.18.1/go.mod h1:xekY+UJKNuX9WP91
 github.com/go-playground/validator/v10 v10.19.0 
h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
 github.com/go-playground/validator/v10 v10.19.0/go.mod 
h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-sql-driver/mysql v1.5.0/go.mod 
h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-sql-driver/mysql v1.7.0/go.mod 
h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
-github.com/go-sql-driver/mysql v1.7.1 
h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
-github.com/go-sql-driver/mysql v1.7.1/go.mod 
h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 
h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod 
h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
 github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-viper/mapstructure/v2 v2.5.0 
h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
+github.com/go-viper/mapstructure/v2 v2.5.0/go.mod 
h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
 github.com/gocarina/gocsv v0.0.0-20220707092902-b9da1f06c77e 
h1:GMIV+S6grz+vlIaUsP+fedQ6L+FovyMPMY26WO8dwQE=
 github.com/gocarina/gocsv v0.0.0-20220707092902-b9da1f06c77e/go.mod 
h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
 github.com/goccy/go-json v0.10.2 
h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
@@ -393,8 +396,9 @@ github.com/mattn/go-isatty v0.0.9/go.mod 
h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
 github.com/mattn/go-isatty v0.0.12/go.mod 
h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.19 
h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-sqlite3 v1.14.5 
h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
 github.com/mattn/go-sqlite3 v1.14.5/go.mod 
h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
+github.com/mattn/go-sqlite3 v1.14.22 
h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod 
h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
 github.com/merico-ai/graphql v0.0.0-20260206020408-b7fd267bcfac 
h1:J3wm8OohrRkYf/+Zy5GxqvhzcP2qHGJRduxTUUbBMdw=
 github.com/merico-ai/graphql v0.0.0-20260206020408-b7fd267bcfac/go.mod 
h1:4WSOgvd/Sv6eLKJE6fvrXlmxePBDGhbwRYKEBeqJr8g=
 github.com/miekg/dns v1.0.14/go.mod 
h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -405,9 +409,8 @@ github.com/mitchellh/gox v0.4.0/go.mod 
h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.4.1 
h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
 github.com/mitchellh/mapstructure v1.4.1/go.mod 
h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.5.0 
h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
-github.com/mitchellh/mapstructure v1.5.0/go.mod 
h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd 
h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -605,8 +608,8 @@ golang.org/x/mod v0.4.0/go.mod 
h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod 
h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
-golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
+golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs=
+golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -816,8 +819,8 @@ golang.org/x/tools 
v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.0/go.mod 
h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.2/go.mod 
h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod 
h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
-golang.org/x/tools v0.48.0/go.mod 
h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
+golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
+golang.org/x/tools v0.49.0/go.mod 
h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -955,13 +958,14 @@ gopkg.in/yaml.v3 v3.0.1/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/datatypes v1.0.1 h1:6npnXbBtjpSb7FFVA2dG/llyTN8tvZfbUqs+WyLrYgQ=
 gorm.io/datatypes v1.0.1/go.mod h1:HEHoUU3/PO5ZXfAJcVWl11+zWlE16+O0X2DgJEb4Ixs=
 gorm.io/driver/mysql v1.0.5/go.mod 
h1:N1OIhHAIhx5SunkMGqWbGFVeh4yTNWKmMo1GOAsohLI=
-gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
-gorm.io/driver/mysql v1.5.1/go.mod 
h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
+gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
+gorm.io/driver/mysql v1.6.0/go.mod 
h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
 gorm.io/driver/postgres v1.0.8/go.mod 
h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
-gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
-gorm.io/driver/postgres v1.5.2/go.mod 
h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
-gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
+gorm.io/driver/postgres v1.6.2 h1:BvXQ/cNUg63q5TFNg672DmDcowZSFrNLkkA3Xe6GXq4=
+gorm.io/driver/postgres v1.6.2/go.mod 
h1:0c4fQA44XhOklXDkgtuKqysHCycTa5i9e3EIpDGCwXk=
 gorm.io/driver/sqlite v1.1.4/go.mod 
h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
+gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
+gorm.io/driver/sqlite v1.6.0/go.mod 
h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
 gorm.io/driver/sqlserver v1.0.7 h1:uwUtb0kdFwW5PkRbd2KJ2h4wlsqvLSjox1XVg/RnzRE=
 gorm.io/driver/sqlserver v1.0.7/go.mod 
h1:ng66aHI47ZIKz/vvnxzDoonzmTS8HXP+JYlgg67wOog=
 gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
@@ -969,9 +973,8 @@ gorm.io/gorm v1.20.12/go.mod 
h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
 gorm.io/gorm v1.21.3/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
 gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
 gorm.io/gorm v1.21.6/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
-gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
-gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
-gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo=
+gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/backend/helpers/migrationhelper/migrationhelper.go 
b/backend/helpers/migrationhelper/migrationhelper.go
index 691413b1a..93186e64c 100644
--- a/backend/helpers/migrationhelper/migrationhelper.go
+++ b/backend/helpers/migrationhelper/migrationhelper.go
@@ -153,6 +153,43 @@ func ChangePrimaryKeyColumnsType[D any](
                return err
        }
 
+       // Some GORM dialects recreate the primary key while AutoMigrate 
changes the
+       // column type, so adding it unconditionally would fail with a 
duplicate key.
+       primaryKeyColumns, err := dal.GetPrimarykeyColumns(db, 
dal.DefaultTabler{Name: tableName})
+       if err != nil {
+               return errors.Default.Wrap(err, fmt.Sprintf("failed to check 
primary key on table [%s]", tableName))
+       }
+       if len(primaryKeyColumns) == len(TargetPriColumns) {
+               existingPrimaryKeyColumns := make(map[string]struct{}, 
len(primaryKeyColumns))
+               for _, column := range primaryKeyColumns {
+                       existingPrimaryKeyColumns[column.Name()] = struct{}{}
+               }
+               allColumnsPresent := true
+               for _, column := range TargetPriColumns {
+                       if _, ok := existingPrimaryKeyColumns[column]; !ok {
+                               allColumnsPresent = false
+                               break
+                       }
+               }
+               if allColumnsPresent {
+                       return nil
+               }
+       }
+
+       if len(primaryKeyColumns) > 0 {
+               if u.Scheme == "mysql" {
+                       sql := fmt.Sprintf("ALTER TABLE %s DROP PRIMARY KEY", 
tableName)
+                       if err := db.Exec(sql); err != nil {
+                               return err
+                       }
+               } else {
+                       sql := fmt.Sprintf("ALTER TABLE %s DROP CONSTRAINT 
%s_pkey", tableName, tableName)
+                       if err := db.Exec(sql); err != nil {
+                               return err
+                       }
+               }
+       }
+
        // Add the primary key
        sql := fmt.Sprintf("ALTER TABLE %s ADD PRIMARY KEY (%s)", tableName, 
strings.Join(TargetPriColumns, ","))
        if err := db.Exec(sql); err != nil {
diff --git a/backend/helpers/pluginhelper/api/mapstructure.go 
b/backend/helpers/pluginhelper/api/mapstructure.go
index ff8e84ee1..8a1a348ec 100644
--- a/backend/helpers/pluginhelper/api/mapstructure.go
+++ b/backend/helpers/pluginhelper/api/mapstructure.go
@@ -28,7 +28,7 @@ import (
        "github.com/apache/incubator-devlake/core/models/common"
        "github.com/go-playground/validator/v10"
 
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 var defaultCustomDecoderHooks = 
[]mapstructure.DecodeHookFunc{decodeHookStringFloat64, decodeHookStringToTime, 
DecodeHook}
diff --git a/backend/helpers/utils/mapstructure.go 
b/backend/helpers/utils/mapstructure.go
index 22ea85949..4b9684156 100644
--- a/backend/helpers/utils/mapstructure.go
+++ b/backend/helpers/utils/mapstructure.go
@@ -28,7 +28,7 @@ import (
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/go-playground/validator/v10"
 
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 func DecodeHook(f reflect.Type, t reflect.Type, data interface{}) 
(interface{}, error) {
diff --git a/backend/impls/dalgorm/dalgorm.go b/backend/impls/dalgorm/dalgorm.go
index 0445995fd..bf5538dda 100644
--- a/backend/impls/dalgorm/dalgorm.go
+++ b/backend/impls/dalgorm/dalgorm.go
@@ -456,7 +456,14 @@ func (d *Dalgorm) DropIndexes(table string, indexNames 
...string) errors.Error {
                if !d.db.Migrator().HasIndex(table, indexName) {
                        continue
                }
-               err := d.db.Migrator().DropIndex(table, indexName)
+               var err error
+               if d.Dialect() == "postgres" {
+                       // gorm.io/driver/postgres v1.6.x quotes its 
CURRENT_SCHEMA()
+                       // expression when dropping an index, yielding invalid 
SQL.
+                       err = d.db.Exec("DROP INDEX IF EXISTS ?", 
clause.Column{Name: indexName}).Error
+               } else {
+                       err = d.db.Migrator().DropIndex(table, indexName)
+               }
                if err != nil {
                        return d.convertGormError(err)
                }
diff --git a/backend/plugins/customize/impl/impl.go 
b/backend/plugins/customize/impl/impl.go
index dd689b794..6df6359a0 100644
--- a/backend/plugins/customize/impl/impl.go
+++ b/backend/plugins/customize/impl/impl.go
@@ -26,7 +26,7 @@ import (
        "github.com/apache/incubator-devlake/plugins/customize/models"
        
"github.com/apache/incubator-devlake/plugins/customize/models/migrationscripts"
        "github.com/apache/incubator-devlake/plugins/customize/tasks"
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 var _ interface {
diff --git a/backend/plugins/github/api/connection_api.go 
b/backend/plugins/github/api/connection_api.go
index a5f0e922d..f09c8def8 100644
--- a/backend/plugins/github/api/connection_api.go
+++ b/backend/plugins/github/api/connection_api.go
@@ -23,7 +23,7 @@ import (
        "net/http"
        "strings"
 
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"
diff --git a/backend/plugins/issue_trace/impl/enricher.go 
b/backend/plugins/issue_trace/impl/enricher.go
index 1506f2563..73280d323 100644
--- a/backend/plugins/issue_trace/impl/enricher.go
+++ b/backend/plugins/issue_trace/impl/enricher.go
@@ -30,7 +30,7 @@ import (
        "github.com/apache/incubator-devlake/plugins/issue_trace/models"
        
"github.com/apache/incubator-devlake/plugins/issue_trace/models/migrationscripts"
        "github.com/apache/incubator-devlake/plugins/issue_trace/tasks"
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 type IssueTrace struct{}
diff --git a/backend/plugins/jira/api/connection_api.go 
b/backend/plugins/jira/api/connection_api.go
index 209ab6c5c..fa1de5848 100644
--- a/backend/plugins/jira/api/connection_api.go
+++ b/backend/plugins/jira/api/connection_api.go
@@ -30,7 +30,7 @@ import (
        "github.com/apache/incubator-devlake/core/plugin"
        "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/plugins/jira/models"
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 type JiraTestConnResponse struct {
diff --git 
a/backend/plugins/sonarqube/e2e/issue_code_block_long_component_test.go 
b/backend/plugins/sonarqube/e2e/issue_code_block_long_component_test.go
index e1a7d52b5..5eecac7be 100644
--- a/backend/plugins/sonarqube/e2e/issue_code_block_long_component_test.go
+++ b/backend/plugins/sonarqube/e2e/issue_code_block_long_component_test.go
@@ -80,10 +80,10 @@ func TestSonarqubeIssueCodeBlockLongComponent(t *testing.T) 
{
                &sonarqubeIssueCodeBlockBeforeText{},
                &cqIssueCodeBlockBeforeText{},
        ))
-       require.NoError(t, dataflowTester.Db.Migrator().DropIndex(
+       require.NoError(t, dataflowTester.Dal.DropIndexes(
                "cq_issue_code_blocks", "idx_cq_issue_code_blocks_component",
        ))
-       require.NoError(t, dataflowTester.Db.Migrator().DropIndex(
+       require.NoError(t, dataflowTester.Dal.DropIndexes(
                "_tool_sonarqube_issue_code_blocks", 
"idx__tool_sonarqube_issue_code_blocks_component",
        ))
 
diff --git a/backend/plugins/zentao/tasks/task_data.go 
b/backend/plugins/zentao/tasks/task_data.go
index 26bc9734c..b1f4d56b1 100644
--- a/backend/plugins/zentao/tasks/task_data.go
+++ b/backend/plugins/zentao/tasks/task_data.go
@@ -24,7 +24,7 @@ import (
        "github.com/apache/incubator-devlake/core/errors"
        helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/plugins/zentao/models"
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 )
 
 type ZentaoApiParams models.ZentaoApiParams
diff --git a/backend/server/services/remote/plugin/scope_api.go 
b/backend/server/services/remote/plugin/scope_api.go
index 9450422e7..78c36f33c 100644
--- a/backend/server/services/remote/plugin/scope_api.go
+++ b/backend/server/services/remote/plugin/scope_api.go
@@ -23,7 +23,7 @@ import (
        "strings"
 
        "github.com/apache/incubator-devlake/server/services/remote/models"
-       "github.com/mitchellh/mapstructure"
+       "github.com/go-viper/mapstructure/v2"
 
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"

Reply via email to