You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Split client into multiple files and add more tests (#3647)
All the client functions were in a single file, which was already very long, and the test file gets even longer as more tests are added. I split it into separate files representing the API path and started adding some tests.
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -13,7 +13,7 @@ | ||||
| *.so | ||||
| *.dylib | ||||
| vendor/ | ||||
| __debug_bin | ||||
| __debug_bin* | ||||
|  | ||||
| # Test binary, built with `go test -c` | ||||
| *.test | ||||
|   | ||||
							
								
								
									
										50
									
								
								woodpecker-go/woodpecker/agent.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								woodpecker-go/woodpecker/agent.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const ( | ||||
| 	pathAgents     = "%s/api/agents" | ||||
| 	pathAgent      = "%s/api/agents/%d" | ||||
| 	pathAgentTasks = "%s/api/agents/%d/tasks" | ||||
| ) | ||||
|  | ||||
| // AgentCreate creates a new agent. | ||||
| func (c *client) AgentCreate(in *Agent) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgents, c.addr) | ||||
| 	return out, c.post(uri, in, out) | ||||
| } | ||||
|  | ||||
| // AgentList returns a list of all registered agents. | ||||
| func (c *client) AgentList() ([]*Agent, error) { | ||||
| 	out := make([]*Agent, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathAgents, c.addr) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
|  | ||||
| // Agent returns an agent by id. | ||||
| func (c *client) Agent(agentID int64) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, agentID) | ||||
| 	return out, c.get(uri, out) | ||||
| } | ||||
|  | ||||
| // AgentUpdate updates the agent with the provided Agent struct. | ||||
| func (c *client) AgentUpdate(in *Agent) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, in.ID) | ||||
| 	return out, c.patch(uri, in, out) | ||||
| } | ||||
|  | ||||
| // AgentDelete deletes the agent with the given id. | ||||
| func (c *client) AgentDelete(agentID int64) error { | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, agentID) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // AgentTasksList returns a list of all tasks for the agent with the given id. | ||||
| func (c *client) AgentTasksList(agentID int64) ([]*Task, error) { | ||||
| 	out := make([]*Task, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathAgentTasks, c.addr, agentID) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
							
								
								
									
										511
									
								
								woodpecker-go/woodpecker/agent_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								woodpecker-go/woodpecker/agent_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,511 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestClient_AgentCreate(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		input    *Agent | ||||
| 		expected *Agent | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPost { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusCreated) | ||||
| 				_, err := fmt.Fprint(w, `{"id":1,"name":"new_agent","backend":"local","capacity":2,"version":"1.0.0"}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			input:    &Agent{Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"}, | ||||
| 			expected: &Agent{ID: 1, Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid input", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPost { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusBadRequest) | ||||
| 			}, | ||||
| 			input:    &Agent{}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPost { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			input:    &Agent{Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"}, | ||||
| 			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) | ||||
| 			agent, err := client.AgentCreate(tt.input) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, agent, tt.expected) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_AgentList(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		expected []*Agent | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `[ | ||||
| 					{ | ||||
| 						"id": 1, | ||||
| 						"name": "agent-1", | ||||
| 						"backend": "local", | ||||
| 						"capacity": 2, | ||||
| 						"version": "1.0.0" | ||||
| 					}, | ||||
| 					{ | ||||
| 						"id": 2, | ||||
| 						"name": "agent-2", | ||||
| 						"backend": "kubernetes", | ||||
| 						"capacity": 4, | ||||
| 						"version": "1.0.0" | ||||
| 					} | ||||
| 				]`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			expected: []*Agent{ | ||||
| 				{ | ||||
| 					ID:       1, | ||||
| 					Name:     "agent-1", | ||||
| 					Backend:  "local", | ||||
| 					Capacity: 2, | ||||
| 					Version:  "1.0.0", | ||||
| 				}, | ||||
| 				{ | ||||
| 					ID:       2, | ||||
| 					Name:     "agent-2", | ||||
| 					Backend:  "kubernetes", | ||||
| 					Capacity: 4, | ||||
| 					Version:  "1.0.0", | ||||
| 				}, | ||||
| 			}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			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) | ||||
| 			}, | ||||
| 			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) | ||||
| 			agents, err := client.AgentList() | ||||
|  | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, tt.expected, agents) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_Agent(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		agentID  int64 | ||||
| 		expected *Agent | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `{"id":1,"name":"agent-1","backend":"local","capacity":2,"version":"1.0.0"}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			agentID:  1, | ||||
| 			expected: &Agent{ID: 1, Name: "agent-1", Backend: "local", Capacity: 2, Version: "1.0.0"}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			agentID:  999, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			agentID:  1, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid response", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `invalid json`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			agentID:  1, | ||||
| 			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) | ||||
| 			agent, err := client.Agent(tt.agentID) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, tt.expected, agent) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_AgentUpdate(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		input    *Agent | ||||
| 		expected *Agent | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `{"id":1,"name":"updated_agent"}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			input:    &Agent{ID: 1, Name: "existing_agent"}, | ||||
| 			expected: &Agent{ID: 1, Name: "updated_agent"}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			input:    &Agent{ID: 999, Name: "nonexistent_agent"}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid input", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusBadRequest) | ||||
| 			}, | ||||
| 			input:    &Agent{}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			input:    &Agent{ID: 1, Name: "existing_agent"}, | ||||
| 			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) | ||||
| 			agent, err := client.AgentUpdate(tt.input) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, agent, tt.expected) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_AgentDelete(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		handler http.HandlerFunc | ||||
| 		agentID int64 | ||||
| 		wantErr bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 			}, | ||||
| 			agentID: 1, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			agentID: 999, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			agentID: 1, | ||||
| 			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) | ||||
| 			err := client.AgentDelete(tt.agentID) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_AgentTasksList(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		agentID  int64 | ||||
| 		expected []*Task | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `[ | ||||
| 					{ | ||||
| 						"id": "4696", | ||||
| 						"data": "", | ||||
| 						"labels": { | ||||
| 							"platform": "linux/amd64", | ||||
| 							"repo": "woodpecker-ci/woodpecker" | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"id": "4697", | ||||
| 						"data": "", | ||||
| 						"labels": { | ||||
| 							"platform": "linux/arm64", | ||||
| 							"repo": "woodpecker-ci/woodpecker" | ||||
| 						} | ||||
| 					} | ||||
| 				]`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			agentID: 1, | ||||
| 			expected: []*Task{ | ||||
| 				{ | ||||
| 					ID:   "4696", | ||||
| 					Data: []byte{}, | ||||
| 					Labels: map[string]string{ | ||||
| 						"platform": "linux/amd64", | ||||
| 						"repo":     "woodpecker-ci/woodpecker", | ||||
| 					}, | ||||
| 				}, | ||||
| 				{ | ||||
| 					ID:   "4697", | ||||
| 					Data: []byte{}, | ||||
| 					Labels: map[string]string{ | ||||
| 						"platform": "linux/arm64", | ||||
| 						"repo":     "woodpecker-ci/woodpecker", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			agentID:  999, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			agentID:  1, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid response", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodGet { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `invalid json`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			agentID:  1, | ||||
| 			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) | ||||
| 			tasks, err := client.AgentTasksList(tt.agentID) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, tt.expected, tasks) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| @@ -26,41 +26,8 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	pathSelf           = "%s/api/user" | ||||
| 	pathRepos          = "%s/api/user/repos" | ||||
| 	pathRepoPost       = "%s/api/repos?forge_remote_id=%d" | ||||
| 	pathRepo           = "%s/api/repos/%d" | ||||
| 	pathRepoLookup     = "%s/api/repos/lookup/%s" | ||||
| 	pathRepoMove       = "%s/api/repos/%d/move?to=%s" | ||||
| 	pathChown          = "%s/api/repos/%d/chown" | ||||
| 	pathRepair         = "%s/api/repos/%d/repair" | ||||
| 	pathPipelines      = "%s/api/repos/%d/pipelines" | ||||
| 	pathPipeline       = "%s/api/repos/%d/pipelines/%v" | ||||
| 	pathPipelineLogs   = "%s/api/repos/%d/logs/%d" | ||||
| 	pathStepLogs       = "%s/api/repos/%d/logs/%d/%d" | ||||
| 	pathApprove        = "%s/api/repos/%d/pipelines/%d/approve" | ||||
| 	pathDecline        = "%s/api/repos/%d/pipelines/%d/decline" | ||||
| 	pathStop           = "%s/api/repos/%d/pipelines/%d/cancel" | ||||
| 	pathRepoSecrets    = "%s/api/repos/%d/secrets" | ||||
| 	pathRepoSecret     = "%s/api/repos/%d/secrets/%s" | ||||
| 	pathRepoRegistries = "%s/api/repos/%d/registry" | ||||
| 	pathRepoRegistry   = "%s/api/repos/%d/registry/%s" | ||||
| 	pathRepoCrons      = "%s/api/repos/%d/cron" | ||||
| 	pathRepoCron       = "%s/api/repos/%d/cron/%d" | ||||
| 	pathOrg            = "%s/api/orgs/%d" | ||||
| 	pathOrgLookup      = "%s/api/orgs/lookup/%s" | ||||
| 	pathOrgSecrets     = "%s/api/orgs/%d/secrets" | ||||
| 	pathOrgSecret      = "%s/api/orgs/%d/secrets/%s" | ||||
| 	pathGlobalSecrets  = "%s/api/secrets" | ||||
| 	pathGlobalSecret   = "%s/api/secrets/%s" | ||||
| 	pathUsers          = "%s/api/users" | ||||
| 	pathUser           = "%s/api/users/%s" | ||||
| 	pathPipelineQueue  = "%s/api/pipelines" | ||||
| 	pathQueue          = "%s/api/queue" | ||||
| 	pathLogLevel       = "%s/api/log-level" | ||||
| 	pathAgents         = "%s/api/agents" | ||||
| 	pathAgent          = "%s/api/agents/%d" | ||||
| 	pathAgentTasks     = "%s/api/agents/%d/tasks" | ||||
| 	pathLogLevel = "%s/api/log-level" | ||||
|  | ||||
| 	// TODO: implement endpoints | ||||
| 	// pathFeed           = "%s/api/user/feed" | ||||
| 	// pathVersion        = "%s/version" | ||||
| @@ -91,422 +58,6 @@ func (c *client) SetAddress(addr string) { | ||||
| 	c.addr = addr | ||||
| } | ||||
|  | ||||
| // Self returns the currently authenticated user. | ||||
| func (c *client) Self() (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathSelf, c.addr) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // User returns a user by login. | ||||
| func (c *client) User(login string) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, login) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserList returns a list of all registered users. | ||||
| func (c *client) UserList() ([]*User, error) { | ||||
| 	var out []*User | ||||
| 	uri := fmt.Sprintf(pathUsers, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserPost creates a new user account. | ||||
| func (c *client) UserPost(in *User) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUsers, c.addr) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserPatch updates a user account. | ||||
| func (c *client) UserPatch(in *User) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, in.Login) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserDel deletes a user account. | ||||
| func (c *client) UserDel(login string) error { | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, login) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Repo returns a repository by id. | ||||
| func (c *client) Repo(repoID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoLookup returns a repository by name. | ||||
| func (c *client) RepoLookup(fullName string) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepoLookup, c.addr, fullName) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoList returns a list of all repositories to which | ||||
| // the user has explicit access in the host system. | ||||
| func (c *client) RepoList() ([]*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) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoPost activates a repository. | ||||
| func (c *client) RepoPost(forgeRemoteID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepoPost, c.addr, forgeRemoteID) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoChown updates a repository owner. | ||||
| func (c *client) RepoChown(repoID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathChown, c.addr, repoID) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoRepair repairs the repository hooks. | ||||
| func (c *client) RepoRepair(repoID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepair, c.addr, repoID) | ||||
| 	return c.post(uri, nil, nil) | ||||
| } | ||||
|  | ||||
| // RepoPatch updates a repository. | ||||
| func (c *client) RepoPatch(repoID int64, in *RepoPatch) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoDel deletes a repository. | ||||
| func (c *client) RepoDel(repoID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RepoMove moves a repository | ||||
| func (c *client) RepoMove(repoID int64, newFullName string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoMove, c.addr, repoID, newFullName) | ||||
| 	return c.post(uri, nil, nil) | ||||
| } | ||||
|  | ||||
| // Pipeline returns a repository pipeline by pipeline-id. | ||||
| func (c *client) Pipeline(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // Pipeline returns the latest repository pipeline by branch. | ||||
| func (c *client) PipelineLast(repoID int64, branch string) (*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) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineList returns a list of recent pipelines for the | ||||
| // the specified repository. | ||||
| func (c *client) PipelineList(repoID int64) ([]*Pipeline, error) { | ||||
| 	var out []*Pipeline | ||||
| 	uri := fmt.Sprintf(pathPipelines, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (c *client) PipelineCreate(repoID int64, options *PipelineOptions) (*Pipeline, error) { | ||||
| 	var out *Pipeline | ||||
| 	uri := fmt.Sprintf(pathPipelines, c.addr, repoID) | ||||
| 	err := c.post(uri, options, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineQueue returns a list of enqueued pipelines. | ||||
| func (c *client) PipelineQueue() ([]*Feed, error) { | ||||
| 	var out []*Feed | ||||
| 	uri := fmt.Sprintf(pathPipelineQueue, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineStart re-starts a stopped pipeline. | ||||
| func (c *client) PipelineStart(repoID, pipeline int64, params map[string]string) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	val := mapValues(params) | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri+"?"+val.Encode(), nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineStop cancels the running step. | ||||
| func (c *client) PipelineStop(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathStop, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, nil) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // PipelineApprove approves a blocked pipeline. | ||||
| func (c *client) PipelineApprove(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathApprove, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineDecline declines a blocked pipeline. | ||||
| func (c *client) PipelineDecline(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathDecline, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineKill force kills the running pipeline. | ||||
| func (c *client) PipelineKill(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // LogsPurge purges the pipeline all steps logs for the specified pipeline. | ||||
| func (c *client) LogsPurge(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathPipelineLogs, c.addr, repoID, pipeline) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // StepLogEntries returns the pipeline logs for the specified step. | ||||
| func (c *client) StepLogEntries(repoID, num, step int64) ([]*LogEntry, error) { | ||||
| 	uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, num, step) | ||||
| 	var out []*LogEntry | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // StepLogsPurge purges the pipeline logs for the specified step. | ||||
| func (c *client) StepLogsPurge(repoID, pipelineNumber, stepID int64) error { | ||||
| 	uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, pipelineNumber, stepID) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	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) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // Registry returns a registry by hostname. | ||||
| func (c *client) Registry(repoID int64, hostname string) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryList returns a list of all repository registries. | ||||
| func (c *client) RegistryList(repoID int64) ([]*Registry, error) { | ||||
| 	var out []*Registry | ||||
| 	uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryCreate creates a registry. | ||||
| func (c *client) RegistryCreate(repoID int64, in *Registry) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryUpdate updates a registry. | ||||
| func (c *client) RegistryUpdate(repoID int64, in *Registry) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, in.Address) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryDelete deletes a registry. | ||||
| func (c *client) RegistryDelete(repoID int64, hostname string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // Secret returns a secret by name. | ||||
| func (c *client) Secret(repoID int64, secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretList returns a list of all repository secrets. | ||||
| func (c *client) SecretList(repoID int64) ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretCreate creates a secret. | ||||
| func (c *client) SecretCreate(repoID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretUpdate updates a secret. | ||||
| func (c *client) SecretUpdate(repoID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretDelete deletes a secret. | ||||
| func (c *client) SecretDelete(repoID int64, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // Org returns an organization by id. | ||||
| func (c *client) Org(orgID int64) (*Org, error) { | ||||
| 	out := new(Org) | ||||
| 	uri := fmt.Sprintf(pathOrg, c.addr, orgID) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgLookup returns a organization by its name. | ||||
| func (c *client) OrgLookup(name string) (*Org, error) { | ||||
| 	out := new(Org) | ||||
| 	uri := fmt.Sprintf(pathOrgLookup, c.addr, name) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecret returns an organization secret by name. | ||||
| func (c *client) OrgSecret(orgID int64, secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretList returns a list of all organization secrets. | ||||
| func (c *client) OrgSecretList(orgID int64) ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretCreate creates an organization secret. | ||||
| func (c *client) OrgSecretCreate(orgID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretUpdate updates an organization secret. | ||||
| func (c *client) OrgSecretUpdate(orgID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretDelete deletes an organization secret. | ||||
| func (c *client) OrgSecretDelete(orgID int64, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // GlobalOrgSecret returns an global secret by name. | ||||
| func (c *client) GlobalSecret(secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretList returns a list of all global secrets. | ||||
| func (c *client) GlobalSecretList() ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretCreate creates a global secret. | ||||
| func (c *client) GlobalSecretCreate(in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.addr) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretUpdate updates a global secret. | ||||
| func (c *client) GlobalSecretUpdate(in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretDelete deletes a global secret. | ||||
| func (c *client) GlobalSecretDelete(secret string) error { | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // QueueInfo returns queue info | ||||
| func (c *client) QueueInfo() (*Info, error) { | ||||
| 	out := new(Info) | ||||
| 	uri := fmt.Sprintf(pathQueue+"/info", c.addr) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // LogLevel returns the current logging level | ||||
| func (c *client) LogLevel() (*LogLevel, error) { | ||||
| 	out := new(LogLevel) | ||||
| @@ -523,96 +74,31 @@ func (c *client) SetLogLevel(in *LogLevel) (*LogLevel, error) { | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (c *client) CronList(repoID int64) ([]*Cron, error) { | ||||
| 	out := make([]*Cron, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
|  | ||||
| func (c *client) CronCreate(repoID int64, in *Cron) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID) | ||||
| 	return out, c.post(uri, in, out) | ||||
| } | ||||
|  | ||||
| func (c *client) CronUpdate(repoID int64, in *Cron) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, in.ID) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| func (c *client) CronDelete(repoID, cronID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| func (c *client) CronGet(repoID, cronID int64) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID) | ||||
| 	return out, c.get(uri, out) | ||||
| } | ||||
|  | ||||
| func (c *client) AgentList() ([]*Agent, error) { | ||||
| 	out := make([]*Agent, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathAgents, c.addr) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
|  | ||||
| func (c *client) Agent(agentID int64) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, agentID) | ||||
| 	return out, c.get(uri, out) | ||||
| } | ||||
|  | ||||
| func (c *client) AgentCreate(in *Agent) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgents, c.addr) | ||||
| 	return out, c.post(uri, in, out) | ||||
| } | ||||
|  | ||||
| func (c *client) AgentUpdate(in *Agent) (*Agent, error) { | ||||
| 	out := new(Agent) | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, in.ID) | ||||
| 	return out, c.patch(uri, in, out) | ||||
| } | ||||
|  | ||||
| func (c *client) AgentDelete(agentID int64) error { | ||||
| 	uri := fmt.Sprintf(pathAgent, c.addr, agentID) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| func (c *client) AgentTasksList(agentID int64) ([]*Task, error) { | ||||
| 	out := make([]*Task, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathAgentTasks, c.addr, agentID) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
|  | ||||
| // | ||||
| // http request helper functions | ||||
| // | ||||
|  | ||||
| // helper function for making an http GET request. | ||||
| // Helper function for making an http GET request. | ||||
| func (c *client) get(rawurl string, out any) error { | ||||
| 	return c.do(rawurl, http.MethodGet, nil, out) | ||||
| } | ||||
|  | ||||
| // helper function for making an http POST request. | ||||
| // Helper function for making an http POST request. | ||||
| func (c *client) post(rawurl string, in, out any) error { | ||||
| 	return c.do(rawurl, http.MethodPost, in, out) | ||||
| } | ||||
|  | ||||
| // helper function for making an http PATCH request. | ||||
| // Helper function for making an http PATCH request. | ||||
| func (c *client) patch(rawurl string, in, out any) error { | ||||
| 	return c.do(rawurl, http.MethodPatch, in, out) | ||||
| } | ||||
|  | ||||
| // helper function for making an http DELETE request. | ||||
| // Helper function for making an http DELETE request. | ||||
| func (c *client) delete(rawurl string) error { | ||||
| 	return c.do(rawurl, http.MethodDelete, nil, nil) | ||||
| } | ||||
|  | ||||
| // helper function to make an http request | ||||
| // Helper function to make an http request. | ||||
| func (c *client) do(rawurl, method string, in, out any) error { | ||||
| 	body, err := c.open(rawurl, method, in) | ||||
| 	if err != nil { | ||||
| @@ -625,7 +111,7 @@ func (c *client) do(rawurl, method string, in, out any) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // helper function to open an http request | ||||
| // Helper function to open an http request. | ||||
| func (c *client) open(rawurl, method string, in any) (io.ReadCloser, error) { | ||||
| 	uri, err := url.Parse(rawurl) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -25,44 +25,6 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func Test_QueueInfo(t *testing.T) { | ||||
| 	fixtureHandler := func(w http.ResponseWriter, _ *http.Request) { | ||||
| 		fmt.Fprint(w, `{ | ||||
| 			"pending": null, | ||||
| 			"running": [ | ||||
| 					{ | ||||
| 							"id": "4696", | ||||
| 							"data": "", | ||||
| 							"labels": { | ||||
| 									"platform": "linux/amd64", | ||||
| 									"repo": "woodpecker-ci/woodpecker" | ||||
| 							}, | ||||
| 							"Dependencies": [], | ||||
| 							"DepStatus": {}, | ||||
| 							"RunOn": null | ||||
| 					} | ||||
| 			], | ||||
| 			"stats": { | ||||
| 					"worker_count": 3, | ||||
| 					"pending_count": 0, | ||||
| 					"waiting_on_deps_count": 0, | ||||
| 					"running_count": 1, | ||||
| 					"completed_count": 0 | ||||
| 			}, | ||||
| 			"Paused": false | ||||
| 	}`) | ||||
| 	} | ||||
|  | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(fixtureHandler)) | ||||
| 	defer ts.Close() | ||||
|  | ||||
| 	client := NewClient(ts.URL, http.DefaultClient) | ||||
|  | ||||
| 	info, err := client.QueueInfo() | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, 3, info.Stats.Workers) | ||||
| } | ||||
|  | ||||
| func Test_LogLevel(t *testing.T) { | ||||
| 	logLevel := "warn" | ||||
| 	fixtureHandler := func(w http.ResponseWriter, r *http.Request) { | ||||
|   | ||||
| @@ -49,7 +49,7 @@ const ( | ||||
| 	LogEntryProgress | ||||
| ) | ||||
|  | ||||
| // StepType identifies the type of step | ||||
| // StepType identifies the type of step. | ||||
| type StepType string | ||||
|  | ||||
| const ( | ||||
|   | ||||
							
								
								
									
										46
									
								
								woodpecker-go/woodpecker/global_secret.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								woodpecker-go/woodpecker/global_secret.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const ( | ||||
| 	pathGlobalSecrets = "%s/api/secrets" | ||||
| 	pathGlobalSecret  = "%s/api/secrets/%s" | ||||
| ) | ||||
|  | ||||
| // GlobalOrgSecret returns an global secret by name. | ||||
| func (c *client) GlobalSecret(secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretList returns a list of all global secrets. | ||||
| func (c *client) GlobalSecretList() ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretCreate creates a global secret. | ||||
| func (c *client) GlobalSecretCreate(in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecrets, c.addr) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretUpdate updates a global secret. | ||||
| func (c *client) GlobalSecretUpdate(in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // GlobalSecretDelete deletes a global secret. | ||||
| func (c *client) GlobalSecretDelete(secret string) error { | ||||
| 	uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
| @@ -190,42 +190,42 @@ type Client interface { | ||||
| 	// QueueInfo returns the queue state. | ||||
| 	QueueInfo() (*Info, error) | ||||
|  | ||||
| 	// LogLevel returns the current logging level | ||||
| 	// LogLevel returns the current logging level. | ||||
| 	LogLevel() (*LogLevel, error) | ||||
|  | ||||
| 	// SetLogLevel sets the server's logging level | ||||
| 	// SetLogLevel sets the server's logging level. | ||||
| 	SetLogLevel(logLevel *LogLevel) (*LogLevel, error) | ||||
|  | ||||
| 	// CronList list all cron jobs of a repo | ||||
| 	// CronList list all cron jobs of a repo. | ||||
| 	CronList(repoID int64) ([]*Cron, error) | ||||
|  | ||||
| 	// CronGet get a specific cron job of a repo by id | ||||
| 	// CronGet get a specific cron job of a repo by id. | ||||
| 	CronGet(repoID, cronID int64) (*Cron, error) | ||||
|  | ||||
| 	// CronDelete delete a specific cron job of a repo by id | ||||
| 	// CronDelete delete a specific cron job of a repo by id. | ||||
| 	CronDelete(repoID, cronID int64) error | ||||
|  | ||||
| 	// CronCreate create a new cron job in a repo | ||||
| 	// CronCreate create a new cron job in a repo. | ||||
| 	CronCreate(repoID int64, cron *Cron) (*Cron, error) | ||||
|  | ||||
| 	// CronUpdate update an existing cron job of a repo | ||||
| 	// CronUpdate update an existing cron job of a repo. | ||||
| 	CronUpdate(repoID int64, cron *Cron) (*Cron, error) | ||||
|  | ||||
| 	// AgentList returns a list of all registered agents | ||||
| 	// AgentList returns a list of all registered agents. | ||||
| 	AgentList() ([]*Agent, error) | ||||
|  | ||||
| 	// Agent returns an agent by id | ||||
| 	// Agent returns an agent by id. | ||||
| 	Agent(int64) (*Agent, error) | ||||
|  | ||||
| 	// AgentCreate creates a new agent | ||||
| 	// AgentCreate creates a new agent. | ||||
| 	AgentCreate(*Agent) (*Agent, error) | ||||
|  | ||||
| 	// AgentUpdate updates an existing agent | ||||
| 	// AgentUpdate updates an existing agent. | ||||
| 	AgentUpdate(*Agent) (*Agent, error) | ||||
|  | ||||
| 	// AgentDelete deletes an agent | ||||
| 	// AgentDelete deletes an agent. | ||||
| 	AgentDelete(int64) error | ||||
|  | ||||
| 	// AgentTasksList returns a list of all tasks executed by an agent | ||||
| 	// AgentTasksList returns a list of all tasks executed by an agent. | ||||
| 	AgentTasksList(int64) ([]*Task, error) | ||||
| } | ||||
|   | ||||
							
								
								
									
										64
									
								
								woodpecker-go/woodpecker/org.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								woodpecker-go/woodpecker/org.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const ( | ||||
| 	pathOrg        = "%s/api/orgs/%d" | ||||
| 	pathOrgLookup  = "%s/api/orgs/lookup/%s" | ||||
| 	pathOrgSecrets = "%s/api/orgs/%d/secrets" | ||||
| 	pathOrgSecret  = "%s/api/orgs/%d/secrets/%s" | ||||
| ) | ||||
|  | ||||
| // Org returns an organization by id. | ||||
| func (c *client) Org(orgID int64) (*Org, error) { | ||||
| 	out := new(Org) | ||||
| 	uri := fmt.Sprintf(pathOrg, c.addr, orgID) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgLookup returns a organization by its name. | ||||
| func (c *client) OrgLookup(name string) (*Org, error) { | ||||
| 	out := new(Org) | ||||
| 	uri := fmt.Sprintf(pathOrgLookup, c.addr, name) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecret returns an organization secret by name. | ||||
| func (c *client) OrgSecret(orgID int64, secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretList returns a list of all organization secrets. | ||||
| func (c *client) OrgSecretList(orgID int64) ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretCreate creates an organization secret. | ||||
| func (c *client) OrgSecretCreate(orgID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretUpdate updates an organization secret. | ||||
| func (c *client) OrgSecretUpdate(orgID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // OrgSecretDelete deletes an organization secret. | ||||
| func (c *client) OrgSecretDelete(orgID int64, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
							
								
								
									
										13
									
								
								woodpecker-go/woodpecker/pipeline.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								woodpecker-go/woodpecker/pipeline.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const pathPipelineQueue = "%s/api/pipelines" | ||||
|  | ||||
| // PipelineQueue returns a list of enqueued pipelines. | ||||
| func (c *client) PipelineQueue() ([]*Feed, error) { | ||||
| 	var out []*Feed | ||||
| 	uri := fmt.Sprintf(pathPipelineQueue, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
							
								
								
									
										13
									
								
								woodpecker-go/woodpecker/queue.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								woodpecker-go/woodpecker/queue.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const pathQueue = "%s/api/queue" | ||||
|  | ||||
| // QueueInfo returns queue info. | ||||
| func (c *client) QueueInfo() (*Info, error) { | ||||
| 	out := new(Info) | ||||
| 	uri := fmt.Sprintf(pathQueue+"/info", c.addr) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
							
								
								
									
										116
									
								
								woodpecker-go/woodpecker/queue_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								woodpecker-go/woodpecker/queue_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestClient_QueueInfo(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		expected *Info | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `{ | ||||
| 					"pending": null, | ||||
| 					"running": [ | ||||
| 							{ | ||||
| 									"id": "4696", | ||||
| 									"data": "", | ||||
| 									"labels": { | ||||
| 											"platform": "linux/amd64", | ||||
| 											"repo": "woodpecker-ci/woodpecker" | ||||
| 									}, | ||||
| 									"Dependencies": [], | ||||
| 									"DepStatus": {}, | ||||
| 									"RunOn": null | ||||
| 							} | ||||
| 					], | ||||
| 					"stats": { | ||||
| 						"worker_count": 2, | ||||
| 						"pending_count": 0, | ||||
| 						"waiting_on_deps_count": 0, | ||||
| 						"running_count": 0, | ||||
| 						"completed_count": 0 | ||||
| 					}, | ||||
| 					"Paused": false | ||||
| 				}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			expected: &Info{ | ||||
| 				Running: []Task{ | ||||
| 					{ | ||||
| 						ID:   "4696", | ||||
| 						Data: []byte{}, | ||||
| 						Labels: map[string]string{ | ||||
| 							"platform": "linux/amd64", | ||||
| 							"repo":     "woodpecker-ci/woodpecker", | ||||
| 						}, | ||||
| 						Dependencies: []string{}, | ||||
| 						DepStatus:    nil, | ||||
| 						RunOn:        nil, | ||||
| 					}, | ||||
| 				}, | ||||
| 				Stats: struct { | ||||
| 					Workers       int `json:"worker_count"` | ||||
| 					Pending       int `json:"pending_count"` | ||||
| 					WaitingOnDeps int `json:"waiting_on_deps_count"` | ||||
| 					Running       int `json:"running_count"` | ||||
| 					Complete      int `json:"completed_count"` | ||||
| 				}{ | ||||
| 					Workers:       2, | ||||
| 					Pending:       0, | ||||
| 					WaitingOnDeps: 0, | ||||
| 					Running:       0, | ||||
| 					Complete:      0, | ||||
| 				}, | ||||
| 			}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			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) | ||||
| 			}, | ||||
| 			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) | ||||
| 			info, err := client.QueueInfo() | ||||
|  | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, tt.expected, info) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										304
									
								
								woodpecker-go/woodpecker/repo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								woodpecker-go/woodpecker/repo.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const ( | ||||
| 	pathRepoPost       = "%s/api/repos?forge_remote_id=%d" | ||||
| 	pathRepo           = "%s/api/repos/%d" | ||||
| 	pathRepoLookup     = "%s/api/repos/lookup/%s" | ||||
| 	pathRepoMove       = "%s/api/repos/%d/move?to=%s" | ||||
| 	pathChown          = "%s/api/repos/%d/chown" | ||||
| 	pathRepair         = "%s/api/repos/%d/repair" | ||||
| 	pathPipelines      = "%s/api/repos/%d/pipelines" | ||||
| 	pathPipeline       = "%s/api/repos/%d/pipelines/%v" | ||||
| 	pathPipelineLogs   = "%s/api/repos/%d/logs/%d" | ||||
| 	pathStepLogs       = "%s/api/repos/%d/logs/%d/%d" | ||||
| 	pathApprove        = "%s/api/repos/%d/pipelines/%d/approve" | ||||
| 	pathDecline        = "%s/api/repos/%d/pipelines/%d/decline" | ||||
| 	pathStop           = "%s/api/repos/%d/pipelines/%d/cancel" | ||||
| 	pathRepoSecrets    = "%s/api/repos/%d/secrets" | ||||
| 	pathRepoSecret     = "%s/api/repos/%d/secrets/%s" | ||||
| 	pathRepoRegistries = "%s/api/repos/%d/registry" | ||||
| 	pathRepoRegistry   = "%s/api/repos/%d/registry/%s" | ||||
| 	pathRepoCrons      = "%s/api/repos/%d/cron" | ||||
| 	pathRepoCron       = "%s/api/repos/%d/cron/%d" | ||||
| ) | ||||
|  | ||||
| // Repo returns a repository by id. | ||||
| func (c *client) Repo(repoID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoLookup returns a repository by name. | ||||
| func (c *client) RepoLookup(fullName string) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepoLookup, c.addr, fullName) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoPost activates a repository. | ||||
| func (c *client) RepoPost(forgeRemoteID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepoPost, c.addr, forgeRemoteID) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoChown updates a repository owner. | ||||
| func (c *client) RepoChown(repoID int64) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathChown, c.addr, repoID) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoRepair repairs the repository hooks. | ||||
| func (c *client) RepoRepair(repoID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepair, c.addr, repoID) | ||||
| 	return c.post(uri, nil, nil) | ||||
| } | ||||
|  | ||||
| // RepoPatch updates a repository. | ||||
| func (c *client) RepoPatch(repoID int64, in *RepoPatch) (*Repo, error) { | ||||
| 	out := new(Repo) | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RepoDel deletes a repository. | ||||
| func (c *client) RepoDel(repoID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepo, c.addr, repoID) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RepoMove moves a repository. | ||||
| func (c *client) RepoMove(repoID int64, newFullName string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoMove, c.addr, repoID, newFullName) | ||||
| 	return c.post(uri, nil, nil) | ||||
| } | ||||
|  | ||||
| // Registry returns a registry by hostname. | ||||
| func (c *client) Registry(repoID int64, hostname string) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryList returns a list of all repository registries. | ||||
| func (c *client) RegistryList(repoID int64) ([]*Registry, error) { | ||||
| 	var out []*Registry | ||||
| 	uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryCreate creates a registry. | ||||
| func (c *client) RegistryCreate(repoID int64, in *Registry) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryUpdate updates a registry. | ||||
| func (c *client) RegistryUpdate(repoID int64, in *Registry) (*Registry, error) { | ||||
| 	out := new(Registry) | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, in.Address) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // RegistryDelete deletes a registry. | ||||
| func (c *client) RegistryDelete(repoID int64, hostname string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // Secret returns a secret by name. | ||||
| func (c *client) Secret(repoID int64, secret string) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretList returns a list of all repository secrets. | ||||
| func (c *client) SecretList(repoID int64) ([]*Secret, error) { | ||||
| 	var out []*Secret | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretCreate creates a secret. | ||||
| func (c *client) SecretCreate(repoID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretUpdate updates a secret. | ||||
| func (c *client) SecretUpdate(repoID int64, in *Secret) (*Secret, error) { | ||||
| 	out := new(Secret) | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, in.Name) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // SecretDelete deletes a secret. | ||||
| func (c *client) SecretDelete(repoID int64, secret string) error { | ||||
| 	uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // CronList returns a list of cronjobs for the specified repository. | ||||
| func (c *client) CronList(repoID int64) ([]*Cron, error) { | ||||
| 	out := make([]*Cron, 0, 5) | ||||
| 	uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID) | ||||
| 	return out, c.get(uri, &out) | ||||
| } | ||||
|  | ||||
| // CronCreate creates a new cron job for the specified repository. | ||||
| func (c *client) CronCreate(repoID int64, in *Cron) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID) | ||||
| 	return out, c.post(uri, in, out) | ||||
| } | ||||
|  | ||||
| // CronUpdate updates an existing cron job for the specified repository. | ||||
| func (c *client) CronUpdate(repoID int64, in *Cron) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, in.ID) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // CronDelete deletes a cron job by cron-id for the specified repository. | ||||
| func (c *client) CronDelete(repoID, cronID int64) error { | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID) | ||||
| 	return c.delete(uri) | ||||
| } | ||||
|  | ||||
| // CronGet returns a cron job by cron-id for the specified repository. | ||||
| func (c *client) CronGet(repoID, cronID int64) (*Cron, error) { | ||||
| 	out := new(Cron) | ||||
| 	uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID) | ||||
| 	return out, c.get(uri, out) | ||||
| } | ||||
|  | ||||
| // Pipeline returns a repository pipeline by pipeline-id. | ||||
| func (c *client) Pipeline(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // Pipeline returns the latest repository pipeline by branch. | ||||
| func (c *client) PipelineLast(repoID int64, branch string) (*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) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineList returns a list of recent pipelines for the | ||||
| // the specified repository. | ||||
| func (c *client) PipelineList(repoID int64) ([]*Pipeline, error) { | ||||
| 	var out []*Pipeline | ||||
| 	uri := fmt.Sprintf(pathPipelines, c.addr, repoID) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineCreate creates a new pipeline for the specified repository. | ||||
| func (c *client) PipelineCreate(repoID int64, options *PipelineOptions) (*Pipeline, error) { | ||||
| 	var out *Pipeline | ||||
| 	uri := fmt.Sprintf(pathPipelines, c.addr, repoID) | ||||
| 	err := c.post(uri, options, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineStart re-starts a stopped pipeline. | ||||
| func (c *client) PipelineStart(repoID, pipeline int64, params map[string]string) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	val := mapValues(params) | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri+"?"+val.Encode(), nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineStop cancels the running step. | ||||
| func (c *client) PipelineStop(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathStop, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, nil) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // PipelineApprove approves a blocked pipeline. | ||||
| func (c *client) PipelineApprove(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathApprove, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineDecline declines a blocked pipeline. | ||||
| func (c *client) PipelineDecline(repoID, pipeline int64) (*Pipeline, error) { | ||||
| 	out := new(Pipeline) | ||||
| 	uri := fmt.Sprintf(pathDecline, c.addr, repoID, pipeline) | ||||
| 	err := c.post(uri, nil, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // PipelineKill force kills the running pipeline. | ||||
| func (c *client) PipelineKill(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // LogsPurge purges the pipeline all steps logs for the specified pipeline. | ||||
| func (c *client) LogsPurge(repoID, pipeline int64) error { | ||||
| 	uri := fmt.Sprintf(pathPipelineLogs, c.addr, repoID, pipeline) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	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) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // StepLogEntries returns the pipeline logs for the specified step. | ||||
| func (c *client) StepLogEntries(repoID, num, step int64) ([]*LogEntry, error) { | ||||
| 	uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, num, step) | ||||
| 	var out []*LogEntry | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // StepLogsPurge purges the pipeline logs for the specified step. | ||||
| func (c *client) StepLogsPurge(repoID, pipelineNumber, stepID int64) error { | ||||
| 	uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, pipelineNumber, stepID) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
| @@ -181,12 +181,22 @@ type ( | ||||
| 		Commit  string `json:"commit,omitempty"` | ||||
| 	} | ||||
|  | ||||
| 	// QueueStats struct { | ||||
| 	// 	Workers       int `json:"worker_count"` | ||||
| 	// 	Pending       int `json:"pending_count"` | ||||
| 	// 	WaitingOnDeps int `json:"waiting_on_deps_count"` | ||||
| 	// 	Running       int `json:"running_count"` | ||||
| 	// 	Complete      int `json:"completed_count"` | ||||
| 	// } | ||||
|  | ||||
| 	// Info provides queue stats. | ||||
| 	Info struct { | ||||
| 		Pending       []Task `json:"pending"` | ||||
| 		WaitingOnDeps []Task `json:"waiting_on_deps"` | ||||
| 		Running       []Task `json:"running"` | ||||
| 		Stats         struct { | ||||
| 		// TODO use dedicated struct in 3.x | ||||
| 		// Stats         QueueStats `json:"stats"` | ||||
| 		Stats struct { | ||||
| 			Workers       int `json:"worker_count"` | ||||
| 			Pending       int `json:"pending_count"` | ||||
| 			WaitingOnDeps int `json:"waiting_on_deps_count"` | ||||
| @@ -196,7 +206,7 @@ type ( | ||||
| 		Paused bool `json:"paused,omitempty"` | ||||
| 	} | ||||
|  | ||||
| 	// LogLevel is for checking/setting logging level | ||||
| 	// LogLevel is for checking/setting logging level. | ||||
| 	LogLevel struct { | ||||
| 		Level string `json:"log-level"` | ||||
| 	} | ||||
| @@ -211,7 +221,7 @@ type ( | ||||
| 		Type   LogEntryType `json:"type"` | ||||
| 	} | ||||
|  | ||||
| 	// Cron is the JSON data of a cron job | ||||
| 	// Cron is the JSON data of a cron job. | ||||
| 	Cron struct { | ||||
| 		ID        int64  `json:"id"` | ||||
| 		Name      string `json:"name"` | ||||
| @@ -223,13 +233,13 @@ type ( | ||||
| 		Branch    string `json:"branch"` | ||||
| 	} | ||||
|  | ||||
| 	// PipelineOptions is the JSON data for creating a new pipeline | ||||
| 	// PipelineOptions is the JSON data for creating a new pipeline. | ||||
| 	PipelineOptions struct { | ||||
| 		Branch    string            `json:"branch"` | ||||
| 		Variables map[string]string `json:"variables"` | ||||
| 	} | ||||
|  | ||||
| 	// Agent is the JSON data for an agent | ||||
| 	// Agent is the JSON data for an agent. | ||||
| 	Agent struct { | ||||
| 		ID          int64  `json:"id"` | ||||
| 		Created     int64  `json:"created"` | ||||
| @@ -245,7 +255,7 @@ type ( | ||||
| 		NoSchedule  bool   `json:"no_schedule"` | ||||
| 	} | ||||
|  | ||||
| 	// Task is the JSON data for a task | ||||
| 	// Task is the JSON data for a task. | ||||
| 	Task struct { | ||||
| 		ID           string            `json:"id"` | ||||
| 		Data         []byte            `json:"data"` | ||||
| @@ -256,7 +266,7 @@ type ( | ||||
| 		AgentID      int64             `json:"agent_id"` | ||||
| 	} | ||||
|  | ||||
| 	// Org is the JSON data for an organization | ||||
| 	// Org is the JSON data for an organization. | ||||
| 	Org struct { | ||||
| 		ID     int64  `json:"id"` | ||||
| 		Name   string `json:"name"` | ||||
|   | ||||
							
								
								
									
										75
									
								
								woodpecker-go/woodpecker/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								woodpecker-go/woodpecker/user.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| const ( | ||||
| 	pathSelf  = "%s/api/user" | ||||
| 	pathRepos = "%s/api/user/repos" | ||||
| 	pathUsers = "%s/api/users" | ||||
| 	pathUser  = "%s/api/users/%s" | ||||
| ) | ||||
|  | ||||
| // Self returns the currently authenticated user. | ||||
| func (c *client) Self() (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathSelf, c.addr) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // User returns a user by login. | ||||
| func (c *client) User(login string) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, login) | ||||
| 	err := c.get(uri, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserList returns a list of all registered users. | ||||
| func (c *client) UserList() ([]*User, error) { | ||||
| 	var out []*User | ||||
| 	uri := fmt.Sprintf(pathUsers, c.addr) | ||||
| 	err := c.get(uri, &out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserPost creates a new user account. | ||||
| func (c *client) UserPost(in *User) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUsers, c.addr) | ||||
| 	err := c.post(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserPatch updates a user account. | ||||
| func (c *client) UserPatch(in *User) (*User, error) { | ||||
| 	out := new(User) | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, in.Login) | ||||
| 	err := c.patch(uri, in, out) | ||||
| 	return out, err | ||||
| } | ||||
|  | ||||
| // UserDel deletes a user account. | ||||
| func (c *client) UserDel(login string) error { | ||||
| 	uri := fmt.Sprintf(pathUser, c.addr, login) | ||||
| 	err := c.delete(uri) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // RepoList returns a list of all repositories to which | ||||
| // the user has explicit access in the host system. | ||||
| func (c *client) RepoList() ([]*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) | ||||
| 	return out, err | ||||
| } | ||||
							
								
								
									
										267
									
								
								woodpecker-go/woodpecker/user_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								woodpecker-go/woodpecker/user_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| package woodpecker | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestClient_UserList(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		expected []*User | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `[{"id":1,"login":"user1"},{"id":2,"login":"user2"}]`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			expected: []*User{{ID: 1, Login: "user1"}, {ID: 2, Login: "user2"}}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "empty response", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `[]`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			expected: []*User{}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			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) | ||||
| 			users, err := client.UserList() | ||||
|  | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, users, tt.expected) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_UserPost(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		input    *User | ||||
| 		expected *User | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusCreated) | ||||
| 				_, err := fmt.Fprint(w, `{"id":1,"login":"new_user"}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			input:    &User{Login: "new_user"}, | ||||
| 			expected: &User{ID: 1, Login: "new_user"}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid input", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusBadRequest) | ||||
| 			}, | ||||
| 			input:    &User{}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, _ *http.Request) { | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			input:    &User{Login: "new_user"}, | ||||
| 			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) | ||||
| 			user, err := client.UserPost(tt.input) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, user, tt.expected) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_UserPatch(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		handler  http.HandlerFunc | ||||
| 		input    *User | ||||
| 		expected *User | ||||
| 		wantErr  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 				_, err := fmt.Fprint(w, `{"id":1,"login":"updated_user"}`) | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| 			input:    &User{ID: 1, Login: "existing_user"}, | ||||
| 			expected: &User{ID: 1, Login: "updated_user"}, | ||||
| 			wantErr:  false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			input:    &User{ID: 999, Login: "nonexistent_user"}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "invalid input", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusBadRequest) | ||||
| 			}, | ||||
| 			input:    &User{}, | ||||
| 			expected: nil, | ||||
| 			wantErr:  true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodPatch { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			input:    &User{ID: 1, Login: "existing_user"}, | ||||
| 			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) | ||||
| 			user, err := client.UserPatch(tt.input) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, user, tt.expected) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestClient_UserDel(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		handler http.HandlerFunc | ||||
| 		login   string | ||||
| 		wantErr bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "success", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusOK) | ||||
| 			}, | ||||
| 			login:   "existing_user", | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "not found", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusNotFound) | ||||
| 			}, | ||||
| 			login:   "nonexistent_user", | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "server error", | ||||
| 			handler: func(w http.ResponseWriter, r *http.Request) { | ||||
| 				if r.Method != http.MethodDelete { | ||||
| 					w.WriteHeader(http.StatusMethodNotAllowed) | ||||
| 					return | ||||
| 				} | ||||
| 				w.WriteHeader(http.StatusInternalServerError) | ||||
| 			}, | ||||
| 			login:   "existing_user", | ||||
| 			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) | ||||
| 			err := client.UserDel(tt.login) | ||||
| 			if tt.wantErr { | ||||
| 				assert.Error(t, err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			assert.NoError(t, err) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user