Skip to content

Commit 04e0ad6

Browse files
author
reearth-app[bot]
committed
Merge branch 'main' into release
2 parents 7f98720 + 010fd26 commit 04e0ad6

File tree

362 files changed

+30555
-53093
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

362 files changed

+30555
-53093
lines changed

.github/workflows/deploy_server_nightly.yml

+7-11
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ on:
55
concurrency:
66
group: ${{ github.workflow }}
77
cancel-in-progress: true
8-
env:
9-
GCP_REGION: us-central1
10-
IMAGE: reearth/reearth-visualizer-api:nightly
11-
IMAGE_GCP: us-central1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/reearth/reearth-visualizer-api:nightly
128
jobs:
139
deploy_test:
1410
runs-on: ubuntu-latest
@@ -20,21 +16,21 @@ jobs:
2016
- uses: actions/checkout@v4
2117
- uses: google-github-actions/auth@v2
2218
with:
23-
service_account: ${{ secrets.GCP_SA_EMAIL }}
24-
workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
19+
service_account: ${{ secrets.GC_SA_EMAIL }}
20+
workload_identity_provider: ${{ secrets.GC_WORKLOAD_IDENTITY_PROVIDER }}
2521
- name: Set up Cloud SDK
2622
uses: google-github-actions/setup-gcloud@v2
2723
- name: Configure docker
2824
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
2925
- name: docker push
3026
run: |
31-
docker pull $IMAGE
32-
docker tag $IMAGE $IMAGE_GCP
33-
docker push $IMAGE_GCP
27+
docker pull ${{ secrets.SERVER_IMAGE }}
28+
docker tag ${{ secrets.SERVER_IMAGE }} ${{ secrets.SERVER_IMAGE_GC }}
29+
docker push ${{ secrets.SERVER_IMAGE_GC }}
3430
- name: Deploy to Cloud Run
3531
run: |
3632
gcloud run deploy reearth-visualizer-api \
37-
--image $IMAGE_GCP \
38-
--region $GCP_REGION \
33+
--image ${{ secrets.SERVER_IMAGE_GC }} \
34+
--region ${{ secrets.GC_REGION }} \
3935
--platform managed \
4036
--quiet

.github/workflows/deploy_web_nightly.yml

+7-11
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ on:
55
concurrency:
66
group: ${{ github.workflow }}
77
cancel-in-progress: true
8-
env:
9-
GCP_REGION: us-central1
10-
IMAGE: reearth/reearth-visualizer-web:nightly
11-
IMAGE_GCP: us-central1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/reearth/reearth-visualizer-web:nightly
128
jobs:
139
deploy_test:
1410
runs-on: ubuntu-latest
@@ -20,21 +16,21 @@ jobs:
2016
- uses: actions/checkout@v4
2117
- uses: google-github-actions/auth@v2
2218
with:
23-
service_account: ${{ secrets.GCP_SA_EMAIL }}
24-
workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
19+
service_account: ${{ secrets.GC_SA_EMAIL }}
20+
workload_identity_provider: ${{ secrets.GC_WORKLOAD_IDENTITY_PROVIDER }}
2521
- name: Set up Cloud SDK
2622
uses: google-github-actions/setup-gcloud@v2
2723
- name: Configure docker
2824
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
2925
- name: docker push
3026
run: |
31-
docker pull $IMAGE
32-
docker tag $IMAGE $IMAGE_GCP
33-
docker push $IMAGE_GCP
27+
docker pull ${{ secrets.WEB_IMAGE }}
28+
docker tag ${{ secrets.WEB_IMAGE }} ${{ secrets.WEB_IMAGE_GC }}
29+
docker push ${{ secrets.WEB_IMAGE_GC }}
3430
- name: Deploy to Cloud Run
3531
run: |
3632
gcloud run deploy reearth-visualizer-web \
37-
--image $IMAGE_GCP \
38-
--region $GCP_REGION \
33+
--image ${{ secrets.WEB_IMAGE_GC }} \
34+
--region ${{ secrets.GC_REGION }} \
3935
--platform managed \
4036
--quiet

