...

Source file src/github.com/google/go-github/v55/github/repos_environments.go

Documentation: github.com/google/go-github/v55/github

     1  // Copyright 2021 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  )
    14  
    15  // Environment represents a single environment in a repository.
    16  type Environment struct {
    17  	Owner                  *string         `json:"owner,omitempty"`
    18  	Repo                   *string         `json:"repo,omitempty"`
    19  	EnvironmentName        *string         `json:"environment_name,omitempty"`
    20  	WaitTimer              *int            `json:"wait_timer,omitempty"`
    21  	Reviewers              []*EnvReviewers `json:"reviewers,omitempty"`
    22  	DeploymentBranchPolicy *BranchPolicy   `json:"deployment_branch_policy,omitempty"`
    23  	// Return/response only values
    24  	ID              *int64            `json:"id,omitempty"`
    25  	NodeID          *string           `json:"node_id,omitempty"`
    26  	Name            *string           `json:"name,omitempty"`
    27  	URL             *string           `json:"url,omitempty"`
    28  	HTMLURL         *string           `json:"html_url,omitempty"`
    29  	CreatedAt       *Timestamp        `json:"created_at,omitempty"`
    30  	UpdatedAt       *Timestamp        `json:"updated_at,omitempty"`
    31  	CanAdminsBypass *bool             `json:"can_admins_bypass,omitempty"`
    32  	ProtectionRules []*ProtectionRule `json:"protection_rules,omitempty"`
    33  }
    34  
    35  // EnvReviewers represents a single environment reviewer entry.
    36  type EnvReviewers struct {
    37  	Type *string `json:"type,omitempty"`
    38  	ID   *int64  `json:"id,omitempty"`
    39  }
    40  
    41  // BranchPolicy represents the options for whether a branch deployment policy is applied to this environment.
    42  type BranchPolicy struct {
    43  	ProtectedBranches    *bool `json:"protected_branches,omitempty"`
    44  	CustomBranchPolicies *bool `json:"custom_branch_policies,omitempty"`
    45  }
    46  
    47  // EnvResponse represents the slightly different format of response that comes back when you list an environment.
    48  type EnvResponse struct {
    49  	TotalCount   *int           `json:"total_count,omitempty"`
    50  	Environments []*Environment `json:"environments,omitempty"`
    51  }
    52  
    53  // ProtectionRule represents a single protection rule applied to the environment.
    54  type ProtectionRule struct {
    55  	ID        *int64              `json:"id,omitempty"`
    56  	NodeID    *string             `json:"node_id,omitempty"`
    57  	Type      *string             `json:"type,omitempty"`
    58  	WaitTimer *int                `json:"wait_timer,omitempty"`
    59  	Reviewers []*RequiredReviewer `json:"reviewers,omitempty"`
    60  }
    61  
    62  // RequiredReviewer represents a required reviewer.
    63  type RequiredReviewer struct {
    64  	Type     *string     `json:"type,omitempty"`
    65  	Reviewer interface{} `json:"reviewer,omitempty"`
    66  }
    67  
    68  // EnvironmentListOptions specifies the optional parameters to the
    69  // RepositoriesService.ListEnvironments method.
    70  type EnvironmentListOptions struct {
    71  	ListOptions
    72  }
    73  
    74  // UnmarshalJSON implements the json.Unmarshaler interface.
    75  // This helps us handle the fact that RequiredReviewer can have either a User or Team type reviewer field.
    76  func (r *RequiredReviewer) UnmarshalJSON(data []byte) error {
    77  	type aliasReviewer RequiredReviewer
    78  	var reviewer aliasReviewer
    79  	if err := json.Unmarshal(data, &reviewer); err != nil {
    80  		return err
    81  	}
    82  
    83  	r.Type = reviewer.Type
    84  
    85  	switch *reviewer.Type {
    86  	case "User":
    87  		reviewer.Reviewer = &User{}
    88  		if err := json.Unmarshal(data, &reviewer); err != nil {
    89  			return err
    90  		}
    91  		r.Reviewer = reviewer.Reviewer
    92  	case "Team":
    93  		reviewer.Reviewer = &Team{}
    94  		if err := json.Unmarshal(data, &reviewer); err != nil {
    95  			return err
    96  		}
    97  		r.Reviewer = reviewer.Reviewer
    98  	default:
    99  		r.Type = nil
   100  		r.Reviewer = nil
   101  		return fmt.Errorf("reviewer.Type is %T, not a string of 'User' or 'Team', unable to unmarshal", reviewer.Type)
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  // ListEnvironments lists all environments for a repository.
   108  //
   109  // GitHub API docs: https://docs.github.com/en/rest/deployments/environments#get-all-environments
   110  func (s *RepositoriesService) ListEnvironments(ctx context.Context, owner, repo string, opts *EnvironmentListOptions) (*EnvResponse, *Response, error) {
   111  	u := fmt.Sprintf("repos/%s/%s/environments", owner, repo)
   112  	u, err := addOptions(u, opts)
   113  	if err != nil {
   114  		return nil, nil, err
   115  	}
   116  
   117  	req, err := s.client.NewRequest("GET", u, nil)
   118  	if err != nil {
   119  		return nil, nil, err
   120  	}
   121  
   122  	var list *EnvResponse
   123  	resp, err := s.client.Do(ctx, req, &list)
   124  	if err != nil {
   125  		return nil, resp, err
   126  	}
   127  	return list, resp, nil
   128  }
   129  
   130  // GetEnvironment get a single environment for a repository.
   131  //
   132  // GitHub API docs: https://docs.github.com/en/rest/deployments/environments#get-an-environment
   133  func (s *RepositoriesService) GetEnvironment(ctx context.Context, owner, repo, name string) (*Environment, *Response, error) {
   134  	u := fmt.Sprintf("repos/%s/%s/environments/%s", owner, repo, name)
   135  
   136  	req, err := s.client.NewRequest("GET", u, nil)
   137  	if err != nil {
   138  		return nil, nil, err
   139  	}
   140  
   141  	var env *Environment
   142  	resp, err := s.client.Do(ctx, req, &env)
   143  	if err != nil {
   144  		return nil, resp, err
   145  	}
   146  	return env, resp, nil
   147  }
   148  
   149  // MarshalJSON implements the json.Marshaler interface.
   150  // As the only way to clear a WaitTimer is to set it to 0, a missing WaitTimer object should default to 0, not null.
   151  // As the default value for CanAdminsBypass is true, a nil value here marshals to true.
   152  func (c *CreateUpdateEnvironment) MarshalJSON() ([]byte, error) {
   153  	type Alias CreateUpdateEnvironment
   154  	if c.WaitTimer == nil {
   155  		c.WaitTimer = Int(0)
   156  	}
   157  	if c.CanAdminsBypass == nil {
   158  		c.CanAdminsBypass = Bool(true)
   159  	}
   160  	return json.Marshal(&struct {
   161  		*Alias
   162  	}{
   163  		Alias: (*Alias)(c),
   164  	})
   165  }
   166  
   167  // CreateUpdateEnvironment represents the fields required for the create/update operation
   168  // following the Create/Update release example.
   169  // See https://github.com/google/go-github/issues/992 for more information.
   170  // Removed omitempty here as the API expects null values for reviewers and deployment_branch_policy to clear them.
   171  type CreateUpdateEnvironment struct {
   172  	WaitTimer              *int            `json:"wait_timer"`
   173  	Reviewers              []*EnvReviewers `json:"reviewers"`
   174  	CanAdminsBypass        *bool           `json:"can_admins_bypass"`
   175  	DeploymentBranchPolicy *BranchPolicy   `json:"deployment_branch_policy"`
   176  }
   177  
   178  // createUpdateEnvironmentNoEnterprise represents the fields accepted for Pro/Teams private repos.
   179  // Ref: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
   180  // See https://github.com/google/go-github/issues/2602 for more information.
   181  type createUpdateEnvironmentNoEnterprise struct {
   182  	DeploymentBranchPolicy *BranchPolicy `json:"deployment_branch_policy"`
   183  }
   184  
   185  // CreateUpdateEnvironment create or update a new environment for a repository.
   186  //
   187  // GitHub API docs: https://docs.github.com/en/rest/deployments/environments#create-or-update-an-environment
   188  func (s *RepositoriesService) CreateUpdateEnvironment(ctx context.Context, owner, repo, name string, environment *CreateUpdateEnvironment) (*Environment, *Response, error) {
   189  	u := fmt.Sprintf("repos/%s/%s/environments/%s", owner, repo, name)
   190  
   191  	req, err := s.client.NewRequest("PUT", u, environment)
   192  	if err != nil {
   193  		return nil, nil, err
   194  	}
   195  
   196  	e := new(Environment)
   197  	resp, err := s.client.Do(ctx, req, e)
   198  	if err != nil {
   199  		// The API returns 422 when the pricing plan doesn't support all the fields sent.
   200  		// This path will be executed for Pro/Teams private repos.
   201  		// For public repos, regardless of the pricing plan, all fields supported.
   202  		// For Free plan private repos the returned error code is 404.
   203  		// We are checking that the user didn't try to send a value for unsupported fields,
   204  		// and return an error if they did.
   205  		if resp != nil && resp.StatusCode == http.StatusUnprocessableEntity && environment != nil && len(environment.Reviewers) == 0 && environment.GetWaitTimer() == 0 {
   206  			return s.createNewEnvNoEnterprise(ctx, u, environment)
   207  		}
   208  		return nil, resp, err
   209  	}
   210  	return e, resp, nil
   211  }
   212  
   213  // createNewEnvNoEnterprise is an internal function for cases where the original call returned 422.
   214  // Currently only the `deployment_branch_policy` parameter is supported for Pro/Team private repos.
   215  func (s *RepositoriesService) createNewEnvNoEnterprise(ctx context.Context, u string, environment *CreateUpdateEnvironment) (*Environment, *Response, error) {
   216  	req, err := s.client.NewRequest("PUT", u, &createUpdateEnvironmentNoEnterprise{
   217  		DeploymentBranchPolicy: environment.DeploymentBranchPolicy,
   218  	})
   219  	if err != nil {
   220  		return nil, nil, err
   221  	}
   222  
   223  	e := new(Environment)
   224  	resp, err := s.client.Do(ctx, req, e)
   225  	if err != nil {
   226  		return nil, resp, err
   227  	}
   228  	return e, resp, nil
   229  }
   230  
   231  // DeleteEnvironment delete an environment from a repository.
   232  //
   233  // GitHub API docs: https://docs.github.com/en/rest/deployments/environments#delete-an-environment
   234  func (s *RepositoriesService) DeleteEnvironment(ctx context.Context, owner, repo, name string) (*Response, error) {
   235  	u := fmt.Sprintf("repos/%s/%s/environments/%s", owner, repo, name)
   236  
   237  	req, err := s.client.NewRequest("DELETE", u, nil)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  	return s.client.Do(ctx, req, nil)
   242  }
   243  

View as plain text