dnscontrol/pkg/cloudflare-go/pages_deployment.go
Tom Limoncelli 7fd6a74e0c
CLOUDFLAREAPI: CF_REDIRECT/CF_TEMP_REDIRECT should dtrt using Single Redirects (#3002)
Co-authored-by: Josh Zhang <jzhang1@stackoverflow.com>
2024-06-18 17:38:50 -04:00

344 lines
10 KiB
Go

package cloudflare
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/goccy/go-json"
)
// SizeOptions can be passed to a list request to configure size and cursor location.
// These values will be defaulted if omitted.
//
// This should be swapped to ResultInfoCursors once the types are corrected.
type SizeOptions struct {
Size int `json:"size,omitempty" url:"size,omitempty"`
Before *int `json:"before,omitempty" url:"before,omitempty"`
After *int `json:"after,omitempty" url:"after,omitempty"`
}
// PagesDeploymentStageLogs represents the logs for a Pages deployment stage.
type PagesDeploymentStageLogs struct {
Name string `json:"name"`
StartedOn *time.Time `json:"started_on"`
EndedOn *time.Time `json:"ended_on"`
Status string `json:"status"`
Start int `json:"start"`
End int `json:"end"`
Total int `json:"total"`
Data []PagesDeploymentStageLogEntry `json:"data"`
}
// PagesDeploymentStageLogEntry represents a single log entry in a Pages deployment stage.
type PagesDeploymentStageLogEntry struct {
ID int `json:"id"`
Timestamp *time.Time `json:"timestamp"`
Message string `json:"message"`
}
// PagesDeploymentLogs represents the logs for a Pages deployment.
type PagesDeploymentLogs struct {
Total int `json:"total"`
IncludesContainerLogs bool `json:"includes_container_logs"`
Data []PagesDeploymentLogEntry `json:"data"`
}
// PagesDeploymentLogEntry represents a single log entry in a Pages deployment.
type PagesDeploymentLogEntry struct {
Timestamp *time.Time `json:"ts"`
Line string `json:"line"`
}
type pagesDeploymentListResponse struct {
Response
Result []PagesProjectDeployment `json:"result"`
ResultInfo `json:"result_info"`
}
type pagesDeploymentResponse struct {
Response
Result PagesProjectDeployment `json:"result"`
}
type pagesDeploymentLogsResponse struct {
Response
Result PagesDeploymentLogs `json:"result"`
ResultInfo `json:"result_info"`
}
type ListPagesDeploymentsParams struct {
ProjectName string `url:"-"`
ResultInfo
}
type GetPagesDeploymentInfoParams struct {
ProjectName string
DeploymentID string
}
type GetPagesDeploymentStageLogsParams struct {
ProjectName string
DeploymentID string
StageName string
SizeOptions
}
type GetPagesDeploymentLogsParams struct {
ProjectName string
DeploymentID string
SizeOptions
}
type DeletePagesDeploymentParams struct {
ProjectName string `url:"-"`
DeploymentID string `url:"-"`
Force bool `url:"force,omitempty"`
}
type CreatePagesDeploymentParams struct {
ProjectName string `json:"-"`
Branch string `json:"branch,omitempty"`
}
type RetryPagesDeploymentParams struct {
ProjectName string
DeploymentID string
}
type RollbackPagesDeploymentParams struct {
ProjectName string
DeploymentID string
}
var (
ErrMissingProjectName = errors.New("required missing project name")
ErrMissingDeploymentID = errors.New("required missing deployment ID")
)
// ListPagesDeployments returns all deployments for a Pages project.
//
// API reference: https://api.cloudflare.com/#pages-deployment-get-deployments
func (api *API) ListPagesDeployments(ctx context.Context, rc *ResourceContainer, params ListPagesDeploymentsParams) ([]PagesProjectDeployment, *ResultInfo, error) {
if rc.Identifier == "" {
return []PagesProjectDeployment{}, &ResultInfo{}, ErrMissingAccountID
}
if params.ProjectName == "" {
return []PagesProjectDeployment{}, &ResultInfo{}, ErrMissingProjectName
}
autoPaginate := true
if params.PerPage >= 1 || params.Page >= 1 {
autoPaginate = false
}
if params.PerPage < 1 {
params.PerPage = 25
}
if params.Page < 1 {
params.Page = 1
}
var deployments []PagesProjectDeployment
var r pagesDeploymentListResponse
for {
uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments", rc.Identifier, params.ProjectName), params)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return []PagesProjectDeployment{}, &ResultInfo{}, err
}
err = json.Unmarshal(res, &r)
if err != nil {
return []PagesProjectDeployment{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
deployments = append(deployments, r.Result...)
params.ResultInfo = r.ResultInfo.Next()
if params.Done() || !autoPaginate {
break
}
}
return deployments, &r.ResultInfo, nil
}
// GetPagesDeploymentInfo returns a deployment for a Pages project.
//
// API reference: https://api.cloudflare.com/#pages-deployment-get-deployment-info
func (api *API) GetPagesDeploymentInfo(ctx context.Context, rc *ResourceContainer, projectName, deploymentID string) (PagesProjectDeployment, error) {
if rc.Identifier == "" {
return PagesProjectDeployment{}, ErrMissingAccountID
}
if projectName == "" {
return PagesProjectDeployment{}, ErrMissingProjectName
}
if deploymentID == "" {
return PagesProjectDeployment{}, ErrMissingDeploymentID
}
uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s", rc.Identifier, projectName, deploymentID)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return PagesProjectDeployment{}, err
}
var r pagesDeploymentResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PagesProjectDeployment{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// GetPagesDeploymentLogs returns the logs for a Pages deployment.
//
// API reference: https://api.cloudflare.com/#pages-deployment-get-deployment-logs
func (api *API) GetPagesDeploymentLogs(ctx context.Context, rc *ResourceContainer, params GetPagesDeploymentLogsParams) (PagesDeploymentLogs, error) {
if rc.Identifier == "" {
return PagesDeploymentLogs{}, ErrMissingAccountID
}
if params.ProjectName == "" {
return PagesDeploymentLogs{}, ErrMissingProjectName
}
if params.DeploymentID == "" {
return PagesDeploymentLogs{}, ErrMissingDeploymentID
}
uri := buildURI(
fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s/history/logs", rc.Identifier, params.ProjectName, params.DeploymentID),
params.SizeOptions,
)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return PagesDeploymentLogs{}, err
}
var r pagesDeploymentLogsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PagesDeploymentLogs{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// DeletePagesDeployment deletes a Pages deployment.
//
// API reference: https://api.cloudflare.com/#pages-deployment-delete-deployment
func (api *API) DeletePagesDeployment(ctx context.Context, rc *ResourceContainer, params DeletePagesDeploymentParams) error {
if rc.Identifier == "" {
return ErrMissingAccountID
}
if params.ProjectName == "" {
return ErrMissingProjectName
}
if params.DeploymentID == "" {
return ErrMissingDeploymentID
}
uri := buildURI(fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s", rc.Identifier, params.ProjectName, params.DeploymentID), params)
_, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
return err
}
return nil
}
// CreatePagesDeployment creates a Pages production deployment.
//
// API reference: https://api.cloudflare.com/#pages-deployment-create-deployment
func (api *API) CreatePagesDeployment(ctx context.Context, rc *ResourceContainer, params CreatePagesDeploymentParams) (PagesProjectDeployment, error) {
if rc.Identifier == "" {
return PagesProjectDeployment{}, ErrMissingAccountID
}
if params.ProjectName == "" {
return PagesProjectDeployment{}, ErrMissingProjectName
}
uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments", rc.Identifier, params.ProjectName)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
if err != nil {
return PagesProjectDeployment{}, err
}
var r pagesDeploymentResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PagesProjectDeployment{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// RetryPagesDeployment retries a specific Pages deployment.
//
// API reference: https://api.cloudflare.com/#pages-deployment-retry-deployment
func (api *API) RetryPagesDeployment(ctx context.Context, rc *ResourceContainer, projectName, deploymentID string) (PagesProjectDeployment, error) {
if rc.Identifier == "" {
return PagesProjectDeployment{}, ErrMissingAccountID
}
if projectName == "" {
return PagesProjectDeployment{}, ErrMissingProjectName
}
if deploymentID == "" {
return PagesProjectDeployment{}, ErrMissingDeploymentID
}
uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s/retry", rc.Identifier, projectName, deploymentID)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil)
if err != nil {
return PagesProjectDeployment{}, err
}
var r pagesDeploymentResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PagesProjectDeployment{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// RollbackPagesDeployment rollbacks the Pages production deployment to a previous production deployment.
//
// API reference: https://api.cloudflare.com/#pages-deployment-rollback-deployment
func (api *API) RollbackPagesDeployment(ctx context.Context, rc *ResourceContainer, projectName, deploymentID string) (PagesProjectDeployment, error) {
if rc.Identifier == "" {
return PagesProjectDeployment{}, ErrMissingAccountID
}
if projectName == "" {
return PagesProjectDeployment{}, ErrMissingProjectName
}
if deploymentID == "" {
return PagesProjectDeployment{}, ErrMissingDeploymentID
}
uri := fmt.Sprintf("/accounts/%s/pages/projects/%s/deployments/%s/rollback", rc.Identifier, projectName, deploymentID)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil)
if err != nil {
return PagesProjectDeployment{}, err
}
var r pagesDeploymentResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PagesProjectDeployment{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}