这是indexloc提供的服务,不要输入任何密码
Skip to content

Add support for Microfrontends #273

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

Merged
Merged
187 changes: 187 additions & 0 deletions client/microfrontend_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package client

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tflog"
)

type MicrofrontendGroup struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
TeamID string `json:"team_id"`
Projects map[string]MicrofrontendGroupMembership `json:"projects"`
DefaultApp MicrofrontendGroupMembership `json:"defaultApp"`
}

type MicrofrontendGroupsAPIResponse struct {
Groups []struct {
Group struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
TeamID string `json:"team_id"`
Projects map[string]struct {
IsDefaultApp bool `json:"isDefaultApp"`
DefaultRoute string `json:"defaultRoute"`
RouteObservabilityToThisProject bool `json:"routeObservabilityToThisProject"`
ProjectID string `json:"projectId"`
Enabled bool `json:"enabled"`
} `json:"projects"`
} `json:"group"`
Projects []MicrofrontendGroupMembershipsResponseAPI `json:"projects"`
} `json:"groups"`
}

func (c *Client) CreateMicrofrontendGroup(ctx context.Context, TeamID string, Name string) (r MicrofrontendGroup, err error) {
if c.teamID(TeamID) == "" {
return r, fmt.Errorf("team_id is required")
}
tflog.Info(ctx, "creating microfrontend group", map[string]interface{}{
"microfrontend_group_name": Name,
"team_id": c.teamID(TeamID),
})
url := fmt.Sprintf("%s/teams/%s/microfrontends", c.baseURL, c.teamID(TeamID))
payload := string(mustMarshal(struct {
NewMicrofrontendsGroupName string `json:"newMicrofrontendsGroupName"`
}{
NewMicrofrontendsGroupName: Name,
}))
apiResponse := struct {
NewMicrofrontendGroup MicrofrontendGroup `json:"newMicrofrontendsGroup"`
}{}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "PATCH",
url: url,
body: payload,
}, &apiResponse)
if err != nil {
return r, err
}
return MicrofrontendGroup{
ID: apiResponse.NewMicrofrontendGroup.ID,
Name: apiResponse.NewMicrofrontendGroup.Name,
Slug: apiResponse.NewMicrofrontendGroup.Slug,
TeamID: c.teamID(TeamID),
}, nil
}

func (c *Client) UpdateMicrofrontendGroup(ctx context.Context, request MicrofrontendGroup) (r MicrofrontendGroup, err error) {
if c.teamID(request.TeamID) == "" {
return r, fmt.Errorf("team_id is required")
}
url := fmt.Sprintf("%s/teams/%s/microfrontends/%s", c.baseURL, c.teamID(request.TeamID), request.ID)
payload := string(mustMarshal(struct {
Name string `json:"name"`
}{
Name: request.Name,
}))
tflog.Info(ctx, "updating microfrontend group", map[string]interface{}{
"url": url,
"payload": payload,
})
apiResponse := struct {
UpdatedMicrofrontendsGroup MicrofrontendGroup `json:"updatedMicrofrontendsGroup"`
}{}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "PATCH",
url: url,
body: payload,
}, &apiResponse)
if err != nil {
return r, err
}
return MicrofrontendGroup{
ID: apiResponse.UpdatedMicrofrontendsGroup.ID,
Name: apiResponse.UpdatedMicrofrontendsGroup.Name,
Slug: apiResponse.UpdatedMicrofrontendsGroup.Slug,
TeamID: c.teamID(request.TeamID),
}, nil
}

func (c *Client) DeleteMicrofrontendGroup(ctx context.Context, request MicrofrontendGroup) (r struct{}, err error) {
if c.teamID(request.TeamID) == "" {
return r, fmt.Errorf("team_id is required")
}
url := fmt.Sprintf("%s/teams/%s/microfrontends/%s", c.baseURL, c.teamID(request.TeamID), request.ID)

tflog.Info(ctx, "deleting microfrontend group", map[string]interface{}{
"url": url,
})

err = c.doRequest(clientRequest{
ctx: ctx,
method: "DELETE",
url: url,
body: "",
}, &r)
return r, err
}