.github/workflows/run_migration.yml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: run-migration
2+
on:
3+
workflow_dispatch:
4+
5+
concurrency:
6+
group: ${{ github.workflow }}-${{ github.ref_name }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
migrate:
11+
name: Run migration (Nightly)
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
id-token: write
16+
env:
17+
GCP_REGION: us-central1
18+
IMAGE: reearth/reearth-visualizer-api:nightly
19+
IMAGE_GCP: us-central1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/reearth/reearth-visualizer-api:nightly
20+
steps:
21+
- name: Authenticate to Google Cloud
22+
uses: google-github-actions/auth@v2
23+
with:
24+
service_account: ${{ secrets.GCP_SA_EMAIL }}
25+
workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
26+
27+
- name: Update Migration Job
28+
run: |
29+
gcloud run jobs update reearth-visualizer-migration \
30+
--image $IMAGE_GCP \
31+
--region $GCP_REGION \
32+
--quiet
33+
34+
- name: Execute Migration Job
35+
run: |
36+
gcloud run jobs execute reearth-visualizer-migration \
37+
--region $GCP_REGION \
38+
--wait \
39+
--quiet

server/Makefile

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ help:
1919
@echo " dev Run the application with hot reloading"
2020
@echo " run-app Run the application"
2121
@echo " run-db Run the MongoDB database using Docker Compose"
22+
@echo " run-reset Initialize the MongoDB data"
2223
@echo " up-gcs Run the fake-gcs-server using Docker Compose"
2324
@echo " down-gcs Stop the fake-gcs-server using Docker Compose"
2425
@echo " gql Generate GraphQL code include dataloader"
@@ -81,6 +82,13 @@ run-app:
8182
run-db:
8283
docker compose -f ../docker-compose.yml up -d reearth-mongo
8384

85+
run-reset:
86+
docker stop reearth-visualizer-reearth-mongo-1
87+
rm -rf ../mongo
88+
rm -rf data
89+
make run-db
90+
make mockuser
91+
8492
generate: dev-install
8593
go generate ./...
8694

@@ -101,4 +109,4 @@ schematyper:
101109
go run $(SCHEMATYPER) -o $(MANIFEST_DIR)/schema_translation.go --package manifest --prefix Translation ./schemas/plugin_manifest_translation.json
102110
go run $(SCHEMATYPER) -o $(MANIFEST_DIR)/schema_gen.go --package manifest ./schemas/plugin_manifest.json
103111

104-
.PHONY: lint test failcheck e2e build dev-install dev run-app run-db gql up-gcs down-gcs mockuser schematyper
112+
.PHONY: lint test failcheck e2e build dev-install dev run-app run-db run-reset gql up-gcs down-gcs mockuser schematyper

server/e2e/common.go

+76-74
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"net"
1010
"net/http"
11+
"reflect"
1112
"regexp"
1213
"strings"
1314
"testing"
@@ -31,13 +32,23 @@ import (
3132
"golang.org/x/text/language"
3233
)
3334

34-
type Seeder func(ctx context.Context, r *repo.Container) error
35+
var (
36+
fr *gateway.File
37+
disabledAuthConfig = &config.Config{
38+
Origins: []string{"https://example.com"},
39+
AuthSrv: config.AuthSrvConfig{
40+
Disabled: true,
41+
},
42+
}
43+
)
44+
45+
type Seeder func(ctx context.Context, r *repo.Container, f gateway.File) error
3546

3647
func init() {
3748
mongotest.Env = "REEARTH_DB"
3849
}
3950

40-
func initRepos(t *testing.T, useMongo bool, seeder Seeder) (repos *repo.Container) {
51+
func initRepos(t *testing.T, useMongo bool, seeder Seeder) (repos *repo.Container, file gateway.File) {
4152
ctx := context.Background()
4253

4354
if useMongo {
@@ -48,18 +59,25 @@ func initRepos(t *testing.T, useMongo bool, seeder Seeder) (repos *repo.Containe
4859
repos = memory.New()
4960
}
5061

62+
file = lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com/"))
63+
fr = &file
5164
if seeder != nil {
52-
if err := seeder(ctx, repos); err != nil {
65+
if err := seeder(ctx, repos, file); err != nil {
5366
t.Fatalf("failed to seed the db: %s", err)
5467
}
5568
}
5669

57-
return repos
70+
return repos, file
5871
}
5972

6073
func initGateway() *gateway.Container {
74+
if fr == nil {
75+
return &gateway.Container{
76+
File: lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com/")),
77+
}
78+
}
6179
return &gateway.Container{
62-
File: lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com")),
80+
File: *fr,
6381
}
6482
}
6583

@@ -117,96 +135,51 @@ func StartGQLServerWithRepos(t *testing.T, cfg *config.Config, repos *repo.Conta
117135
}
118136

119137
func StartGQLServerAndRepos(t *testing.T, seeder Seeder) (*httpexpect.Expect, *accountrepo.Container) {
120-
cfg := &config.Config{
121-
Origins: []string{"https://example.com"},
122-
AuthSrv: config.AuthSrvConfig{
123-
Disabled: true,
124-
},
125-
}
126-
repos := initRepos(t, true, seeder)
127-
e, _, _ := StartGQLServerWithRepos(t, cfg, repos)
138+
repos, _ := initRepos(t, true, seeder)
139+
e, _, _ := StartGQLServerWithRepos(t, disabledAuthConfig, repos)
128140
return e, repos.AccountRepos()
129141
}
130142

131-
func initServer(cfg *config.Config, repos *repo.Container, ctx context.Context) (*app.WebServer, *gateway.Container) {
132-
gateways := initGateway()
133-
return app.NewServer(ctx, &app.ServerConfig{
134-
Config: cfg,
135-
Repos: repos,
136-
AccountRepos: repos.AccountRepos(),
137-
Gateways: gateways,
138-
Debug: true,
139-
}), gateways
143+
func startServer(t *testing.T, cfg *config.Config, useMongo bool, seeder Seeder) (*httpexpect.Expect, *repo.Container, *gateway.Container) {
144+
repos, _ := initRepos(t, useMongo, seeder)
145+
e, gateways, _ := StartGQLServerWithRepos(t, cfg, repos)
146+
return e, repos, gateways
140147
}
141148

142-
func StartServerWithRepos(t *testing.T, cfg *config.Config, repos *repo.Container) (*httpexpect.Expect, *gateway.Container) {
143-
t.Helper()
144-
145-
if testing.Short() {
146-
t.Skip("skipping test in short mode.")
147-
}
148-
149-
ctx := context.Background()
150-
151-
l, err := net.Listen("tcp", ":0")
152-
if err != nil {
153-
t.Fatalf("server failed to listen: %v", err)
154-
}
155-
156-
srv, gateways := initServer(cfg, repos, ctx)
157-
158-
ch := make(chan error)
159-
go func() {
160-
if err := srv.Serve(l); err != http.ErrServerClosed {
161-
ch <- err
162-
}
163-
close(ch)
164-
}()
165-
t.Cleanup(func() {
166-
if err := srv.Shutdown(context.Background()); err != nil {
167-
t.Fatalf("server shutdown: %v", err)
168-
}
169-
170-
if err := <-ch; err != nil {
171-
t.Fatalf("server serve: %v", err)
172-
}
173-
})
174-
return httpexpect.Default(t, "http://"+l.Addr().String()), gateways
149+
func ServerAndRepos(t *testing.T, seeder Seeder) (*httpexpect.Expect, *repo.Container, *gateway.Container) {
150+
return startServer(t, disabledAuthConfig, true, seeder)
175151
}
176152

177-
func StartServerAndRepos(t *testing.T, cfg *config.Config, useMongo bool, seeder Seeder) (*httpexpect.Expect, *repo.Container, *gateway.Container) {
178-
repos := initRepos(t, useMongo, seeder)
179-
e, gateways := StartServerWithRepos(t, cfg, repos)
180-
return e, repos, gateways
153+
func Server(t *testing.T, seeder Seeder) *httpexpect.Expect {
154+
e, _, _ := startServer(t, disabledAuthConfig, true, seeder)
155+
return e
181156
}
182157

183-
func StartServer(t *testing.T, cfg *config.Config, useMongo bool, seeder Seeder) *httpexpect.Expect {
184-
e, _, _ := StartServerAndRepos(t, cfg, useMongo, seeder)
158+
func ServerPingTest(t *testing.T) *httpexpect.Expect {
159+
e, _, _ := startServer(t, disabledAuthConfig, false, nil)
185160
return e
186161
}
187162

188-
func Server(t *testing.T, seeder Seeder) *httpexpect.Expect {
163+
func ServerMockTest(t *testing.T) *httpexpect.Expect {
189164
c := &config.Config{
190-
Origins: []string{"https://example.com"},
165+
Dev: true,
166+
MockAuth: true,
167+
Origins: []string{"https://example.com"},
191168
AuthSrv: config.AuthSrvConfig{
192169
Disabled: true,
193170
},
194171
}
195-
return StartServer(t, c, true, seeder)
172+
e, _, _ := startServer(t, c, true, nil)
173+
return e
196174
}
197175

198176
func ServerLanguage(t *testing.T, lang language.Tag) *httpexpect.Expect {
199-
c := &config.Config{
200-
Origins: []string{"https://example.com"},
201-
AuthSrv: config.AuthSrvConfig{
202-
Disabled: true,
203-
},
204-
}
205-
return StartServer(t, c, true,
206-
func(ctx context.Context, r *repo.Container) error {
207-
return baseSeederWithLang(ctx, r, lang)
177+
e, _, _ := startServer(t, disabledAuthConfig, true,
178+
func(ctx context.Context, r *repo.Container, f gateway.File) error {
179+
return baseSeederWithLang(ctx, r, f, lang)
208180
},
209181
)
182+
return e
210183
}
211184

212185
type GraphQLRequest struct {
@@ -275,6 +248,7 @@ func RegexpJSONEReadCloser(t *testing.T, actual io.ReadCloser, expected string)
275248
actualBuf := new(bytes.Buffer)
276249
_, err := actualBuf.ReadFrom(actual)
277250
assert.NoError(t, err)
251+
// ActualDump(actualBuf)
278252
return JSONEqRegexp(t, actualBuf.String(), expected)
279253
}
280254

@@ -284,6 +258,13 @@ func JSONEqRegexpInterface(t *testing.T, actual interface{}, expected string) bo
284258
return JSONEqRegexp(t, string(actualBytes), expected)
285259
}
286260

261+
func JSONEqRegexpValue(t *testing.T, actual *httpexpect.Value, expected string) bool {
262+
if actualData, ok := actual.Raw().(map[string]interface{}); ok {
263+
return JSONEqRegexpInterface(t, actualData, expected)
264+
}
265+
return false
266+
}
267+
287268
func aligningJSON(t *testing.T, str string) string {
288269
// Unmarshal and Marshal to make the JSON format consistent
289270
var obj interface{}
@@ -295,9 +276,30 @@ func aligningJSON(t *testing.T, str string) string {
295276
}
296277

297278
func ValueDump(val *httpexpect.Value) {
298-
if data, ok := val.Raw().(map[string]interface{}); ok {
279+
raw := val.Raw()
280+
switch data := raw.(type) {
281+
case map[string]interface{}:
299282
if text, err := json.MarshalIndent(data, "", " "); err == nil {
300283
fmt.Println(string(text))
301284
}
285+
case []interface{}:
286+
if text, err := json.MarshalIndent(data, "", " "); err == nil {
287+
fmt.Println(string(text))
288+
}
289+
default:
290+
fmt.Println("Unsupported type:", reflect.TypeOf(raw))
291+
}
292+
}
293+
294+
func ActualDump(actual *bytes.Buffer) {
295+
var data interface{}
296+
if err := json.Unmarshal(actual.Bytes(), &data); err != nil {
297+
fmt.Println("Invalid JSON:", err)
298+
return
299+
}
300+
if text, err := json.MarshalIndent(data, "", " "); err == nil {
301+
fmt.Println(string(text))
302+
} else {
303+
fmt.Println("Failed to format JSON:", err)
302304
}
303305
}

0 commit comments

Comments
 (0)