Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ci,server,worker): implement schemata and items copy #1331

Merged
merged 35 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d5bd2da
add copy endpoint
nourbalaha Dec 3, 2024
3ac705a
wip
nourbalaha Dec 3, 2024
e5bf984
add comments
nourbalaha Dec 3, 2024
3637b2b
refactor
nourbalaha Dec 5, 2024
940cd8e
wip
nourbalaha Dec 5, 2024
66488fc
wip: server implementation
nourbalaha Dec 10, 2024
1fed519
update copy model function name
nourbalaha Dec 11, 2024
03bba70
wip: copier ci
nourbalaha Dec 11, 2024
599555e
Merge branch 'main' into feat-server/schemata-item-copy
nourbalaha Dec 11, 2024
2e19994
remove copy of the internal server files in worker docker image
nourbalaha Dec 11, 2024
6cc70dd
wip: worker
nourbalaha Dec 13, 2024
ff5e8a4
wip: repo
nourbalaha Dec 17, 2024
6f67abe
Merge branch 'main' into feat-server/schemata-item-copy
nourbalaha Dec 17, 2024
c246f47
apply new changes from worker to server
nourbalaha Dec 17, 2024
8f4514c
refactor changes type
nourbalaha Dec 17, 2024
e233002
refactor copier in mongo
nourbalaha Dec 19, 2024
a4f7e43
refactor
nourbalaha Dec 19, 2024
46bf7cc
feat: refactor copier main file
nourbalaha Dec 19, 2024
bf78f86
add e2e test
nourbalaha Dec 19, 2024
d14362a
wip: server test cases
nourbalaha Dec 20, 2024
2fac5ce
wip: worker tests
nourbalaha Dec 20, 2024
d2f3636
update TestSchema_CopyFrom
nourbalaha Dec 23, 2024
e80cf07
refactor
nourbalaha Dec 23, 2024
d69c7e4
Merge branch 'main' into feat-server/schemata-item-copy
nourbalaha Jan 6, 2025
31914d9
lint
nourbalaha Jan 6, 2025
c1c8124
requested changes copier
nourbalaha Jan 9, 2025
43e3756
add key to params
nourbalaha Jan 9, 2025
0ac1161
wip
nourbalaha Jan 14, 2025
cb5d2e2
refactor
nourbalaha Jan 14, 2025
7382546
add a log after data successfully copied
nourbalaha Jan 14, 2025
2d38a47
improve triggerCopyEvent logging
nourbalaha Jan 14, 2025
086a8de
Merge branch 'main' into feat-server/schemata-item-copy
nourbalaha Jan 14, 2025
a798a8b
fix db URI
nourbalaha Jan 14, 2025
90b5277
add more unit tests
nourbalaha Jan 14, 2025
ce70e17
Merge branch 'main' into feat-server/schemata-item-copy
nourbalaha Jan 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions .github/workflows/build_copier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: copier-build
on:
workflow_run:
workflows: [ci-worker]
types: [completed]
branches: [main, release]
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

jobs:
info:
name: Collect information
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'failure' && github.event.repository.full_name == 'reearth/reearth-cms' && (github.event.workflow_run.head_branch == 'release' || !startsWith(github.event.workflow_run.head_commit.message, 'v'))
outputs:
sha_short: ${{ steps.info.outputs.sha_short }}
new_tag: ${{ steps.info.outputs.new_tag }}
new_tag_short: ${{ steps.info.outputs.new_tag_short }}
name: ${{ steps.info.outputs.name }}
steps:
- name: checkout
uses: actions/checkout@v4
- name: Fetch tags
run: git fetch --prune --unshallow --tags
- name: Get info
id: info
# The tag name should be retrieved lazily, as tagging may be delayed.
env:
BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
if [[ "$BRANCH" = "release" ]]; then
TAG=$(git tag --points-at HEAD)
if [[ ! -z "$TAG" ]]; then
echo "new_tag=$TAG" >> "$GITHUB_OUTPUT"
echo "new_tag_short=${TAG#v}" >> "$GITHUB_OUTPUT"
else
echo "name=rc" >> "$GITHUB_OUTPUT"
fi
else
echo "name=nightly" >> "$GITHUB_OUTPUT"
fi
- name: Show info
env:
SHA_SHORT: ${{ steps.info.outputs.sha_short }}
NEW_TAG: ${{ steps.info.outputs.new_tag }}
NEW_TAG_SHORT: ${{ steps.info.outputs.new_tag_short }}
NAME: ${{ steps.info.outputs.name }}
run: echo "sha_short=$SHA_SHORT, new_tag=$NEW_TAG, new_tag_short=$NEW_TAG_SHORT, name=$NAME"

