230 lines
8.8 KiB
Go
230 lines
8.8 KiB
Go
package forge
|
|
|
|
import (
|
|
"context"
|
|
"iter"
|
|
"strconv"
|
|
|
|
goio "io"
|
|
|
|
"dappco.re/go/core/forge/types"
|
|
)
|
|
|
|
// ReleaseService handles release operations within a repository.
|
|
//
|
|
// Usage:
|
|
//
|
|
// f := forge.NewForge("https://forge.lthn.ai", "token")
|
|
// _, err := f.Releases.ListAll(ctx, forge.Params{"owner": "core", "repo": "go-forge"})
|
|
type ReleaseService struct {
|
|
Resource[types.Release, types.CreateReleaseOption, types.EditReleaseOption]
|
|
}
|
|
|
|
// ReleaseListOptions controls filtering for repository release listings.
|
|
//
|
|
// Usage:
|
|
//
|
|
// opts := forge.ReleaseListOptions{Draft: true, Query: "1.0"}
|
|
type ReleaseListOptions struct {
|
|
Draft bool
|
|
PreRelease bool
|
|
Query string
|
|
}
|
|
|
|
// String returns a safe summary of the release list filters.
|
|
func (o ReleaseListOptions) String() string {
|
|
return optionString("forge.ReleaseListOptions",
|
|
"draft", o.Draft,
|
|
"pre-release", o.PreRelease,
|
|
"q", o.Query,
|
|
)
|
|
}
|
|
|
|
// GoString returns a safe Go-syntax summary of the release list filters.
|
|
func (o ReleaseListOptions) GoString() string { return o.String() }
|
|
|
|
func (o ReleaseListOptions) queryParams() map[string]string {
|
|
query := make(map[string]string, 3)
|
|
if o.Draft {
|
|
query["draft"] = strconv.FormatBool(true)
|
|
}
|
|
if o.PreRelease {
|
|
query["pre-release"] = strconv.FormatBool(true)
|
|
}
|
|
if o.Query != "" {
|
|
query["q"] = o.Query
|
|
}
|
|
if len(query) == 0 {
|
|
return nil
|
|
}
|
|
return query
|
|
}
|
|
|
|
// ReleaseAttachmentUploadOptions controls metadata sent when uploading a release attachment.
|
|
//
|
|
// Usage:
|
|
//
|
|
// opts := forge.ReleaseAttachmentUploadOptions{Name: "release.zip"}
|
|
type ReleaseAttachmentUploadOptions struct {
|
|
Name string
|
|
ExternalURL string
|
|
}
|
|
|
|
// String returns a safe summary of the release attachment upload metadata.
|
|
func (o ReleaseAttachmentUploadOptions) String() string {
|
|
return optionString("forge.ReleaseAttachmentUploadOptions",
|
|
"name", o.Name,
|
|
"external_url", o.ExternalURL,
|
|
)
|
|
}
|
|
|
|
// GoString returns a safe Go-syntax summary of the release attachment upload metadata.
|
|
func (o ReleaseAttachmentUploadOptions) GoString() string { return o.String() }
|
|
|
|
func releaseAttachmentUploadQuery(opts *ReleaseAttachmentUploadOptions) map[string]string {
|
|
if opts == nil || opts.Name == "" {
|
|
return nil
|
|
}
|
|
query := make(map[string]string, 1)
|
|
if opts.Name != "" {
|
|
query["name"] = opts.Name
|
|
}
|
|
return query
|
|
}
|
|
|
|
func newReleaseService(c *Client) *ReleaseService {
|
|
return &ReleaseService{
|
|
Resource: *NewResource[types.Release, types.CreateReleaseOption, types.EditReleaseOption](
|
|
c, "/api/v1/repos/{owner}/{repo}/releases/{id}",
|
|
),
|
|
}
|
|
}
|
|
|
|
// ListReleases returns all releases in a repository.
|
|
func (s *ReleaseService) ListReleases(ctx context.Context, owner, repo string, filters ...ReleaseListOptions) ([]types.Release, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases", pathParams("owner", owner, "repo", repo))
|
|
return ListAll[types.Release](ctx, s.client, path, releaseListQuery(filters...))
|
|
}
|
|
|
|
// IterReleases returns an iterator over all releases in a repository.
|
|
func (s *ReleaseService) IterReleases(ctx context.Context, owner, repo string, filters ...ReleaseListOptions) iter.Seq2[types.Release, error] {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases", pathParams("owner", owner, "repo", repo))
|
|
return ListIter[types.Release](ctx, s.client, path, releaseListQuery(filters...))
|
|
}
|
|
|
|
// CreateRelease creates a release in a repository.
|
|
func (s *ReleaseService) CreateRelease(ctx context.Context, owner, repo string, opts *types.CreateReleaseOption) (*types.Release, error) {
|
|
var out types.Release
|
|
if err := s.client.Post(ctx, ResolvePath("/api/v1/repos/{owner}/{repo}/releases", pathParams("owner", owner, "repo", repo)), opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetByTag returns a release by its tag name.
|
|
func (s *ReleaseService) GetByTag(ctx context.Context, owner, repo, tag string) (*types.Release, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/tags/{tag}", pathParams("owner", owner, "repo", repo, "tag", tag))
|
|
var out types.Release
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetLatest returns the most recent non-prerelease, non-draft release.
|
|
func (s *ReleaseService) GetLatest(ctx context.Context, owner, repo string) (*types.Release, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/latest", pathParams("owner", owner, "repo", repo))
|
|
var out types.Release
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteByTag deletes a release by its tag name.
|
|
func (s *ReleaseService) DeleteByTag(ctx context.Context, owner, repo, tag string) error {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/tags/{tag}", pathParams("owner", owner, "repo", repo, "tag", tag))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListAssets returns all assets for a release.
|
|
func (s *ReleaseService) ListAssets(ctx context.Context, owner, repo string, releaseID int64) ([]types.Attachment, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{id}/assets", pathParams("owner", owner, "repo", repo, "id", int64String(releaseID)))
|
|
return ListAll[types.Attachment](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// CreateAttachment uploads a new attachment to a release.
|
|
//
|
|
// If opts.ExternalURL is set, the upload uses the external_url form field and
|
|
// ignores filename/content.
|
|
func (s *ReleaseService) CreateAttachment(ctx context.Context, owner, repo string, releaseID int64, opts *ReleaseAttachmentUploadOptions, filename string, content goio.Reader) (*types.Attachment, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{id}/assets", pathParams("owner", owner, "repo", repo, "id", int64String(releaseID)))
|
|
fields := make(map[string]string, 1)
|
|
fieldName := "attachment"
|
|
if opts != nil && opts.ExternalURL != "" {
|
|
fields["external_url"] = opts.ExternalURL
|
|
fieldName = ""
|
|
filename = ""
|
|
content = nil
|
|
}
|
|
var out types.Attachment
|
|
if err := s.client.postMultipartJSON(ctx, path, releaseAttachmentUploadQuery(opts), fields, fieldName, filename, content, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// EditAttachment updates a release attachment.
|
|
func (s *ReleaseService) EditAttachment(ctx context.Context, owner, repo string, releaseID, attachmentID int64, opts *types.EditAttachmentOptions) (*types.Attachment, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}", pathParams("owner", owner, "repo", repo, "id", int64String(releaseID), "attachment_id", int64String(attachmentID)))
|
|
var out types.Attachment
|
|
if err := s.client.Patch(ctx, path, opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// CreateAsset uploads a new asset to a release.
|
|
func (s *ReleaseService) CreateAsset(ctx context.Context, owner, repo string, releaseID int64, opts *ReleaseAttachmentUploadOptions, filename string, content goio.Reader) (*types.Attachment, error) {
|
|
return s.CreateAttachment(ctx, owner, repo, releaseID, opts, filename, content)
|
|
}
|
|
|
|
// EditAsset updates a release asset.
|
|
func (s *ReleaseService) EditAsset(ctx context.Context, owner, repo string, releaseID, attachmentID int64, opts *types.EditAttachmentOptions) (*types.Attachment, error) {
|
|
return s.EditAttachment(ctx, owner, repo, releaseID, attachmentID, opts)
|
|
}
|
|
|
|
// IterAssets returns an iterator over all assets for a release.
|
|
func (s *ReleaseService) IterAssets(ctx context.Context, owner, repo string, releaseID int64) iter.Seq2[types.Attachment, error] {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{id}/assets", pathParams("owner", owner, "repo", repo, "id", int64String(releaseID)))
|
|
return ListIter[types.Attachment](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// GetAsset returns a single asset for a release.
|
|
func (s *ReleaseService) GetAsset(ctx context.Context, owner, repo string, releaseID, assetID int64) (*types.Attachment, error) {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{releaseID}/assets/{assetID}", pathParams("owner", owner, "repo", repo, "releaseID", int64String(releaseID), "assetID", int64String(assetID)))
|
|
var out types.Attachment
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteAsset deletes a single asset from a release.
|
|
func (s *ReleaseService) DeleteAsset(ctx context.Context, owner, repo string, releaseID, assetID int64) error {
|
|
path := ResolvePath("/api/v1/repos/{owner}/{repo}/releases/{releaseID}/assets/{assetID}", pathParams("owner", owner, "repo", repo, "releaseID", int64String(releaseID), "assetID", int64String(assetID)))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
func releaseListQuery(filters ...ReleaseListOptions) map[string]string {
|
|
query := make(map[string]string, len(filters))
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
query[key] = value
|
|
}
|
|
}
|
|
if len(query) == 0 {
|
|
return nil
|
|
}
|
|
return query
|
|
}
|