package gitea import ( "fmt" "io" "iter" "mime/multipart" "net/http" "net/url" "os" "strconv" gitea_api "sirherobrine23.com.br/go-bds/request/gitea/structs" "sirherobrine23.com.br/go-bds/request/internal/gitpaginator" "sirherobrine23.com.br/go-bds/request/v3" ) // Get release by tag name func (client Gitea) ReleaseTag(tagName string) (*gitea_api.Release, error) { reqOptions := &request.Options{Method: "GET", Header: http.Header{}, Codes: processCodes} client.authHeader(&reqOptions.Header) res, _, err := request.JSON[*gitea_api.Release](client.pathJoin("v1/repos", client.repoPath(), "releases/tags", url.PathEscape(tagName)), reqOptions) return res, err } // Get release by ID func (client Gitea) Release(id int) (*gitea_api.Release, error) { reqOptions := &request.Options{Method: "GET", Header: http.Header{}, Codes: processCodes} client.authHeader(&reqOptions.Header) res, _, err := request.JSON[*gitea_api.Release](client.pathJoin("v1/repos", client.repoPath(), "releases", strconv.Itoa(id)), reqOptions) return res, err } // Create release if not exists else return current release based in tag name func (client Gitea) CreateRelease(opt *gitea_api.CreateReleaseOption) (*gitea_api.Release, error) { reqOptions := &request.Options{ Method: "POST", Header: http.Header{ "Content-Type": {"application/json"}, }, Body: opt, Codes: processCodes.Extends(request.CodeProcess{ 400: func(req *request.RequestStatus) (res *http.Response, err error) { req.Options.Method = "GET" delete(req.Options.Header, "Content-Type") delete(req.Options.Codes, 400) // ignore loop return request.Request(client.pathJoin("v1/repos", client.repoPath(), "releases/tags", url.PathEscape(opt.TagName)), req.Options) }, }), } client.authHeader(&reqOptions.Header) res, _, err := request.JSON[*gitea_api.Release](client.pathJoin("v1/repos", client.repoPath(), "releases"), reqOptions) return res, err } // DeleteRelease deletes a release from the repository identified by the given release ID. func (client Gitea) DeleteRelease(id int64) error { reqOptions := &request.Options{Method: "DELETE", Codes: processCodes} client.authHeader(&reqOptions.Header) res, err := request.Request(client.pathJoin("v1/repos", client.repoPath(), "releases", strconv.FormatInt(id, 10)), reqOptions) if res != nil { defer res.Body.Close() } return err } func (client Gitea) DeleteReleaseByTag(tagName string) error { reqOptions := &request.Options{Method: "DELETE", Codes: processCodes} client.authHeader(&reqOptions.Header) res, err := request.Request(client.pathJoin("v1/repos", client.repoPath(), "releases/rags", url.PathEscape(tagName)), reqOptions) if res != nil { defer res.Body.Close() } return err } // List all release from gitea APIs func (client Gitea) ReleasesSeq() iter.Seq2[*gitea_api.Release, error] { releases, res, err := []*gitea_api.Release{}, (*http.Response)(nil), error(nil) reqOptions := &request.Options{Method: "GET", Header: http.Header{}, Codes: processCodes} client.authHeader(&reqOptions.Header) return func(yield func(*gitea_api.Release, error) bool) { requestUrl := client.pathJoin(client.repoPath(), "releases") requestUrl.RawQuery = "limit=100" if client.Settings != nil && client.Settings.MaxResponseItems > 0 { requestUrl.RawQuery = fmt.Sprintf("limit=%d", client.Settings.MaxResponseItems) } for requestUrl != nil { if len(releases) == 0 { if releases, res, err = request.JSON[[]*gitea_api.Release](requestUrl, reqOptions); res != nil { requestUrl, err = url.Parse(gitpaginator.ParsePaginator(res.Header).NextPageToken) } else { requestUrl = nil } } if err != nil { yield(nil, err) return } for len(releases) > 0 { if !yield(releases[0], nil) { return } releases = releases[1:] } } } } // List all release Assets in [iter.Seq2] func (client Gitea) AssetsSeq(releaseID int) iter.Seq2[*gitea_api.Attachment, error] { asserts, res, err := []*gitea_api.Attachment{}, (*http.Response)(nil), error(nil) reqOptions := &request.Options{Method: "GET", Header: http.Header{}, Codes: processCodes} client.authHeader(&reqOptions.Header) return func(yield func(*gitea_api.Attachment, error) bool) { requestUrl := client.pathJoin("v1/repos", client.repoPath(), "releases", strconv.Itoa(releaseID), "assets") for requestUrl != nil { if len(asserts) == 0 { if asserts, res, err = request.JSON[[]*gitea_api.Attachment](requestUrl, reqOptions); res != nil { requestUrl, err = url.Parse(gitpaginator.ParsePaginator(res.Header).NextPageToken) } else { requestUrl = nil } } if err != nil { yield(nil, err) return } for len(asserts) > 0 { if !yield(asserts[0], nil) { return } asserts = asserts[1:] } } } } // Get all releases from Gitea APIs and return slice with all versions func (client Gitea) Releases() ([]*gitea_api.Release, error) { releases := []*gitea_api.Release{} for release, err := range client.ReleasesSeq() { if err != nil { return nil, err } releases = append(releases, release) } return releases, nil } // List all release Assets in to slice func (client Gitea) AllAssets(releaseID int) ([]*gitea_api.Attachment, error) { asserts := []*gitea_api.Attachment{} for assert, err := range client.AssetsSeq(releaseID) { if err != nil { return nil, err } asserts = append(asserts, assert) } return asserts, nil } // Delete assert file from Release func (client Gitea) DeleteAsset(releaseID, assetID int) error { reqOptions := &request.Options{Method: "DELETE", Header: http.Header{}, Codes: processCodes} client.authHeader(&reqOptions.Header) res, err := request.Request(client.pathJoin("v1/repos", client.repoPath(), "releases", strconv.Itoa(releaseID), "assets", strconv.Itoa(assetID)), reqOptions) res.Body.Close() return err } // Upload file to Release func (client Gitea) UploadAsset(releaseID int, name string, file io.Reader) (fileInfo *gitea_api.Attachment, err error) { tmpWrite, err := os.CreateTemp("", "form_*_upload") if err != nil { return nil, fmt.Errorf("cannot make temporary file to body: %w", err) } defer os.Remove(tmpWrite.Name()) defer tmpWrite.Close() mp := multipart.NewWriter(tmpWrite) defer mp.Close() part, err := mp.CreateFormFile("attachment", name) if err != nil { return nil, fmt.Errorf("cannot make form file: %w", err) } else if _, err = io.Copy(part, file); err != nil { return nil, fmt.Errorf("cannot copy file body: %w", err) } else if err = mp.Close(); err != nil { return nil, fmt.Errorf("error on close form body: %w", err) } tmpWrite.Seek(0, 0) reqOptions := &request.Options{ Method: "POST", Body: tmpWrite, Header: http.Header{ "Content-Type": {mp.FormDataContentType()}, }, Codes: processCodes.Extends(request.CodeProcess{ 201: func(req *request.RequestStatus) (res *http.Response, err error) { return req.Res, nil }, 422: func(req *request.RequestStatus) (res *http.Response, err error) { return nil, fmt.Errorf("same filename exists in release: %s", name) }, }), } client.authHeader(&reqOptions.Header) fileInfo = new(gitea_api.Attachment) reqUrl := client.pathJoin("v1/repos", client.repoPath(), "releases", strconv.Itoa(releaseID), "assets") reqUrl.RawQuery = (&url.Values{"name": {name}}).Encode() _, err = request.DecodeJSON(reqUrl, reqOptions, fileInfo) return }