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

Add support for Microfrontends #273

Merged
177 changes: 177 additions & 0 deletions client/microfrontend_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
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 MicrofrontendGroupsAPI struct {
Group MicrofrontendGroup `json:"group"`
Projects []MicrofrontendGroupMembershipsResponseAPI `json:"projects"`
}

type MicrofrontendGroupsAPIResponse struct {
Groups []MicrofrontendGroupsAPI `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,
})
res := MicrofrontendGroupsAPIResponse{}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "GET",
url: url,
body: "",
}, &res)

if err != nil {
return r, err
}

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

for i := range res.Groups {
if res.Groups[i].Group.ID == microfrontendGroupID {
projects := map[string]MicrofrontendGroupMembership{}
defaultApp := MicrofrontendGroupMembership{}
for _, p := range res.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]
}
}
res := MicrofrontendGroup{
ID: res.Groups[i].Group.ID,
Name: res.Groups[i].Group.Name,
Slug: res.Groups[i].Group.Slug,
TeamID: c.teamID(teamID),
DefaultApp: defaultApp,
Projects: projects,
}
tflog.Info(ctx, "returning microfrontend group", map[string]interface{}{
"res": res,
})
return res, 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, request MicrofrontendGroupMembership) (r MicrofrontendGroupMembership, err error) {
tflog.Info(ctx, "getting microfrontend group", map[string]interface{}{
"project_id": request.ProjectID,
"group_id": request.MicrofrontendGroupID,
"team_id": c.teamID(request.TeamID),
})
group, err := c.GetMicrofrontendGroup(ctx, request.MicrofrontendGroupID, c.teamID(request.TeamID))
if err != nil {
return r, err
}
tflog.Info(ctx, "getting microfrontend group membership", map[string]interface{}{
"project_id": request.ProjectID,
"group": group,
})
return group.Projects[request.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
}
33 changes: 33 additions & 0 deletions docs/data-sources/microfrontend_group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
# 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.



<!-- 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` (String) The default app for the project. Used as the entry point for the microfrontend.
- `name` (String) A human readable name for the microfrontends group.
- `slug` (String) A slugified version of the name.
33 changes: 33 additions & 0 deletions docs/data-sources/microfrontend_group_membership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "vercel_microfrontend_group_membership Data Source - terraform-provider-vercel"
subcategory: ""
description: |-
Provides information about an existing Microfrontend Group Membership.
A Microfrontend Group Membership is a definition of a Vercel Project being a part of a Microfrontend Group.
---

# vercel_microfrontend_group_membership (Data Source)

Provides information about an existing Microfrontend Group Membership.

A Microfrontend Group Membership is a definition of a Vercel Project being a part of a Microfrontend Group.



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

### Required

- `microfrontend_group_id` (String) The ID of the microfrontend group.
- `project_id` (String) The ID of the project.

### Optional

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

### Read-Only

- `default_route` (String) The default route for the project. Used for the screenshot of deployments.
- `route_observability_to_this_project` (Boolean) Whether the project is route observability for this project. If dalse, the project will be route observability for all projects to the default project.
Loading
Loading