Compare commits

...

5 Commits

Author SHA1 Message Date
appleboy 8110db1e6d feat: implement Gitea Repo Action Secrets Management (#662)
- Add imports for "bytes", "encoding/json", and "net/http" in `repo_action.go`
- Implement `CreateRepoActionSecret` function to create a secret for a repository in Gitea Actions
- Add a new test file `repo_action_test.go` with tests for creating, updating, and listing repository action secrets

<img width="518" alt="image" src="/attachments/c8e457c4-395f-4ffe-8482-0b7f5d2541cb">

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/662
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2024-05-08 09:29:30 +00:00
Bo-Yi Wu 83c73e79a5 ci: update Gitea testing configurations for 1.22 release (#663)
- Update Gitea image version to `1.22.0-rc1` in testing workflow
- Increase the number of milestones to be checked in the test from `2` to `3`
- Modify the theme setting from `auto` to `gitea-auto` in user settings test
- Update the Avatar URL in user test to use `http://gitea:3000/avatars/` instead of `https://secure.gravatar.com/avatar/`
- Increase the number of user emails to be checked in the test from `2` to `3`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/663
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-08 01:53:26 +00:00
Bo-Yi Wu 6c0938dc15 feat: implement organization action secret creation (#661)
- Add `bytes` and `encoding/json` imports to `org_action.go`
- Implement `CreateSecretOption` struct with validation in `org_action.go`
- Add `CreateOrgActionSecret` function to create or update organization secrets in `org_action.go`
- Create new test file `org_action_test.go` with tests for creating and updating organization secrets
- Add `Data` field to `Secret` struct in `secret.go`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/661
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-03 13:52:34 +00:00
tobiasbp 0a99bda0cb Get fields loginName & SourceID for users (#654)
This _PR_ adds the following fields to the _User_ struct:

-  _LoginName_: Currently returned by the Gitea API.
- _SourceID_: [Scheduled to be returned by the Gitea API as of version 1.22.0](https://github.com/go-gitea/gitea/pull/29718).

The fields are used for users with non-local Authentication Sources (LDAP, oAuth etc.).

Co-authored-by: tobias.petersen <tobias.petersen@unity3d.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@noreply.gitea.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/654
Reviewed-by: appleboy <appleboy.tw@gmail.com>
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: tobiasbp <tobiasbp@noreply.gitea.com>
Co-committed-by: tobiasbp <tobiasbp@noreply.gitea.com>
2024-05-02 17:33:09 +00:00
Bo-Yi Wu 36723e11c8 feat(repo): support list of repo secrets (#660)
- Update comment to correctly describe `ListOrgActionSecretOption` as listing organization secrets instead of members
- Add new file `repo_action.go` with functionality to list a repository's secrets including the structure and API call

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/660
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-02 06:04:51 +00:00
11 changed files with 220 additions and 10 deletions

View File

@ -28,7 +28,7 @@ jobs:
- run: make test
services:
gitea:
image: gitea/gitea:1.21.10
image: gitea/gitea:1.22.0-rc1
cmd:
- bash
- -c

View File

@ -43,7 +43,7 @@ func TestMilestones(t *testing.T) {
// ListRepoMilestones
ml, _, err := c.ListRepoMilestones(repo.Owner.UserName, repo.Name, ListMilestoneOption{})
assert.NoError(t, err)
assert.Len(t, ml, 2)
assert.Len(t, ml, 3)
ml, _, err = c.ListRepoMilestones(repo.Owner.UserName, repo.Name, ListMilestoneOption{State: StateClosed})
assert.NoError(t, err)
assert.Len(t, ml, 1)

View File

@ -19,7 +19,7 @@ func TestIssue(t *testing.T) {
createIssue(t, c)
// Little sleep in order to give some time for gitea to properly store all information on database. Without this sleep, CI is a bit unstable
time.Sleep(100 * time.Millisecond)
time.Sleep(200 * time.Millisecond)
editIssues(t, c)
listIssues(t, c)
deleteIssue(t, c)

View File

@ -5,16 +5,19 @@
package gitea
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
// ListOrgMembershipOption list OrgMembership options
// ListOrgActionSecretOption list OrgActionSecret options
type ListOrgActionSecretOption struct {
ListOptions
}
// ListOrgMembership list an organization's members
// ListOrgActionSecret list an organization's secrets
func (c *Client) ListOrgActionSecret(org string, opt ListOrgActionSecretOption) ([]*Secret, *Response, error) {
if err := escapeValidatePathSegments(&org); err != nil {
return nil, nil, err
@ -27,3 +30,58 @@ func (c *Client) ListOrgActionSecret(org string, opt ListOrgActionSecretOption)
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &secrets)
return secrets, resp, err
}
// CreateSecretOption represents the options for creating a secret.
type CreateSecretOption struct {
Name string `json:"name"` // Name is the name of the secret.
Data string `json:"data"` // Data is the data of the secret.
}
// Validate checks if the CreateSecretOption is valid.
// It returns an error if any of the validation checks fail.
func (opt *CreateSecretOption) Validate() error {
if len(opt.Name) == 0 {
return fmt.Errorf("name required")
}
if len(opt.Name) > 30 {
return fmt.Errorf("name to long")
}
if len(opt.Data) == 0 {
return fmt.Errorf("data required")
}
return nil
}
// CreateOrgActionSecret creates a secret for the specified organization in the Gitea Actions.
// It takes the organization name and the secret options as parameters.
// The function returns the HTTP response and an error, if any.
func (c *Client) CreateOrgActionSecret(org string, opt CreateSecretOption) (*Response, error) {
if err := escapeValidatePathSegments(&org); err != nil {
return nil, err
}
if err := (&opt).Validate(); err != nil {
return nil, err
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, err
}
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/actions/secrets/%s", org, opt.Name), jsonHeader, bytes.NewReader(body))
if err != nil {
return nil, err
}
switch status {
case http.StatusCreated:
return resp, nil
case http.StatusNoContent:
return resp, nil
case http.StatusNotFound:
return resp, fmt.Errorf("forbidden")
case http.StatusBadRequest:
return resp, fmt.Errorf("bad request")
default:
return resp, fmt.Errorf("unexpected Status: %d", status)
}
}

39
gitea/org_action_test.go Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gitea
import (
"log"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateOrgActionSecret(t *testing.T) {
log.Println("== TestCreateOrgActionSecret ==")
c := newTestClient()
user := createTestUser(t, "org_action_user", c)
c.SetSudo(user.UserName)
newOrg, _, err := c.CreateOrg(CreateOrgOption{Name: "ActionOrg"})
assert.NoError(t, err)
assert.NotNil(t, newOrg)
// create secret
resp, err := c.CreateOrgActionSecret(newOrg.UserName, CreateSecretOption{Name: "test", Data: "test"})
assert.NoError(t, err)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// update secret
resp, err = c.CreateOrgActionSecret(newOrg.UserName, CreateSecretOption{Name: "test", Data: "test2"})
assert.NoError(t, err)
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
// list secrets
secrets, _, err := c.ListOrgActionSecret(newOrg.UserName, ListOrgActionSecretOption{})
assert.NoError(t, err)
assert.Len(t, secrets, 1)
}

66
gitea/repo_action.go Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gitea
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
// ListRepoActionSecretOption list RepoActionSecret options
type ListRepoActionSecretOption struct {
ListOptions
}
// ListRepoActionSecret list a repository's secrets
func (c *Client) ListRepoActionSecret(user, repo string, opt ListRepoActionSecretOption) ([]*Secret, *Response, error) {
if err := escapeValidatePathSegments(&user, &repo); err != nil {
return nil, nil, err
}
opt.setDefaults()
secrets := make([]*Secret, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/secrets", user, repo))
link.RawQuery = opt.getURLQuery().Encode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &secrets)
return secrets, resp, err
}
// CreateRepoActionSecret creates a secret for the specified repository in the Gitea Actions.
// It takes the organization name and the secret options as parameters.
// The function returns the HTTP response and an error, if any.
func (c *Client) CreateRepoActionSecret(user, repo string, opt CreateSecretOption) (*Response, error) {
if err := escapeValidatePathSegments(&user, &repo); err != nil {
return nil, err
}
if err := (&opt).Validate(); err != nil {
return nil, err
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, err
}
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/actions/secrets/%s", user, repo, opt.Name), jsonHeader, bytes.NewReader(body))
if err != nil {
return nil, err
}
switch status {
case http.StatusCreated:
return resp, nil
case http.StatusNoContent:
return resp, nil
case http.StatusNotFound:
return resp, fmt.Errorf("forbidden")
case http.StatusBadRequest:
return resp, fmt.Errorf("bad request")
default:
return resp, fmt.Errorf("unexpected Status: %d", status)
}
}

41
gitea/repo_action_test.go Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package gitea
import (
"log"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateRepoActionSecret(t *testing.T) {
log.Println("== TestCreateRepoActionSecret ==")
c := newTestClient()
user := createTestUser(t, "repo_action_user", c)
c.SetSudo(user.UserName)
newRepo, _, err := c.CreateRepo(CreateRepoOption{
Name: "test",
})
assert.NoError(t, err)
assert.NotNil(t, newRepo)
// create secret
resp, err := c.CreateRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, CreateSecretOption{Name: "test", Data: "test"})
assert.NoError(t, err)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// update secret
resp, err = c.CreateRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, CreateSecretOption{Name: "test", Data: "test2"})
assert.NoError(t, err)
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
// list secrets
secrets, _, err := c.ListRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, ListRepoActionSecretOption{})
assert.NoError(t, err)
assert.Len(t, secrets, 1)
}

View File

@ -9,6 +9,8 @@ import "time"
type Secret struct {
// the secret's name
Name string `json:"name"`
// the secret's data
Data string `json:"data"`
// Date and Time of secret creation
Created time.Time `json:"created_at"`
}

View File

@ -17,6 +17,10 @@ type User struct {
ID int64 `json:"id"`
// the user's username
UserName string `json:"login"`
// The login_name of non local users (e.g. LDAP / OAuth / SMTP)
LoginName string `json:"login_name"`
// The ID of the Authentication Source for non local users.
SourceID int64 `json:"source_id"`
// the user's full name
FullName string `json:"full_name"`
Email string `json:"email"`

View File

@ -19,7 +19,7 @@ func TestUserSettings(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, userConf)
assert.EqualValues(t, UserSettings{
Theme: "auto",
Theme: "gitea-auto",
HideEmail: false,
HideActivity: false,
}, *userConf)
@ -33,7 +33,7 @@ func TestUserSettings(t *testing.T) {
assert.NotNil(t, userConf)
assert.EqualValues(t, UserSettings{
FullName: "Admin User on Test",
Theme: "auto",
Theme: "gitea-auto",
Language: "de_de",
HideEmail: true,
HideActivity: false,

View File

@ -21,7 +21,7 @@ func TestMyUser(t *testing.T) {
assert.EqualValues(t, "test01", user.UserName)
assert.EqualValues(t, "test01@gitea.io", user.Email)
assert.EqualValues(t, "", user.FullName)
assert.EqualValues(t, "https://secure.gravatar.com/avatar/d794373e882a68fb173cef817fb6180a?d=identicon", user.AvatarURL)
assert.EqualValues(t, "http://gitea:3000/avatars/d794373e882a68fb173cef817fb6180a", user.AvatarURL)
assert.True(t, user.IsAdmin)
}
@ -144,14 +144,14 @@ func TestUserEmail(t *testing.T) {
el, _, err := c.ListEmails(ListEmailsOptions{})
assert.NoError(t, err)
assert.Len(t, el, 1)
assert.EqualValues(t, "testuseremail@gitea.io", el[0].Email)
assert.EqualValues(t, "TestUserEmail@gitea.io", el[0].Email)
assert.True(t, el[0].Primary)
// AddEmail
mails := []string{"wow@mail.send", "speed@mail.me"}
el, _, err = c.AddEmail(CreateEmailOption{Emails: mails})
assert.NoError(t, err)
assert.Len(t, el, 2)
assert.Len(t, el, 3)
_, _, err = c.AddEmail(CreateEmailOption{Emails: []string{mails[1]}})
assert.Error(t, err)
el, _, err = c.ListEmails(ListEmailsOptions{})