Compare commits

...

6 commits

Author SHA1 Message Date
Robert Kaussow d711cab28d
Merge 932e128d20 into 2d66cfcce2 2024-04-27 20:06:22 +00:00
Robert Kaussow 932e128d20
add RepoPostOptions 2024-04-27 22:06:15 +02:00
Robert Kaussow 0d6be94065
add PipelineLastOptions 2024-04-27 21:34:33 +02:00
Robert Kaussow d629c0b3f1
add DeployOptions and PipelineStartOptions 2024-04-27 21:02:33 +02:00
Robert Kaussow 58fec6049c
expose pipeline list options to cli 2024-04-27 19:42:47 +02:00
Robert Kaussow bf2dfd36e5
Add options to RepoList 2024-04-27 18:46:31 +02:00
14 changed files with 547 additions and 76 deletions

View file

@ -78,7 +78,7 @@ func deploy(c *cli.Context) error {
var number int64
if pipelineArg == "last" {
// Fetch the pipeline number from the last pipeline
pipelines, berr := client.PipelineList(repoID, woodpecker.PipelineListsOptions{})
pipelines, berr := client.PipelineList(repoID, woodpecker.PipelineListOptions{})
if berr != nil {
return berr
}
@ -112,9 +112,12 @@ func deploy(c *cli.Context) error {
return fmt.Errorf("please specify the target environment (i.e. production)")
}
params := internal.ParseKeyPair(c.StringSlice("param"))
opt := woodpecker.DeployOptions{
DeployTo: env,
Params: internal.ParseKeyPair(c.StringSlice("param")),
}
deploy, err := client.Deploy(repoID, number, env, params)
deploy, err := client.Deploy(repoID, number, opt)
if err != nil {
return err
}

View file

@ -23,6 +23,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var pipelineInfoCmd = &cli.Command{
@ -48,7 +49,7 @@ func pipelineInfo(c *cli.Context) error {
var number int64
if pipelineArg == "last" || len(pipelineArg) == 0 {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(repoID, "")
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
if err != nil {
return err
}

View file

@ -22,6 +22,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var pipelineLastCmd = &cli.Command{
@ -50,7 +51,11 @@ func pipelineLast(c *cli.Context) error {
return err
}
pipeline, err := client.PipelineLast(repoID, c.String("branch"))
opt := woodpecker.PipelineLastOptions{
Branch: c.String("branch"),
}
pipeline, err := client.PipelineLast(repoID, opt)
if err != nil {
return err
}

View file

@ -17,6 +17,7 @@ package pipeline
import (
"os"
"text/template"
"time"
"github.com/urfave/cli/v2"
@ -50,6 +51,16 @@ var pipelineListCmd = &cli.Command{
Usage: "limit the list size",
Value: 25,
},
&cli.TimestampFlag{
Name: "before",
Usage: "only return pipelines before this RFC3339 date",
Layout: time.RFC3339,
},
&cli.TimestampFlag{
Name: "after",
Usage: "only return pipelines after this RFC3339 date",
Layout: time.RFC3339,
},
},
}
@ -64,7 +75,18 @@ func pipelineList(c *cli.Context) error {
return err
}
pipelines, err := client.PipelineList(repoID, woodpecker.PipelineListsOptions{})
opt := woodpecker.PipelineListOptions{}
before := c.Timestamp("before")
after := c.Timestamp("after")
if before != nil {
opt.Before = *before
}
if after != nil {
opt.After = *after
}
pipelines, err := client.PipelineList(repoID, opt)
if err != nil {
return err
}

View file

@ -23,6 +23,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var pipelinePsCmd = &cli.Command{
@ -49,7 +50,7 @@ func pipelinePs(c *cli.Context) error {
if pipelineArg == "last" || len(pipelineArg) == 0 {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(repoID, "")
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
if err != nil {
return err
}

View file

@ -22,6 +22,7 @@ import (
"github.com/urfave/cli/v2"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var pipelineStartCmd = &cli.Command{
@ -53,7 +54,7 @@ func pipelineStart(c *cli.Context) (err error) {
var number int64
if pipelineArg == "last" {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(repoID, "")
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
if err != nil {
return err
}
@ -68,9 +69,11 @@ func pipelineStart(c *cli.Context) (err error) {
}
}
params := internal.ParseKeyPair(c.StringSlice("param"))
opt := woodpecker.PipelineStartOptions{
Params: internal.ParseKeyPair(c.StringSlice("param")),
}
pipeline, err := client.PipelineStart(repoID, number, params)
pipeline, err := client.PipelineStart(repoID, number, opt)
if err != nil {
return err
}

View file

@ -21,6 +21,7 @@ import (
"github.com/urfave/cli/v2"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var repoAddCmd = &cli.Command{
@ -42,7 +43,11 @@ func repoAdd(c *cli.Context) error {
return err
}
repo, err := client.RepoPost(int64(forgeRemoteID))
opt := woodpecker.RepoPostOptions{
ForgeRemoteID: int64(forgeRemoteID),
}
repo, err := client.RepoPost(opt)
if err != nil {
return err
}

View file

@ -22,6 +22,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var repoListCmd = &cli.Command{
@ -35,6 +36,10 @@ var repoListCmd = &cli.Command{
Name: "org",
Usage: "filter by organization",
},
&cli.BoolFlag{
Name: "all",
Usage: "query all repos, including inactive ones",
},
},
}
@ -44,7 +49,11 @@ func repoList(c *cli.Context) error {
return err
}
repos, err := client.RepoList()
opt := woodpecker.RepoListOptions{
All: c.Bool("all"),
}
repos, err := client.RepoList(opt)
if err != nil || len(repos) == 0 {
return err
}
@ -67,4 +76,4 @@ func repoList(c *cli.Context) error {
}
// template for repository list items
var tmplRepoList = "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }})"
var tmplRepoList = "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}, isActive: {{ .IsActive }})"

View file

@ -22,6 +22,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var repoSyncCmd = &cli.Command{
@ -39,7 +40,11 @@ func repoSync(c *cli.Context) error {
return err
}
repos, err := client.RepoListOpts(true)
opt := woodpecker.RepoListOptions{
All: true,
}
repos, err := client.RepoList(opt)
if err != nil || len(repos) == 0 {
return err
}

View file

@ -52,14 +52,10 @@ type Client interface {
// RepoList returns a list of all repositories to which the user has explicit
// access in the host system.
RepoList() ([]*Repo, error)
// RepoListOpts returns a list of all repositories to which the user has
// explicit access in the host system.
RepoListOpts(bool) ([]*Repo, error)
RepoList(opt RepoListOptions) ([]*Repo, error)
// RepoPost activates a repository.
RepoPost(forgeRemoteID int64) (*Repo, error)
RepoPost(opt RepoPostOptions) (*Repo, error)
// RepoPatch updates a repository.
RepoPatch(repoID int64, repo *RepoPatch) (*Repo, error)
@ -79,13 +75,12 @@ type Client interface {
// Pipeline returns a repository pipeline by number.
Pipeline(repoID, pipeline int64) (*Pipeline, error)
// PipelineLast returns the latest repository pipeline by branch. An empty branch
// will result in the default branch.
PipelineLast(repoID int64, branch string) (*Pipeline, error)
// PipelineLast returns the latest repository pipeline.
PipelineLast(repoID int64, opt PipelineLastOptions) (*Pipeline, error)
// PipelineList returns a list of recent pipelines for the
// the specified repository.
PipelineList(repoID int64, opt PipelineListsOptions) ([]*Pipeline, error)
PipelineList(repoID int64, opt PipelineListOptions) ([]*Pipeline, error)
// PipelineQueue returns a list of enqueued pipelines.
PipelineQueue() ([]*Feed, error)
@ -94,7 +89,7 @@ type Client interface {
PipelineCreate(repoID int64, opts *PipelineOptions) (*Pipeline, error)
// PipelineStart re-starts a stopped pipeline.
PipelineStart(repoID, num int64, params map[string]string) (*Pipeline, error)
PipelineStart(repoID, num int64, opt PipelineStartOptions) (*Pipeline, error)
// PipelineStop stops the given pipeline.
PipelineStop(repoID, pipeline int64) error
@ -113,7 +108,7 @@ type Client interface {
// Deploy triggers a deployment for an existing pipeline using the specified
// target environment.
Deploy(repoID, pipeline int64, env string, params map[string]string) (*Pipeline, error)
Deploy(repoID, pipeline int64, opt DeployOptions) (*Pipeline, error)
// LogsPurge purges the pipeline logs for the specified pipeline.
LogsPurge(repoID, pipeline int64) error

View file

@ -3,11 +3,12 @@ package woodpecker
import (
"fmt"
"net/url"
"strconv"
"time"
)
const (
pathRepoPost = "%s/api/repos?forge_remote_id=%d"
pathRepoPost = "%s/api/repos"
pathRepo = "%s/api/repos/%d"
pathRepoLookup = "%s/api/repos/lookup/%s"
pathRepoMove = "%s/api/repos/%d/move?to=%s"
@ -28,14 +29,31 @@ const (
pathRepoCron = "%s/api/repos/%d/cron/%d"
)
type PipelineListsOptions struct {
type PipelineListOptions struct {
ListOptions
Before time.Time
After time.Time
}
// QueryEncode returns the URL query parameters for the PipelineListsOptions.
func (opt *PipelineListsOptions) QueryEncode() string {
type DeployOptions struct {
DeployTo string // override the target deploy value
Params map[string]string // custom KEY=value parameters to be injected into the step environment
}
type PipelineStartOptions struct {
Params map[string]string // custom KEY=value parameters to be injected into the step environment
}
type PipelineLastOptions struct {
Branch string // last pipeline from given branch, an empty branch will result in the default branch
}
type RepoPostOptions struct {
ForgeRemoteID int64
}
// QueryEncode returns the URL query parameters for the PipelineListOptions.
func (opt *PipelineListOptions) QueryEncode() string {
query := opt.getURLQuery()
if !opt.Before.IsZero() {
query.Add("before", opt.Before.Format(time.RFC3339))
@ -46,6 +64,38 @@ func (opt *PipelineListsOptions) QueryEncode() string {
return query.Encode()
}
// QueryEncode returns the URL query parameters for the DeployOptions.
func (opt *DeployOptions) QueryEncode() string {
query := mapValues(opt.Params)
if opt.DeployTo != "" {
query.Add("deploy_to", opt.DeployTo)
}
query.Add("event", EventDeploy)
return query.Encode()
}
// QueryEncode returns the URL query parameters for the PipelineStartOptions.
func (opt *PipelineStartOptions) QueryEncode() string {
query := mapValues(opt.Params)
return query.Encode()
}
// QueryEncode returns the URL query parameters for the PipelineLastOptions.
func (opt *PipelineLastOptions) QueryEncode() string {
query := make(url.Values)
if opt.Branch != "" {
query.Add("branch", opt.Branch)
}
return query.Encode()
}
// QueryEncode returns the URL query parameters for the RepoPostOptions.
func (opt *RepoPostOptions) QueryEncode() string {
query := make(url.Values)
query.Add("forge_remote_id", strconv.FormatInt(opt.ForgeRemoteID, 10))
return query.Encode()
}
// Repo returns a repository by id.
func (c *client) Repo(repoID int64) (*Repo, error) {
out := new(Repo)
@ -63,10 +113,12 @@ func (c *client) RepoLookup(fullName string) (*Repo, error) {
}
// RepoPost activates a repository.
func (c *client) RepoPost(forgeRemoteID int64) (*Repo, error) {
func (c *client) RepoPost(opt RepoPostOptions) (*Repo, error) {
out := new(Repo)
uri := fmt.Sprintf(pathRepoPost, c.addr, forgeRemoteID)
err := c.post(uri, nil, out)
uri, _ := url.Parse(fmt.Sprintf(pathRepoPost, c.addr))
uri.RawQuery = opt.QueryEncode()
fmt.Println("!!!!!!!!!!", uri.String())
err := c.post(uri.String(), nil, out)
return out, err
}
@ -224,25 +276,21 @@ func (c *client) Pipeline(repoID, pipeline int64) (*Pipeline, error) {
return out, err
}
// Pipeline returns the latest repository pipeline by branch.
func (c *client) PipelineLast(repoID int64, branch string) (*Pipeline, error) {
// Pipeline returns the latest repository pipeline.
func (c *client) PipelineLast(repoID int64, opt PipelineLastOptions) (*Pipeline, error) {
out := new(Pipeline)
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, "latest")
if len(branch) != 0 {
uri += "?branch=" + branch
}
err := c.get(uri, out)
uri, _ := url.Parse(fmt.Sprintf(pathPipeline, c.addr, repoID, "latest"))
uri.RawQuery = opt.QueryEncode()
err := c.get(uri.String(), out)
return out, err
}
// PipelineList returns a list of recent pipelines for the
// the specified repository.
func (c *client) PipelineList(repoID int64, opt PipelineListsOptions) ([]*Pipeline, error) {
func (c *client) PipelineList(repoID int64, opt PipelineListOptions) ([]*Pipeline, error) {
var out []*Pipeline
uri, _ := url.Parse(fmt.Sprintf(pathPipelines, c.addr, repoID))
uri.RawQuery = opt.QueryEncode()
err := c.get(uri.String(), &out)
return out, err
}
@ -256,11 +304,11 @@ func (c *client) PipelineCreate(repoID int64, options *PipelineOptions) (*Pipeli
}
// PipelineStart re-starts a stopped pipeline.
func (c *client) PipelineStart(repoID, pipeline int64, params map[string]string) (*Pipeline, error) {
func (c *client) PipelineStart(repoID, pipeline int64, opt PipelineStartOptions) (*Pipeline, error) {
out := new(Pipeline)
val := mapValues(params)
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
err := c.post(uri+"?"+val.Encode(), nil, out)
uri, _ := url.Parse(fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline))
uri.RawQuery = opt.QueryEncode()
err := c.post(uri.String(), nil, out)
return out, err
}
@ -303,13 +351,11 @@ func (c *client) LogsPurge(repoID, pipeline int64) error {
// Deploy triggers a deployment for an existing pipeline using the
// specified target environment.
func (c *client) Deploy(repoID, pipeline int64, env string, params map[string]string) (*Pipeline, error) {
func (c *client) Deploy(repoID, pipeline int64, opt DeployOptions) (*Pipeline, error) {
out := new(Pipeline)
val := mapValues(params)
val.Set("event", EventDeploy)
val.Set("deploy_to", env)
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
err := c.post(uri+"?"+val.Encode(), nil, out)
uri, _ := url.Parse(fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline))
uri.RawQuery = opt.QueryEncode()
err := c.post(uri.String(), nil, out)
return out, err
}

View file

@ -13,15 +13,15 @@ import (
func TestPipelineList(t *testing.T) {
tests := []struct {
name string
fixtureHandler http.HandlerFunc
opts PipelineListsOptions
handler http.HandlerFunc
opts PipelineListOptions
wantErr bool
expectedLength int
expectedIDs []int64
}{
{
name: "success",
fixtureHandler: func(w http.ResponseWriter, r *http.Request) {
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method)
assert.Equal(t, "/api/repos/123/pipelines?after=2023-01-15T00%3A00%3A00Z&before=2023-01-16T00%3A00%3A00Z&page=2&perPage=10", r.URL.RequestURI())
@ -29,7 +29,7 @@ func TestPipelineList(t *testing.T) {
_, err := fmt.Fprint(w, `[{"id":1},{"id":2}]`)
assert.NoError(t, err)
},
opts: PipelineListsOptions{
opts: PipelineListOptions{
ListOptions: ListOptions{
Page: 2,
PerPage: 10,
@ -42,7 +42,7 @@ func TestPipelineList(t *testing.T) {
},
{
name: "empty ListOptions",
fixtureHandler: func(w http.ResponseWriter, r *http.Request) {
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method)
assert.Equal(t, "/api/repos/123/pipelines", r.URL.RequestURI())
@ -50,23 +50,23 @@ func TestPipelineList(t *testing.T) {
_, err := fmt.Fprint(w, `[{"id":1},{"id":2}]`)
assert.NoError(t, err)
},
opts: PipelineListsOptions{},
opts: PipelineListOptions{},
expectedLength: 2,
expectedIDs: []int64{1, 2},
},
{
name: "error",
fixtureHandler: func(w http.ResponseWriter, _ *http.Request) {
name: "server error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
opts: PipelineListsOptions{},
opts: PipelineListOptions{},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.fixtureHandler)
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
@ -86,3 +86,299 @@ func TestPipelineList(t *testing.T) {
})
}
}
func TestClientDeploy(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
repoID int64
pipelineID int64
opts DeployOptions
wantErr bool
expectedPipeline *Pipeline
}{
{
name: "success",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/repos/123/pipelines/456?event=deployment", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":789}`)
assert.NoError(t, err)
},
repoID: 123,
pipelineID: 456,
opts: DeployOptions{},
expectedPipeline: &Pipeline{
ID: 789,
},
},
{
name: "error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
repoID: 123,
pipelineID: 456,
opts: DeployOptions{},
wantErr: true,
},
{
name: "with options",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/repos/123/pipelines/456?deploy_to=production&event=deployment", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":789}`)
assert.NoError(t, err)
},
repoID: 123,
pipelineID: 456,
opts: DeployOptions{
DeployTo: "production",
},
expectedPipeline: &Pipeline{
ID: 789,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
pipeline, err := client.Deploy(tt.repoID, tt.pipelineID, tt.opts)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expectedPipeline, pipeline)
})
}
}
func TestClientPipelineStart(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
repoID int64
pipelineID int64
opts PipelineStartOptions
wantErr bool
expectedPipeline *Pipeline
}{
{
name: "success",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/repos/123/pipelines/456", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":789}`)
assert.NoError(t, err)
},
repoID: 123,
pipelineID: 456,
opts: PipelineStartOptions{},
expectedPipeline: &Pipeline{
ID: 789,
},
},
{
name: "error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
repoID: 123,
pipelineID: 456,
opts: PipelineStartOptions{},
wantErr: true,
},
{
name: "with options",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/repos/123/pipelines/456?foo=bar", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":789}`)
assert.NoError(t, err)
},
repoID: 123,
pipelineID: 456,
opts: PipelineStartOptions{
Params: map[string]string{"foo": "bar"},
},
expectedPipeline: &Pipeline{
ID: 789,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
pipeline, err := client.PipelineStart(tt.repoID, tt.pipelineID, tt.opts)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expectedPipeline, pipeline)
})
}
}
func TestClient_PipelineLast(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
repoID int64
opts PipelineLastOptions
expected *Pipeline
wantErr bool
}{
{
name: "success",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/repos/1/pipelines/latest?branch=main", r.URL.Path+"?"+r.URL.RawQuery)
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":1,"number":1,"status":"success","event":"push","branch":"main"}`)
assert.NoError(t, err)
},
repoID: 1,
opts: PipelineLastOptions{Branch: "main"},
expected: &Pipeline{
ID: 1,
Number: 1,
Status: "success",
Event: "push",
Branch: "main",
},
wantErr: false,
},
{
name: "server error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
repoID: 1,
opts: PipelineLastOptions{},
expected: nil,
wantErr: true,
},
{
name: "invalid response",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `invalid json`)
assert.NoError(t, err)
},
repoID: 1,
opts: PipelineLastOptions{},
expected: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
pipeline, err := client.PipelineLast(tt.repoID, tt.opts)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expected, pipeline)
})
}
}
func TestClientRepoPost(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
opts RepoPostOptions
expected *Repo
wantErr bool
}{
{
name: "success",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/api/repos?forge_remote_id=10", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `{"id":1,"name":"test","owner":"owner","full_name":"owner/test","forge_remote_id":"10"}`)
assert.NoError(t, err)
},
opts: RepoPostOptions{
ForgeRemoteID: 10,
},
expected: &Repo{
ID: 1,
ForgeRemoteID: "10",
Name: "test",
Owner: "owner",
FullName: "owner/test",
},
wantErr: false,
},
{
name: "server error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
opts: RepoPostOptions{},
expected: nil,
wantErr: true,
},
{
name: "invalid response",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `invalid json`)
assert.NoError(t, err)
},
opts: RepoPostOptions{},
expected: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
repo, err := client.RepoPost(tt.opts)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expected, repo)
})
}
}

View file

@ -1,6 +1,9 @@
package woodpecker
import "fmt"
import (
"fmt"
"net/url"
)
const (
pathSelf = "%s/api/user"
@ -9,6 +12,19 @@ const (
pathUser = "%s/api/users/%s"
)
type RepoListOptions struct {
All bool // query all repos, including inactive ones
}
// QueryEncode returns the URL query parameters for the RepoListOptions.
func (opt *RepoListOptions) QueryEncode() string {
query := make(url.Values)
if opt.All {
query.Add("all", "true")
}
return query.Encode()
}
// Self returns the currently authenticated user.
func (c *client) Self() (*User, error) {
out := new(User)
@ -58,18 +74,10 @@ func (c *client) UserDel(login string) error {
// RepoList returns a list of all repositories to which
// the user has explicit access in the host system.
func (c *client) RepoList() ([]*Repo, error) {
func (c *client) RepoList(opt RepoListOptions) ([]*Repo, error) {
var out []*Repo
uri := fmt.Sprintf(pathRepos, c.addr)
err := c.get(uri, &out)
return out, err
}
// RepoListOpts returns a list of all repositories to which
// the user has explicit access in the host system.
func (c *client) RepoListOpts(all bool) ([]*Repo, error) {
var out []*Repo
uri := fmt.Sprintf(pathRepos+"?all=%v", c.addr, all)
err := c.get(uri, &out)
uri, _ := url.Parse(fmt.Sprintf(pathRepos, c.addr))
uri.RawQuery = opt.QueryEncode()
err := c.get(uri.String(), &out)
return out, err
}

View file

@ -265,3 +265,75 @@ func TestClient_UserDel(t *testing.T) {
})
}
}
func TestClient_RepoList(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
opt RepoListOptions
expected []*Repo
wantErr bool
}{
{
name: "success",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `[{"id":1,"name":"repo1"},{"id":2,"name":"repo2"}]`)
assert.NoError(t, err)
},
opt: RepoListOptions{},
expected: []*Repo{{ID: 1, Name: "repo1"}, {ID: 2, Name: "repo2"}},
wantErr: false,
},
{
name: "empty response",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `[]`)
assert.NoError(t, err)
},
opt: RepoListOptions{},
expected: []*Repo{},
wantErr: false,
},
{
name: "server error",
handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
},
opt: RepoListOptions{},
expected: nil,
wantErr: true,
},
{
name: "with options",
handler: func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/user/repos?all=true", r.URL.RequestURI())
w.WriteHeader(http.StatusOK)
_, err := fmt.Fprint(w, `[]`)
assert.NoError(t, err)
},
opt: RepoListOptions{All: true},
expected: []*Repo{},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(tt.handler)
defer ts.Close()
client := NewClient(ts.URL, http.DefaultClient)
repos, err := client.RepoList(tt.opt)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expected, repos)
})
}
}