func (c *Client) GetMicrofrontendGroup(ctx context.Context, microfrontendGroupID string, teamID string) (r MicrofrontendGroup, err error) {
if c.teamID(teamID) == "" {
return r, fmt.Errorf("team_id is required")
}
url := fmt.Sprintf("%s/v1/microfrontends/groups", c.baseURL)
if c.teamID(teamID) != "" {
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(teamID))
}

tflog.Info(ctx, "getting microfrontend group", map[string]interface{}{
"url": url,
})
out := MicrofrontendGroupsAPIResponse{}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "GET",
url: url,
body: "",
}, &out)

if err != nil {
return r, err
}

tflog.Info(ctx, "getting microfrontend group", map[string]interface{}{
"out": out,
})

for i := range out.Groups {
if out.Groups[i].Group.ID == microfrontendGroupID {
projects := map[string]MicrofrontendGroupMembership{}
defaultApp := MicrofrontendGroupMembership{}
for _, p := range out.Groups[i].Projects {
projects[p.ID] = MicrofrontendGroupMembership{
MicrofrontendGroupID: microfrontendGroupID,
ProjectID: p.ID,
TeamID: c.teamID(teamID),
Enabled: p.Microfrontends.Enabled,
IsDefaultApp: p.Microfrontends.IsDefaultApp,
DefaultRoute: p.Microfrontends.DefaultRoute,
RouteObservabilityToThisProject: p.Microfrontends.RouteObservabilityToThisProject,
}
if p.Microfrontends.IsDefaultApp {
defaultApp = projects[p.ID]
}
}
r := MicrofrontendGroup{
ID: out.Groups[i].Group.ID,
Name: out.Groups[i].Group.Name,
Slug: out.Groups[i].Group.Slug,
TeamID: c.teamID(teamID),
DefaultApp: defaultApp,
Projects: projects,
}
tflog.Info(ctx, "returning microfrontend group", map[string]interface{}{
"r": r,
})
return r, nil
}
}

return r, fmt.Errorf("microfrontend group not found")
}
137 changes: 137 additions & 0 deletions client/microfrontend_group_membership.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package client

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tflog"
)

type MicrofrontendGroupMembership struct {
MicrofrontendGroupID string `json:"microfrontendsGroupId"`
IsDefaultApp bool `json:"isDefaultApp"`
DefaultRoute string `json:"defaultRoute"`
RouteObservabilityToThisProject bool `json:"routeObservabilityToThisProject"`
ProjectID string `json:"projectId"`
Enabled bool `json:"enabled"`
TeamID string `json:"team_id"`
}

type MicrofrontendGroupMembershipResponseAPI struct {
GroupIds []string `json:"groupIds"`
Enabled bool `json:"enabled"`
IsDefaultApp bool `json:"isDefaultApp"`
DefaultRoute string `json:"defaultRoute"`
RouteObservabilityToThisProject bool `json:"routeObservabilityToThisProject"`
TeamID string `json:"team_id"`
UpdatedAt int `json:"updatedAt"`
}

type MicrofrontendGroupMembershipsResponseAPI struct {
ID string `json:"id"`
Microfrontends MicrofrontendGroupMembershipResponseAPI `json:"microfrontends"`
}

func (c *Client) GetMicrofrontendGroupMembership(ctx context.Context, TeamID string, GroupID string, ProjectID string) (r MicrofrontendGroupMembership, err error) {
tflog.Info(ctx, "getting microfrontend group", map[string]interface{}{
"project_id": ProjectID,
"group_id": GroupID,
"team_id": c.teamID(TeamID),
})
group, err := c.GetMicrofrontendGroup(ctx, GroupID, c.teamID(TeamID))
if err != nil {
return r, err
}
tflog.Info(ctx, "getting microfrontend group membership", map[string]interface{}{
"project_id": ProjectID,
"group": group,
})
return group.Projects[ProjectID], nil
}

func (c *Client) AddOrUpdateMicrofrontendGroupMembership(ctx context.Context, request MicrofrontendGroupMembership) (r MicrofrontendGroupMembership, err error) {
tflog.Info(ctx, "adding / updating microfrontend project to group", map[string]interface{}{
"is_default_app": request.IsDefaultApp,
"project_id": request.ProjectID,
"group_id": request.MicrofrontendGroupID,
})
p, err := c.PatchMicrofrontendGroupMembership(ctx, MicrofrontendGroupMembership{
ProjectID: request.ProjectID,
TeamID: c.teamID(request.TeamID),
Enabled: true,
IsDefaultApp: request.IsDefaultApp,
DefaultRoute: request.DefaultRoute,
RouteObservabilityToThisProject: request.RouteObservabilityToThisProject,
MicrofrontendGroupID: request.MicrofrontendGroupID,
})
if err != nil {
return r, err
}
return p, nil
}

