Skip to content

Commit 420e494

Browse files
fabiolucianoFábio Luciano
andauthored
feat(docker): add Dockerfile.local for local development and fix migrations (#8866)
* fix(migrations): add new fields and improve migration scripts for various plugins * feat(docker): add Dockerfile.local for local development and update docker-compose configuration * chore: add license to dockerfile --------- Co-authored-by: Fábio Luciano <fabio.gois@sicoob.com.br>
1 parent a6232fb commit 420e494

10 files changed

Lines changed: 175 additions & 76 deletions

File tree

backend/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ COPY --from=debian-arm64 /lib/aarch64-linux-gnu /rootfs-arm64/lib/aarch64-linux-
6363

6464
RUN for arch in aarch64 x86_64 ; do \
6565
mkdir -p /tmp/build/${arch} && cd /tmp/build/${arch} && \
66-
wget https://github.com/libgit2/libgit2/archive/refs/tags/v1.3.2.tar.gz -O - | tar -xz && \
67-
cd libgit2-1.3.2 && \
66+
wget https://github.com/libgit2/libgit2/archive/refs/tags/v1.3.0.tar.gz -O - | tar -xz && \
67+
cd libgit2-1.3.0 && \
6868
mkdir build && cd build && \
6969
if [ "$arch" = "aarch64" ] ; then \
7070
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \

backend/Dockerfile.local

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
#Apache DevLake is an effort undergoing incubation at The Apache Software
17+
#Foundation (ASF), sponsored by the Apache Incubator PMC.
18+
#
19+
#Incubation is required of all newly accepted projects until a further review
20+
#indicates that the infrastructure, communications, and decision making process
21+
#have stabilized in a manner consistent with other successful ASF projects.
22+
#
23+
#While incubation status is not necessarily a reflection of the completeness or stability of the code,
24+
#it does indicate that the project has yet to be fully endorsed by the ASF.
25+
26+
FROM golang:1.20.5-bookworm as builder
27+
28+
ARG GOPROXY=
29+
ARG HTTP_PROXY=
30+
ARG HTTPS_PROXY=
31+
32+
RUN apt-get update && apt-get install -y \
33+
gcc \
34+
binutils \
35+
libfindbin-libs-perl \
36+
cmake \
37+
libssh2-1-dev \
38+
libssl-dev \
39+
zlib1g-dev
40+
41+
# Install libgit2 for native platform only
42+
RUN mkdir -p /tmp/build && cd /tmp/build && \
43+
wget https://github.com/libgit2/libgit2/archive/refs/tags/v1.3.0.tar.gz -O - | tar -xz && \
44+
cd libgit2-1.3.0 && \
45+
mkdir build && cd build && \
46+
cmake .. -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local && \
47+
make -j$(nproc) install && \
48+
ldconfig
49+
50+
RUN go install github.com/vektra/mockery/v2@v2.20.0
51+
RUN go install github.com/swaggo/swag/cmd/swag@v1.16.1
52+
53+
WORKDIR /app
54+
COPY . /app
55+
ENV GOBIN=/app/bin
56+
57+
ARG TAG=
58+
ARG SHA=
59+
60+
# Generate mocks and swagger
61+
RUN make mock
62+
RUN make swag
63+
64+
# Build plugins
65+
RUN make build-plugin
66+
67+
# Build server
68+
RUN VERSION=${TAG}@${SHA} make build-server
69+
70+
FROM debian:bookworm-slim
71+
72+
RUN apt-get update && apt-get install -y \
73+
libssh2-1 \
74+
libssl3 \
75+
ca-certificates \
76+
&& rm -rf /var/lib/apt/lists/*
77+
78+
# Copy libgit2
79+
COPY --from=builder /usr/local/lib/libgit2.so* /usr/local/lib/
80+
RUN ldconfig
81+
82+
WORKDIR /app
83+
84+
COPY --from=builder /app/bin ./bin
85+
86+
# Create empty python plugins dir to avoid startup error
87+
RUN mkdir -p python/plugins
88+
89+
ENV PORT=8080
90+
EXPOSE 8080
91+
92+
CMD ["./bin/lake"]

backend/plugins/github/models/migrationscripts/20240821_add_index_to_tool_github_jobs.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ func (script *addIndexToGithubJobs) Up(basicRes context.BasicRes) errors.Error {
4343
if err := db.Exec(sql); err != nil {
4444
return err
4545
}
46+
} else if u.Scheme == "postgres" || u.Scheme == "postgresql" {
47+
sql := "CREATE INDEX IF NOT EXISTS idx_repo_id_connection_id ON _tool_github_jobs (repo_id, connection_id)"
48+
if err := db.Exec(sql); err != nil {
49+
return err
50+
}
4651
}
4752
return nil
4853
}

backend/plugins/q_dev/models/migrationscripts/20250623_add_display_name_fields.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,44 @@ import (
2121
"github.com/apache/incubator-devlake/core/context"
2222
"github.com/apache/incubator-devlake/core/errors"
2323
"github.com/apache/incubator-devlake/core/plugin"
24+
"github.com/apache/incubator-devlake/helpers/migrationhelper"
2425
)
2526

2627
var _ plugin.MigrationScript = (*addDisplayNameFields)(nil)
2728

2829
type addDisplayNameFields struct{}
2930

30-
func (*addDisplayNameFields) Up(basicRes context.BasicRes) errors.Error {
31-
db := basicRes.GetDal()
31+
type QDevConnection20250623 struct {
32+
IdentityStoreId string `gorm:"type:VARCHAR(255)"`
33+
IdentityStoreRegion string `gorm:"type:VARCHAR(255)"`
34+
}
35+
36+
func (QDevConnection20250623) TableName() string {
37+
return "_tool_q_dev_connections"
38+
}
39+
40+
type QDevUserData20250623 struct {
41+
DisplayName string `gorm:"type:VARCHAR(255)"`
42+
}
3243

33-
// Add Identity Center fields to connections table
34-
// Ignore error if column already exists (MySQL error 1060)
35-
_ = db.Exec("ALTER TABLE _tool_q_dev_connections ADD COLUMN identity_store_id VARCHAR(255)")
36-
_ = db.Exec("ALTER TABLE _tool_q_dev_connections ADD COLUMN identity_store_region VARCHAR(255)")
44+
func (QDevUserData20250623) TableName() string {
45+
return "_tool_q_dev_user_data"
46+
}
3747

38-
// Add display_name column to user_data table
39-
// Ignore error if column already exists (MySQL error 1060)
40-
_ = db.Exec("ALTER TABLE _tool_q_dev_user_data ADD COLUMN display_name VARCHAR(255)")
48+
type QDevUserMetrics20250623 struct {
49+
DisplayName string `gorm:"type:VARCHAR(255)"`
50+
}
4151

42-
// Add display_name column to user_metrics table
43-
// Ignore error if column already exists (MySQL error 1060)
44-
_ = db.Exec("ALTER TABLE _tool_q_dev_user_metrics ADD COLUMN display_name VARCHAR(255)")
52+
func (QDevUserMetrics20250623) TableName() string {
53+
return "_tool_q_dev_user_metrics"
54+
}
4555

46-
return nil
56+
func (*addDisplayNameFields) Up(basicRes context.BasicRes) errors.Error {
57+
return migrationhelper.AutoMigrateTables(basicRes,
58+
&QDevConnection20250623{},
59+
&QDevUserData20250623{},
60+
&QDevUserMetrics20250623{},
61+
)
4762
}
4863

4964
func (*addDisplayNameFields) Version() uint64 {

backend/plugins/q_dev/models/migrationscripts/20251123_add_scope_config_id_to_s3_slice.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,21 @@ package migrationscripts
2020
import (
2121
"github.com/apache/incubator-devlake/core/context"
2222
"github.com/apache/incubator-devlake/core/errors"
23+
"github.com/apache/incubator-devlake/helpers/migrationhelper"
2324
)
2425

2526
type addScopeConfigIdToS3Slice struct{}
2627

28+
type QDevS3Slice20251123 struct {
29+
ScopeConfigId uint64 `gorm:"type:BIGINT DEFAULT 0"`
30+
}
31+
32+
func (QDevS3Slice20251123) TableName() string {
33+
return "_tool_q_dev_s3_slices"
34+
}
35+
2736
func (*addScopeConfigIdToS3Slice) Up(basicRes context.BasicRes) errors.Error {
28-
db := basicRes.GetDal()
29-
30-
// Add scope_config_id column to _tool_q_dev_s3_slices table
31-
err := db.Exec(`
32-
ALTER TABLE _tool_q_dev_s3_slices
33-
ADD COLUMN scope_config_id BIGINT UNSIGNED DEFAULT 0
34-
`)
35-
if err != nil {
36-
return errors.Convert(err)
37-
}
38-
39-
return nil
37+
return migrationhelper.AutoMigrateTables(basicRes, &QDevS3Slice20251123{})
4038
}
4139

4240
func (*addScopeConfigIdToS3Slice) Version() uint64 {

backend/plugins/sonarqube/models/migrationscripts/20230316_modify_character_set.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,61 +18,53 @@ limitations under the License.
1818
package migrationscripts
1919

2020
import (
21-
"net/url"
22-
2321
"github.com/apache/incubator-devlake/core/context"
2422
"github.com/apache/incubator-devlake/core/errors"
2523
)
2624

2725
type modifyCharacterSet struct{}
2826

2927
func (*modifyCharacterSet) Up(basicRes context.BasicRes) errors.Error {
30-
dbUrl := basicRes.GetConfig("DB_URL")
31-
if dbUrl == "" {
32-
return errors.BadInput.New("DB_URL is required")
33-
}
34-
u, err1 := url.Parse(dbUrl)
35-
if err1 != nil {
36-
return errors.Convert(err1)
37-
}
38-
if u.Scheme == "mysql" {
39-
err := basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_projects CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
28+
db := basicRes.GetDal()
29+
// Character set conversion is MySQL-specific; PostgreSQL uses UTF-8 by default
30+
if db.Dialect() == "mysql" {
31+
err := db.Exec(`ALTER TABLE _tool_sonarqube_projects CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
4032
if err != nil {
4133
return err
4234
}
43-
err = basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_issues CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
35+
err = db.Exec(`ALTER TABLE _tool_sonarqube_issues CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
4436
if err != nil {
4537
return err
4638
}
47-
err = basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_issue_code_blocks CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
39+
err = db.Exec(`ALTER TABLE _tool_sonarqube_issue_code_blocks CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
4840
if err != nil {
4941
return err
5042
}
51-
err = basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_hotspots CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
43+
err = db.Exec(`ALTER TABLE _tool_sonarqube_hotspots CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
5244
if err != nil {
5345
return err
5446
}
55-
err = basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_file_metrics CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
47+
err = db.Exec(`ALTER TABLE _tool_sonarqube_file_metrics CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
5648
if err != nil {
5749
return err
5850
}
59-
err = basicRes.GetDal().Exec(`ALTER TABLE _tool_sonarqube_accounts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
51+
err = db.Exec(`ALTER TABLE _tool_sonarqube_accounts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
6052
if err != nil {
6153
return err
6254
}
63-
err = basicRes.GetDal().Exec(`ALTER TABLE cq_projects CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
55+
err = db.Exec(`ALTER TABLE cq_projects CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
6456
if err != nil {
6557
return err
6658
}
67-
err = basicRes.GetDal().Exec(`ALTER TABLE cq_issues CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
59+
err = db.Exec(`ALTER TABLE cq_issues CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
6860
if err != nil {
6961
return err
7062
}
71-
err = basicRes.GetDal().Exec(`ALTER TABLE cq_issue_code_blocks CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
63+
err = db.Exec(`ALTER TABLE cq_issue_code_blocks CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
7264
if err != nil {
7365
return err
7466
}
75-
err = basicRes.GetDal().Exec(`ALTER TABLE cq_file_metrics CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
67+
err = db.Exec(`ALTER TABLE cq_file_metrics CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`)
7668
if err != nil {
7769
return err
7870
}

backend/plugins/sonarqube/models/migrationscripts/20240325_modify_commit_character_type.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,21 @@ limitations under the License.
1818
package migrationscripts
1919

2020
import (
21-
"net/url"
22-
2321
"github.com/apache/incubator-devlake/core/context"
2422
"github.com/apache/incubator-devlake/core/errors"
2523
)
2624

2725
type modifyCommitCharacterType struct{}
2826

2927
func (*modifyCommitCharacterType) Up(basicRes context.BasicRes) errors.Error {
30-
dbUrl := basicRes.GetConfig("DB_URL")
31-
if dbUrl == "" {
32-
return errors.BadInput.New("DB_URL is required")
33-
}
34-
u, err1 := url.Parse(dbUrl)
35-
if err1 != nil {
36-
return errors.Convert(err1)
37-
}
38-
if u.Scheme == "mysql" {
39-
err := basicRes.GetDal().Exec(`ALTER TABLE commits MODIFY COLUMN message LONGTEXT CHARACTER SET binary;`)
28+
db := basicRes.GetDal()
29+
// Binary column types are MySQL-specific; PostgreSQL uses bytea natively
30+
if db.Dialect() == "mysql" {
31+
err := db.Exec(`ALTER TABLE commits MODIFY COLUMN message LONGTEXT CHARACTER SET binary;`)
4032
if err != nil {
4133
return err
4234
}
43-
err = basicRes.GetDal().Exec(`ALTER TABLE commit_files MODIFY COLUMN file_path VARBINARY(255);`)
35+
err = db.Exec(`ALTER TABLE commit_files MODIFY COLUMN file_path VARBINARY(255);`)
4436
if err != nil {
4537
return err
4638
}

backend/plugins/sonarqube/models/migrationscripts/20240508_modify_commit_character_type.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,17 @@ limitations under the License.
1818
package migrationscripts
1919

2020
import (
21-
"net/url"
22-
2321
"github.com/apache/incubator-devlake/core/context"
2422
"github.com/apache/incubator-devlake/core/errors"
2523
)
2624

2725
type modifyCommitCharacterType0508 struct{}
2826

2927
func (*modifyCommitCharacterType0508) Up(basicRes context.BasicRes) errors.Error {
30-
dbUrl := basicRes.GetConfig("DB_URL")
31-
if dbUrl == "" {
32-
return errors.BadInput.New("DB_URL is required")
33-
}
34-
u, err1 := url.Parse(dbUrl)
35-
if err1 != nil {
36-
return errors.Convert(err1)
37-
}
38-
if u.Scheme == "mysql" {
39-
err := basicRes.GetDal().Exec(`ALTER TABLE commit_files MODIFY COLUMN file_path VARBINARY(1024);`)
28+
db := basicRes.GetDal()
29+
// VARBINARY is MySQL-specific; PostgreSQL uses bytea natively
30+
if db.Dialect() == "mysql" {
31+
err := db.Exec(`ALTER TABLE commit_files MODIFY COLUMN file_path VARBINARY(1024);`)
4032
if err != nil {
4133
return err
4234
}

backend/plugins/testmo/models/migrationscripts/20250629_add_scope_config_id_to_projects.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,21 @@ import (
2121
"github.com/apache/incubator-devlake/core/context"
2222
"github.com/apache/incubator-devlake/core/errors"
2323
"github.com/apache/incubator-devlake/core/plugin"
24+
"github.com/apache/incubator-devlake/helpers/migrationhelper"
2425
)
2526

2627
type addScopeConfigIdToProjects struct{}
2728

29+
type TestmoProject20250629 struct {
30+
ScopeConfigId uint64 `gorm:"type:BIGINT NOT NULL DEFAULT 0"`
31+
}
32+
33+
func (TestmoProject20250629) TableName() string {
34+
return "_tool_testmo_projects"
35+
}
36+
2837
func (*addScopeConfigIdToProjects) Up(basicRes context.BasicRes) errors.Error {
29-
db := basicRes.GetDal()
30-
return db.Exec("ALTER TABLE `_tool_testmo_projects` ADD COLUMN `scope_config_id` bigint unsigned NOT NULL DEFAULT 0")
38+
return migrationhelper.AutoMigrateTables(basicRes, &TestmoProject20250629{})
3139
}
3240

3341
func (*addScopeConfigIdToProjects) Version() uint64 {

docker-compose-dev.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ services:
7979
- mysql
8080

8181
devlake:
82-
image: devlake.docker.scarf.sh/apache/devlake:latest
82+
image: devlake-local:latest
8383
build:
8484
context: backend
85+
dockerfile: Dockerfile.local
8586
args:
8687
HTTPS_PROXY: "${HTTPS_PROXY}"
8788
GOPROXY: "${GOPROXY}"
@@ -93,6 +94,10 @@ services:
9394
env_file:
9495
- ./.env
9596
environment:
97+
DB_URL: postgres://merico:merico@postgres:5432/lake?sslmode=disable
98+
E2E_DB_URL: postgres://merico:merico@postgres:5432/lake_test?sslmode=disable
99+
REMOTE_PLUGIN_DIR: ""
100+
FORCE_MIGRATION: "true"
96101
LOGGING_DIR: /app/logs
97102
TZ: UTC
98103
# LOGOUT_URI: https://xxx.amazoncognito.com/logout?client_id=yyy&logout_uri=http%3A%2F%2Flocalhost%3A4180%2Foauth2%2Fsign_out

0 commit comments

Comments
 (0)