Browse Source

release: Fix UpdateBuildForAppStoreVersion

世界 10 tháng trước cách đây
mục cha
commit
64a94e8144

+ 30 - 0
cmd/internal/app_store_connect/client.go

@@ -0,0 +1,30 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	_ "unsafe"
+
+	"github.com/cidertool/asc-go/asc"
+)
+
+type Client struct {
+	*asc.Client
+}
+
+func (c *Client) UpdateBuildForAppStoreVersion(ctx context.Context, id string, buildID *string) (*asc.Response, error) {
+	linkage := newRelationshipDeclaration(buildID, "builds")
+	url := fmt.Sprintf("appStoreVersions/%s/relationships/build", id)
+	return c.patch(ctx, url, newRequestBody(linkage), nil)
+}
+
+func newRelationshipDeclaration(id *string, relationshipType string) *asc.RelationshipData {
+	if id == nil {
+		return nil
+	}
+
+	return &asc.RelationshipData{
+		ID:   *id,
+		Type: relationshipType,
+	}
+}

+ 140 - 0
cmd/internal/app_store_connect/client_linkname.go

@@ -0,0 +1,140 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"reflect"
+	_ "unsafe"
+
+	"github.com/cidertool/asc-go/asc"
+	"github.com/google/go-querystring/query"
+)
+
+func (c *Client) newRequest(ctx context.Context, method string, path string, body *requestBody, options ...requestOption) (*http.Request, error) {
+	return clientNewRequest(c.Client, ctx, method, path, body, options...)
+}
+
+//go:linkname clientNewRequest github.com/cidertool/asc-go/asc.(*Client).newRequest
+func clientNewRequest(c *asc.Client, ctx context.Context, method string, path string, body *requestBody, options ...requestOption) (*http.Request, error)
+
+func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) (*asc.Response, error) {
+	return clientDo(c.Client, ctx, req, v)
+}
+
+//go:linkname clientDo github.com/cidertool/asc-go/asc.(*Client).do
+func clientDo(c *asc.Client, ctx context.Context, req *http.Request, v interface{}) (*asc.Response, error)
+
+// get sends a GET request to the API as configured.
+func (c *Client) get(ctx context.Context, url string, query interface{}, v interface{}, options ...requestOption) (*asc.Response, error) {
+	var err error
+	if query != nil {
+		url, err = appendingQueryOptions(url, query)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	req, err := c.newRequest(ctx, "GET", url, nil, options...)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := c.do(ctx, req, v)
+	if err != nil {
+		return resp, err
+	}
+
+	return resp, err
+}
+
+// post sends a POST request to the API as configured.
+func (c *Client) post(ctx context.Context, url string, body *requestBody, v interface{}) (*asc.Response, error) {
+	req, err := c.newRequest(ctx, "POST", url, body, withContentType("application/json"))
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := c.do(ctx, req, v)
+	if err != nil {
+		return resp, err
+	}
+
+	return resp, err
+}
+
+// patch sends a PATCH request to the API as configured.
+func (c *Client) patch(ctx context.Context, url string, body *requestBody, v interface{}) (*asc.Response, error) {
+	req, err := c.newRequest(ctx, "PATCH", url, body, withContentType("application/json"))
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := c.do(ctx, req, v)
+	if err != nil {
+		return resp, err
+	}
+
+	return resp, err
+}
+
+// delete sends a DELETE request to the API as configured.
+func (c *Client) delete(ctx context.Context, url string, body *requestBody) (*asc.Response, error) {
+	req, err := c.newRequest(ctx, "DELETE", url, body, withContentType("application/json"))
+	if err != nil {
+		return nil, err
+	}
+
+	return c.do(ctx, req, nil)
+}
+
+// request is a common structure for a request body sent to the API.
+type requestBody struct {
+	Data     interface{} `json:"data"`
+	Included interface{} `json:"included,omitempty"`
+}
+
+func newRequestBody(data interface{}) *requestBody {
+	return newRequestBodyWithIncluded(data, nil)
+}
+
+func newRequestBodyWithIncluded(data interface{}, included interface{}) *requestBody {
+	return &requestBody{Data: data, Included: included}
+}
+
+type requestOption func(*http.Request)
+
+func withAccept(typ string) requestOption {
+	return func(req *http.Request) {
+		req.Header.Set("Accept", typ)
+	}
+}
+
+func withContentType(typ string) requestOption {
+	return func(req *http.Request) {
+		req.Header.Set("Content-Type", typ)
+	}
+}
+
+// AddOptions adds the parameters in opt as URL query parameters to s.  opt
+// must be a struct whose fields may contain "url" tags.
+func appendingQueryOptions(s string, opt interface{}) (string, error) {
+	v := reflect.ValueOf(opt)
+	if v.Kind() == reflect.Ptr && v.IsNil() {
+		return s, nil
+	}
+
+	u, err := url.Parse(s)
+	if err != nil {
+		return s, err
+	}
+
+	qs, err := query.Values(opt)
+	if err != nil {
+		return s, err
+	}
+
+	u.RawQuery = qs.Encode()
+
+	return u.String(), nil
+}

+ 7 - 3
cmd/internal/app_store_connect/main.go

@@ -54,7 +54,7 @@ const (
 	groupID = "5c5f3b78-b7a0-40c0-bcad-e6ef87bbefda"
 )
 
-func createClient() *asc.Client {
+func createClient() *Client {
 	privateKey, err := os.ReadFile(os.Getenv("ASC_KEY_PATH"))
 	if err != nil {
 		log.Fatal(err)
@@ -63,7 +63,7 @@ func createClient() *asc.Client {
 	if err != nil {
 		log.Fatal(err)
 	}
-	return asc.NewClient(tokenConfig.Client())
+	return &Client{asc.NewClient(tokenConfig.Client())}
 }
 
 func fetchMacOSVersion(ctx context.Context) error {
@@ -242,10 +242,14 @@ func prepareAppStore(ctx context.Context) error {
 					log.Fatal(string(platform), " ", tag, " unknown state ", string(*version.Attributes.AppStoreState))
 				}
 				log.Info(string(platform), " ", tag, " update build")
-				_, _, err = client.Apps.UpdateBuildForAppStoreVersion(ctx, version.ID, buildID)
+				response, err = client.UpdateBuildForAppStoreVersion(ctx, version.ID, buildID)
 				if err != nil {
 					return err
 				}
+				if response.StatusCode != http.StatusNoContent {
+					response.Write(os.Stderr)
+					log.Fatal(string(platform), " ", tag, " unexpected response: ", response.Status)
+				}
 			} else {
 				switch *version.Attributes.AppStoreState {
 				case asc.AppStoreVersionStatePrepareForSubmission,