func (c *Client) RemoveMicrofrontendGroupMembership(ctx context.Context, request MicrofrontendGroupMembership) (r MicrofrontendGroupMembership, err error) {
tflog.Info(ctx, "removing microfrontend project from group", map[string]interface{}{
"project_id": request.ProjectID,
"group_id": request.MicrofrontendGroupID,
"team_id": c.teamID(request.TeamID),
})
p, err := c.PatchMicrofrontendGroupMembership(ctx, MicrofrontendGroupMembership{
ProjectID: request.ProjectID,
TeamID: c.teamID(request.TeamID),
Enabled: false,
MicrofrontendGroupID: request.MicrofrontendGroupID,
})
if err != nil {
return r, err
}
return p, nil
}

func (c *Client) PatchMicrofrontendGroupMembership(ctx context.Context, request MicrofrontendGroupMembership) (r MicrofrontendGroupMembership, err error) {
url := fmt.Sprintf("%s/projects/%s/microfrontends", c.baseURL, request.ProjectID)
payload := string(mustMarshal(MicrofrontendGroupMembership{
IsDefaultApp: request.IsDefaultApp,
DefaultRoute: request.DefaultRoute,
RouteObservabilityToThisProject: request.RouteObservabilityToThisProject,
ProjectID: request.ProjectID,
Enabled: request.Enabled,
MicrofrontendGroupID: request.MicrofrontendGroupID,
}))
if !request.Enabled {
payload = string(mustMarshal(struct {
ProjectID string `json:"projectId"`
Enabled bool `json:"enabled"`
}{
ProjectID: request.ProjectID,
Enabled: request.Enabled,
}))
}
if c.teamID(request.TeamID) != "" {
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID))
}

tflog.Info(ctx, "updating microfrontend group membership", map[string]interface{}{
"url": url,
"payload": payload,
})
apiResponse := MicrofrontendGroupMembershipsResponseAPI{}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "PATCH",
url: url,
body: payload,
}, &apiResponse)
if err != nil {
return r, err
}
return MicrofrontendGroupMembership{
MicrofrontendGroupID: request.MicrofrontendGroupID,
ProjectID: request.ProjectID,
TeamID: c.teamID(request.TeamID),
Enabled: apiResponse.Microfrontends.Enabled,
IsDefaultApp: apiResponse.Microfrontends.IsDefaultApp,
DefaultRoute: apiResponse.Microfrontends.DefaultRoute,
RouteObservabilityToThisProject: apiResponse.Microfrontends.RouteObservabilityToThisProject,
}, nil
}
47 changes: 47 additions & 0 deletions docs/data-sources/microfrontend_group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "vercel_microfrontend_group Data Source - terraform-provider-vercel"
subcategory: ""
description: |-
Provides information about an existing Microfrontend Group.
A Microfrontend Group is a definition of a microfrontend belonging to a Vercel Team.
---

# vercel_microfrontend_group (Data Source)

Provides information about an existing Microfrontend Group.

A Microfrontend Group is a definition of a microfrontend belonging to a Vercel Team.

## Example Usage

```terraform
data "vercel_microfrontend_group" "example" {
id = "mfe_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `id` (String) A unique identifier for the group of microfrontends. Example: mfe_12HKQaOmR5t5Uy6vdcQsNIiZgHGB

### Optional

- `team_id` (String) The team ID to add the project to. Required when configuring a team resource if a default team has not been set in the provider.

### Read-Only

- `default_app` (Attributes) The default app for the project. Used as the entry point for the microfrontend. (see [below for nested schema](#nestedatt--default_app))
- `name` (String) A human readable name for the microfrontends group.
- `slug` (String) A slugified version of the name.

<a id="nestedatt--default_app"></a>
### Nested Schema for `default_app`

Read-Only:

- `default_route` (String) The default route for the project. Used for the screenshot of deployments.
- `project_id` (String) The ID of the project.
Loading