github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/release/create/http.go (about)

     1  package create
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"net/url"
    11  
    12  	"github.com/ungtb10d/cli/v2/api"
    13  	"github.com/ungtb10d/cli/v2/internal/ghinstance"
    14  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    15  	"github.com/ungtb10d/cli/v2/pkg/cmd/release/shared"
    16  	"github.com/shurcooL/githubv4"
    17  )
    18  
    19  type tag struct {
    20  	Name string `json:"name"`
    21  }
    22  
    23  type releaseNotes struct {
    24  	Name string `json:"name"`
    25  	Body string `json:"body"`
    26  }
    27  
    28  var notImplementedError = errors.New("not implemented")
    29  
    30  func remoteTagExists(httpClient *http.Client, repo ghrepo.Interface, tagName string) (bool, error) {
    31  	gql := api.NewClientFromHTTP(httpClient)
    32  	qualifiedTagName := fmt.Sprintf("refs/tags/%s", tagName)
    33  	var query struct {
    34  		Repository struct {
    35  			Ref struct {
    36  				ID string
    37  			} `graphql:"ref(qualifiedName: $tagName)"`
    38  		} `graphql:"repository(owner: $owner, name: $name)"`
    39  	}
    40  	variables := map[string]interface{}{
    41  		"owner":   githubv4.String(repo.RepoOwner()),
    42  		"name":    githubv4.String(repo.RepoName()),
    43  		"tagName": githubv4.String(qualifiedTagName),
    44  	}
    45  	err := gql.Query(repo.RepoHost(), "RepositoryFindRef", &query, variables)
    46  	return query.Repository.Ref.ID != "", err
    47  }
    48  
    49  func getTags(httpClient *http.Client, repo ghrepo.Interface, limit int) ([]tag, error) {
    50  	path := fmt.Sprintf("repos/%s/%s/tags?per_page=%d", repo.RepoOwner(), repo.RepoName(), limit)
    51  	url := ghinstance.RESTPrefix(repo.RepoHost()) + path
    52  	req, err := http.NewRequest("GET", url, nil)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	req.Header.Set("Content-Type", "application/json; charset=utf-8")
    58  
    59  	resp, err := httpClient.Do(req)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	defer resp.Body.Close()
    64  
    65  	success := resp.StatusCode >= 200 && resp.StatusCode < 300
    66  	if !success {
    67  		return nil, api.HandleHTTPError(resp)
    68  	}
    69  
    70  	b, err := io.ReadAll(resp.Body)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	var tags []tag
    76  	err = json.Unmarshal(b, &tags)
    77  	return tags, err
    78  }
    79  
    80  func generateReleaseNotes(httpClient *http.Client, repo ghrepo.Interface, tagName, target, previousTagName string) (*releaseNotes, error) {
    81  	params := map[string]interface{}{
    82  		"tag_name": tagName,
    83  	}
    84  	if target != "" {
    85  		params["target_commitish"] = target
    86  	}
    87  	if previousTagName != "" {
    88  		params["previous_tag_name"] = previousTagName
    89  	}
    90  
    91  	bodyBytes, err := json.Marshal(params)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	path := fmt.Sprintf("repos/%s/%s/releases/generate-notes", repo.RepoOwner(), repo.RepoName())
    97  	url := ghinstance.RESTPrefix(repo.RepoHost()) + path
    98  	req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes))
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	req.Header.Set("Accept", "application/vnd.github.v3+json")
   104  	req.Header.Set("Content-Type", "application/json; charset=utf-8")
   105  
   106  	resp, err := httpClient.Do(req)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	defer resp.Body.Close()
   111  
   112  	if resp.StatusCode == 404 {
   113  		return nil, notImplementedError
   114  	}
   115  
   116  	success := resp.StatusCode >= 200 && resp.StatusCode < 300
   117  	if !success {
   118  		return nil, api.HandleHTTPError(resp)
   119  	}
   120  
   121  	b, err := io.ReadAll(resp.Body)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	var rn releaseNotes
   127  	err = json.Unmarshal(b, &rn)
   128  	return &rn, err
   129  }
   130  
   131  func publishedReleaseExists(httpClient *http.Client, repo ghrepo.Interface, tagName string) (bool, error) {
   132  	path := fmt.Sprintf("repos/%s/%s/releases/tags/%s", repo.RepoOwner(), repo.RepoName(), url.PathEscape(tagName))
   133  	url := ghinstance.RESTPrefix(repo.RepoHost()) + path
   134  	req, err := http.NewRequest("HEAD", url, nil)
   135  	if err != nil {
   136  		return false, err
   137  	}
   138  
   139  	resp, err := httpClient.Do(req)
   140  	if err != nil {
   141  		return false, err
   142  	}
   143  	if resp.Body != nil {
   144  		defer resp.Body.Close()
   145  	}
   146  
   147  	if resp.StatusCode == 200 {
   148  		return true, nil
   149  	} else if resp.StatusCode == 404 {
   150  		return false, nil
   151  	} else {
   152  		return false, api.HandleHTTPError(resp)
   153  	}
   154  }
   155  
   156  func createRelease(httpClient *http.Client, repo ghrepo.Interface, params map[string]interface{}) (*shared.Release, error) {
   157  	bodyBytes, err := json.Marshal(params)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	path := fmt.Sprintf("repos/%s/%s/releases", repo.RepoOwner(), repo.RepoName())
   163  	url := ghinstance.RESTPrefix(repo.RepoHost()) + path
   164  	req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes))
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	req.Header.Set("Content-Type", "application/json; charset=utf-8")
   170  
   171  	resp, err := httpClient.Do(req)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  	defer resp.Body.Close()
   176  
   177  	success := resp.StatusCode >= 200 && resp.StatusCode < 300
   178  	if !success {
   179  		return nil, api.HandleHTTPError(resp)
   180  	}
   181  
   182  	b, err := io.ReadAll(resp.Body)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	var newRelease shared.Release
   188  	err = json.Unmarshal(b, &newRelease)
   189  	return &newRelease, err
   190  }
   191  
   192  func publishRelease(httpClient *http.Client, releaseURL string, discussionCategory string) (*shared.Release, error) {
   193  	params := map[string]interface{}{"draft": false}
   194  	if discussionCategory != "" {
   195  		params["discussion_category_name"] = discussionCategory
   196  	}
   197  
   198  	bodyBytes, err := json.Marshal(params)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	req, err := http.NewRequest("PATCH", releaseURL, bytes.NewBuffer(bodyBytes))
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	req.Header.Add("Content-Type", "application/json")
   208  
   209  	resp, err := httpClient.Do(req)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	defer resp.Body.Close()
   215  	if resp.StatusCode > 299 {
   216  		return nil, api.HandleHTTPError(resp)
   217  	}
   218  
   219  	b, err := io.ReadAll(resp.Body)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	var release shared.Release
   225  	err = json.Unmarshal(b, &release)
   226  	return &release, err
   227  }