docker:
name: Build and push Docker image
runs-on: ubuntu-latest
needs:
- info
if: needs.info.outputs.name || needs.info.outputs.new_tag
env:
IMAGE_NAME: reearth/reearth-cms-copier
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get options
id: options
env:
TAG: ${{ needs.info.outputs.new_tag_short }}
NAME: ${{ needs.info.outputs.name }}
SHA: ${{ needs.info.outputs.sha_short }}
run: |
if [[ -n $TAG ]]; then
PLATFORMS=linux/amd64,linux/arm64
VERSION=$TAG
TAGS=$IMAGE_NAME:$TAG
if [[ ! $TAG =~ '-' ]]; then
TAGS+=,${IMAGE_NAME}:${TAG%.*}
TAGS+=,${IMAGE_NAME}:${TAG%%.*}
TAGS+=,${IMAGE_NAME}:latest
fi
else
PLATFORMS=linux/amd64
VERSION=$SHA
TAGS=$IMAGE_NAME:$NAME
fi
echo "platforms=$PLATFORMS" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
- name: Build and push docker image
uses: docker/build-push-action@v6
with:
context: ./worker
file: ./worker/copier.Dockerfile
platforms: ${{ steps.options.outputs.platforms }}
push: true
build-args: VERSION=${{ steps.options.outputs.version }}
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
nourbalaha marked this conversation as resolved.
Show resolved Hide resolved
53 changes: 53 additions & 0 deletions .github/workflows/build_worker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,56 @@ jobs:
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

docker_copier:
runs-on: ubuntu-latest
if: inputs.name || inputs.new_tag
env:
IMAGE_NAME: reearth/reearth-cms-copier
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get options
id: options
env:
TAG: ${{ inputs.new_tag_short }}
NAME: ${{ inputs.name }}
SHA: ${{ inputs.sha_short }}
run: |
if [[ -n $TAG ]]; then
PLATFORMS=linux/amd64,linux/arm64
VERSION=$TAG
TAGS=$IMAGE_NAME:$TAG
if [[ ! $TAG =~ '-' ]]; then
TAGS+=,${IMAGE_NAME}:${TAG%.*}
TAGS+=,${IMAGE_NAME}:${TAG%%.*}
TAGS+=,${IMAGE_NAME}:latest
fi
else
PLATFORMS=linux/amd64
VERSION=$SHA
TAGS=$IMAGE_NAME:$NAME
fi
echo "platforms=$PLATFORMS" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
- name: Build and push docker image
uses: docker/build-push-action@v6
with:
context: ./worker
file: ./worker/copier.Dockerfile
platforms: ${{ steps.options.outputs.platforms }}
push: true
build-args: VERSION=${{ steps.options.outputs.version }}
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
82 changes: 82 additions & 0 deletions server/e2e/integration_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,88 @@ func TestIntegrationModelGetAPI(t *testing.T) {
obj.Value("lastModified").NotNull()
}

