mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 06:21:11 +00:00 
			
		
		
		
	- Resolves https://codeberg.org/forgejo/forgejo/issues/580 - Return a `upload_field` to any release API response, which points to the API URL for uploading new assets. - Adds unit test. - Adds integration testing to verify URL is returned correctly and that upload endpoint actually works (cherry picked from commit074413a2dc) (cherry picked from commit33feed4723) (cherry picked from commit1ca21b95ff) (cherry picked from commit874f07cec2) (cherry picked from commita78c538d8e) (cherry picked from commitbef38ce382)
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package integration
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"mime/multipart"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 
 | |
| 	auth_model "code.gitea.io/gitea/models/auth"
 | |
| 	repo_model "code.gitea.io/gitea/models/repo"
 | |
| 	"code.gitea.io/gitea/models/unittest"
 | |
| 	user_model "code.gitea.io/gitea/models/user"
 | |
| 	"code.gitea.io/gitea/modules/git"
 | |
| 	api "code.gitea.io/gitea/modules/structs"
 | |
| 	"code.gitea.io/gitea/tests"
 | |
| 
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| )
 | |
| 
 | |
| func TestAPIListReleases(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | |
| 	token := getUserToken(t, user2.LowerName, auth_model.AccessTokenScopeReadRepository)
 | |
| 
 | |
| 	link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
 | |
| 	link.RawQuery = url.Values{"token": {token}}.Encode()
 | |
| 	resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
 | |
| 	var apiReleases []*api.Release
 | |
| 	DecodeJSON(t, resp, &apiReleases)
 | |
| 	if assert.Len(t, apiReleases, 3) {
 | |
| 		for _, release := range apiReleases {
 | |
| 			switch release.ID {
 | |
| 			case 1:
 | |
| 				assert.False(t, release.IsDraft)
 | |
| 				assert.False(t, release.IsPrerelease)
 | |
| 				assert.True(t, strings.HasSuffix(release.UploadURL, "/api/v1/repos/user2/repo1/releases/1/assets"), release.UploadURL)
 | |
| 			case 4:
 | |
| 				assert.True(t, release.IsDraft)
 | |
| 				assert.False(t, release.IsPrerelease)
 | |
| 				assert.True(t, strings.HasSuffix(release.UploadURL, "/api/v1/repos/user2/repo1/releases/4/assets"), release.UploadURL)
 | |
| 			case 5:
 | |
| 				assert.False(t, release.IsDraft)
 | |
| 				assert.True(t, release.IsPrerelease)
 | |
| 				assert.True(t, strings.HasSuffix(release.UploadURL, "/api/v1/repos/user2/repo1/releases/5/assets"), release.UploadURL)
 | |
| 			default:
 | |
| 				assert.NoError(t, fmt.Errorf("unexpected release: %v", release))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// test filter
 | |
| 	testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
 | |
| 		if auth {
 | |
| 			query.Set("token", token)
 | |
| 		}
 | |
| 		link.RawQuery = query.Encode()
 | |
| 		resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
 | |
| 		DecodeJSON(t, resp, &apiReleases)
 | |
| 		assert.Len(t, apiReleases, expectedLength, msgAndArgs)
 | |
| 	}
 | |
| 
 | |
| 	testFilterByLen(false, url.Values{"draft": {"true"}}, 0, "anon should not see drafts")
 | |
| 	testFilterByLen(true, url.Values{"draft": {"true"}}, 1, "repo owner should see drafts")
 | |
| 	testFilterByLen(true, url.Values{"draft": {"false"}}, 2, "exclude drafts")
 | |
| 	testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
 | |
| 	testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
 | |
| 	testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
 | |
| }
 | |
| 
 | |
| func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
 | |
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
 | |
| 		owner.Name, repo.Name, token)
 | |
| 	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
 | |
| 		TagName:      name,
 | |
| 		Title:        title,
 | |
| 		Note:         desc,
 | |
| 		IsDraft:      false,
 | |
| 		IsPrerelease: false,
 | |
| 		Target:       target,
 | |
| 	})
 | |
| 	resp := MakeRequest(t, req, http.StatusCreated)
 | |
| 
 | |
| 	var newRelease api.Release
 | |
| 	DecodeJSON(t, resp, &newRelease)
 | |
| 	rel := &repo_model.Release{
 | |
| 		ID:      newRelease.ID,
 | |
| 		TagName: newRelease.TagName,
 | |
| 		Title:   newRelease.Title,
 | |
| 	}
 | |
| 	unittest.AssertExistsAndLoadBean(t, rel)
 | |
| 	assert.EqualValues(t, newRelease.Note, rel.Note)
 | |
| 
 | |
| 	return &newRelease
 | |
| }
 | |
| 
 | |
| func TestAPICreateAndUpdateRelease(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 	session := loginUser(t, owner.LowerName)
 | |
| 	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
 | |
| 
 | |
| 	gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | |
| 	assert.NoError(t, err)
 | |
| 	defer gitRepo.Close()
 | |
| 
 | |
| 	err = gitRepo.CreateTag("v0.0.1", "master")
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	target, err := gitRepo.GetTagCommitID("v0.0.1")
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	newRelease := createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", target, "v0.0.1", "test")
 | |
| 
 | |
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
 | |
| 		owner.Name, repo.Name, newRelease.ID, token)
 | |
| 	req := NewRequest(t, "GET", urlStr)
 | |
| 	resp := MakeRequest(t, req, http.StatusOK)
 | |
| 
 | |
| 	var release api.Release
 | |
| 	DecodeJSON(t, resp, &release)
 | |
| 
 | |
| 	assert.Equal(t, newRelease.TagName, release.TagName)
 | |
| 	assert.Equal(t, newRelease.Title, release.Title)
 | |
| 	assert.Equal(t, newRelease.Note, release.Note)
 | |
| 
 | |
| 	req = NewRequestWithJSON(t, "PATCH", urlStr, &api.EditReleaseOption{
 | |
| 		TagName:      release.TagName,
 | |
| 		Title:        release.Title,
 | |
| 		Note:         "updated",
 | |
| 		IsDraft:      &release.IsDraft,
 | |
| 		IsPrerelease: &release.IsPrerelease,
 | |
| 		Target:       release.Target,
 | |
| 	})
 | |
| 	resp = MakeRequest(t, req, http.StatusOK)
 | |
| 
 | |
| 	DecodeJSON(t, resp, &newRelease)
 | |
| 	rel := &repo_model.Release{
 | |
| 		ID:      newRelease.ID,
 | |
| 		TagName: newRelease.TagName,
 | |
| 		Title:   newRelease.Title,
 | |
| 	}
 | |
| 	unittest.AssertExistsAndLoadBean(t, rel)
 | |
| 	assert.EqualValues(t, rel.Note, newRelease.Note)
 | |
| }
 | |
| 
 | |
| func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 	session := loginUser(t, owner.LowerName)
 | |
| 	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
 | |
| 
 | |
| 	createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
 | |
| }
 | |
| 
 | |
| func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 	session := loginUser(t, owner.LowerName)
 | |
| 	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
 | |
| 
 | |
| 	gitRepo, err := git.OpenRepository(git.DefaultContext, repo.RepoPath())
 | |
| 	assert.NoError(t, err)
 | |
| 	defer gitRepo.Close()
 | |
| 
 | |
| 	err = gitRepo.CreateTag("v0.0.1", "master")
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
 | |
| }
 | |
| 
 | |
| func TestAPIGetLatestRelease(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 
 | |
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/latest",
 | |
| 		owner.Name, repo.Name)
 | |
| 
 | |
| 	req := NewRequestf(t, "GET", urlStr)
 | |
| 	resp := MakeRequest(t, req, http.StatusOK)
 | |
| 
 | |