// POST /models/{modelId}/copy
func TestIntegrationModelCopy(t *testing.T) {
endpoint := "/api/models/{modelId}/copy"
e := StartServer(t, &app.Config{}, true, baseSeeder)

e.POST(endpoint, id.NewModelID()).
Expect().
Status(http.StatusUnauthorized)

e.POST(endpoint, id.NewModelID()).
WithHeader("authorization", "secret_abc").
Expect().
Status(http.StatusUnauthorized)

e.POST(endpoint, id.NewModelID()).
WithHeader("authorization", "Bearer secret_abc").
Expect().
Status(http.StatusUnauthorized)

oldModelId := mId1.String()
oldModel := e.GET("/api/models/{modelId}", oldModelId).
WithHeader("authorization", "Bearer "+secret).
Expect().
Status(http.StatusOK).
JSON().
Object()

newName := "new name"
newModel := e.POST(endpoint, oldModelId).
WithHeader("authorization", "Bearer "+secret).
WithJSON(map[string]interface{}{
"name": newName,
}).
Expect().
Status(http.StatusOK).
JSON().
Object()

newModel.
ContainsKey("id").
ContainsKey("projectId").
ContainsKey("schemaId").
ContainsKey("public").
ContainsKey("createdAt").
ContainsKey("updatedAt").
ContainsKey("key")

newModelID := newModel.Value("id").String()
newModelID.NotEqual(oldModelId)
copiedModel := e.GET("/api/models/{modelId}", newModelID.Raw()).
WithHeader("authorization", "Bearer "+secret).
Expect().
Status(http.StatusOK).
JSON().
Object()
copiedModel.
HasValue("id", newModelID.Raw()).
HasValue("projectId", oldModel.Value("projectId").String().Raw()).
HasValue("public", oldModel.Value("public").Boolean().Raw()).
HasValue("name", newName).
HasValue("description", oldModel.Value("description").String().Raw())

copiedModel.Value("schemaId").NotNull()
oldSchemaId := oldModel.Value("schemaId").String()
copiedSchemaId := copiedModel.Value("schemaId").String()
copiedSchemaId.NotEqual(oldSchemaId.Raw())

oldSchema := oldModel.Value("schema").Object()
copiedSchema := copiedModel.Value("schema").Object()
copiedSchema.Value("fields").Array().Length().IsEqual(oldSchema.Value("fields").Array().Length().Raw())
copiedSchema.Value("titleField").String().IsEqual(oldSchema.Value("titleField").String().Raw())

copiedModel.Value("metadataSchemaId").NotNull()
oldMetadataSchemaId := oldModel.Value("metadataSchemaId").String()
copiedMetadataSchemaId := copiedModel.Value("metadataSchemaId").String()
copiedMetadataSchemaId.NotEqual(oldMetadataSchemaId.Raw())

oldMetadataSchema := oldModel.Value("metadataSchema").Object()
copiedMetadataSchema := copiedModel.Value("metadataSchema").Object()
copiedMetadataSchema.Value("fields").Array().Length().IsEqual(oldMetadataSchema.Value("fields").Array().Length().Raw())
}

// PATCH /models/{modelId}
func TestIntegrationModelUpdateAPI(t *testing.T) {
endpoint := "/api/models/{modelId}"
Expand Down
31 changes: 31 additions & 0 deletions server/internal/adapter/integration/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,37 @@ func (s *Server) ModelGet(ctx context.Context, request ModelGetRequestObject) (M
return ModelGet200JSONResponse(integrationapi.NewModel(m, sp, lastModified)), nil
}

func (s *Server) CopyModel(ctx context.Context, request CopyModelRequestObject) (CopyModelResponseObject, error) {
uc := adapter.Usecases(ctx)
op := adapter.Operator(ctx)

m, err := uc.Model.Copy(ctx, interfaces.CopyModelParam{
ModelId: request.ModelId,
Name: request.Body.Name,
}, op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return CopyModel404Response{}, err
}
return CopyModel500Response{}, err
}

sp, err := uc.Schema.FindByModel(ctx, m.ID(), op)
if err != nil {
if errors.Is(err, rerror.ErrNotFound) {
return CopyModel404Response{}, err
}
return CopyModel500Response{}, err
}

lastModified, err := uc.Item.LastModifiedByModel(ctx, m.ID(), op)
if err != nil && !errors.Is(err, rerror.ErrNotFound) {
return CopyModel500Response{}, err
}
nourbalaha marked this conversation as resolved.
Show resolved Hide resolved

return CopyModel200JSONResponse(integrationapi.NewModel(m, sp, lastModified)), nil
}

func (s *Server) ModelGetWithProject(ctx context.Context, request ModelGetWithProjectRequestObject) (ModelGetWithProjectResponseObject, error) {
uc := adapter.Usecases(ctx)
op := adapter.Operator(ctx)
Expand Down
Loading
Loading