| 	var release *api.Release
 | |
| 	DecodeJSON(t, resp, &release)
 | |
| 
 | |
| 	assert.Equal(t, "testing-release", release.Title)
 | |
| }
 | |
| 
 | |
| func TestAPIGetReleaseByTag(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 
 | |
| 	tag := "v1.1"
 | |
| 
 | |
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s",
 | |
| 		owner.Name, repo.Name, tag)
 | |
| 
 | |
| 	req := NewRequestf(t, "GET", urlStr)
 | |
| 	resp := MakeRequest(t, req, http.StatusOK)
 | |
| 
 | |
| 	var release *api.Release
 | |
| 	DecodeJSON(t, resp, &release)
 | |
| 
 | |
| 	assert.Equal(t, "testing-release", release.Title)
 | |
| 
 | |
| 	nonexistingtag := "nonexistingtag"
 | |
| 
 | |
| 	urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s",
 | |
| 		owner.Name, repo.Name, nonexistingtag)
 | |
| 
 | |
| 	req = NewRequestf(t, "GET", urlStr)
 | |
| 	resp = MakeRequest(t, req, http.StatusNotFound)
 | |
| 
 | |
| 	var err *api.APIError
 | |
| 	DecodeJSON(t, resp, &err)
 | |
| 	assert.NotEmpty(t, err.Message)
 | |
| }
 | |
| 
 | |
| func TestAPIDeleteReleaseByTagName(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 	session := loginUser(t, owner.LowerName)
 | |
| 	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
 | |
| 
 | |
| 	createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
 | |
| 
 | |
| 	// delete release
 | |
| 	req := NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag?token=%s", owner.Name, repo.Name, token))
 | |
| 	_ = MakeRequest(t, req, http.StatusNoContent)
 | |
| 
 | |
| 	// make sure release is deleted
 | |
| 	req = NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/release-tag?token=%s", owner.Name, repo.Name, token))
 | |
| 	_ = MakeRequest(t, req, http.StatusNotFound)
 | |
| 
 | |
| 	// delete release tag too
 | |
| 	req = NewRequestf(t, http.MethodDelete, fmt.Sprintf("/api/v1/repos/%s/%s/tags/release-tag?token=%s", owner.Name, repo.Name, token))
 | |
| 	_ = MakeRequest(t, req, http.StatusNoContent)
 | |
| }
 | |
| 
 | |
| func TestAPIUploadAssetRelease(t *testing.T) {
 | |
| 	defer tests.PrepareTestEnv(t)()
 | |
| 
 | |
| 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | |
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | |
| 	session := loginUser(t, owner.LowerName)
 | |
| 	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
 | |
| 
 | |
| 	r := createNewReleaseUsingAPI(t, session, token, owner, repo, "release-tag", "", "Release Tag", "test")
 | |
| 
 | |
| 	filename := "image.png"
 | |
| 	buff := generateImg()
 | |
| 	body := &bytes.Buffer{}
 | |
| 
 | |
| 	writer := multipart.NewWriter(body)
 | |
| 	part, err := writer.CreateFormFile("attachment", filename)
 | |
| 	assert.NoError(t, err)
 | |
| 	_, err = io.Copy(part, &buff)
 | |
| 	assert.NoError(t, err)
 | |
| 	err = writer.Close()
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	req := NewRequestWithBody(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d/assets?name=test-asset&token=%s", owner.Name, repo.Name, r.ID, token), body)
 | |
| 	req.Header.Add("Content-Type", writer.FormDataContentType())
 | |
| 	resp := MakeRequest(t, req, http.StatusCreated)
 | |
| 
 | |
| 	var attachment *api.Attachment
 | |
| 	DecodeJSON(t, resp, &attachment)
 | |
| 
 | |
| 	assert.EqualValues(t, "test-asset", attachment.Name)
 | |
| 	assert.EqualValues(t, 104, attachment.Size)
 | |
| }
 |