Merge pull request #37 from gabriel-samfira/add-ghe-server-support
Add GitHub Enterprise support
This commit is contained in:
commit
eba42b0481
196 changed files with 6808 additions and 1818 deletions
282
apiserver/controllers/enterprises.go
Normal file
282
apiserver/controllers/enterprises.go
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"garm/apiserver/params"
|
||||
gErrors "garm/errors"
|
||||
runnerParams "garm/params"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (a *APIController) CreateEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var enterpriseData runnerParams.CreateEnterpriseParams
|
||||
if err := json.NewDecoder(r.Body).Decode(&enterpriseData); err != nil {
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
enterprise, err := a.r.CreateEnterprise(ctx, enterpriseData)
|
||||
if err != nil {
|
||||
log.Printf("error creating enterprise: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(enterprise)
|
||||
}
|
||||
|
||||
func (a *APIController) ListEnterprisesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
enterprise, err := a.r.ListEnterprises(ctx)
|
||||
if err != nil {
|
||||
log.Printf("listing enterprise: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(enterprise)
|
||||
}
|
||||
|
||||
func (a *APIController) GetEnterpriseByIDHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
enterprise, err := a.r.GetEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
log.Printf("fetching enterprise: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(enterprise)
|
||||
}
|
||||
|
||||
func (a *APIController) DeleteEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.r.DeleteEnterprise(ctx, enterpriseID); err != nil {
|
||||
log.Printf("removing enterprise: %+v", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
}
|
||||
|
||||
func (a *APIController) UpdateEnterpriseHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var updatePayload runnerParams.UpdateRepositoryParams
|
||||
if err := json.NewDecoder(r.Body).Decode(&updatePayload); err != nil {
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
enterprise, err := a.r.UpdateEnterprise(ctx, enterpriseID, updatePayload)
|
||||
if err != nil {
|
||||
log.Printf("error updating enterprise: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(enterprise)
|
||||
}
|
||||
|
||||
func (a *APIController) CreateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var poolData runnerParams.CreatePoolParams
|
||||
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
|
||||
log.Printf("failed to decode: %s", err)
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.r.CreateEnterprisePool(ctx, enterpriseID, poolData)
|
||||
if err != nil {
|
||||
log.Printf("error creating enterprise pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) ListEnterprisePoolsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
pools, err := a.r.ListEnterprisePools(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pools)
|
||||
}
|
||||
|
||||
func (a *APIController) GetEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, enterpriseOk := vars["enterpriseID"]
|
||||
poolID, poolOk := vars["poolID"]
|
||||
if !enterpriseOk || !poolOk {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise or pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.r.GetEnterprisePoolByID(ctx, enterpriseID, poolID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
||||
func (a *APIController) DeleteEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, enterpriseOk := vars["enterpriseID"]
|
||||
poolID, poolOk := vars["poolID"]
|
||||
if !enterpriseOk || !poolOk {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise or pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.r.DeleteEnterprisePool(ctx, enterpriseID, poolID); err != nil {
|
||||
log.Printf("removing pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
}
|
||||
|
||||
func (a *APIController) UpdateEnterprisePoolHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, enterpriseOk := vars["enterpriseID"]
|
||||
poolID, poolOk := vars["poolID"]
|
||||
if !enterpriseOk || !poolOk {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise or pool ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var poolData runnerParams.UpdatePoolParams
|
||||
if err := json.NewDecoder(r.Body).Decode(&poolData); err != nil {
|
||||
log.Printf("failed to decode: %s", err)
|
||||
handleError(w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.r.UpdateEnterprisePool(ctx, enterpriseID, poolID, poolData)
|
||||
if err != nil {
|
||||
log.Printf("error creating enterprise pool: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(pool)
|
||||
}
|
||||
|
|
@ -136,7 +136,31 @@ func (a *APIController) ListOrgInstancesHandler(w http.ResponseWriter, r *http.R
|
|||
|
||||
instances, err := a.r.ListOrgInstances(ctx, orgID)
|
||||
if err != nil {
|
||||
log.Printf("listing pools: %s", err)
|
||||
log.Printf("listing instances: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(instances)
|
||||
}
|
||||
|
||||
func (a *APIController) ListEnterpriseInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vars := mux.Vars(r)
|
||||
enterpriseID, ok := vars["enterpriseID"]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(params.APIErrorResponse{
|
||||
Error: "Bad Request",
|
||||
Details: "No enterprise ID specified",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
instances, err := a.r.ListEnterpriseInstances(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
log.Printf("listing instances: %s", err)
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,45 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
apiRouter.Handle("/organizations/", log(logWriter, http.HandlerFunc(han.CreateOrgHandler))).Methods("POST", "OPTIONS")
|
||||
apiRouter.Handle("/organizations", log(logWriter, http.HandlerFunc(han.CreateOrgHandler))).Methods("POST", "OPTIONS")
|
||||
|
||||
/////////////////////////////
|
||||
// Enterprises and pools //
|
||||
/////////////////////////////
|
||||
// Get pool
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}/", log(logWriter, http.HandlerFunc(han.GetEnterprisePoolHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}", log(logWriter, http.HandlerFunc(han.GetEnterprisePoolHandler))).Methods("GET", "OPTIONS")
|
||||
// Delete pool
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}/", log(logWriter, http.HandlerFunc(han.DeleteEnterprisePoolHandler))).Methods("DELETE", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}", log(logWriter, http.HandlerFunc(han.DeleteEnterprisePoolHandler))).Methods("DELETE", "OPTIONS")
|
||||
// Update pool
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}/", log(logWriter, http.HandlerFunc(han.UpdateEnterprisePoolHandler))).Methods("PUT", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/{poolID}", log(logWriter, http.HandlerFunc(han.UpdateEnterprisePoolHandler))).Methods("PUT", "OPTIONS")
|
||||
// List pools
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/", log(logWriter, http.HandlerFunc(han.ListEnterprisePoolsHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools", log(logWriter, http.HandlerFunc(han.ListEnterprisePoolsHandler))).Methods("GET", "OPTIONS")
|
||||
// Create pool
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools/", log(logWriter, http.HandlerFunc(han.CreateEnterprisePoolHandler))).Methods("POST", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/pools", log(logWriter, http.HandlerFunc(han.CreateEnterprisePoolHandler))).Methods("POST", "OPTIONS")
|
||||
|
||||
// Repo instances list
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/instances/", log(logWriter, http.HandlerFunc(han.ListEnterpriseInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/instances", log(logWriter, http.HandlerFunc(han.ListEnterpriseInstancesHandler))).Methods("GET", "OPTIONS")
|
||||
|
||||
// Get org
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/", log(logWriter, http.HandlerFunc(han.GetEnterpriseByIDHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}", log(logWriter, http.HandlerFunc(han.GetEnterpriseByIDHandler))).Methods("GET", "OPTIONS")
|
||||
// Update org
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/", log(logWriter, http.HandlerFunc(han.UpdateEnterpriseHandler))).Methods("PUT", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}", log(logWriter, http.HandlerFunc(han.UpdateEnterpriseHandler))).Methods("PUT", "OPTIONS")
|
||||
// Delete org
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}/", log(logWriter, http.HandlerFunc(han.DeleteEnterpriseHandler))).Methods("DELETE", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises/{enterpriseID}", log(logWriter, http.HandlerFunc(han.DeleteEnterpriseHandler))).Methods("DELETE", "OPTIONS")
|
||||
// List orgs
|
||||
apiRouter.Handle("/enterprises/", log(logWriter, http.HandlerFunc(han.ListEnterprisesHandler))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises", log(logWriter, http.HandlerFunc(han.ListEnterprisesHandler))).Methods("GET", "OPTIONS")
|
||||
// Create org
|
||||
apiRouter.Handle("/enterprises/", log(logWriter, http.HandlerFunc(han.CreateEnterpriseHandler))).Methods("POST", "OPTIONS")
|
||||
apiRouter.Handle("/enterprises", log(logWriter, http.HandlerFunc(han.CreateEnterpriseHandler))).Methods("POST", "OPTIONS")
|
||||
|
||||
// Credentials and providers
|
||||
apiRouter.Handle("/credentials/", log(logWriter, http.HandlerFunc(han.ListCredentials))).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/credentials", log(logWriter, http.HandlerFunc(han.ListCredentials))).Methods("GET", "OPTIONS")
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
package cloudconfig
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"garm/config"
|
||||
|
|
@ -73,6 +74,29 @@ type CloudInit struct {
|
|||
SystemInfo *SystemInfo `yaml:"system_info,omitempty"`
|
||||
RunCmd []string `yaml:"runcmd,omitempty"`
|
||||
WriteFiles []File `yaml:"write_files,omitempty"`
|
||||
CACerts CACerts `yaml:"ca-certs,omitempty"`
|
||||
}
|
||||
|
||||
type CACerts struct {
|
||||
RemoveDefaults bool `yaml:"remove-defaults"`
|
||||
Trusted []string `yaml:"trusted"`
|
||||
}
|
||||
|
||||
func (c *CloudInit) AddCACert(cert []byte) error {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
if cert == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
if ok := roots.AppendCertsFromPEM(cert); !ok {
|
||||
return fmt.Errorf("failed to parse CA cert bundle")
|
||||
}
|
||||
c.CACerts.Trusted = append(c.CACerts.Trusted, string(cert))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CloudInit) AddSSHKey(keys ...string) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,16 @@ function fail() {
|
|||
}
|
||||
|
||||
sendStatus "downloading tools from {{ .DownloadURL }}"
|
||||
curl -L -o "/home/runner/{{ .FileName }}" "{{ .DownloadURL }}" || fail "failed to download tools"
|
||||
|
||||
TEMP_TOKEN=""
|
||||
|
||||
|
||||
|
||||
if [ ! -z "{{ .TempDownloadToken }}" ]; then
|
||||
TEMP_TOKEN="Authorization: Bearer {{ .TempDownloadToken }}"
|
||||
fi
|
||||
|
||||
curl -L -H "${TEMP_TOKEN}" -o "/home/runner/{{ .FileName }}" "{{ .DownloadURL }}" || fail "failed to download tools"
|
||||
|
||||
mkdir -p /home/runner/actions-runner || fail "failed to create actions-runner folder"
|
||||
|
||||
|
|
@ -84,16 +93,17 @@ success "runner successfully installed" $AGENT_ID
|
|||
`
|
||||
|
||||
type InstallRunnerParams struct {
|
||||
FileName string
|
||||
DownloadURL string
|
||||
RunnerUsername string
|
||||
RunnerGroup string
|
||||
RepoURL string
|
||||
GithubToken string
|
||||
RunnerName string
|
||||
RunnerLabels string
|
||||
CallbackURL string
|
||||
CallbackToken string
|
||||
FileName string
|
||||
DownloadURL string
|
||||
RunnerUsername string
|
||||
RunnerGroup string
|
||||
RepoURL string
|
||||
GithubToken string
|
||||
RunnerName string
|
||||
RunnerLabels string
|
||||
CallbackURL string
|
||||
CallbackToken string
|
||||
TempDownloadToken string
|
||||
}
|
||||
|
||||
func InstallRunnerScript(params InstallRunnerParams) ([]byte, error) {
|
||||
|
|
|
|||
203
cmd/garm-cli/client/enterprises.go
Normal file
203
cmd/garm-cli/client/enterprises.go
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"garm/params"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *Client) ListEnterprises() ([]params.Enterprise, error) {
|
||||
var enterprises []params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&enterprises).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return nil, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return nil, fmt.Errorf("error fetching enterprises: %s", apiErr.Details)
|
||||
}
|
||||
return enterprises, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateEnterprise(param params.CreateEnterpriseParams) (params.Enterprise, error) {
|
||||
var response params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
|
||||
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error creating enterprise: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetEnterprise(enterpriseID string) (params.Enterprise, error) {
|
||||
var response params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error fetching enterprise: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteEnterprise(enterpriseID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error fetching removing enterprise: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateEnterprisePool(enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error creating enterprise pool: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListEnterprisePools(enterpriseID string) ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error listing enterprise pools: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetEnterprisePool(enterpriseID, poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error fetching enterprise pool: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteEnterprisePool(enterpriseID, poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error deleting enterprise pool: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateEnterprisePool(enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error updating enterprise pool: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListEnterpriseInstances(enterpriseID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/instances", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error listing enterprise instances: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ func (c *Client) CreateOrganization(param params.CreateOrgParams) (params.Organi
|
|||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
return response, fmt.Errorf("error creating org: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ func (c *Client) GetOrganization(orgID string) (params.Organization, error) {
|
|||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error fetching orgs: %s", apiErr.Details)
|
||||
return response, fmt.Errorf("error fetching org: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ func (c *Client) DeleteOrganization(orgID string) error {
|
|||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error fetching orgs: %s", apiErr.Details)
|
||||
return fmt.Errorf("error removing org: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func init() {
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
creds, err := cli.ListCredentials()
|
||||
|
|
@ -63,10 +63,10 @@ func init() {
|
|||
|
||||
func formatGithubCredentials(creds []params.GithubCredentials) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"Name", "Description"}
|
||||
header := table.Row{"Name", "Description", "Base URL", "API URL", "Upload URL"}
|
||||
t.AppendHeader(header)
|
||||
for _, val := range creds {
|
||||
t.AppendRow(table.Row{val.Name, val.Description})
|
||||
t.AppendRow(table.Row{val.Name, val.Description, val.BaseURL, val.APIBaseURL, val.UploadBaseURL})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
|
|
|
|||
190
cmd/garm-cli/cmd/enterprise.go
Normal file
190
cmd/garm-cli/cmd/enterprise.go
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
enterpriseName string
|
||||
enterpriseWebhookSecret string
|
||||
enterpriseCreds string
|
||||
)
|
||||
|
||||
// enterpriseCmd represents the enterprise command
|
||||
var enterpriseCmd = &cobra.Command{
|
||||
Use: "enterprise",
|
||||
Aliases: []string{"ent"},
|
||||
SilenceUsage: true,
|
||||
Short: "Manage enterprise",
|
||||
Long: `Add, remove or update enterprise for which we manage
|
||||
self hosted runners.
|
||||
|
||||
This command allows you to define a new enterprise or manage an existing
|
||||
enterprise for which garm maintains pools of self hosted runners.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
var enterpriseAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Aliases: []string{"create"},
|
||||
Short: "Add enterprise",
|
||||
Long: `Add a new enterprise to the manager.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newEnterpriseReq := params.CreateEnterpriseParams{
|
||||
Name: enterpriseName,
|
||||
WebhookSecret: enterpriseWebhookSecret,
|
||||
CredentialsName: enterpriseCreds,
|
||||
}
|
||||
enterprise, err := cli.CreateEnterprise(newEnterpriseReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneEnterprise(enterprise)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var enterpriseListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List enterprises",
|
||||
Long: `List all configured enterprises that are currently managed.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
enterprises, err := cli.ListEnterprises()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatEnterprises(enterprises)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var enterpriseShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show details for one enterprise",
|
||||
Long: `Displays detailed information about a single enterprise.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a enterprise ID")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
enterprise, err := cli.GetEnterprise(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneEnterprise(enterprise)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var enterpriseDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Removes one enterprise",
|
||||
Long: `Delete one enterprise from the manager.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a enterprise ID")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteEnterprise(args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
enterpriseAddCmd.Flags().StringVar(&enterpriseName, "name", "", "The name of the enterprise")
|
||||
enterpriseAddCmd.Flags().StringVar(&enterpriseWebhookSecret, "webhook-secret", "", "The webhook secret for this enterprise")
|
||||
enterpriseAddCmd.Flags().StringVar(&enterpriseCreds, "credentials", "", "Credentials name. See credentials list.")
|
||||
enterpriseAddCmd.MarkFlagRequired("credentials")
|
||||
enterpriseAddCmd.MarkFlagRequired("name")
|
||||
|
||||
enterpriseCmd.AddCommand(
|
||||
enterpriseListCmd,
|
||||
enterpriseAddCmd,
|
||||
enterpriseShowCmd,
|
||||
enterpriseDeleteCmd,
|
||||
)
|
||||
|
||||
rootCmd.AddCommand(enterpriseCmd)
|
||||
}
|
||||
|
||||
func formatEnterprises(enterprises []params.Enterprise) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"ID", "Name", "Credentials name", "Pool mgr running"}
|
||||
t.AppendHeader(header)
|
||||
for _, val := range enterprises {
|
||||
t.AppendRow(table.Row{val.ID, val.Name, val.CredentialsName, val.PoolManagerStatus.IsRunning})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
||||
func formatOneEnterprise(enterprise params.Enterprise) {
|
||||
t := table.NewWriter()
|
||||
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
||||
header := table.Row{"Field", "Value"}
|
||||
t.AppendHeader(header)
|
||||
t.AppendRow(table.Row{"ID", enterprise.ID})
|
||||
t.AppendRow(table.Row{"Name", enterprise.Name})
|
||||
t.AppendRow(table.Row{"Credentials", enterprise.CredentialsName})
|
||||
t.AppendRow(table.Row{"Pool manager running", enterprise.PoolManagerStatus.IsRunning})
|
||||
if !enterprise.PoolManagerStatus.IsRunning {
|
||||
t.AppendRow(table.Row{"Failure reason", enterprise.PoolManagerStatus.FailureReason})
|
||||
}
|
||||
|
||||
if len(enterprise.Pools) > 0 {
|
||||
for _, pool := range enterprise.Pools {
|
||||
t.AppendRow(table.Row{"Pools", pool.ID}, rowConfigAutoMerge)
|
||||
}
|
||||
}
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Number: 1, AutoMerge: true},
|
||||
{Number: 2, AutoMerge: true},
|
||||
})
|
||||
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ var orgRunnerListCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ var orgPoolAddCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -91,7 +91,7 @@ var orgPoolListCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -117,7 +117,7 @@ var orgPoolShowCmd = &cobra.Command{
|
|||
Long: `Displays detailed information about a single pool.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
|
|
@ -142,7 +142,7 @@ var orgPoolDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
return fmt.Errorf("command requires orgID and poolID")
|
||||
|
|
@ -167,7 +167,7 @@ explicitly remove them using the runner delete command.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ var organizationCmd = &cobra.Command{
|
|||
self hosted runners.
|
||||
|
||||
This command allows you to define a new organization or manage an existing
|
||||
organization for which the garm maintains pools of self hosted runners.`,
|
||||
organization for which garm maintains pools of self hosted runners.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ var orgAddCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newOrgReq := params.CreateOrgParams{
|
||||
|
|
@ -71,11 +71,11 @@ var orgListCmd = &cobra.Command{
|
|||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List organizations",
|
||||
Long: `List all configured respositories that are currently managed.`,
|
||||
Long: `List all configured organizations that are currently managed.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
orgs, err := cli.ListOrganizations()
|
||||
|
|
@ -94,7 +94,7 @@ var orgShowCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a organization ID")
|
||||
|
|
@ -119,30 +119,7 @@ var orgDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a organization ID")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteOrganization(args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var orgInstanceListCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Removes one organization",
|
||||
Long: `Delete one organization from the manager.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a organization ID")
|
||||
|
|
@ -177,10 +154,10 @@ func init() {
|
|||
|
||||
func formatOrganizations(orgs []params.Organization) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"ID", "Name", "Credentials name"}
|
||||
header := table.Row{"ID", "Name", "Credentials name", "Pool mgr running"}
|
||||
t.AppendHeader(header)
|
||||
for _, val := range orgs {
|
||||
t.AppendRow(table.Row{val.ID, val.Name, val.CredentialsName})
|
||||
t.AppendRow(table.Row{val.ID, val.Name, val.CredentialsName, val.PoolManagerStatus.IsRunning})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
|
|
@ -194,7 +171,10 @@ func formatOneOrganization(org params.Organization) {
|
|||
t.AppendRow(table.Row{"ID", org.ID})
|
||||
t.AppendRow(table.Row{"Name", org.Name})
|
||||
t.AppendRow(table.Row{"Credentials", org.CredentialsName})
|
||||
|
||||
t.AppendRow(table.Row{"Pool manager running", org.PoolManagerStatus.IsRunning})
|
||||
if !org.PoolManagerStatus.IsRunning {
|
||||
t.AppendRow(table.Row{"Failure reason", org.PoolManagerStatus.FailureReason})
|
||||
}
|
||||
if len(org.Pools) > 0 {
|
||||
for _, pool := range org.Pools {
|
||||
t.AppendRow(table.Row{"Pools", pool.ID}, rowConfigAutoMerge)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
var (
|
||||
poolRepository string
|
||||
poolOrganization string
|
||||
poolEnterprise string
|
||||
poolAll bool
|
||||
)
|
||||
|
||||
|
|
@ -57,6 +58,9 @@ Example:
|
|||
List pools from one org:
|
||||
garm-cli pool list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
|
||||
|
||||
List pools from one enterprise:
|
||||
garm-cli pool list --org=a8ee4c66-e762-4cbe-a35d-175dba2c9e62
|
||||
|
||||
List all pools from all repos and orgs:
|
||||
garm-cli pool list --all
|
||||
|
||||
|
|
@ -64,7 +68,7 @@ Example:
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
var pools []params.Pool
|
||||
|
|
@ -76,6 +80,8 @@ Example:
|
|||
pools, err = cli.ListRepoPools(poolRepository)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pools, err = cli.ListOrgPools(poolOrganization)
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
pools, err = cli.ListEnterprisePools(poolEnterprise)
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
pools, err = cli.ListAllPools()
|
||||
} else {
|
||||
|
|
@ -102,7 +108,7 @@ var poolShowCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -130,7 +136,7 @@ var poolDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -156,7 +162,7 @@ var poolAddCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
tags := strings.Split(poolTags, ",")
|
||||
|
|
@ -183,6 +189,8 @@ var poolAddCmd = &cobra.Command{
|
|||
pool, err = cli.CreateRepoPool(poolRepository, newPoolParams)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pool, err = cli.CreateOrgPool(poolOrganization, newPoolParams)
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
pool, err = cli.CreateEnterprisePool(poolEnterprise, newPoolParams)
|
||||
} else {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
|
|
@ -208,7 +216,7 @@ explicitly remove them using the runner delete command.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -270,8 +278,9 @@ explicitly remove them using the runner delete command.
|
|||
func init() {
|
||||
poolListCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "List all pools within this repository.")
|
||||
poolListCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "List all pools withing this organization.")
|
||||
poolListCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "List all pools withing this enterprise.")
|
||||
poolListCmd.Flags().BoolVarP(&poolAll, "all", "a", false, "List all pools, regardless of org or repo.")
|
||||
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
|
||||
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all", "enterprise")
|
||||
|
||||
poolUpdateCmd.Flags().StringVar(&poolImage, "image", "", "The provider-specific image name to use for runners in this pool.")
|
||||
poolUpdateCmd.Flags().StringVar(&poolFlavor, "flavor", "", "The flavor to use for this runner.")
|
||||
|
|
@ -300,7 +309,8 @@ func init() {
|
|||
|
||||
poolAddCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "Add the new pool within this repository.")
|
||||
poolAddCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "Add the new pool withing this organization.")
|
||||
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org")
|
||||
poolAddCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "Add the new pool withing this enterprise.")
|
||||
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise")
|
||||
|
||||
poolCmd.AddCommand(
|
||||
poolListCmd,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ file of the garm client.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if cfg == nil {
|
||||
|
|
@ -76,7 +76,7 @@ var profileDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -101,7 +101,7 @@ var poolSwitchCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -177,7 +177,7 @@ installation, by performing a login.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if cfg == nil {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func init() {
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
providers, err := cli.ListProviders()
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ var repoRunnerListCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ var repoPoolAddCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -97,41 +97,13 @@ var repoPoolAddCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
var repoPoolListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List repository pools",
|
||||
Long: `List all configured pools for a given repository.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
pools, err := cli.ListRepoPools(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatPools(pools)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var repoPoolShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show details for one pool",
|
||||
Long: `Displays detailed information about a single pool.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
|
|
@ -156,7 +128,7 @@ var repoPoolDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
return fmt.Errorf("command requires repoID and poolID")
|
||||
|
|
@ -181,7 +153,7 @@ explicitly remove them using the runner delete command.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) < 2 || len(args) > 2 {
|
||||
|
|
@ -286,6 +258,9 @@ func formatPools(pools []params.Pool) {
|
|||
} else if pool.OrgID != "" && pool.OrgName != "" {
|
||||
belongsTo = pool.OrgName
|
||||
level = "org"
|
||||
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
|
||||
belongsTo = pool.EnterpriseName
|
||||
level = "enterprise"
|
||||
}
|
||||
t.AppendRow(table.Row{pool.ID, pool.Image, pool.Flavor, strings.Join(tags, " "), belongsTo, level, pool.Enabled})
|
||||
t.AppendSeparator()
|
||||
|
|
@ -313,6 +288,9 @@ func formatOnePool(pool params.Pool) {
|
|||
} else if pool.OrgID != "" && pool.OrgName != "" {
|
||||
belongsTo = pool.OrgName
|
||||
level = "org"
|
||||
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
|
||||
belongsTo = pool.EnterpriseName
|
||||
level = "enterprise"
|
||||
}
|
||||
|
||||
t.AppendHeader(header)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ var repoAddCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newRepoReq := params.CreateRepoParams{
|
||||
|
|
@ -77,7 +77,7 @@ var repoListCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
repos, err := cli.ListRepositories()
|
||||
|
|
@ -96,7 +96,7 @@ var repoShowCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
|
|
@ -121,30 +121,7 @@ var repoDeleteCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteRepository(args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var repoInstanceListCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Aliases: []string{"remove", "rm", "del"},
|
||||
Short: "Removes one repository",
|
||||
Long: `Delete one repository from the manager.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("requires a repository ID")
|
||||
|
|
@ -181,10 +158,10 @@ func init() {
|
|||
|
||||
func formatRepositories(repos []params.Repository) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"ID", "Owner", "Name", "Credentials name"}
|
||||
header := table.Row{"ID", "Owner", "Name", "Credentials name", "Pool mgr running"}
|
||||
t.AppendHeader(header)
|
||||
for _, val := range repos {
|
||||
t.AppendRow(table.Row{val.ID, val.Owner, val.Name, val.CredentialsName})
|
||||
t.AppendRow(table.Row{val.ID, val.Owner, val.Name, val.CredentialsName, val.PoolManagerStatus.IsRunning})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
|
|
@ -199,6 +176,10 @@ func formatOneRepository(repo params.Repository) {
|
|||
t.AppendRow(table.Row{"Owner", repo.Owner})
|
||||
t.AppendRow(table.Row{"Name", repo.Name})
|
||||
t.AppendRow(table.Row{"Credentials", repo.CredentialsName})
|
||||
t.AppendRow(table.Row{"Pool manager running", repo.PoolManagerStatus.IsRunning})
|
||||
if !repo.PoolManagerStatus.IsRunning {
|
||||
t.AppendRow(table.Row{"Failure reason", repo.PoolManagerStatus.FailureReason})
|
||||
}
|
||||
|
||||
if len(repo.Pools) > 0 {
|
||||
for _, pool := range repo.Pools {
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ import (
|
|||
var Version string
|
||||
|
||||
var (
|
||||
cfg *config.Config
|
||||
mgr config.Manager
|
||||
cli *client.Client
|
||||
active string
|
||||
needsInit bool
|
||||
debug bool
|
||||
needsInitError = fmt.Errorf("Please log into a garm installation first")
|
||||
cfg *config.Config
|
||||
mgr config.Manager
|
||||
cli *client.Client
|
||||
active string
|
||||
needsInit bool
|
||||
debug bool
|
||||
errNeedsInitError = fmt.Errorf("please log into a garm installation first")
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
var (
|
||||
runnerRepository string
|
||||
runnerOrganization string
|
||||
runnerEnterprise string
|
||||
runnerAll bool
|
||||
forceRemove bool
|
||||
)
|
||||
|
|
@ -61,6 +62,9 @@ Example:
|
|||
List runners from one org:
|
||||
garm-cli runner list --org=5493e51f-3170-4ce3-9f05-3fe690fc6ec6
|
||||
|
||||
List runners from one enterprise:
|
||||
garm-cli runner list --enterprise=a966188b-0e05-4edc-9b82-bc81a1fd38ed
|
||||
|
||||
List all runners from all pools belonging to all repos and orgs:
|
||||
garm-cli runner list --all
|
||||
|
||||
|
|
@ -68,7 +72,7 @@ Example:
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
var instances []params.Instance
|
||||
|
|
@ -78,9 +82,10 @@ Example:
|
|||
case 1:
|
||||
if cmd.Flags().Changed("repo") ||
|
||||
cmd.Flags().Changed("org") ||
|
||||
cmd.Flags().Changed("enterprise") ||
|
||||
cmd.Flags().Changed("all") {
|
||||
|
||||
return fmt.Errorf("specifying a pool ID and any of [all org repo] are mutually exclusive")
|
||||
return fmt.Errorf("specifying a pool ID and any of [all org repo enterprise] are mutually exclusive")
|
||||
}
|
||||
instances, err = cli.ListPoolInstances(args[0])
|
||||
case 0:
|
||||
|
|
@ -88,6 +93,8 @@ Example:
|
|||
instances, err = cli.ListRepoInstances(runnerRepository)
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
instances, err = cli.ListOrgInstances(runnerOrganization)
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
instances, err = cli.ListEnterpriseInstances(runnerEnterprise)
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
instances, err = cli.ListAllInstances()
|
||||
} else {
|
||||
|
|
@ -114,7 +121,7 @@ var runnerShowCmd = &cobra.Command{
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -151,7 +158,7 @@ to either cancel the workflow or wait for it to finish.
|
|||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return needsInitError
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
|
|
@ -172,8 +179,9 @@ to either cancel the workflow or wait for it to finish.
|
|||
func init() {
|
||||
runnerListCmd.Flags().StringVarP(&runnerRepository, "repo", "r", "", "List all runners from all pools within this repository.")
|
||||
runnerListCmd.Flags().StringVarP(&runnerOrganization, "org", "o", "", "List all runners from all pools withing this organization.")
|
||||
runnerListCmd.Flags().StringVarP(&runnerEnterprise, "enterprise", "e", "", "List all runners from all pools withing this enterprise.")
|
||||
runnerListCmd.Flags().BoolVarP(&runnerAll, "all", "a", false, "List all runners, regardless of org or repo.")
|
||||
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all")
|
||||
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "all")
|
||||
|
||||
runnerDeleteCmd.Flags().BoolVarP(&forceRemove, "force-remove-runner", "f", false, "Confirm you want to delete a runner")
|
||||
runnerDeleteCmd.MarkFlagsMutuallyExclusive("force-remove-runner")
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
|
@ -66,7 +65,13 @@ const (
|
|||
// of time and no new updates have been made to it's state, it will be removed.
|
||||
DefaultRunnerBootstrapTimeout = 20
|
||||
|
||||
GithubBaseURL = "https://github.com"
|
||||
// DefaultGithubURL is the default URL where Github or Github Enterprise can be accessed.
|
||||
DefaultGithubURL = "https://github.com"
|
||||
|
||||
// defaultBaseURL is the default URL for the github API.
|
||||
defaultBaseURL = "https://api.github.com/"
|
||||
// uploadBaseURL is the default URL for guthub uploads.
|
||||
uploadBaseURL = "https://uploads.github.com/"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -190,15 +195,69 @@ func (d *Default) Validate() error {
|
|||
// Github hold configuration options specific to interacting with github.
|
||||
// Currently that is just a OAuth2 personal token.
|
||||
type Github struct {
|
||||
Name string `toml:"name" json:"name"`
|
||||
Description string `toml:"description" json:"description"`
|
||||
OAuth2Token string `toml:"oauth2_token" json:"oauth2-token"`
|
||||
Name string `toml:"name" json:"name"`
|
||||
Description string `toml:"description" json:"description"`
|
||||
OAuth2Token string `toml:"oauth2_token" json:"oauth2-token"`
|
||||
APIBaseURL string `toml:"api_base_url" json:"api-base-url"`
|
||||
UploadBaseURL string `toml:"upload_base_url" json:"upload-base-url"`
|
||||
BaseURL string `toml:"base_url" json:"base-url"`
|
||||
// CACertBundlePath is the path on disk to a CA certificate bundle that
|
||||
// can validate the endpoints defined above. Leave empty if not using a
|
||||
// self signed certificate.
|
||||
CACertBundlePath string `toml:"ca_cert_bundle" json:"ca-cert-bundle"`
|
||||
}
|
||||
|
||||
func (g *Github) APIEndpoint() string {
|
||||
if g.APIBaseURL != "" {
|
||||
return g.APIBaseURL
|
||||
}
|
||||
return defaultBaseURL
|
||||
}
|
||||
|
||||
func (g *Github) CACertBundle() ([]byte, error) {
|
||||
if g.CACertBundlePath == "" {
|
||||
// No CA bundle defined.
|
||||
return nil, nil
|
||||
}
|
||||
if _, err := os.Stat(g.CACertBundlePath); err != nil {
|
||||
return nil, errors.Wrap(err, "accessing CA bundle")
|
||||
}
|
||||
|
||||
contents, err := os.ReadFile(g.CACertBundlePath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reading CA bundle")
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
if ok := roots.AppendCertsFromPEM(contents); !ok {
|
||||
return nil, fmt.Errorf("failed to parse CA cert bundle")
|
||||
}
|
||||
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func (g *Github) UploadEndpoint() string {
|
||||
if g.UploadBaseURL == "" {
|
||||
if g.APIBaseURL != "" {
|
||||
return g.APIBaseURL
|
||||
}
|
||||
return uploadBaseURL
|
||||
}
|
||||
return g.UploadBaseURL
|
||||
}
|
||||
|
||||
func (g *Github) BaseEndpoint() string {
|
||||
if g.BaseURL != "" {
|
||||
return g.BaseURL
|
||||
}
|
||||
return DefaultGithubURL
|
||||
}
|
||||
|
||||
func (g *Github) Validate() error {
|
||||
if g.OAuth2Token == "" {
|
||||
return fmt.Errorf("missing github oauth2 token")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +431,7 @@ func (t *TLSConfig) TLSConfig() (*tls.Config, error) {
|
|||
|
||||
var roots *x509.CertPool
|
||||
if t.CACert != "" {
|
||||
caCertPEM, err := ioutil.ReadFile(t.CACert)
|
||||
caCertPEM, err := os.ReadFile(t.CACert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
"garm/params"
|
||||
)
|
||||
|
||||
type Store interface {
|
||||
type RepoStore interface {
|
||||
CreateRepository(ctx context.Context, owner, name, credentialsName, webhookSecret string) (params.Repository, error)
|
||||
GetRepository(ctx context.Context, owner, name string) (params.Repository, error)
|
||||
GetRepositoryByID(ctx context.Context, repoID string) (params.Repository, error)
|
||||
|
|
@ -27,6 +27,18 @@ type Store interface {
|
|||
DeleteRepository(ctx context.Context, repoID string) error
|
||||
UpdateRepository(ctx context.Context, repoID string, param params.UpdateRepositoryParams) (params.Repository, error)
|
||||
|
||||
CreateRepositoryPool(ctx context.Context, repoId string, param params.CreatePoolParams) (params.Pool, error)
|
||||
|
||||
GetRepositoryPool(ctx context.Context, repoID, poolID string) (params.Pool, error)
|
||||
DeleteRepositoryPool(ctx context.Context, repoID, poolID string) error
|
||||
UpdateRepositoryPool(ctx context.Context, repoID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
|
||||
FindRepositoryPoolByTags(ctx context.Context, repoID string, tags []string) (params.Pool, error)
|
||||
|
||||
ListRepoPools(ctx context.Context, repoID string) ([]params.Pool, error)
|
||||
ListRepoInstances(ctx context.Context, repoID string) ([]params.Instance, error)
|
||||
}
|
||||
|
||||
type OrgStore interface {
|
||||
CreateOrganization(ctx context.Context, name, credentialsName, webhookSecret string) (params.Organization, error)
|
||||
GetOrganization(ctx context.Context, name string) (params.Organization, error)
|
||||
GetOrganizationByID(ctx context.Context, orgID string) (params.Organization, error)
|
||||
|
|
@ -34,53 +46,77 @@ type Store interface {
|
|||
DeleteOrganization(ctx context.Context, orgID string) error
|
||||
UpdateOrganization(ctx context.Context, orgID string, param params.UpdateRepositoryParams) (params.Organization, error)
|
||||
|
||||
CreateRepositoryPool(ctx context.Context, repoId string, param params.CreatePoolParams) (params.Pool, error)
|
||||
CreateOrganizationPool(ctx context.Context, orgId string, param params.CreatePoolParams) (params.Pool, error)
|
||||
|
||||
GetRepositoryPool(ctx context.Context, repoID, poolID string) (params.Pool, error)
|
||||
GetOrganizationPool(ctx context.Context, orgID, poolID string) (params.Pool, error)
|
||||
DeleteOrganizationPool(ctx context.Context, orgID, poolID string) error
|
||||
UpdateOrganizationPool(ctx context.Context, orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
|
||||
|
||||
ListRepoPools(ctx context.Context, repoID string) ([]params.Pool, error)
|
||||
FindOrganizationPoolByTags(ctx context.Context, orgID string, tags []string) (params.Pool, error)
|
||||
ListOrgPools(ctx context.Context, orgID string) ([]params.Pool, error)
|
||||
ListOrgInstances(ctx context.Context, orgID string) ([]params.Instance, error)
|
||||
}
|
||||
|
||||
type EnterpriseStore interface {
|
||||
CreateEnterprise(ctx context.Context, name, credentialsName, webhookSecret string) (params.Enterprise, error)
|
||||
GetEnterprise(ctx context.Context, name string) (params.Enterprise, error)
|
||||
GetEnterpriseByID(ctx context.Context, enterpriseID string) (params.Enterprise, error)
|
||||
ListEnterprises(ctx context.Context) ([]params.Enterprise, error)
|
||||
DeleteEnterprise(ctx context.Context, enterpriseID string) error
|
||||
UpdateEnterprise(ctx context.Context, enterpriseID string, param params.UpdateRepositoryParams) (params.Enterprise, error)
|
||||
|
||||
CreateEnterprisePool(ctx context.Context, enterpriseID string, param params.CreatePoolParams) (params.Pool, error)
|
||||
GetEnterprisePool(ctx context.Context, enterpriseID, poolID string) (params.Pool, error)
|
||||
DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID string) error
|
||||
UpdateEnterprisePool(ctx context.Context, enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
|
||||
|
||||
FindEnterprisePoolByTags(ctx context.Context, enterpriseID string, tags []string) (params.Pool, error)
|
||||
ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error)
|
||||
ListEnterpriseInstances(ctx context.Context, enterpriseID string) ([]params.Instance, error)
|
||||
}
|
||||
|
||||
type PoolStore interface {
|
||||
// Probably a bad idea without some king of filter or at least pagination
|
||||
// TODO: add filter/pagination
|
||||
ListAllPools(ctx context.Context) ([]params.Pool, error)
|
||||
GetPoolByID(ctx context.Context, poolID string) (params.Pool, error)
|
||||
DeletePoolByID(ctx context.Context, poolID string) error
|
||||
|
||||
DeleteRepositoryPool(ctx context.Context, repoID, poolID string) error
|
||||
DeleteOrganizationPool(ctx context.Context, orgID, poolID string) error
|
||||
|
||||
UpdateRepositoryPool(ctx context.Context, repoID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
|
||||
UpdateOrganizationPool(ctx context.Context, orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
|
||||
|
||||
FindRepositoryPoolByTags(ctx context.Context, repoID string, tags []string) (params.Pool, error)
|
||||
FindOrganizationPoolByTags(ctx context.Context, orgID string, tags []string) (params.Pool, error)
|
||||
|
||||
CreateInstance(ctx context.Context, poolID string, param params.CreateInstanceParams) (params.Instance, error)
|
||||
DeleteInstance(ctx context.Context, poolID string, instanceName string) error
|
||||
UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error)
|
||||
|
||||
ListPoolInstances(ctx context.Context, poolID string) ([]params.Instance, error)
|
||||
ListRepoInstances(ctx context.Context, repoID string) ([]params.Instance, error)
|
||||
ListOrgInstances(ctx context.Context, orgID string) ([]params.Instance, error)
|
||||
|
||||
PoolInstanceCount(ctx context.Context, poolID string) (int64, error)
|
||||
|
||||
// Probably a bad idea without some king of filter or at least pagination
|
||||
// TODO: add filter/pagination
|
||||
ListAllInstances(ctx context.Context) ([]params.Instance, error)
|
||||
|
||||
GetPoolInstanceByName(ctx context.Context, poolID string, instanceName string) (params.Instance, error)
|
||||
GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error)
|
||||
AddInstanceStatusMessage(ctx context.Context, instanceID string, statusMessage string) error
|
||||
}
|
||||
|
||||
type UserStore interface {
|
||||
GetUser(ctx context.Context, user string) (params.User, error)
|
||||
GetUserByID(ctx context.Context, userID string) (params.User, error)
|
||||
|
||||
CreateUser(ctx context.Context, user params.NewUserParams) (params.User, error)
|
||||
UpdateUser(ctx context.Context, user string, param params.UpdateUserParams) (params.User, error)
|
||||
HasAdminUser(ctx context.Context) bool
|
||||
}
|
||||
|
||||
type InstanceStore interface {
|
||||
CreateInstance(ctx context.Context, poolID string, param params.CreateInstanceParams) (params.Instance, error)
|
||||
DeleteInstance(ctx context.Context, poolID string, instanceName string) error
|
||||
UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error)
|
||||
|
||||
// Probably a bad idea without some king of filter or at least pagination
|
||||
// TODO: add filter/pagination
|
||||
ListAllInstances(ctx context.Context) ([]params.Instance, error)
|
||||
|
||||
GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error)
|
||||
AddInstanceStatusMessage(ctx context.Context, instanceID string, statusMessage string) error
|
||||
}
|
||||
|
||||
//go:generate mockery --name=Store
|
||||
type Store interface {
|
||||
RepoStore
|
||||
OrgStore
|
||||
EnterpriseStore
|
||||
PoolStore
|
||||
UserStore
|
||||
InstanceStore
|
||||
|
||||
ControllerInfo() (params.ControllerInfo, error)
|
||||
InitController() (params.ControllerInfo, error)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,48 @@ func (_m *Store) ControllerInfo() (params.ControllerInfo, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateEnterprise provides a mock function with given fields: ctx, name, credentialsName, webhookSecret
|
||||
func (_m *Store) CreateEnterprise(ctx context.Context, name string, credentialsName string, webhookSecret string) (params.Enterprise, error) {
|
||||
ret := _m.Called(ctx, name, credentialsName, webhookSecret)
|
||||
|
||||
var r0 params.Enterprise
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) params.Enterprise); ok {
|
||||
r0 = rf(ctx, name, credentialsName, webhookSecret)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Enterprise)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
|
||||
r1 = rf(ctx, name, credentialsName, webhookSecret)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateEnterprisePool provides a mock function with given fields: ctx, enterpriseID, param
|
||||
func (_m *Store) CreateEnterprisePool(ctx context.Context, enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
ret := _m.Called(ctx, enterpriseID, param)
|
||||
|
||||
var r0 params.Pool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, params.CreatePoolParams) params.Pool); ok {
|
||||
r0 = rf(ctx, enterpriseID, param)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Pool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, params.CreatePoolParams) error); ok {
|
||||
r1 = rf(ctx, enterpriseID, param)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateInstance provides a mock function with given fields: ctx, poolID, param
|
||||
func (_m *Store) CreateInstance(ctx context.Context, poolID string, param params.CreateInstanceParams) (params.Instance, error) {
|
||||
ret := _m.Called(ctx, poolID, param)
|
||||
|
|
@ -175,6 +217,34 @@ func (_m *Store) CreateUser(ctx context.Context, user params.NewUserParams) (par
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteEnterprise provides a mock function with given fields: ctx, enterpriseID
|
||||
func (_m *Store) DeleteEnterprise(ctx context.Context, enterpriseID string) error {
|
||||
ret := _m.Called(ctx, enterpriseID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteEnterprisePool provides a mock function with given fields: ctx, enterpriseID, poolID
|
||||
func (_m *Store) DeleteEnterprisePool(ctx context.Context, enterpriseID string, poolID string) error {
|
||||
ret := _m.Called(ctx, enterpriseID, poolID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, enterpriseID, poolID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteInstance provides a mock function with given fields: ctx, poolID, instanceName
|
||||
func (_m *Store) DeleteInstance(ctx context.Context, poolID string, instanceName string) error {
|
||||
ret := _m.Called(ctx, poolID, instanceName)
|
||||
|
|
@ -259,6 +329,27 @@ func (_m *Store) DeleteRepositoryPool(ctx context.Context, repoID string, poolID
|
|||
return r0
|
||||
}
|
||||
|
||||
// FindEnterprisePoolByTags provides a mock function with given fields: ctx, enterpriseID, tags
|
||||
func (_m *Store) FindEnterprisePoolByTags(ctx context.Context, enterpriseID string, tags []string) (params.Pool, error) {
|
||||
ret := _m.Called(ctx, enterpriseID, tags)
|
||||
|
||||
var r0 params.Pool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, []string) params.Pool); ok {
|
||||
r0 = rf(ctx, enterpriseID, tags)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Pool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, []string) error); ok {
|
||||
r1 = rf(ctx, enterpriseID, tags)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindOrganizationPoolByTags provides a mock function with given fields: ctx, orgID, tags
|
||||
func (_m *Store) FindOrganizationPoolByTags(ctx context.Context, orgID string, tags []string) (params.Pool, error) {
|
||||
ret := _m.Called(ctx, orgID, tags)
|
||||
|
|
@ -301,6 +392,69 @@ func (_m *Store) FindRepositoryPoolByTags(ctx context.Context, repoID string, ta
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetEnterprise provides a mock function with given fields: ctx, name
|
||||
func (_m *Store) GetEnterprise(ctx context.Context, name string) (params.Enterprise, error) {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
var r0 params.Enterprise
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) params.Enterprise); ok {
|
||||
r0 = rf(ctx, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Enterprise)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetEnterpriseByID provides a mock function with given fields: ctx, enterpriseID
|
||||
func (_m *Store) GetEnterpriseByID(ctx context.Context, enterpriseID string) (params.Enterprise, error) {
|
||||
ret := _m.Called(ctx, enterpriseID)
|
||||
|
||||
var r0 params.Enterprise
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) params.Enterprise); ok {
|
||||
r0 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Enterprise)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetEnterprisePool provides a mock function with given fields: ctx, enterpriseID, poolID
|
||||
func (_m *Store) GetEnterprisePool(ctx context.Context, enterpriseID string, poolID string) (params.Pool, error) {
|
||||
ret := _m.Called(ctx, enterpriseID, poolID)
|
||||
|
||||
var r0 params.Pool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) params.Pool); ok {
|
||||
r0 = rf(ctx, enterpriseID, poolID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Pool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, enterpriseID, poolID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetInstanceByName provides a mock function with given fields: ctx, instanceName
|
||||
func (_m *Store) GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error) {
|
||||
ret := _m.Called(ctx, instanceName)
|
||||
|
|
@ -613,6 +767,75 @@ func (_m *Store) ListAllPools(ctx context.Context) ([]params.Pool, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// ListEnterpriseInstances provides a mock function with given fields: ctx, enterpriseID
|
||||
func (_m *Store) ListEnterpriseInstances(ctx context.Context, enterpriseID string) ([]params.Instance, error) {
|
||||
ret := _m.Called(ctx, enterpriseID)
|
||||
|
||||
var r0 []params.Instance
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []params.Instance); ok {
|
||||
r0 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]params.Instance)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListEnterprisePools provides a mock function with given fields: ctx, enterpriseID
|
||||
func (_m *Store) ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error) {
|
||||
ret := _m.Called(ctx, enterpriseID)
|
||||
|
||||
var r0 []params.Pool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []params.Pool); ok {
|
||||
r0 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]params.Pool)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, enterpriseID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListEnterprises provides a mock function with given fields: ctx
|
||||
func (_m *Store) ListEnterprises(ctx context.Context) ([]params.Enterprise, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 []params.Enterprise
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []params.Enterprise); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]params.Enterprise)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListOrgInstances provides a mock function with given fields: ctx, orgID
|
||||
func (_m *Store) ListOrgInstances(ctx context.Context, orgID string) ([]params.Instance, error) {
|
||||
ret := _m.Called(ctx, orgID)
|
||||
|
|
@ -795,6 +1018,48 @@ func (_m *Store) PoolInstanceCount(ctx context.Context, poolID string) (int64, e
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateEnterprise provides a mock function with given fields: ctx, enterpriseID, param
|
||||
func (_m *Store) UpdateEnterprise(ctx context.Context, enterpriseID string, param params.UpdateRepositoryParams) (params.Enterprise, error) {
|
||||
ret := _m.Called(ctx, enterpriseID, param)
|
||||
|
||||
var r0 params.Enterprise
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, params.UpdateRepositoryParams) params.Enterprise); ok {
|
||||
r0 = rf(ctx, enterpriseID, param)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Enterprise)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, params.UpdateRepositoryParams) error); ok {
|
||||
r1 = rf(ctx, enterpriseID, param)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateEnterprisePool provides a mock function with given fields: ctx, enterpriseID, poolID, param
|
||||
func (_m *Store) UpdateEnterprisePool(ctx context.Context, enterpriseID string, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
ret := _m.Called(ctx, enterpriseID, poolID, param)
|
||||
|
||||
var r0 params.Pool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, params.UpdatePoolParams) params.Pool); ok {
|
||||
r0 = rf(ctx, enterpriseID, poolID, param)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.Pool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, params.UpdatePoolParams) error); ok {
|
||||
r1 = rf(ctx, enterpriseID, poolID, param)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateInstance provides a mock function with given fields: ctx, instanceID, param
|
||||
func (_m *Store) UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error) {
|
||||
ret := _m.Called(ctx, instanceID, param)
|
||||
|
|
|
|||
367
database/sql/enterprise.go
Normal file
367
database/sql/enterprise.go
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
"garm/util"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (s *sqlDatabase) CreateEnterprise(ctx context.Context, name, credentialsName, webhookSecret string) (params.Enterprise, error) {
|
||||
secret := []byte{}
|
||||
var err error
|
||||
if webhookSecret != "" {
|
||||
secret, err = util.Aes256EncodeString(webhookSecret, s.cfg.Passphrase)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, fmt.Errorf("failed to encrypt string")
|
||||
}
|
||||
}
|
||||
newEnterprise := Enterprise{
|
||||
Name: name,
|
||||
WebhookSecret: secret,
|
||||
CredentialsName: credentialsName,
|
||||
}
|
||||
|
||||
q := s.conn.Create(&newEnterprise)
|
||||
if q.Error != nil {
|
||||
return params.Enterprise{}, errors.Wrap(q.Error, "creating enterprise")
|
||||
}
|
||||
|
||||
param := s.sqlToCommonEnterprise(newEnterprise)
|
||||
param.WebhookSecret = webhookSecret
|
||||
|
||||
return param, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) GetEnterprise(ctx context.Context, name string) (params.Enterprise, error) {
|
||||
enterprise, err := s.getEnterprise(ctx, name)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
param := s.sqlToCommonEnterprise(enterprise)
|
||||
secret, err := util.Aes256DecodeString(enterprise.WebhookSecret, s.cfg.Passphrase)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "decrypting secret")
|
||||
}
|
||||
param.WebhookSecret = secret
|
||||
|
||||
return param, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) GetEnterpriseByID(ctx context.Context, enterpriseID string) (params.Enterprise, error) {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID, "Pools")
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
param := s.sqlToCommonEnterprise(enterprise)
|
||||
secret, err := util.Aes256DecodeString(enterprise.WebhookSecret, s.cfg.Passphrase)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "decrypting secret")
|
||||
}
|
||||
param.WebhookSecret = secret
|
||||
|
||||
return param, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListEnterprises(ctx context.Context) ([]params.Enterprise, error) {
|
||||
var enterprises []Enterprise
|
||||
q := s.conn.Find(&enterprises)
|
||||
if q.Error != nil {
|
||||
return []params.Enterprise{}, errors.Wrap(q.Error, "fetching enterprise from database")
|
||||
}
|
||||
|
||||
ret := make([]params.Enterprise, len(enterprises))
|
||||
for idx, val := range enterprises {
|
||||
ret[idx] = s.sqlToCommonEnterprise(val)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) DeleteEnterprise(ctx context.Context, enterpriseID string) error {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
q := s.conn.Unscoped().Delete(&enterprise)
|
||||
if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrap(q.Error, "deleting enterprise")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateEnterprise(ctx context.Context, enterpriseID string, param params.UpdateRepositoryParams) (params.Enterprise, error) {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
if param.CredentialsName != "" {
|
||||
enterprise.CredentialsName = param.CredentialsName
|
||||
}
|
||||
|
||||
if param.WebhookSecret != "" {
|
||||
secret, err := util.Aes256EncodeString(param.WebhookSecret, s.cfg.Passphrase)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, fmt.Errorf("failed to encrypt string")
|
||||
}
|
||||
enterprise.WebhookSecret = secret
|
||||
}
|
||||
|
||||
q := s.conn.Save(&enterprise)
|
||||
if q.Error != nil {
|
||||
return params.Enterprise{}, errors.Wrap(q.Error, "saving enterprise")
|
||||
}
|
||||
|
||||
newParams := s.sqlToCommonEnterprise(enterprise)
|
||||
secret, err := util.Aes256DecodeString(enterprise.WebhookSecret, s.cfg.Passphrase)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "decrypting secret")
|
||||
}
|
||||
newParams.WebhookSecret = secret
|
||||
return newParams, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) CreateEnterprisePool(ctx context.Context, enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
if len(param.Tags) == 0 {
|
||||
return params.Pool{}, runnerErrors.NewBadRequestError("no tags specified")
|
||||
}
|
||||
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
newPool := Pool{
|
||||
ProviderName: param.ProviderName,
|
||||
MaxRunners: param.MaxRunners,
|
||||
MinIdleRunners: param.MinIdleRunners,
|
||||
Image: param.Image,
|
||||
Flavor: param.Flavor,
|
||||
OSType: param.OSType,
|
||||
OSArch: param.OSArch,
|
||||
EnterpriseID: enterprise.ID,
|
||||
Enabled: param.Enabled,
|
||||
RunnerBootstrapTimeout: param.RunnerBootstrapTimeout,
|
||||
}
|
||||
|
||||
_, err = s.getEnterprisePoolByUniqueFields(ctx, enterpriseID, newPool.ProviderName, newPool.Image, newPool.Flavor)
|
||||
if err != nil {
|
||||
if !errors.Is(err, runnerErrors.ErrNotFound) {
|
||||
return params.Pool{}, errors.Wrap(err, "creating pool")
|
||||
}
|
||||
} else {
|
||||
return params.Pool{}, runnerErrors.NewConflictError("pool with the same image and flavor already exists on this provider")
|
||||
}
|
||||
|
||||
tags := []Tag{}
|
||||
for _, val := range param.Tags {
|
||||
t, err := s.getOrCreateTag(val)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching tag")
|
||||
}
|
||||
tags = append(tags, t)
|
||||
}
|
||||
|
||||
q := s.conn.Create(&newPool)
|
||||
if q.Error != nil {
|
||||
return params.Pool{}, errors.Wrap(q.Error, "adding pool")
|
||||
}
|
||||
|
||||
for _, tt := range tags {
|
||||
if err := s.conn.Model(&newPool).Association("Tags").Append(&tt); err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "saving tag")
|
||||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
return s.sqlToCommonPool(pool), nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) GetEnterprisePool(ctx context.Context, enterpriseID, poolID string) (params.Pool, error) {
|
||||
pool, err := s.getEnterprisePool(ctx, enterpriseID, poolID, "Tags", "Instances")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return s.sqlToCommonPool(pool), nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID string) error {
|
||||
pool, err := s.getEnterprisePool(ctx, enterpriseID, poolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "looking up enterprise pool")
|
||||
}
|
||||
q := s.conn.Unscoped().Delete(&pool)
|
||||
if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrap(q.Error, "deleting pool")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateEnterprisePool(ctx context.Context, enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
pool, err := s.getEnterprisePool(ctx, enterpriseID, poolID, "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
return s.updatePool(pool, param)
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) FindEnterprisePoolByTags(ctx context.Context, enterpriseID string, tags []string) (params.Pool, error) {
|
||||
pool, err := s.findPoolByTags(enterpriseID, "enterprise_id", tags)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error) {
|
||||
pools, err := s.getEnterprisePools(ctx, enterpriseID, "Tags", "Enterprise")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pools")
|
||||
}
|
||||
|
||||
ret := make([]params.Pool, len(pools))
|
||||
for idx, pool := range pools {
|
||||
ret[idx] = s.sqlToCommonPool(pool)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListEnterpriseInstances(ctx context.Context, enterpriseID string) ([]params.Instance, error) {
|
||||
pools, err := s.getEnterprisePools(ctx, enterpriseID, "Instances")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
ret := []params.Instance{}
|
||||
for _, pool := range pools {
|
||||
for _, instance := range pool.Instances {
|
||||
ret = append(ret, s.sqlToParamsInstance(instance))
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getEnterprise(ctx context.Context, name string) (Enterprise, error) {
|
||||
var enterprise Enterprise
|
||||
|
||||
q := s.conn.Where("name = ? COLLATE NOCASE", name)
|
||||
q = q.First(&enterprise)
|
||||
if q.Error != nil {
|
||||
if errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
||||
return Enterprise{}, runnerErrors.ErrNotFound
|
||||
}
|
||||
return Enterprise{}, errors.Wrap(q.Error, "fetching enterprise from database")
|
||||
}
|
||||
return enterprise, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getEnterpriseByID(ctx context.Context, id string, preload ...string) (Enterprise, error) {
|
||||
u, err := uuid.FromString(id)
|
||||
if err != nil {
|
||||
return Enterprise{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
|
||||
}
|
||||
var enterprise Enterprise
|
||||
|
||||
q := s.conn
|
||||
if len(preload) > 0 {
|
||||
for _, field := range preload {
|
||||
q = q.Preload(field)
|
||||
}
|
||||
}
|
||||
q = q.Where("id = ?", u).First(&enterprise)
|
||||
|
||||
if q.Error != nil {
|
||||
if errors.Is(q.Error, gorm.ErrRecordNotFound) {
|
||||
return Enterprise{}, runnerErrors.ErrNotFound
|
||||
}
|
||||
return Enterprise{}, errors.Wrap(q.Error, "fetching enterprise from database")
|
||||
}
|
||||
return enterprise, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getEnterprisePoolByUniqueFields(ctx context.Context, enterpriseID string, provider, image, flavor string) (Pool, error) {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return Pool{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
q := s.conn
|
||||
var pool []Pool
|
||||
err = q.Model(&enterprise).Association("Pools").Find(&pool, "provider_name = ? and image = ? and flavor = ?", provider, image, flavor)
|
||||
if err != nil {
|
||||
return Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
if len(pool) == 0 {
|
||||
return Pool{}, runnerErrors.ErrNotFound
|
||||
}
|
||||
|
||||
return pool[0], nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getEnterprisePool(ctx context.Context, enterpriseID, poolID string, preload ...string) (Pool, error) {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return Pool{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
u, err := uuid.FromString(poolID)
|
||||
if err != nil {
|
||||
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
|
||||
}
|
||||
|
||||
q := s.conn
|
||||
if len(preload) > 0 {
|
||||
for _, item := range preload {
|
||||
q = q.Preload(item)
|
||||
}
|
||||
}
|
||||
|
||||
var pool []Pool
|
||||
err = q.Model(&enterprise).Association("Pools").Find(&pool, "id = ?", u)
|
||||
if err != nil {
|
||||
return Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
if len(pool) == 0 {
|
||||
return Pool{}, runnerErrors.ErrNotFound
|
||||
}
|
||||
|
||||
return pool[0], nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) getEnterprisePools(ctx context.Context, enterpriseID string, preload ...string) ([]Pool, error) {
|
||||
enterprise, err := s.getEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
var pools []Pool
|
||||
|
||||
q := s.conn.Model(&enterprise)
|
||||
if len(preload) > 0 {
|
||||
for _, item := range preload {
|
||||
q = q.Preload(item)
|
||||
}
|
||||
}
|
||||
err = q.Association("Pools").Find(&pools)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
return pools, nil
|
||||
}
|
||||
|
|
@ -71,6 +71,9 @@ type Pool struct {
|
|||
OrgID uuid.UUID `gorm:"index"`
|
||||
Organization Organization `gorm:"foreignKey:OrgID"`
|
||||
|
||||
EnterpriseID uuid.UUID `gorm:"index"`
|
||||
Enterprise Enterprise `gorm:"foreignKey:EnterpriseID"`
|
||||
|
||||
Instances []Instance `gorm:"foreignKey:PoolID"`
|
||||
}
|
||||
|
||||
|
|
@ -93,6 +96,15 @@ type Organization struct {
|
|||
Pools []Pool `gorm:"foreignKey:OrgID"`
|
||||
}
|
||||
|
||||
type Enterprise struct {
|
||||
Base
|
||||
|
||||
CredentialsName string
|
||||
Name string `gorm:"index:idx_ent_name_nocase,collate:nocase"`
|
||||
WebhookSecret []byte
|
||||
Pools []Pool `gorm:"foreignKey:EnterpriseID"`
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
Base
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ func (s *sqlDatabase) ListOrganizations(ctx context.Context) ([]params.Organizat
|
|||
var orgs []Organization
|
||||
q := s.conn.Find(&orgs)
|
||||
if q.Error != nil {
|
||||
return []params.Organization{}, errors.Wrap(q.Error, "fetching user from database")
|
||||
return []params.Organization{}, errors.Wrap(q.Error, "fetching org from database")
|
||||
}
|
||||
|
||||
ret := make([]params.Organization, len(orgs))
|
||||
|
|
@ -197,7 +197,7 @@ func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgId string,
|
|||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Organization", "Repository")
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
@ -262,7 +262,7 @@ func (s *sqlDatabase) ListOrgInstances(ctx context.Context, orgID string) ([]par
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateOrganizationPool(ctx context.Context, orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
pool, err := s.getOrgPool(ctx, orgID, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
pool, err := s.getOrgPool(ctx, orgID, poolID, "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ func (s *OrgTestSuite) TestListOrganizationsDBFetchErr() {
|
|||
|
||||
s.assertSQLMockExpectations()
|
||||
s.Require().NotNil(err)
|
||||
s.Require().Equal("fetching user from database: fetching user from database mock error", err.Error())
|
||||
s.Require().Equal("fetching org from database: fetching user from database mock error", err.Error())
|
||||
}
|
||||
|
||||
func (s *OrgTestSuite) TestDeleteOrganization() {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ func (s *sqlDatabase) ListAllPools(ctx context.Context) ([]params.Pool, error) {
|
|||
Preload("Tags").
|
||||
Preload("Organization").
|
||||
Preload("Repository").
|
||||
Preload("Enterprise").
|
||||
Find(&pools)
|
||||
if q.Error != nil {
|
||||
return nil, errors.Wrap(q.Error, "fetching all pools")
|
||||
|
|
@ -42,7 +43,7 @@ func (s *sqlDatabase) ListAllPools(ctx context.Context) ([]params.Pool, error) {
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) GetPoolByID(ctx context.Context, poolID string) (params.Pool, error) {
|
||||
pool, err := s.getPoolByID(ctx, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
pool, err := s.getPoolByID(ctx, poolID, "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool by ID")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, p
|
|||
}
|
||||
}
|
||||
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Organization", "Repository")
|
||||
pool, err := s.getPoolByID(ctx, newPool.ID.String(), "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
@ -271,7 +271,7 @@ func (s *sqlDatabase) ListRepoInstances(ctx context.Context, repoID string) ([]p
|
|||
}
|
||||
|
||||
func (s *sqlDatabase) UpdateRepositoryPool(ctx context.Context, repoID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
pool, err := s.getRepoPool(ctx, repoID, poolID, "Tags", "Instances", "Organization", "Repository")
|
||||
pool, err := s.getRepoPool(ctx, repoID, poolID, "Tags", "Instances", "Enterprise", "Organization", "Repository")
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,13 +96,14 @@ func (s *sqlDatabase) migrateDB() error {
|
|||
&Pool{},
|
||||
&Repository{},
|
||||
&Organization{},
|
||||
&Enterprise{},
|
||||
&Address{},
|
||||
&InstanceStatusUpdate{},
|
||||
&Instance{},
|
||||
&ControllerInfo{},
|
||||
&User{},
|
||||
); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "running auto migrate")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -85,6 +85,21 @@ func (s *sqlDatabase) sqlToCommonOrganization(org Organization) params.Organizat
|
|||
return ret
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise) params.Enterprise {
|
||||
ret := params.Enterprise{
|
||||
ID: enterprise.ID.String(),
|
||||
Name: enterprise.Name,
|
||||
CredentialsName: enterprise.CredentialsName,
|
||||
Pools: make([]params.Pool, len(enterprise.Pools)),
|
||||
}
|
||||
|
||||
for idx, pool := range enterprise.Pools {
|
||||
ret.Pools[idx] = s.sqlToCommonPool(pool)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) sqlToCommonPool(pool Pool) params.Pool {
|
||||
ret := params.Pool{
|
||||
ID: pool.ID.String(),
|
||||
|
|
@ -113,6 +128,11 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) params.Pool {
|
|||
ret.OrgName = pool.Organization.Name
|
||||
}
|
||||
|
||||
if pool.EnterpriseID != uuid.Nil && pool.Enterprise.Name != "" {
|
||||
ret.EnterpriseID = pool.EnterpriseID.String()
|
||||
ret.EnterpriseName = pool.Enterprise.Name
|
||||
}
|
||||
|
||||
for idx, val := range pool.Tags {
|
||||
ret.Tags[idx] = s.sqlToCommonTags(*val)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
# Configuring github credentials
|
||||
|
||||
Garm needs a [Personal Access Token (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to create runner registration tokens, list current self hosted runners and potentially remove them if they become orphaned (the VM was manually removed on the provider).
|
||||
The ```github``` config section holds credentials and API endpoint information for accessing the GitHub APIs. Credentials are tied to the instance of GitHub you're using. Whether you're using [github.com](https://github.com) or your own deployment of GitHub Enterprise server, this section is how ```garm``` knows where it should create the runners.
|
||||
|
||||
Tying the API endpoint info to the credentials allows us to use the same ```garm``` installation with both [github.com](https://github.com) and private deployments. All you have to do is to add the needed endpoint info (see bellow).
|
||||
|
||||
|
||||
Garm uses a [Personal Access Token (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to create runner registration tokens, list current self hosted runners and potentially remove them if they become orphaned (the VM was manually removed on the provider).
|
||||
|
||||
|
||||
From the list of scopes, you will need to select:
|
||||
|
||||
* ```public_repo``` - for access to a repository
|
||||
* ```repo``` - for access to a private repository
|
||||
* ```admin:org``` - if you plan on using this with an organization to which you have access
|
||||
* ```manage_runners:enterprise``` - if you plan to use garm at the enterprise level
|
||||
|
||||
The resulting token must be configured in the ```[[github]]``` section of the config. Sample as follows:
|
||||
|
||||
|
|
@ -24,6 +31,21 @@ The resulting token must be configured in the ```[[github]]``` section of the co
|
|||
# to work with repositories, and the admin:org needs to be set if you plan on
|
||||
# adding an organization.
|
||||
oauth2_token = "super secret token"
|
||||
# base_url (optional) is the URL at which your GitHub Enterprise Server can be accessed.
|
||||
# If these credentials are for github.com, leave this setting blank
|
||||
base_url = "https://ghe.example.com"
|
||||
# api_base_url (optional) is the base URL where the GitHub Enterprise Server API can be accessed.
|
||||
# Leave this blank if these credentials are for github.com.
|
||||
api_base_url = "https://ghe.example.com"
|
||||
# upload_base_url (optional) is the base URL where the GitHub Enterprise Server upload API can be accessed.
|
||||
# Leave this blank if these credentials are for github.com, or if you don't have a separate URL
|
||||
# for the upload API.
|
||||
upload_base_url = "https://api.ghe.example.com"
|
||||
# ca_cert_bundle (optional) is the CA certificate bundle in PEM format that will be used by the github
|
||||
# client to talk to the API. This bundle will also be sent to all runners as bootstrap params.
|
||||
# Use this option if you're using a self signed certificate.
|
||||
# Leave this blank if you're using github.com or if your certificare is signed by a valid CA.
|
||||
ca_cert_bundle = "/etc/garm/ghe.crt"
|
||||
```
|
||||
|
||||
The double paranthesis means that this is an array. You can specify the ```[[github]]``` section multiple times, with different tokens from different users, or with different access levels. You will then be able to list the available credentials using the API, and reference these credentials when adding repositories or organizations.
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ Pools are objects that define one type of worker and rules by which that pool of
|
|||
Before we can create a pool, we need to list the available providers. Providers are defined in the config (see above), but we need to reference them by name in the pool.
|
||||
|
||||
```bash
|
||||
ubuntu@experiments:~$ garm-cli provider list
|
||||
ubuntu@experiments:~$ garm-cli provider list
|
||||
+-----------+------------------------+------+
|
||||
| NAME | DESCRIPTION | TYPE |
|
||||
+-----------+------------------------+------+
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -6,7 +6,7 @@ require (
|
|||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/go-github/v43 v43.0.0
|
||||
github.com/google/go-github/v48 v48.0.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
|
|
|
|||
7
go.sum
7
go.sum
|
|
@ -116,9 +116,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U=
|
||||
github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-github/v48 v48.0.0 h1:9H5fWVXFK6ZsRriyPbjtnFAkJnoj0WKFtTYfpCRrTm8=
|
||||
github.com/google/go-github/v48 v48.0.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
|
|
@ -438,7 +438,6 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
"garm/runner/providers/common"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
|
|
@ -98,6 +98,8 @@ type BootstrapInstance struct {
|
|||
// provider supports it.
|
||||
SSHKeys []string `json:"ssh-keys"`
|
||||
|
||||
CACertBundle []byte `json:"ca-cert-bundle"`
|
||||
|
||||
OSArch config.OSArch `json:"arch"`
|
||||
Flavor string `json:"flavor"`
|
||||
Image string `json:"image"`
|
||||
|
|
@ -126,6 +128,8 @@ type Pool struct {
|
|||
RepoName string `json:"repo_name,omitempty"`
|
||||
OrgID string `json:"org_id,omitempty"`
|
||||
OrgName string `json:"org_name,omitempty"`
|
||||
EnterpriseID string `json:"enterprise_id,omitempty"`
|
||||
EnterpriseName string `json:"enterprise_name,omitempty"`
|
||||
RunnerBootstrapTimeout uint `json:"runner_bootstrap_timeout"`
|
||||
}
|
||||
|
||||
|
|
@ -141,23 +145,38 @@ type Internal struct {
|
|||
ControllerID string `json:"controller_id"`
|
||||
InstanceCallbackURL string `json:"instance_callback_url"`
|
||||
JWTSecret string `json:"jwt_secret"`
|
||||
// GithubCredentialsDetails contains all info about the credentials, except the
|
||||
// token, which is added above.
|
||||
GithubCredentialsDetails GithubCredentials `json:"gh_creds_details"`
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
ID string `json:"id"`
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
Pools []Pool `json:"pool,omitempty"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
ID string `json:"id"`
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
Pools []Pool `json:"pool,omitempty"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
PoolManagerStatus PoolManagerStatus `json:"pool_manager_status,omitempty"`
|
||||
// Do not serialize sensitive info.
|
||||
WebhookSecret string `json:"-"`
|
||||
}
|
||||
|
||||
type Organization struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pools []Pool `json:"pool,omitempty"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pools []Pool `json:"pool,omitempty"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
PoolManagerStatus PoolManagerStatus `json:"pool_manager_status,omitempty"`
|
||||
// Do not serialize sensitive info.
|
||||
WebhookSecret string `json:"-"`
|
||||
}
|
||||
|
||||
type Enterprise struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pools []Pool `json:"pool,omitempty"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
PoolManagerStatus PoolManagerStatus `json:"pool_manager_status,omitempty"`
|
||||
// Do not serialize sensitive info.
|
||||
WebhookSecret string `json:"-"`
|
||||
}
|
||||
|
|
@ -186,8 +205,12 @@ type ControllerInfo struct {
|
|||
}
|
||||
|
||||
type GithubCredentials struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
BaseURL string `json:"base_url"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
UploadBaseURL string `json:"upload_base_url"`
|
||||
CABundle []byte `json:"ca_bundle,omitempty"`
|
||||
}
|
||||
|
||||
type Provider struct {
|
||||
|
|
@ -199,3 +222,8 @@ type Provider struct {
|
|||
type UpdatePoolStateParams struct {
|
||||
WebhookSecret string
|
||||
}
|
||||
|
||||
type PoolManagerStatus struct {
|
||||
IsRunning bool `json:"running"`
|
||||
FailureReason string `json:"failure_reason,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,23 @@ func (c *CreateOrgParams) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type CreateEnterpriseParams struct {
|
||||
Name string `json:"name"`
|
||||
CredentialsName string `json:"credentials_name"`
|
||||
WebhookSecret string `json:"webhook_secret"`
|
||||
}
|
||||
|
||||
func (c *CreateEnterpriseParams) Validate() error {
|
||||
if c.Name == "" {
|
||||
return errors.NewBadRequestError("missing org name")
|
||||
}
|
||||
|
||||
if c.CredentialsName == "" {
|
||||
return errors.NewBadRequestError("missing credentials name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUserParams holds the needed information to create
|
||||
// a new user
|
||||
type NewUserParams struct {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ package mocks
|
|||
import (
|
||||
context "context"
|
||||
|
||||
github "github.com/google/go-github/v43/github"
|
||||
github "github.com/google/go-github/v48/github"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
|
|
@ -78,6 +78,38 @@ func (_m *GithubClient) CreateRegistrationToken(ctx context.Context, owner strin
|
|||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// GetWorkflowJobByID provides a mock function with given fields: ctx, owner, repo, jobID
|
||||
func (_m *GithubClient) GetWorkflowJobByID(ctx context.Context, owner string, repo string, jobID int64) (*github.WorkflowJob, *github.Response, error) {
|
||||
ret := _m.Called(ctx, owner, repo, jobID)
|
||||
|
||||
var r0 *github.WorkflowJob
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, int64) *github.WorkflowJob); ok {
|
||||
r0 = rf(ctx, owner, repo, jobID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*github.WorkflowJob)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *github.Response
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, int64) *github.Response); ok {
|
||||
r1 = rf(ctx, owner, repo, jobID)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*github.Response)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, string, string, int64) error); ok {
|
||||
r2 = rf(ctx, owner, repo, jobID)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListOrganizationRunnerApplicationDownloads provides a mock function with given fields: ctx, owner
|
||||
func (_m *GithubClient) ListOrganizationRunnerApplicationDownloads(ctx context.Context, owner string) ([]*github.RunnerApplicationDownload, *github.Response, error) {
|
||||
ret := _m.Called(ctx, owner)
|
||||
|
|
|
|||
149
runner/common/mocks/GithubEnterpriseClient.go
Normal file
149
runner/common/mocks/GithubEnterpriseClient.go
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
github "github.com/google/go-github/v48/github"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// GithubEnterpriseClient is an autogenerated mock type for the GithubEnterpriseClient type
|
||||
type GithubEnterpriseClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateRegistrationToken provides a mock function with given fields: ctx, enterprise
|
||||
func (_m *GithubEnterpriseClient) CreateRegistrationToken(ctx context.Context, enterprise string) (*github.RegistrationToken, *github.Response, error) {
|
||||
ret := _m.Called(ctx, enterprise)
|
||||
|
||||
var r0 *github.RegistrationToken
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) *github.RegistrationToken); ok {
|
||||
r0 = rf(ctx, enterprise)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*github.RegistrationToken)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *github.Response
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok {
|
||||
r1 = rf(ctx, enterprise)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*github.Response)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
|
||||
r2 = rf(ctx, enterprise)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListRunnerApplicationDownloads provides a mock function with given fields: ctx, enterprise
|
||||
func (_m *GithubEnterpriseClient) ListRunnerApplicationDownloads(ctx context.Context, enterprise string) ([]*github.RunnerApplicationDownload, *github.Response, error) {
|
||||
ret := _m.Called(ctx, enterprise)
|
||||
|
||||
var r0 []*github.RunnerApplicationDownload
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []*github.RunnerApplicationDownload); ok {
|
||||
r0 = rf(ctx, enterprise)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*github.RunnerApplicationDownload)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *github.Response
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok {
|
||||
r1 = rf(ctx, enterprise)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*github.Response)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
|
||||
r2 = rf(ctx, enterprise)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListRunners provides a mock function with given fields: ctx, enterprise, opts
|
||||
func (_m *GithubEnterpriseClient) ListRunners(ctx context.Context, enterprise string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
|
||||
ret := _m.Called(ctx, enterprise, opts)
|
||||
|
||||
var r0 *github.Runners
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *github.ListOptions) *github.Runners); ok {
|
||||
r0 = rf(ctx, enterprise, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*github.Runners)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *github.Response
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, *github.ListOptions) *github.Response); ok {
|
||||
r1 = rf(ctx, enterprise, opts)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*github.Response)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, string, *github.ListOptions) error); ok {
|
||||
r2 = rf(ctx, enterprise, opts)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// RemoveRunner provides a mock function with given fields: ctx, enterprise, runnerID
|
||||
func (_m *GithubEnterpriseClient) RemoveRunner(ctx context.Context, enterprise string, runnerID int64) (*github.Response, error) {
|
||||
ret := _m.Called(ctx, enterprise, runnerID)
|
||||
|
||||
var r0 *github.Response
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, int64) *github.Response); ok {
|
||||
r0 = rf(ctx, enterprise, runnerID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*github.Response)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
|
||||
r1 = rf(ctx, enterprise, runnerID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewGithubEnterpriseClient interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewGithubEnterpriseClient creates a new instance of GithubEnterpriseClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewGithubEnterpriseClient(t mockConstructorTestingTNewGithubEnterpriseClient) *GithubEnterpriseClient {
|
||||
mock := &GithubEnterpriseClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
|
@ -83,6 +83,20 @@ func (_m *PoolManager) Start() error {
|
|||
return r0
|
||||
}
|
||||
|
||||
// Status provides a mock function with given fields:
|
||||
func (_m *PoolManager) Status() params.PoolManagerStatus {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 params.PoolManagerStatus
|
||||
if rf, ok := ret.Get(0).(func() params.PoolManagerStatus); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.PoolManagerStatus)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Stop provides a mock function with given fields:
|
||||
func (_m *PoolManager) Stop() error {
|
||||
ret := _m.Called()
|
||||
|
|
|
|||
|
|
@ -27,9 +27,19 @@ const (
|
|||
|
||||
PoolConsilitationInterval = 5 * time.Second
|
||||
PoolReapTimeoutInterval = 5 * time.Minute
|
||||
PoolToolUpdateInterval = 3 * time.Hour
|
||||
// Temporary tools download token is valid for 1 hour by default.
|
||||
// Set this to 15 minutes. This should allow enough time even on slow
|
||||
// clouds for the instance to spin up, download the tools and join gh.
|
||||
PoolToolUpdateInterval = 15 * time.Minute
|
||||
|
||||
// UnauthorizedBackoffTimer is the time we wait before making another request
|
||||
// after getting an unauthorized error from github. It is unlikely that a second
|
||||
// request will not receive the same error, unless the config is changed with new
|
||||
// credentials and garm is restarted.
|
||||
UnauthorizedBackoffTimer = 3 * time.Hour
|
||||
)
|
||||
|
||||
//go:generate mockery --all
|
||||
type PoolManager interface {
|
||||
ID() string
|
||||
WebhookSecret() string
|
||||
|
|
@ -41,5 +51,6 @@ type PoolManager interface {
|
|||
// PoolManager lifecycle functions. Start/stop pool.
|
||||
Start() error
|
||||
Stop() error
|
||||
Status() params.PoolManagerStatus
|
||||
Wait() error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"garm/params"
|
||||
)
|
||||
|
||||
//go:generate mockery --all
|
||||
type Provider interface {
|
||||
// CreateInstance creates a new compute instance in the provider.
|
||||
CreateInstance(ctx context.Context, bootstrapParams params.BootstrapInstance) (params.Instance, error)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package common
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
)
|
||||
|
||||
// GithubClient that describes the minimum list of functions we need to interact with github.
|
||||
// Allows for easier testing.
|
||||
//
|
||||
//go:generate mockery --all
|
||||
type GithubClient interface {
|
||||
// GetWorkflowJobByID gets details about a single workflow job.
|
||||
GetWorkflowJobByID(ctx context.Context, owner, repo string, jobID int64) (*github.WorkflowJob, *github.Response, error)
|
||||
|
|
@ -31,3 +33,15 @@ type GithubClient interface {
|
|||
// CreateOrganizationRegistrationToken creates a runner registration token for an organization.
|
||||
CreateOrganizationRegistrationToken(ctx context.Context, owner string) (*github.RegistrationToken, *github.Response, error)
|
||||
}
|
||||
|
||||
type GithubEnterpriseClient interface {
|
||||
// ListRunners lists all runners within a repository.
|
||||
ListRunners(ctx context.Context, enterprise string, opts *github.ListOptions) (*github.Runners, *github.Response, error)
|
||||
// RemoveRunner removes one runner from an enterprise.
|
||||
RemoveRunner(ctx context.Context, enterprise string, runnerID int64) (*github.Response, error)
|
||||
// CreateRegistrationToken creates a runner registration token for an enterprise.
|
||||
CreateRegistrationToken(ctx context.Context, enterprise string) (*github.RegistrationToken, *github.Response, error)
|
||||
// ListRunnerApplicationDownloads returns a list of github runner application downloads for the
|
||||
// various supported operating systems and architectures.
|
||||
ListRunnerApplicationDownloads(ctx context.Context, enterprise string) ([]*github.RunnerApplicationDownload, *github.Response, error)
|
||||
}
|
||||
|
|
|
|||
333
runner/enterprises.go
Normal file
333
runner/enterprises.go
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"garm/auth"
|
||||
"garm/config"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
"garm/runner/common"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterpriseParams) (enterprise params.Enterprise, err error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return enterprise, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
err = param.Validate()
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "validating params")
|
||||
}
|
||||
|
||||
creds, ok := r.credentials[param.CredentialsName]
|
||||
if !ok {
|
||||
return params.Enterprise{}, runnerErrors.NewBadRequestError("credentials %s not defined", param.CredentialsName)
|
||||
}
|
||||
|
||||
_, err = r.store.GetEnterprise(ctx, param.Name)
|
||||
if err != nil {
|
||||
if !errors.Is(err, runnerErrors.ErrNotFound) {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
} else {
|
||||
return params.Enterprise{}, runnerErrors.NewConflictError("enterprise %s already exists", param.Name)
|
||||
}
|
||||
|
||||
enterprise, err = r.store.CreateEnterprise(ctx, param.Name, creds.Name, param.WebhookSecret)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "creating enterprise")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
r.store.DeleteEnterprise(ctx, enterprise.ID)
|
||||
}
|
||||
}()
|
||||
|
||||
var poolMgr common.PoolManager
|
||||
poolMgr, err = r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "creating enterprise pool manager")
|
||||
}
|
||||
if err := poolMgr.Start(); err != nil {
|
||||
if deleteErr := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); deleteErr != nil {
|
||||
log.Printf("failed to cleanup pool manager for enterprise %s", enterprise.ID)
|
||||
}
|
||||
return params.Enterprise{}, errors.Wrap(err, "starting enterprise pool manager")
|
||||
}
|
||||
return enterprise, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListEnterprises(ctx context.Context) ([]params.Enterprise, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
enterprises, err := r.store.ListEnterprises(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "listing enterprises")
|
||||
}
|
||||
|
||||
var allEnterprises []params.Enterprise
|
||||
|
||||
for _, enterprise := range enterprises {
|
||||
poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
|
||||
if err != nil {
|
||||
enterprise.PoolManagerStatus.IsRunning = false
|
||||
enterprise.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
} else {
|
||||
enterprise.PoolManagerStatus = poolMgr.Status()
|
||||
}
|
||||
allEnterprises = append(allEnterprises, enterprise)
|
||||
}
|
||||
|
||||
return allEnterprises, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetEnterpriseByID(ctx context.Context, enterpriseID string) (params.Enterprise, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Enterprise{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
|
||||
if err != nil {
|
||||
enterprise.PoolManagerStatus.IsRunning = false
|
||||
enterprise.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
}
|
||||
enterprise.PoolManagerStatus = poolMgr.Status()
|
||||
return enterprise, nil
|
||||
}
|
||||
|
||||
func (r *Runner) DeleteEnterprise(ctx context.Context, enterpriseID string) error {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
pools, err := r.store.ListEnterprisePools(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching enterprise pools")
|
||||
}
|
||||
|
||||
if len(pools) > 0 {
|
||||
poolIds := []string{}
|
||||
for _, pool := range pools {
|
||||
poolIds = append(poolIds, pool.ID)
|
||||
}
|
||||
|
||||
return runnerErrors.NewBadRequestError("enterprise has pools defined (%s)", strings.Join(poolIds, ", "))
|
||||
}
|
||||
|
||||
if err := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); err != nil {
|
||||
return errors.Wrap(err, "deleting enterprise pool manager")
|
||||
}
|
||||
|
||||
if err := r.store.DeleteEnterprise(ctx, enterpriseID); err != nil {
|
||||
return errors.Wrapf(err, "removing enterprise %s", enterpriseID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) UpdateEnterprise(ctx context.Context, enterpriseID string, param params.UpdateRepositoryParams) (params.Enterprise, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Enterprise{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
if param.CredentialsName != "" {
|
||||
// Check that credentials are set before saving to db
|
||||
if _, ok := r.credentials[param.CredentialsName]; !ok {
|
||||
return params.Enterprise{}, runnerErrors.NewBadRequestError("invalid credentials (%s) for enterprise %s", param.CredentialsName, enterprise.Name)
|
||||
}
|
||||
}
|
||||
|
||||
enterprise, err = r.store.UpdateEnterprise(ctx, enterpriseID, param)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "updating enterprise")
|
||||
}
|
||||
|
||||
poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
|
||||
if err != nil {
|
||||
newState := params.UpdatePoolStateParams{
|
||||
WebhookSecret: enterprise.WebhookSecret,
|
||||
}
|
||||
// stop the pool mgr
|
||||
if err := poolMgr.RefreshState(newState); err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "updating enterprise pool manager")
|
||||
}
|
||||
} else {
|
||||
if _, err := r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store); err != nil {
|
||||
return params.Enterprise{}, errors.Wrap(err, "creating enterprise pool manager")
|
||||
}
|
||||
}
|
||||
|
||||
return enterprise, nil
|
||||
}
|
||||
|
||||
func (r *Runner) CreateEnterprisePool(ctx context.Context, enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
if _, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise); err != nil {
|
||||
return params.Pool{}, runnerErrors.ErrNotFound
|
||||
}
|
||||
|
||||
createPoolParams, err := r.appendTagsToCreatePoolParams(param)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool params")
|
||||
}
|
||||
|
||||
if param.RunnerBootstrapTimeout == 0 {
|
||||
param.RunnerBootstrapTimeout = config.DefaultRunnerBootstrapTimeout
|
||||
}
|
||||
|
||||
pool, err := r.store.CreateEnterprisePool(ctx, enterpriseID, createPoolParams)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "creating pool")
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetEnterprisePoolByID(ctx context.Context, enterpriseID, poolID string) (params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
pool, err := r.store.GetEnterprisePool(ctx, enterpriseID, poolID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID string) error {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
// TODO: dedup instance count verification
|
||||
pool, err := r.store.GetEnterprisePool(ctx, enterpriseID, poolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
instances, err := r.store.ListPoolInstances(ctx, pool.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
|
||||
// TODO: implement a count function
|
||||
if len(instances) > 0 {
|
||||
runnerIDs := []string{}
|
||||
for _, run := range instances {
|
||||
runnerIDs = append(runnerIDs, run.ID)
|
||||
}
|
||||
return runnerErrors.NewBadRequestError("pool has runners: %s", strings.Join(runnerIDs, ", "))
|
||||
}
|
||||
|
||||
if err := r.store.DeleteEnterprisePool(ctx, enterpriseID, poolID); err != nil {
|
||||
return errors.Wrap(err, "deleting pool")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListEnterprisePools(ctx context.Context, enterpriseID string) ([]params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return []params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
pools, err := r.store.ListEnterprisePools(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pools")
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
|
||||
func (r *Runner) UpdateEnterprisePool(ctx context.Context, enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.Pool{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
pool, err := r.store.GetEnterprisePool(ctx, enterpriseID, poolID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
|
||||
maxRunners := pool.MaxRunners
|
||||
minIdleRunners := pool.MinIdleRunners
|
||||
|
||||
if param.MaxRunners != nil {
|
||||
maxRunners = *param.MaxRunners
|
||||
}
|
||||
if param.MinIdleRunners != nil {
|
||||
minIdleRunners = *param.MinIdleRunners
|
||||
}
|
||||
|
||||
if minIdleRunners > maxRunners {
|
||||
return params.Pool{}, runnerErrors.NewBadRequestError("min_idle_runners cannot be larger than max_runners")
|
||||
}
|
||||
|
||||
newPool, err := r.store.UpdateEnterprisePool(ctx, enterpriseID, poolID, param)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "updating pool")
|
||||
}
|
||||
return newPool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListEnterpriseInstances(ctx context.Context, enterpriseID string) ([]params.Instance, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
instances, err := r.store.ListEnterpriseInstances(ctx, enterpriseID)
|
||||
if err != nil {
|
||||
return []params.Instance{}, errors.Wrap(err, "fetching instances")
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func (r *Runner) findEnterprisePoolManager(name string) (common.PoolManager, error) {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
enterprise, err := r.store.GetEnterprise(r.ctx, name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
|
||||
poolManager, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pool manager for enterprise")
|
||||
}
|
||||
return poolManager, nil
|
||||
}
|
||||
|
|
@ -21,16 +21,31 @@ import (
|
|||
"garm/runner/common"
|
||||
)
|
||||
|
||||
//go:generate mockery --name=PoolManagerController
|
||||
|
||||
type PoolManagerController interface {
|
||||
type RepoPoolManager interface {
|
||||
CreateRepoPoolManager(ctx context.Context, repo params.Repository, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error)
|
||||
GetRepoPoolManager(repo params.Repository) (common.PoolManager, error)
|
||||
DeleteRepoPoolManager(repo params.Repository) error
|
||||
GetRepoPoolManagers() (map[string]common.PoolManager, error)
|
||||
}
|
||||
|
||||
type OrgPoolManager interface {
|
||||
CreateOrgPoolManager(ctx context.Context, org params.Organization, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error)
|
||||
GetOrgPoolManager(org params.Organization) (common.PoolManager, error)
|
||||
DeleteOrgPoolManager(org params.Organization) error
|
||||
GetOrgPoolManagers() (map[string]common.PoolManager, error)
|
||||
}
|
||||
|
||||
type EnterprisePoolManager interface {
|
||||
CreateEnterprisePoolManager(ctx context.Context, enterprise params.Enterprise, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error)
|
||||
GetEnterprisePoolManager(enterprise params.Enterprise) (common.PoolManager, error)
|
||||
DeleteEnterprisePoolManager(enterprise params.Enterprise) error
|
||||
GetEnterprisePoolManagers() (map[string]common.PoolManager, error)
|
||||
}
|
||||
|
||||
//go:generate mockery --name=PoolManagerController
|
||||
|
||||
type PoolManagerController interface {
|
||||
RepoPoolManager
|
||||
OrgPoolManager
|
||||
EnterprisePoolManager
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,29 @@ type PoolManagerController struct {
|
|||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateEnterprisePoolManager provides a mock function with given fields: ctx, enterprise, providers, store
|
||||
func (_m *PoolManagerController) CreateEnterprisePoolManager(ctx context.Context, enterprise params.Enterprise, providers map[string]common.Provider, store databasecommon.Store) (common.PoolManager, error) {
|
||||
ret := _m.Called(ctx, enterprise, providers, store)
|
||||
|
||||
var r0 common.PoolManager
|
||||
if rf, ok := ret.Get(0).(func(context.Context, params.Enterprise, map[string]common.Provider, databasecommon.Store) common.PoolManager); ok {
|
||||
r0 = rf(ctx, enterprise, providers, store)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(common.PoolManager)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, params.Enterprise, map[string]common.Provider, databasecommon.Store) error); ok {
|
||||
r1 = rf(ctx, enterprise, providers, store)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateOrgPoolManager provides a mock function with given fields: ctx, org, providers, store
|
||||
func (_m *PoolManagerController) CreateOrgPoolManager(ctx context.Context, org params.Organization, providers map[string]common.Provider, store databasecommon.Store) (common.PoolManager, error) {
|
||||
ret := _m.Called(ctx, org, providers, store)
|
||||
|
|
@ -64,6 +87,20 @@ func (_m *PoolManagerController) CreateRepoPoolManager(ctx context.Context, repo
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteEnterprisePoolManager provides a mock function with given fields: enterprise
|
||||
func (_m *PoolManagerController) DeleteEnterprisePoolManager(enterprise params.Enterprise) error {
|
||||
ret := _m.Called(enterprise)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(params.Enterprise) error); ok {
|
||||
r0 = rf(enterprise)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteOrgPoolManager provides a mock function with given fields: org
|
||||
func (_m *PoolManagerController) DeleteOrgPoolManager(org params.Organization) error {
|
||||
ret := _m.Called(org)
|
||||
|
|
@ -92,6 +129,52 @@ func (_m *PoolManagerController) DeleteRepoPoolManager(repo params.Repository) e
|
|||
return r0
|
||||
}
|
||||
|
||||
// GetEnterprisePoolManager provides a mock function with given fields: enterprise
|
||||
func (_m *PoolManagerController) GetEnterprisePoolManager(enterprise params.Enterprise) (common.PoolManager, error) {
|
||||
ret := _m.Called(enterprise)
|
||||
|
||||
var r0 common.PoolManager
|
||||
if rf, ok := ret.Get(0).(func(params.Enterprise) common.PoolManager); ok {
|
||||
r0 = rf(enterprise)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(common.PoolManager)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(params.Enterprise) error); ok {
|
||||
r1 = rf(enterprise)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetEnterprisePoolManagers provides a mock function with given fields:
|
||||
func (_m *PoolManagerController) GetEnterprisePoolManagers() (map[string]common.PoolManager, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 map[string]common.PoolManager
|
||||
if rf, ok := ret.Get(0).(func() map[string]common.PoolManager); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]common.PoolManager)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetOrgPoolManager provides a mock function with given fields: org
|
||||
func (_m *PoolManagerController) GetOrgPoolManager(org params.Organization) (common.PoolManager, error) {
|
||||
ret := _m.Called(org)
|
||||
|
|
@ -16,6 +16,7 @@ package runner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
|
|
@ -85,7 +86,21 @@ func (r *Runner) ListOrganizations(ctx context.Context) ([]params.Organization,
|
|||
return nil, errors.Wrap(err, "listing organizations")
|
||||
}
|
||||
|
||||
return orgs, nil
|
||||
var allOrgs []params.Organization
|
||||
|
||||
for _, org := range orgs {
|
||||
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
|
||||
if err != nil {
|
||||
org.PoolManagerStatus.IsRunning = false
|
||||
org.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
} else {
|
||||
org.PoolManagerStatus = poolMgr.Status()
|
||||
}
|
||||
|
||||
allOrgs = append(allOrgs, org)
|
||||
}
|
||||
|
||||
return allOrgs, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetOrganizationByID(ctx context.Context, orgID string) (params.Organization, error) {
|
||||
|
|
@ -97,6 +112,13 @@ func (r *Runner) GetOrganizationByID(ctx context.Context, orgID string) (params.
|
|||
if err != nil {
|
||||
return params.Organization{}, errors.Wrap(err, "fetching organization")
|
||||
}
|
||||
|
||||
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
|
||||
if err != nil {
|
||||
org.PoolManagerStatus.IsRunning = false
|
||||
org.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
}
|
||||
org.PoolManagerStatus = poolMgr.Status()
|
||||
return org, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,8 @@ func (s *OrgTestSuite) TestCreateOrganizationStartPoolMgrFailed() {
|
|||
}
|
||||
|
||||
func (s *OrgTestSuite) TestListOrganizations() {
|
||||
s.Fixtures.PoolMgrCtrlMock.On("GetOrgPoolManager", mock.AnythingOfType("params.Organization")).Return(s.Fixtures.PoolMgrMock, nil)
|
||||
s.Fixtures.PoolMgrMock.On("Status").Return(params.PoolManagerStatus{IsRunning: true}, nil)
|
||||
orgs, err := s.Runner.ListOrganizations(s.Fixtures.AdminContext)
|
||||
|
||||
s.Require().Nil(err)
|
||||
|
|
@ -275,6 +277,8 @@ func (s *OrgTestSuite) TestListOrganizationsErrUnauthorized() {
|
|||
}
|
||||
|
||||
func (s *OrgTestSuite) TestGetOrganizationByID() {
|
||||
s.Fixtures.PoolMgrCtrlMock.On("GetOrgPoolManager", mock.AnythingOfType("params.Organization")).Return(s.Fixtures.PoolMgrMock, nil)
|
||||
s.Fixtures.PoolMgrMock.On("Status").Return(params.PoolManagerStatus{IsRunning: true}, nil)
|
||||
org, err := s.Runner.GetOrganizationByID(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-1"].ID)
|
||||
|
||||
s.Require().Nil(err)
|
||||
|
|
|
|||
207
runner/pool/enterprise.go
Normal file
207
runner/pool/enterprise.go
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
package pool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
dbCommon "garm/database/common"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
"garm/runner/common"
|
||||
"garm/util"
|
||||
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// test that we implement PoolManager
|
||||
var _ poolHelper = &organization{}
|
||||
|
||||
func NewEnterprisePoolManager(ctx context.Context, cfg params.Enterprise, cfgInternal params.Internal, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) {
|
||||
ghc, ghEnterpriseClient, err := util.GithubClient(ctx, cfgInternal.OAuth2Token, cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting github client")
|
||||
}
|
||||
|
||||
helper := &enterprise{
|
||||
cfg: cfg,
|
||||
cfgInternal: cfgInternal,
|
||||
ctx: ctx,
|
||||
ghcli: ghc,
|
||||
ghcEnterpriseCli: ghEnterpriseClient,
|
||||
id: cfg.ID,
|
||||
store: store,
|
||||
}
|
||||
|
||||
repo := &basePoolManager{
|
||||
ctx: ctx,
|
||||
store: store,
|
||||
providers: providers,
|
||||
controllerID: cfgInternal.ControllerID,
|
||||
quit: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
helper: helper,
|
||||
credsDetails: cfgInternal.GithubCredentialsDetails,
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
type enterprise struct {
|
||||
cfg params.Enterprise
|
||||
cfgInternal params.Internal
|
||||
ctx context.Context
|
||||
ghcli common.GithubClient
|
||||
ghcEnterpriseCli common.GithubEnterpriseClient
|
||||
id string
|
||||
store dbCommon.Store
|
||||
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
func (r *enterprise) GetRunnerNameFromWorkflow(job params.WorkflowJob) (string, error) {
|
||||
workflow, ghResp, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Repository.Owner.Login, job.Repository.Name, job.WorkflowJob.ID)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners")
|
||||
}
|
||||
return "", errors.Wrap(err, "fetching workflow info")
|
||||
}
|
||||
if workflow.RunnerName != nil {
|
||||
return *workflow.RunnerName, nil
|
||||
}
|
||||
return "", fmt.Errorf("failed to find runner name from workflow")
|
||||
}
|
||||
|
||||
func (r *enterprise) UpdateState(param params.UpdatePoolStateParams) error {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
r.cfg.WebhookSecret = param.WebhookSecret
|
||||
|
||||
ghc, ghcEnterprise, err := util.GithubClient(r.ctx, r.GetGithubToken(), r.cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting github client")
|
||||
}
|
||||
r.ghcli = ghc
|
||||
r.ghcEnterpriseCli = ghcEnterprise
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *enterprise) GetGithubToken() string {
|
||||
return r.cfgInternal.OAuth2Token
|
||||
}
|
||||
|
||||
func (r *enterprise) GetGithubRunners() ([]*github.Runner, error) {
|
||||
opts := github.ListOptions{
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
var allRunners []*github.Runner
|
||||
for {
|
||||
runners, ghResp, err := r.ghcEnterpriseCli.ListRunners(r.ctx, r.cfg.Name, &opts)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runners")
|
||||
}
|
||||
allRunners = append(allRunners, runners.Runners...)
|
||||
if ghResp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
opts.Page = ghResp.NextPage
|
||||
}
|
||||
return allRunners, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) FetchTools() ([]*github.RunnerApplicationDownload, error) {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
tools, ghResp, err := r.ghcEnterpriseCli.ListRunnerApplicationDownloads(r.ctx, r.cfg.Name)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runner tools")
|
||||
}
|
||||
|
||||
return tools, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) FetchDbInstances() ([]params.Instance, error) {
|
||||
return r.store.ListEnterpriseInstances(r.ctx, r.id)
|
||||
}
|
||||
|
||||
func (r *enterprise) RemoveGithubRunner(runnerID int64) (*github.Response, error) {
|
||||
return r.ghcEnterpriseCli.RemoveRunner(r.ctx, r.cfg.Name, runnerID)
|
||||
}
|
||||
|
||||
func (r *enterprise) ListPools() ([]params.Pool, error) {
|
||||
pools, err := r.store.ListEnterprisePools(r.ctx, r.id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching pools")
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) GithubURL() string {
|
||||
return fmt.Sprintf("%s/enterprises/%s", r.cfgInternal.GithubCredentialsDetails.BaseURL, r.cfg.Name)
|
||||
}
|
||||
|
||||
func (r *enterprise) JwtToken() string {
|
||||
return r.cfgInternal.JWTSecret
|
||||
}
|
||||
|
||||
func (r *enterprise) GetGithubRegistrationToken() (string, error) {
|
||||
tk, ghResp, err := r.ghcEnterpriseCli.CreateRegistrationToken(r.ctx, r.cfg.Name)
|
||||
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching registration token")
|
||||
}
|
||||
return "", errors.Wrap(err, "creating runner token")
|
||||
}
|
||||
return *tk.Token, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) String() string {
|
||||
return r.cfg.Name
|
||||
}
|
||||
|
||||
func (r *enterprise) WebhookSecret() string {
|
||||
return r.cfg.WebhookSecret
|
||||
}
|
||||
|
||||
func (r *enterprise) GetCallbackURL() string {
|
||||
return r.cfgInternal.InstanceCallbackURL
|
||||
}
|
||||
|
||||
func (r *enterprise) FindPoolByTags(labels []string) (params.Pool, error) {
|
||||
pool, err := r.store.FindEnterprisePoolByTags(r.ctx, r.id, labels)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching suitable pool")
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) GetPoolByID(poolID string) (params.Pool, error) {
|
||||
pool, err := r.store.GetEnterprisePool(r.ctx, r.id, poolID)
|
||||
if err != nil {
|
||||
return params.Pool{}, errors.Wrap(err, "fetching pool")
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (r *enterprise) ValidateOwner(job params.WorkflowJob) error {
|
||||
if !strings.EqualFold(job.Enterprise.Slug, r.cfg.Name) {
|
||||
return runnerErrors.NewBadRequestError("job not meant for this pool manager")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *enterprise) ID() string {
|
||||
return r.id
|
||||
}
|
||||
|
|
@ -17,19 +17,21 @@ package pool
|
|||
import (
|
||||
"garm/params"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
)
|
||||
|
||||
type poolHelper interface {
|
||||
GetGithubToken() string
|
||||
GetGithubRunners() ([]*github.Runner, error)
|
||||
FetchTools() ([]*github.RunnerApplicationDownload, error)
|
||||
FetchDbInstances() ([]params.Instance, error)
|
||||
GetGithubRegistrationToken() (string, error)
|
||||
GetRunnerNameFromWorkflow(job params.WorkflowJob) (string, error)
|
||||
RemoveGithubRunner(runnerID int64) (*github.Response, error)
|
||||
FetchTools() ([]*github.RunnerApplicationDownload, error)
|
||||
|
||||
FetchDbInstances() ([]params.Instance, error)
|
||||
ListPools() ([]params.Pool, error)
|
||||
GithubURL() string
|
||||
JwtToken() string
|
||||
GetGithubRegistrationToken() (string, error)
|
||||
String() string
|
||||
GetCallbackURL() string
|
||||
FindPoolByTags(labels []string) (params.Pool, error)
|
||||
|
|
@ -37,6 +39,5 @@ type poolHelper interface {
|
|||
ValidateOwner(job params.WorkflowJob) error
|
||||
UpdateState(param params.UpdatePoolStateParams) error
|
||||
WebhookSecret() string
|
||||
GetRunnerNameFromWorkflow(job params.WorkflowJob) (string, error)
|
||||
ID() string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ package pool
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"garm/config"
|
||||
dbCommon "garm/database/common"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
"garm/runner/common"
|
||||
"garm/util"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ import (
|
|||
var _ poolHelper = &organization{}
|
||||
|
||||
func NewOrganizationPoolManager(ctx context.Context, cfg params.Organization, cfgInternal params.Internal, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) {
|
||||
ghc, err := util.GithubClient(ctx, cfgInternal.OAuth2Token)
|
||||
ghc, _, err := util.GithubClient(ctx, cfgInternal.OAuth2Token, cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting github client")
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func NewOrganizationPoolManager(ctx context.Context, cfg params.Organization, cf
|
|||
store: store,
|
||||
}
|
||||
|
||||
repo := &basePool{
|
||||
repo := &basePoolManager{
|
||||
ctx: ctx,
|
||||
store: store,
|
||||
providers: providers,
|
||||
|
|
@ -57,6 +57,7 @@ func NewOrganizationPoolManager(ctx context.Context, cfg params.Organization, cf
|
|||
quit: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
helper: helper,
|
||||
credsDetails: cfgInternal.GithubCredentialsDetails,
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
|
@ -73,8 +74,11 @@ type organization struct {
|
|||
}
|
||||
|
||||
func (r *organization) GetRunnerNameFromWorkflow(job params.WorkflowJob) (string, error) {
|
||||
workflow, _, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Organization.Login, job.Repository.Name, job.WorkflowJob.ID)
|
||||
workflow, ghResp, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Organization.Login, job.Repository.Name, job.WorkflowJob.ID)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runner name")
|
||||
}
|
||||
return "", errors.Wrap(err, "fetching workflow info")
|
||||
}
|
||||
if workflow.RunnerName != nil {
|
||||
|
|
@ -89,7 +93,7 @@ func (r *organization) UpdateState(param params.UpdatePoolStateParams) error {
|
|||
|
||||
r.cfg.WebhookSecret = param.WebhookSecret
|
||||
|
||||
ghc, err := util.GithubClient(r.ctx, r.GetGithubToken())
|
||||
ghc, _, err := util.GithubClient(r.ctx, r.GetGithubToken(), r.cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting github client")
|
||||
}
|
||||
|
|
@ -102,19 +106,37 @@ func (r *organization) GetGithubToken() string {
|
|||
}
|
||||
|
||||
func (r *organization) GetGithubRunners() ([]*github.Runner, error) {
|
||||
runners, _, err := r.ghcli.ListOrganizationRunners(r.ctx, r.cfg.Name, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching runners")
|
||||
opts := github.ListOptions{
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
return runners.Runners, nil
|
||||
var allRunners []*github.Runner
|
||||
for {
|
||||
runners, ghResp, err := r.ghcli.ListOrganizationRunners(r.ctx, r.cfg.Name, &opts)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runners")
|
||||
}
|
||||
allRunners = append(allRunners, runners.Runners...)
|
||||
if ghResp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
opts.Page = ghResp.NextPage
|
||||
}
|
||||
|
||||
return allRunners, nil
|
||||
}
|
||||
|
||||
func (r *organization) FetchTools() ([]*github.RunnerApplicationDownload, error) {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
tools, _, err := r.ghcli.ListOrganizationRunnerApplicationDownloads(r.ctx, r.cfg.Name)
|
||||
tools, ghResp, err := r.ghcli.ListOrganizationRunnerApplicationDownloads(r.ctx, r.cfg.Name)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching tools")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runner tools")
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +160,7 @@ func (r *organization) ListPools() ([]params.Pool, error) {
|
|||
}
|
||||
|
||||
func (r *organization) GithubURL() string {
|
||||
return fmt.Sprintf("%s/%s", config.GithubBaseURL, r.cfg.Name)
|
||||
return fmt.Sprintf("%s/%s", r.cfgInternal.GithubCredentialsDetails.BaseURL, r.cfg.Name)
|
||||
}
|
||||
|
||||
func (r *organization) JwtToken() string {
|
||||
|
|
@ -146,9 +168,13 @@ func (r *organization) JwtToken() string {
|
|||
}
|
||||
|
||||
func (r *organization) GetGithubRegistrationToken() (string, error) {
|
||||
tk, _, err := r.ghcli.CreateOrganizationRegistrationToken(r.ctx, r.cfg.Name)
|
||||
tk, ghResp, err := r.ghcli.CreateOrganizationRegistrationToken(r.ctx, r.cfg.Name)
|
||||
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching token")
|
||||
}
|
||||
|
||||
return "", errors.Wrap(err, "creating runner token")
|
||||
}
|
||||
return *tk.Token, nil
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
"garm/runner/common"
|
||||
providerCommon "garm/runner/providers/common"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -47,7 +47,7 @@ const (
|
|||
maxCreateAttempts = 5
|
||||
)
|
||||
|
||||
type basePool struct {
|
||||
type basePoolManager struct {
|
||||
ctx context.Context
|
||||
controllerID string
|
||||
|
||||
|
|
@ -58,7 +58,11 @@ type basePool struct {
|
|||
quit chan struct{}
|
||||
done chan struct{}
|
||||
|
||||
helper poolHelper
|
||||
helper poolHelper
|
||||
credsDetails params.GithubCredentials
|
||||
|
||||
managerIsRunning bool
|
||||
managerErrorReason string
|
||||
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
|
@ -80,7 +84,7 @@ func controllerIDFromLabels(labels []*github.RunnerLabels) string {
|
|||
// happens, github will remove the ephemeral worker and send a webhook our way.
|
||||
// If we were offline and did not process the webhook, the instance will linger.
|
||||
// We need to remove it from the provider and database.
|
||||
func (r *basePool) cleanupOrphanedProviderRunners(runners []*github.Runner) error {
|
||||
func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runner) error {
|
||||
dbInstances, err := r.helper.FetchDbInstances()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances from db")
|
||||
|
|
@ -115,7 +119,7 @@ func (r *basePool) cleanupOrphanedProviderRunners(runners []*github.Runner) erro
|
|||
// reapTimedOutRunners will mark as pending_delete any runner that has a status
|
||||
// of "running" in the provider, but that has not registered with Github, and has
|
||||
// received no new updates in the configured timeout interval.
|
||||
func (r *basePool) reapTimedOutRunners(runners []*github.Runner) error {
|
||||
func (r *basePoolManager) reapTimedOutRunners(runners []*github.Runner) error {
|
||||
dbInstances, err := r.helper.FetchDbInstances()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instances from db")
|
||||
|
|
@ -151,7 +155,7 @@ func (r *basePool) reapTimedOutRunners(runners []*github.Runner) error {
|
|||
// as offline and for which we no longer have a local instance.
|
||||
// This may happen if someone manually deletes the instance in the provider. We need to
|
||||
// first remove the instance from github, and then from our database.
|
||||
func (r *basePool) cleanupOrphanedGithubRunners(runners []*github.Runner) error {
|
||||
func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner) error {
|
||||
for _, runner := range runners {
|
||||
runnerControllerID := controllerIDFromLabels(runner.Labels)
|
||||
if runnerControllerID != r.controllerID {
|
||||
|
|
@ -179,6 +183,13 @@ func (r *basePool) cleanupOrphanedGithubRunners(runners []*github.Runner) error
|
|||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
continue
|
||||
}
|
||||
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
failureReason := fmt.Sprintf("failed to remove github runner: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "removing runner")
|
||||
}
|
||||
continue
|
||||
|
|
@ -216,6 +227,12 @@ func (r *basePool) cleanupOrphanedGithubRunners(runners []*github.Runner) error
|
|||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
log.Printf("runner dissapeared from github")
|
||||
} else {
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
failureReason := fmt.Sprintf("failed to remove github runner: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "removing runner from github")
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +259,7 @@ func (r *basePool) cleanupOrphanedGithubRunners(runners []*github.Runner) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) fetchInstance(runnerName string) (params.Instance, error) {
|
||||
func (r *basePoolManager) fetchInstance(runnerName string) (params.Instance, error) {
|
||||
runner, err := r.store.GetInstanceByName(r.ctx, runnerName)
|
||||
if err != nil {
|
||||
return params.Instance{}, errors.Wrap(err, "fetching instance")
|
||||
|
|
@ -251,7 +268,7 @@ func (r *basePool) fetchInstance(runnerName string) (params.Instance, error) {
|
|||
return runner, nil
|
||||
}
|
||||
|
||||
func (r *basePool) setInstanceRunnerStatus(runnerName string, status providerCommon.RunnerStatus) error {
|
||||
func (r *basePoolManager) setInstanceRunnerStatus(runnerName string, status providerCommon.RunnerStatus) error {
|
||||
updateParams := params.UpdateInstanceParams{
|
||||
RunnerStatus: status,
|
||||
}
|
||||
|
|
@ -262,7 +279,7 @@ func (r *basePool) setInstanceRunnerStatus(runnerName string, status providerCom
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) updateInstance(runnerName string, update params.UpdateInstanceParams) error {
|
||||
func (r *basePoolManager) updateInstance(runnerName string, update params.UpdateInstanceParams) error {
|
||||
runner, err := r.fetchInstance(runnerName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching instance")
|
||||
|
|
@ -274,7 +291,7 @@ func (r *basePool) updateInstance(runnerName string, update params.UpdateInstanc
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) setInstanceStatus(runnerName string, status providerCommon.InstanceStatus, providerFault []byte) error {
|
||||
func (r *basePoolManager) setInstanceStatus(runnerName string, status providerCommon.InstanceStatus, providerFault []byte) error {
|
||||
updateParams := params.UpdateInstanceParams{
|
||||
Status: status,
|
||||
ProviderFault: providerFault,
|
||||
|
|
@ -286,7 +303,7 @@ func (r *basePool) setInstanceStatus(runnerName string, status providerCommon.In
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) acquireNewInstance(job params.WorkflowJob) error {
|
||||
func (r *basePoolManager) acquireNewInstance(job params.WorkflowJob) error {
|
||||
requestedLabels := job.WorkflowJob.Labels
|
||||
if len(requestedLabels) == 0 {
|
||||
// no labels were requested.
|
||||
|
|
@ -321,7 +338,7 @@ func (r *basePool) acquireNewInstance(job params.WorkflowJob) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) AddRunner(ctx context.Context, poolID string) error {
|
||||
func (r *basePoolManager) AddRunner(ctx context.Context, poolID string) error {
|
||||
pool, err := r.helper.GetPoolByID(poolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching pool")
|
||||
|
|
@ -347,19 +364,20 @@ func (r *basePool) AddRunner(ctx context.Context, poolID string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) loop() {
|
||||
func (r *basePoolManager) loop() {
|
||||
consolidateTimer := time.NewTicker(common.PoolConsilitationInterval)
|
||||
reapTimer := time.NewTicker(common.PoolReapTimeoutInterval)
|
||||
toolUpdateTimer := time.NewTicker(common.PoolToolUpdateInterval)
|
||||
defer func() {
|
||||
log.Printf("repository %s loop exited", r.helper.String())
|
||||
log.Printf("%s loop exited", r.helper.String())
|
||||
consolidateTimer.Stop()
|
||||
reapTimer.Stop()
|
||||
toolUpdateTimer.Stop()
|
||||
close(r.done)
|
||||
}()
|
||||
log.Printf("starting loop for %s", r.helper.String())
|
||||
// TODO: Consolidate runners on loop start. Provider runners must match runners
|
||||
|
||||
// Consolidate runners on loop start. Provider runners must match runners
|
||||
// in github and DB. When a Workflow job is received, we will first create/update
|
||||
// an entity in the database, before sending the request to the provider to create/delete
|
||||
// an instance. If a "queued" job is received, we create an entity in the db with
|
||||
|
|
@ -369,45 +387,114 @@ func (r *basePool) loop() {
|
|||
// in the database.
|
||||
// We also ensure we have runners created based on pool characteristics. This is where
|
||||
// we spin up "MinWorkers" for each runner type.
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-reapTimer.C:
|
||||
runners, err := r.helper.GetGithubRunners()
|
||||
if err != nil {
|
||||
log.Printf("error fetching github runners: %s", err)
|
||||
continue
|
||||
}
|
||||
if err := r.reapTimedOutRunners(runners); err != nil {
|
||||
log.Printf("failed to reap timed out runners: %q", err)
|
||||
}
|
||||
switch r.managerIsRunning {
|
||||
case true:
|
||||
select {
|
||||
case <-reapTimer.C:
|
||||
runners, err := r.helper.GetGithubRunners()
|
||||
if err != nil {
|
||||
failureReason := fmt.Sprintf("error fetching github runners for %s: %s", r.helper.String(), err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := r.reapTimedOutRunners(runners); err != nil {
|
||||
log.Printf("failed to reap timed out runners: %q", err)
|
||||
}
|
||||
|
||||
if err := r.cleanupOrphanedGithubRunners(runners); err != nil {
|
||||
log.Printf("failed to clean orphaned github runners: %q", err)
|
||||
if err := r.cleanupOrphanedGithubRunners(runners); err != nil {
|
||||
log.Printf("failed to clean orphaned github runners: %q", err)
|
||||
}
|
||||
case <-consolidateTimer.C:
|
||||
// consolidate.
|
||||
r.consolidate()
|
||||
case <-toolUpdateTimer.C:
|
||||
// Update tools cache.
|
||||
tools, err := r.helper.FetchTools()
|
||||
if err != nil {
|
||||
failureReason := fmt.Sprintf("failed to update tools for repo %s: %s", r.helper.String(), err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
r.mux.Lock()
|
||||
r.tools = tools
|
||||
r.mux.Unlock()
|
||||
case <-r.ctx.Done():
|
||||
// daemon is shutting down.
|
||||
return
|
||||
case <-r.quit:
|
||||
// this worker was stopped.
|
||||
return
|
||||
}
|
||||
case <-consolidateTimer.C:
|
||||
// consolidate.
|
||||
r.consolidate()
|
||||
case <-toolUpdateTimer.C:
|
||||
// Update tools cache.
|
||||
default:
|
||||
log.Printf("attempting to start pool manager for %s", r.helper.String())
|
||||
tools, err := r.helper.FetchTools()
|
||||
var failureReason string
|
||||
if err != nil {
|
||||
log.Printf("failed to update tools for repo %s: %s", r.helper.String(), err)
|
||||
failureReason = fmt.Sprintf("failed to fetch tools from github for %s: %q", r.helper.String(), err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
r.waitForTimeoutOrCanceled(common.UnauthorizedBackoffTimer)
|
||||
} else {
|
||||
r.waitForTimeoutOrCanceled(60 * time.Second)
|
||||
}
|
||||
continue
|
||||
}
|
||||
r.mux.Lock()
|
||||
r.tools = tools
|
||||
r.mux.Unlock()
|
||||
case <-r.ctx.Done():
|
||||
// daemon is shutting down.
|
||||
return
|
||||
case <-r.quit:
|
||||
// this worker was stopped.
|
||||
return
|
||||
|
||||
if err := r.runnerCleanup(); err != nil {
|
||||
failureReason = fmt.Sprintf("failed to clean runners for %s: %q", r.helper.String(), err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
r.waitForTimeoutOrCanceled(common.UnauthorizedBackoffTimer)
|
||||
} else {
|
||||
r.waitForTimeoutOrCanceled(60 * time.Second)
|
||||
}
|
||||
continue
|
||||
}
|
||||
r.setPoolRunningState(true, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *basePool) addInstanceToProvider(instance params.Instance) error {
|
||||
func (r *basePoolManager) Status() params.PoolManagerStatus {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
return params.PoolManagerStatus{
|
||||
IsRunning: r.managerIsRunning,
|
||||
FailureReason: r.managerErrorReason,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *basePoolManager) waitForTimeoutOrCanceled(timeout time.Duration) {
|
||||
log.Printf("sleeping for %.2f minutes", timeout.Minutes())
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
case <-r.ctx.Done():
|
||||
case <-r.quit:
|
||||
}
|
||||
}
|
||||
|
||||
func (r *basePoolManager) setPoolRunningState(isRunning bool, failureReason string) {
|
||||
r.mux.Lock()
|
||||
r.managerErrorReason = failureReason
|
||||
r.managerIsRunning = isRunning
|
||||
r.mux.Unlock()
|
||||
}
|
||||
|
||||
func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error {
|
||||
pool, err := r.helper.GetPoolByID(instance.PoolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching pool")
|
||||
|
|
@ -415,7 +502,7 @@ func (r *basePool) addInstanceToProvider(instance params.Instance) error {
|
|||
|
||||
provider, ok := r.providers[pool.ProviderName]
|
||||
if !ok {
|
||||
return runnerErrors.NewNotFoundError("invalid provider ID")
|
||||
return fmt.Errorf("unknown provider %s for pool %s", pool.ProviderName, pool.ID)
|
||||
}
|
||||
|
||||
labels := []string{}
|
||||
|
|
@ -427,6 +514,11 @@ func (r *basePool) addInstanceToProvider(instance params.Instance) error {
|
|||
|
||||
tk, err := r.helper.GetGithubRegistrationToken()
|
||||
if err != nil {
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
failureReason := fmt.Sprintf("failed to fetch registration token: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
}
|
||||
return errors.Wrap(err, "fetching registration token")
|
||||
}
|
||||
|
||||
|
|
@ -454,6 +546,7 @@ func (r *basePool) addInstanceToProvider(instance params.Instance) error {
|
|||
Image: pool.Image,
|
||||
Labels: labels,
|
||||
PoolID: instance.PoolID,
|
||||
CACertBundle: r.credsDetails.CABundle,
|
||||
}
|
||||
|
||||
var instanceIDToDelete string
|
||||
|
|
@ -488,7 +581,7 @@ func (r *basePool) addInstanceToProvider(instance params.Instance) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) getRunnerNameFromJob(job params.WorkflowJob) (string, error) {
|
||||
func (r *basePoolManager) getRunnerNameFromJob(job params.WorkflowJob) (string, error) {
|
||||
if job.WorkflowJob.RunnerName != "" {
|
||||
return job.WorkflowJob.RunnerName, nil
|
||||
}
|
||||
|
|
@ -498,13 +591,18 @@ func (r *basePool) getRunnerNameFromJob(job params.WorkflowJob) (string, error)
|
|||
log.Printf("runner name not found in workflow job, attempting to fetch from API")
|
||||
runnerName, err := r.helper.GetRunnerNameFromWorkflow(job)
|
||||
if err != nil {
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
failureReason := fmt.Sprintf("failed to fetch runner name from API: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
}
|
||||
return "", errors.Wrap(err, "fetching runner name from API")
|
||||
}
|
||||
|
||||
return runnerName, nil
|
||||
}
|
||||
|
||||
func (r *basePool) HandleWorkflowJob(job params.WorkflowJob) error {
|
||||
func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
|
||||
if err := r.helper.ValidateOwner(job); err != nil {
|
||||
return errors.Wrap(err, "validating owner")
|
||||
}
|
||||
|
|
@ -557,15 +655,15 @@ func (r *basePool) HandleWorkflowJob(job params.WorkflowJob) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) poolLabel(poolID string) string {
|
||||
func (r *basePoolManager) poolLabel(poolID string) string {
|
||||
return fmt.Sprintf("%s%s", poolIDLabelprefix, poolID)
|
||||
}
|
||||
|
||||
func (r *basePool) controllerLabel() string {
|
||||
func (r *basePoolManager) controllerLabel() string {
|
||||
return fmt.Sprintf("%s%s", controllerLabelPrefix, r.controllerID)
|
||||
}
|
||||
|
||||
func (r *basePool) updateArgsFromProviderInstance(providerInstance params.Instance) params.UpdateInstanceParams {
|
||||
func (r *basePoolManager) updateArgsFromProviderInstance(providerInstance params.Instance) params.UpdateInstanceParams {
|
||||
return params.UpdateInstanceParams{
|
||||
ProviderID: providerInstance.ProviderID,
|
||||
OSName: providerInstance.OSName,
|
||||
|
|
@ -577,7 +675,7 @@ func (r *basePool) updateArgsFromProviderInstance(providerInstance params.Instan
|
|||
}
|
||||
}
|
||||
|
||||
func (r *basePool) ensureIdleRunnersForOnePool(pool params.Pool) {
|
||||
func (r *basePoolManager) ensureIdleRunnersForOnePool(pool params.Pool) {
|
||||
if !pool.Enabled {
|
||||
return
|
||||
}
|
||||
|
|
@ -620,7 +718,7 @@ func (r *basePool) ensureIdleRunnersForOnePool(pool params.Pool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *basePool) retryFailedInstancesForOnePool(pool params.Pool) {
|
||||
func (r *basePoolManager) retryFailedInstancesForOnePool(pool params.Pool) {
|
||||
if !pool.Enabled {
|
||||
return
|
||||
}
|
||||
|
|
@ -662,7 +760,7 @@ func (r *basePool) retryFailedInstancesForOnePool(pool params.Pool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *basePool) retryFailedInstances() {
|
||||
func (r *basePoolManager) retryFailedInstances() {
|
||||
pools, err := r.helper.ListPools()
|
||||
if err != nil {
|
||||
log.Printf("error listing pools: %s", err)
|
||||
|
|
@ -679,7 +777,7 @@ func (r *basePool) retryFailedInstances() {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func (r *basePool) ensureMinIdleRunners() {
|
||||
func (r *basePoolManager) ensureMinIdleRunners() {
|
||||
pools, err := r.helper.ListPools()
|
||||
if err != nil {
|
||||
log.Printf("error listing pools: %s", err)
|
||||
|
|
@ -696,7 +794,7 @@ func (r *basePool) ensureMinIdleRunners() {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func (r *basePool) deleteInstanceFromProvider(instance params.Instance) error {
|
||||
func (r *basePoolManager) deleteInstanceFromProvider(instance params.Instance) error {
|
||||
pool, err := r.helper.GetPoolByID(instance.PoolID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching pool")
|
||||
|
|
@ -704,7 +802,7 @@ func (r *basePool) deleteInstanceFromProvider(instance params.Instance) error {
|
|||
|
||||
provider, ok := r.providers[pool.ProviderName]
|
||||
if !ok {
|
||||
return runnerErrors.NewNotFoundError("invalid provider ID")
|
||||
return fmt.Errorf("unknown provider %s for pool %s", pool.ProviderName, pool.ID)
|
||||
}
|
||||
|
||||
identifier := instance.ProviderID
|
||||
|
|
@ -724,7 +822,7 @@ func (r *basePool) deleteInstanceFromProvider(instance params.Instance) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) deletePendingInstances() {
|
||||
func (r *basePoolManager) deletePendingInstances() {
|
||||
instances, err := r.helper.FetchDbInstances()
|
||||
if err != nil {
|
||||
log.Printf("failed to fetch instances from store: %s", err)
|
||||
|
|
@ -762,7 +860,7 @@ func (r *basePool) deletePendingInstances() {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *basePool) addPendingInstances() {
|
||||
func (r *basePoolManager) addPendingInstances() {
|
||||
// TODO: filter instances by status.
|
||||
instances, err := r.helper.FetchDbInstances()
|
||||
if err != nil {
|
||||
|
|
@ -794,7 +892,7 @@ func (r *basePool) addPendingInstances() {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *basePool) consolidate() {
|
||||
func (r *basePoolManager) consolidate() {
|
||||
// TODO(gabriel-samfira): replace this with something more efficient.
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
|
@ -824,7 +922,7 @@ func (r *basePool) consolidate() {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func (r *basePool) Wait() error {
|
||||
func (r *basePoolManager) Wait() error {
|
||||
select {
|
||||
case <-r.done:
|
||||
case <-time.After(20 * time.Second):
|
||||
|
|
@ -833,17 +931,14 @@ func (r *basePool) Wait() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) Start() error {
|
||||
tools, err := r.helper.FetchTools()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initializing tools")
|
||||
}
|
||||
r.mux.Lock()
|
||||
r.tools = tools
|
||||
r.mux.Unlock()
|
||||
|
||||
func (r *basePoolManager) runnerCleanup() error {
|
||||
runners, err := r.helper.GetGithubRunners()
|
||||
if err != nil {
|
||||
if errors.Is(err, runnerErrors.ErrUnauthorized) {
|
||||
failureReason := fmt.Sprintf("failed to fetch runners: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
}
|
||||
return errors.Wrap(err, "fetching github runners")
|
||||
}
|
||||
if err := r.cleanupOrphanedProviderRunners(runners); err != nil {
|
||||
|
|
@ -853,28 +948,35 @@ func (r *basePool) Start() error {
|
|||
if err := r.cleanupOrphanedGithubRunners(runners); err != nil {
|
||||
return errors.Wrap(err, "cleaning orphaned github runners")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *basePoolManager) Start() error {
|
||||
go r.loop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) Stop() error {
|
||||
func (r *basePoolManager) Stop() error {
|
||||
close(r.quit)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *basePool) RefreshState(param params.UpdatePoolStateParams) error {
|
||||
func (r *basePoolManager) RefreshState(param params.UpdatePoolStateParams) error {
|
||||
return r.helper.UpdateState(param)
|
||||
}
|
||||
|
||||
func (r *basePool) WebhookSecret() string {
|
||||
func (r *basePoolManager) WebhookSecret() string {
|
||||
return r.helper.WebhookSecret()
|
||||
}
|
||||
|
||||
func (r *basePool) ID() string {
|
||||
func (r *basePoolManager) ID() string {
|
||||
return r.helper.ID()
|
||||
}
|
||||
|
||||
func (r *basePool) ForceDeleteRunner(runner params.Instance) error {
|
||||
func (r *basePoolManager) ForceDeleteRunner(runner params.Instance) error {
|
||||
if !r.managerIsRunning {
|
||||
return runnerErrors.NewConflictError("pool manager is not running for %s", r.helper.String())
|
||||
}
|
||||
if runner.AgentID != 0 {
|
||||
resp, err := r.helper.RemoveGithubRunner(runner.AgentID)
|
||||
if err != nil {
|
||||
|
|
@ -885,6 +987,13 @@ func (r *basePool) ForceDeleteRunner(runner params.Instance) error {
|
|||
case http.StatusNotFound:
|
||||
// Runner may have been deleted by a finished job, or manually by the user.
|
||||
log.Printf("runner with agent id %d was not found in github", runner.AgentID)
|
||||
case http.StatusUnauthorized:
|
||||
// Mark the pool as offline from this point forward
|
||||
failureReason := fmt.Sprintf("failed to remove runner: %q", err)
|
||||
r.setPoolRunningState(false, failureReason)
|
||||
log.Print(failureReason)
|
||||
// evaluate the next switch case.
|
||||
fallthrough
|
||||
default:
|
||||
return errors.Wrap(err, "removing runner")
|
||||
}
|
||||
|
|
@ -894,6 +1003,7 @@ func (r *basePool) ForceDeleteRunner(runner params.Instance) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
log.Printf("setting instance status for: %v", runner.Name)
|
||||
|
||||
if err := r.setInstanceStatus(runner.Name, providerCommon.InstancePendingDelete, nil); err != nil {
|
||||
log.Printf("failed to update runner %s status", runner.Name)
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ package pool
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"garm/config"
|
||||
dbCommon "garm/database/common"
|
||||
runnerErrors "garm/errors"
|
||||
"garm/params"
|
||||
"garm/runner/common"
|
||||
"garm/util"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ import (
|
|||
var _ poolHelper = &repository{}
|
||||
|
||||
func NewRepositoryPoolManager(ctx context.Context, cfg params.Repository, cfgInternal params.Internal, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) {
|
||||
ghc, err := util.GithubClient(ctx, cfgInternal.OAuth2Token)
|
||||
ghc, _, err := util.GithubClient(ctx, cfgInternal.OAuth2Token, cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting github client")
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func NewRepositoryPoolManager(ctx context.Context, cfg params.Repository, cfgInt
|
|||
store: store,
|
||||
}
|
||||
|
||||
repo := &basePool{
|
||||
repo := &basePoolManager{
|
||||
ctx: ctx,
|
||||
store: store,
|
||||
providers: providers,
|
||||
|
|
@ -57,6 +57,7 @@ func NewRepositoryPoolManager(ctx context.Context, cfg params.Repository, cfgInt
|
|||
quit: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
helper: helper,
|
||||
credsDetails: cfgInternal.GithubCredentialsDetails,
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
|
@ -75,8 +76,11 @@ type repository struct {
|
|||
}
|
||||
|
||||
func (r *repository) GetRunnerNameFromWorkflow(job params.WorkflowJob) (string, error) {
|
||||
workflow, _, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Repository.Owner.Login, job.Repository.Name, job.WorkflowJob.ID)
|
||||
workflow, ghResp, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Repository.Owner.Login, job.Repository.Name, job.WorkflowJob.ID)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runner name")
|
||||
}
|
||||
return "", errors.Wrap(err, "fetching workflow info")
|
||||
}
|
||||
if workflow.RunnerName != nil {
|
||||
|
|
@ -91,7 +95,7 @@ func (r *repository) UpdateState(param params.UpdatePoolStateParams) error {
|
|||
|
||||
r.cfg.WebhookSecret = param.WebhookSecret
|
||||
|
||||
ghc, err := util.GithubClient(r.ctx, r.GetGithubToken())
|
||||
ghc, _, err := util.GithubClient(r.ctx, r.GetGithubToken(), r.cfgInternal.GithubCredentialsDetails)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting github client")
|
||||
}
|
||||
|
|
@ -104,19 +108,37 @@ func (r *repository) GetGithubToken() string {
|
|||
}
|
||||
|
||||
func (r *repository) GetGithubRunners() ([]*github.Runner, error) {
|
||||
runners, _, err := r.ghcli.ListRunners(r.ctx, r.cfg.Owner, r.cfg.Name, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching runners")
|
||||
opts := github.ListOptions{
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
return runners.Runners, nil
|
||||
var allRunners []*github.Runner
|
||||
for {
|
||||
runners, ghResp, err := r.ghcli.ListRunners(r.ctx, r.cfg.Owner, r.cfg.Name, &opts)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runners")
|
||||
}
|
||||
allRunners = append(allRunners, runners.Runners...)
|
||||
if ghResp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
opts.Page = ghResp.NextPage
|
||||
}
|
||||
|
||||
return allRunners, nil
|
||||
}
|
||||
|
||||
func (r *repository) FetchTools() ([]*github.RunnerApplicationDownload, error) {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
tools, _, err := r.ghcli.ListRunnerApplicationDownloads(r.ctx, r.cfg.Owner, r.cfg.Name)
|
||||
tools, ghResp, err := r.ghcli.ListRunnerApplicationDownloads(r.ctx, r.cfg.Owner, r.cfg.Name)
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching tools")
|
||||
}
|
||||
return nil, errors.Wrap(err, "fetching runner tools")
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +162,7 @@ func (r *repository) ListPools() ([]params.Pool, error) {
|
|||
}
|
||||
|
||||
func (r *repository) GithubURL() string {
|
||||
return fmt.Sprintf("%s/%s/%s", config.GithubBaseURL, r.cfg.Owner, r.cfg.Name)
|
||||
return fmt.Sprintf("%s/%s/%s", r.cfgInternal.GithubCredentialsDetails.BaseURL, r.cfg.Owner, r.cfg.Name)
|
||||
}
|
||||
|
||||
func (r *repository) JwtToken() string {
|
||||
|
|
@ -148,9 +170,12 @@ func (r *repository) JwtToken() string {
|
|||
}
|
||||
|
||||
func (r *repository) GetGithubRegistrationToken() (string, error) {
|
||||
tk, _, err := r.ghcli.CreateRegistrationToken(r.ctx, r.cfg.Owner, r.cfg.Name)
|
||||
tk, ghResp, err := r.ghcli.CreateRegistrationToken(r.ctx, r.cfg.Owner, r.cfg.Name)
|
||||
|
||||
if err != nil {
|
||||
if ghResp.StatusCode == http.StatusUnauthorized {
|
||||
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching token")
|
||||
}
|
||||
return "", errors.Wrap(err, "creating runner token")
|
||||
}
|
||||
return *tk.Token, nil
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package runner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"garm/auth"
|
||||
runnerErrors "garm/errors"
|
||||
|
|
@ -112,6 +113,10 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
|
|||
newPool, err = r.store.UpdateRepositoryPool(ctx, pool.RepoID, poolID, param)
|
||||
} else if pool.OrgID != "" {
|
||||
newPool, err = r.store.UpdateOrganizationPool(ctx, pool.OrgID, poolID, param)
|
||||
} else if pool.EnterpriseID != "" {
|
||||
newPool, err = r.store.UpdateEnterprisePool(ctx, pool.EnterpriseID, poolID, param)
|
||||
} else {
|
||||
return params.Pool{}, fmt.Errorf("pool not bound to a repo, org or enterprise")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"garm/runner/common"
|
||||
"garm/util"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
lxd "github.com/lxc/lxd/client"
|
||||
"github.com/lxc/lxd/shared/api"
|
||||
"github.com/pkg/errors"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package runner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
|
|
@ -85,7 +86,20 @@ func (r *Runner) ListRepositories(ctx context.Context) ([]params.Repository, err
|
|||
return nil, errors.Wrap(err, "listing repositories")
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
var allRepos []params.Repository
|
||||
|
||||
for _, repo := range repos {
|
||||
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
|
||||
if err != nil {
|
||||
repo.PoolManagerStatus.IsRunning = false
|
||||
repo.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
} else {
|
||||
repo.PoolManagerStatus = poolMgr.Status()
|
||||
}
|
||||
allRepos = append(allRepos, repo)
|
||||
}
|
||||
|
||||
return allRepos, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetRepositoryByID(ctx context.Context, repoID string) (params.Repository, error) {
|
||||
|
|
@ -97,6 +111,13 @@ func (r *Runner) GetRepositoryByID(ctx context.Context, repoID string) (params.R
|
|||
if err != nil {
|
||||
return params.Repository{}, errors.Wrap(err, "fetching repository")
|
||||
}
|
||||
|
||||
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
|
||||
if err != nil {
|
||||
repo.PoolManagerStatus.IsRunning = false
|
||||
repo.PoolManagerStatus.FailureReason = fmt.Sprintf("failed to get pool manager: %q", err)
|
||||
}
|
||||
repo.PoolManagerStatus = poolMgr.Status()
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,8 @@ func (s *RepoTestSuite) TestCreateRepositoryStartPoolMgrFailed() {
|
|||
}
|
||||
|
||||
func (s *RepoTestSuite) TestListRepositories() {
|
||||
s.Fixtures.PoolMgrCtrlMock.On("GetRepoPoolManager", mock.AnythingOfType("params.Repository")).Return(s.Fixtures.PoolMgrMock, nil)
|
||||
s.Fixtures.PoolMgrMock.On("Status").Return(params.PoolManagerStatus{IsRunning: true}, nil)
|
||||
repos, err := s.Runner.ListRepositories(s.Fixtures.AdminContext)
|
||||
|
||||
s.Require().Nil(err)
|
||||
|
|
@ -278,6 +280,8 @@ func (s *RepoTestSuite) TestListRepositoriesErrUnauthorized() {
|
|||
}
|
||||
|
||||
func (s *RepoTestSuite) TestGetRepositoryByID() {
|
||||
s.Fixtures.PoolMgrCtrlMock.On("GetRepoPoolManager", mock.AnythingOfType("params.Repository")).Return(s.Fixtures.PoolMgrMock, nil)
|
||||
s.Fixtures.PoolMgrMock.On("Status").Return(params.PoolManagerStatus{IsRunning: true}, nil)
|
||||
repo, err := s.Runner.GetRepositoryByID(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID)
|
||||
|
||||
s.Require().Nil(err)
|
||||
|
|
|
|||
220
runner/runner.go
220
runner/runner.go
|
|
@ -23,9 +23,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -43,7 +41,6 @@ import (
|
|||
"garm/util"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewRunner(ctx context.Context, cfg config.Config) (*Runner, error) {
|
||||
|
|
@ -74,6 +71,7 @@ func NewRunner(ctx context.Context, cfg config.Config) (*Runner, error) {
|
|||
credentials: creds,
|
||||
repositories: map[string]common.PoolManager{},
|
||||
organizations: map[string]common.PoolManager{},
|
||||
enterprises: map[string]common.PoolManager{},
|
||||
}
|
||||
runner := &Runner{
|
||||
ctx: ctx,
|
||||
|
|
@ -84,7 +82,7 @@ func NewRunner(ctx context.Context, cfg config.Config) (*Runner, error) {
|
|||
credentials: creds,
|
||||
}
|
||||
|
||||
if err := runner.loadReposAndOrgs(); err != nil {
|
||||
if err := runner.loadReposOrgsAndEnterprises(); err != nil {
|
||||
return nil, errors.Wrap(err, "loading pool managers")
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +98,7 @@ type poolManagerCtrl struct {
|
|||
|
||||
repositories map[string]common.PoolManager
|
||||
organizations map[string]common.PoolManager
|
||||
enterprises map[string]common.PoolManager
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) CreateRepoPoolManager(ctx context.Context, repo params.Repository, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) {
|
||||
|
|
@ -184,17 +183,71 @@ func (p *poolManagerCtrl) GetOrgPoolManagers() (map[string]common.PoolManager, e
|
|||
return p.organizations, nil
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) CreateEnterprisePoolManager(ctx context.Context, enterprise params.Enterprise, providers map[string]common.Provider, store dbCommon.Store) (common.PoolManager, error) {
|
||||
p.mux.Lock()
|
||||
defer p.mux.Unlock()
|
||||
|
||||
cfgInternal, err := p.getInternalConfig(enterprise.CredentialsName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching internal config")
|
||||
}
|
||||
poolManager, err := pool.NewEnterprisePoolManager(ctx, enterprise, cfgInternal, providers, store)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating enterprise pool manager")
|
||||
}
|
||||
p.enterprises[enterprise.ID] = poolManager
|
||||
return poolManager, nil
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) GetEnterprisePoolManager(enterprise params.Enterprise) (common.PoolManager, error) {
|
||||
if enterprisePoolMgr, ok := p.enterprises[enterprise.ID]; ok {
|
||||
return enterprisePoolMgr, nil
|
||||
}
|
||||
return nil, errors.Wrapf(runnerErrors.ErrNotFound, "enterprise %s pool manager not loaded", enterprise.Name)
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) DeleteEnterprisePoolManager(enterprise params.Enterprise) error {
|
||||
p.mux.Lock()
|
||||
defer p.mux.Unlock()
|
||||
|
||||
poolMgr, ok := p.enterprises[enterprise.ID]
|
||||
if ok {
|
||||
if err := poolMgr.Stop(); err != nil {
|
||||
return errors.Wrap(err, "stopping enterprise pool manager")
|
||||
}
|
||||
delete(p.enterprises, enterprise.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) GetEnterprisePoolManagers() (map[string]common.PoolManager, error) {
|
||||
return p.enterprises, nil
|
||||
}
|
||||
|
||||
func (p *poolManagerCtrl) getInternalConfig(credsName string) (params.Internal, error) {
|
||||
creds, ok := p.credentials[credsName]
|
||||
if !ok {
|
||||
return params.Internal{}, runnerErrors.NewBadRequestError("invalid credential name (%s)", credsName)
|
||||
}
|
||||
|
||||
caBundle, err := creds.CACertBundle()
|
||||
if err != nil {
|
||||
return params.Internal{}, fmt.Errorf("fetching CA bundle for creds: %w", err)
|
||||
}
|
||||
|
||||
return params.Internal{
|
||||
OAuth2Token: creds.OAuth2Token,
|
||||
ControllerID: p.controllerID,
|
||||
InstanceCallbackURL: p.config.Default.CallbackURL,
|
||||
JWTSecret: p.config.JWTAuth.Secret,
|
||||
GithubCredentialsDetails: params.GithubCredentials{
|
||||
Name: creds.Name,
|
||||
Description: creds.Description,
|
||||
BaseURL: creds.BaseEndpoint(),
|
||||
APIBaseURL: creds.APIEndpoint(),
|
||||
UploadBaseURL: creds.UploadEndpoint(),
|
||||
CABundle: caBundle,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -219,8 +272,11 @@ func (r *Runner) ListCredentials(ctx context.Context) ([]params.GithubCredential
|
|||
|
||||
for _, val := range r.config.Github {
|
||||
ret = append(ret, params.GithubCredentials{
|
||||
Name: val.Name,
|
||||
Description: val.Description,
|
||||
Name: val.Name,
|
||||
Description: val.Description,
|
||||
BaseURL: val.BaseEndpoint(),
|
||||
APIBaseURL: val.APIEndpoint(),
|
||||
UploadBaseURL: val.UploadEndpoint(),
|
||||
})
|
||||
}
|
||||
return ret, nil
|
||||
|
|
@ -238,7 +294,7 @@ func (r *Runner) ListProviders(ctx context.Context) ([]params.Provider, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *Runner) loadReposAndOrgs() error {
|
||||
func (r *Runner) loadReposOrgsAndEnterprises() error {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
|
|
@ -252,7 +308,12 @@ func (r *Runner) loadReposAndOrgs() error {
|
|||
return errors.Wrap(err, "fetching organizations")
|
||||
}
|
||||
|
||||
expectedReplies := len(repos) + len(orgs)
|
||||
enterprises, err := r.store.ListEnterprises(r.ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching enterprises")
|
||||
}
|
||||
|
||||
expectedReplies := len(repos) + len(orgs) + len(enterprises)
|
||||
errChan := make(chan error, expectedReplies)
|
||||
|
||||
for _, repo := range repos {
|
||||
|
|
@ -271,6 +332,14 @@ func (r *Runner) loadReposAndOrgs() error {
|
|||
}(org)
|
||||
}
|
||||
|
||||
for _, enterprise := range enterprises {
|
||||
go func(enterprise params.Enterprise) {
|
||||
log.Printf("creating pool manager for enterprise %s", enterprise.Name)
|
||||
_, err := r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store)
|
||||
errChan <- err
|
||||
}(enterprise)
|
||||
}
|
||||
|
||||
for i := 0; i < expectedReplies; i++ {
|
||||
select {
|
||||
case err := <-errChan:
|
||||
|
|
@ -299,7 +368,12 @@ func (r *Runner) Start() error {
|
|||
return errors.Wrap(err, "fetch org pool managers")
|
||||
}
|
||||
|
||||
expectedReplies := len(repositories) + len(organizations)
|
||||
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch enterprise pool managers")
|
||||
}
|
||||
|
||||
expectedReplies := len(repositories) + len(organizations) + len(enterprises)
|
||||
errChan := make(chan error, expectedReplies)
|
||||
|
||||
for _, repo := range repositories {
|
||||
|
|
@ -318,6 +392,14 @@ func (r *Runner) Start() error {
|
|||
|
||||
}
|
||||
|
||||
for _, enterprise := range enterprises {
|
||||
go func(org common.PoolManager) {
|
||||
err := org.Start()
|
||||
errChan <- err
|
||||
}(enterprise)
|
||||
|
||||
}
|
||||
|
||||
for i := 0; i < expectedReplies; i++ {
|
||||
select {
|
||||
case err := <-errChan:
|
||||
|
|
@ -339,19 +421,49 @@ func (r *Runner) Stop() error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "fetch repo pool managers")
|
||||
}
|
||||
for _, repo := range repos {
|
||||
if err := repo.Stop(); err != nil {
|
||||
return errors.Wrap(err, "stopping repo pool manager")
|
||||
}
|
||||
}
|
||||
|
||||
orgs, err := r.poolManagerCtrl.GetOrgPoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch org pool managers")
|
||||
}
|
||||
|
||||
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch enterprise pool managers")
|
||||
}
|
||||
|
||||
expectedReplies := len(repos) + len(orgs) + len(enterprises)
|
||||
errChan := make(chan error, expectedReplies)
|
||||
|
||||
for _, repo := range repos {
|
||||
go func(poolMgr common.PoolManager) {
|
||||
err := poolMgr.Stop()
|
||||
errChan <- err
|
||||
}(repo)
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
if err := org.Stop(); err != nil {
|
||||
return errors.Wrap(err, "stopping org pool manager")
|
||||
go func(poolMgr common.PoolManager) {
|
||||
err := poolMgr.Stop()
|
||||
errChan <- err
|
||||
}(org)
|
||||
}
|
||||
|
||||
for _, enterprise := range enterprises {
|
||||
go func(poolMgr common.PoolManager) {
|
||||
err := poolMgr.Stop()
|
||||
errChan <- err
|
||||
}(enterprise)
|
||||
}
|
||||
|
||||
for i := 0; i < expectedReplies; i++ {
|
||||
select {
|
||||
case err := <-errChan:
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stopping pool manager")
|
||||
}
|
||||
case <-time.After(60 * time.Second):
|
||||
return fmt.Errorf("timed out waiting for pool mamager stop")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -367,6 +479,17 @@ func (r *Runner) Wait() error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "fetch repo pool managers")
|
||||
}
|
||||
|
||||
orgs, err := r.poolManagerCtrl.GetOrgPoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch org pool managers")
|
||||
}
|
||||
|
||||
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch enterprise pool managers")
|
||||
}
|
||||
|
||||
for poolId, repo := range repos {
|
||||
wg.Add(1)
|
||||
go func(id string, poolMgr common.PoolManager) {
|
||||
|
|
@ -377,10 +500,6 @@ func (r *Runner) Wait() error {
|
|||
}(poolId, repo)
|
||||
}
|
||||
|
||||
orgs, err := r.poolManagerCtrl.GetOrgPoolManagers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch org pool managers")
|
||||
}
|
||||
for poolId, org := range orgs {
|
||||
wg.Add(1)
|
||||
go func(id string, poolMgr common.PoolManager) {
|
||||
|
|
@ -390,6 +509,17 @@ func (r *Runner) Wait() error {
|
|||
}
|
||||
}(poolId, org)
|
||||
}
|
||||
|
||||
for poolId, enterprise := range enterprises {
|
||||
wg.Add(1)
|
||||
go func(id string, poolMgr common.PoolManager) {
|
||||
defer wg.Done()
|
||||
if err := poolMgr.Wait(); err != nil {
|
||||
log.Printf("timed out waiting for pool manager %s to exit", id)
|
||||
}
|
||||
}(poolId, enterprise)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -456,6 +586,8 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, jobData [
|
|||
poolManager, err = r.findRepoPoolManager(job.Repository.Owner.Login, job.Repository.Name)
|
||||
case OrganizationHook:
|
||||
poolManager, err = r.findOrgPoolManager(job.Organization.Login)
|
||||
case EnterpriseHook:
|
||||
poolManager, err = r.findEnterprisePoolManager(job.Enterprise.Slug)
|
||||
default:
|
||||
return runnerErrors.NewBadRequestError("cannot handle hook target type %s", hookTargetType)
|
||||
}
|
||||
|
|
@ -480,45 +612,6 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, jobData [
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) sshDir() string {
|
||||
return filepath.Join(r.config.Default.ConfigDir, "ssh")
|
||||
}
|
||||
|
||||
func (r *Runner) sshKeyPath() string {
|
||||
keyPath := filepath.Join(r.sshDir(), "runner_rsa_key")
|
||||
return keyPath
|
||||
}
|
||||
|
||||
func (r *Runner) sshPubKeyPath() string {
|
||||
keyPath := filepath.Join(r.sshDir(), "runner_rsa_key.pub")
|
||||
return keyPath
|
||||
}
|
||||
|
||||
func (r *Runner) parseSSHKey() (ssh.Signer, error) {
|
||||
r.mux.Lock()
|
||||
defer r.mux.Unlock()
|
||||
|
||||
key, err := ioutil.ReadFile(r.sshKeyPath())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "reading private key %s", r.sshKeyPath())
|
||||
}
|
||||
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing private key %s", r.sshKeyPath())
|
||||
}
|
||||
|
||||
return signer, nil
|
||||
}
|
||||
|
||||
func (r *Runner) sshPubKey() ([]byte, error) {
|
||||
key, err := ioutil.ReadFile(r.sshPubKeyPath())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "reading public key %s", r.sshPubKeyPath())
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (r *Runner) appendTagsToCreatePoolParams(param params.CreatePoolParams) (params.CreatePoolParams, error) {
|
||||
if err := param.Validate(); err != nil {
|
||||
return params.CreatePoolParams{}, errors.Wrapf(runnerErrors.ErrBadRequest, "validating params: %s", err)
|
||||
|
|
@ -670,6 +763,15 @@ func (r *Runner) ForceDeleteRunner(ctx context.Context, instanceName string) err
|
|||
if err != nil {
|
||||
return errors.Wrapf(err, "fetching pool manager for org %s", pool.OrgName)
|
||||
}
|
||||
} else if pool.EnterpriseID != "" {
|
||||
enterprise, err := r.store.GetEnterpriseByID(ctx, pool.EnterpriseID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetching enterprise")
|
||||
}
|
||||
poolMgr, err = r.findEnterprisePoolManager(enterprise.Name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "fetching pool manager for enterprise %s", pool.EnterpriseName)
|
||||
}
|
||||
}
|
||||
|
||||
if err := poolMgr.ForceDeleteRunner(instance); err != nil {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type HookTargetType string
|
|||
const (
|
||||
RepoHook HookTargetType = "repository"
|
||||
OrganizationHook HookTargetType = "organization"
|
||||
EnterpriseHook HookTargetType = "business"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
15
testdata/config.toml
vendored
15
testdata/config.toml
vendored
|
|
@ -192,3 +192,18 @@ provider_type = "external"
|
|||
# to work with repositories, and the admin:org needs to be set if you plan on
|
||||
# adding an organization.
|
||||
oauth2_token = "super secret token"
|
||||
# base_url (optional) is the URL at which your GitHub Enterprise Server can be accessed.
|
||||
# If these credentials are for github.com, leave this setting blank
|
||||
base_url = "https://ghe.example.com"
|
||||
# api_base_url (optional) is the base URL where the GitHub Enterprise Server API can be accessed.
|
||||
# Leave this blank if these credentials are for github.com.
|
||||
api_base_url = "https://ghe.example.com"
|
||||
# upload_base_url (optional) is the base URL where the GitHub Enterprise Server upload API can be accessed.
|
||||
# Leave this blank if these credentials are for github.com, or if you don't have a separate URL
|
||||
# for the upload API.
|
||||
upload_base_url = "https://api.ghe.example.com"
|
||||
# ca_cert_bundle (optional) is the CA certificate bundle in PEM format that will be used by the github
|
||||
# client to talk to the API. This bundle will also be sent to all runners as bootstrap params.
|
||||
# Use this option if you're using a self signed certificate.
|
||||
# Leave this blank if you're using github.com or if your certificare is signed by a valid CA.
|
||||
ca_cert_bundle = "/etc/garm/ghe.crt"
|
||||
|
|
|
|||
71
util/util.go
71
util/util.go
|
|
@ -19,10 +19,13 @@ import (
|
|||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
|
|
@ -35,7 +38,7 @@ import (
|
|||
"garm/params"
|
||||
"garm/runner/common"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/oauth2"
|
||||
|
|
@ -160,32 +163,64 @@ func OSToOSType(os string) (config.OSType, error) {
|
|||
return osType, nil
|
||||
}
|
||||
|
||||
func GithubClient(ctx context.Context, token string) (common.GithubClient, error) {
|
||||
func GithubClient(ctx context.Context, token string, credsDetails params.GithubCredentials) (common.GithubClient, common.GithubEnterpriseClient, error) {
|
||||
var roots *x509.CertPool
|
||||
if credsDetails.CABundle != nil && len(credsDetails.CABundle) > 0 {
|
||||
roots = x509.NewCertPool()
|
||||
ok := roots.AppendCertsFromPEM(credsDetails.CABundle)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("failed to parse CA cert")
|
||||
}
|
||||
}
|
||||
httpTransport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
ClientCAs: roots,
|
||||
},
|
||||
}
|
||||
httpClient := &http.Client{Transport: httpTransport}
|
||||
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
|
||||
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
|
||||
tc := oauth2.NewClient(ctx, ts)
|
||||
|
||||
ghClient := github.NewClient(tc)
|
||||
ghClient, err := github.NewEnterpriseClient(credsDetails.APIBaseURL, credsDetails.UploadBaseURL, tc)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "fetching github client")
|
||||
}
|
||||
|
||||
return ghClient.Actions, nil
|
||||
return ghClient.Actions, ghClient.Enterprise, nil
|
||||
}
|
||||
|
||||
func GetCloudConfig(bootstrapParams params.BootstrapInstance, tools github.RunnerApplicationDownload, runnerName string) (string, error) {
|
||||
cloudCfg := cloudconfig.NewDefaultCloudInitConfig()
|
||||
|
||||
if tools.Filename == nil {
|
||||
return "", fmt.Errorf("missing tools filename")
|
||||
}
|
||||
|
||||
if tools.DownloadURL == nil {
|
||||
return "", fmt.Errorf("missing tools download URL")
|
||||
}
|
||||
|
||||
var tempToken string
|
||||
if tools.TempDownloadToken != nil {
|
||||
tempToken = *tools.TempDownloadToken
|
||||
}
|
||||
|
||||
installRunnerParams := cloudconfig.InstallRunnerParams{
|
||||
FileName: *tools.Filename,
|
||||
DownloadURL: *tools.DownloadURL,
|
||||
GithubToken: bootstrapParams.GithubRunnerAccessToken,
|
||||
RunnerUsername: config.DefaultUser,
|
||||
RunnerGroup: config.DefaultUser,
|
||||
RepoURL: bootstrapParams.RepoURL,
|
||||
RunnerName: runnerName,
|
||||
RunnerLabels: strings.Join(bootstrapParams.Labels, ","),
|
||||
CallbackURL: bootstrapParams.CallbackURL,
|
||||
CallbackToken: bootstrapParams.InstanceToken,
|
||||
FileName: *tools.Filename,
|
||||
DownloadURL: *tools.DownloadURL,
|
||||
TempDownloadToken: tempToken,
|
||||
GithubToken: bootstrapParams.GithubRunnerAccessToken,
|
||||
RunnerUsername: config.DefaultUser,
|
||||
RunnerGroup: config.DefaultUser,
|
||||
RepoURL: bootstrapParams.RepoURL,
|
||||
RunnerName: runnerName,
|
||||
RunnerLabels: strings.Join(bootstrapParams.Labels, ","),
|
||||
CallbackURL: bootstrapParams.CallbackURL,
|
||||
CallbackToken: bootstrapParams.InstanceToken,
|
||||
}
|
||||
|
||||
installScript, err := cloudconfig.InstallRunnerScript(installRunnerParams)
|
||||
|
|
@ -198,6 +233,12 @@ func GetCloudConfig(bootstrapParams params.BootstrapInstance, tools github.Runne
|
|||
cloudCfg.AddRunCmd("/install_runner.sh")
|
||||
cloudCfg.AddRunCmd("rm -f /install_runner.sh")
|
||||
|
||||
if bootstrapParams.CACertBundle != nil && len(bootstrapParams.CACertBundle) > 0 {
|
||||
if err := cloudCfg.AddCACert(bootstrapParams.CACertBundle); err != nil {
|
||||
return "", errors.Wrap(err, "adding CA cert bundle")
|
||||
}
|
||||
}
|
||||
|
||||
asStr, err := cloudCfg.Serialize()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "creating cloud config")
|
||||
|
|
|
|||
38
vendor/github.com/google/go-github/v43/github/repos_merging.go
generated
vendored
38
vendor/github.com/google/go-github/v43/github/repos_merging.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RepositoryMergeRequest represents a request to merge a branch in a
|
||||
// repository.
|
||||
type RepositoryMergeRequest struct {
|
||||
Base *string `json:"base,omitempty"`
|
||||
Head *string `json:"head,omitempty"`
|
||||
CommitMessage *string `json:"commit_message,omitempty"`
|
||||
}
|
||||
|
||||
// Merge a branch in the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#merge-a-branch
|
||||
func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/merges", owner, repo)
|
||||
req, err := s.client.NewRequest("POST", u, request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
commit := new(RepositoryCommit)
|
||||
resp, err := s.client.Do(ctx, req, commit)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return commit, resp, nil
|
||||
}
|
||||
|
|
@ -59,6 +59,7 @@ Beyang Liu <beyang.liu@gmail.com>
|
|||
Billy Keyes <bluekeyes@gmail.com>
|
||||
Billy Lynch <wlynch92@gmail.com>
|
||||
Björn Häuser <b.haeuser@rebuy.de>
|
||||
Bjorn Neergaard <bjorn@neersighted.com>
|
||||
boljen <bol.christophe@gmail.com>
|
||||
Brad Harris <bmharris@gmail.com>
|
||||
Brad Moylan <moylan.brad@gmail.com>
|
||||
|
|
@ -8,5 +8,5 @@ package github
|
|||
// ActionsService handles communication with the actions related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/
|
||||
type ActionsService service
|
||||
|
|
@ -16,7 +16,7 @@ import (
|
|||
// data between jobs in a workflow and provide storage for data
|
||||
// once a workflow is complete.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#artifacts
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts
|
||||
type Artifact struct {
|
||||
ID *int64 `json:"id,omitempty"`
|
||||
NodeID *string `json:"node_id,omitempty"`
|
||||
|
|
@ -30,7 +30,7 @@ type Artifact struct {
|
|||
|
||||
// ArtifactList represents a list of GitHub artifacts.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#artifacts
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#artifacts
|
||||
type ArtifactList struct {
|
||||
TotalCount *int64 `json:"total_count,omitempty"`
|
||||
Artifacts []*Artifact `json:"artifacts,omitempty"`
|
||||
|
|
@ -38,7 +38,7 @@ type ArtifactList struct {
|
|||
|
||||
// ListArtifacts lists all artifacts that belong to a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-artifacts-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#list-artifacts-for-a-repository
|
||||
func (s *ActionsService) ListArtifacts(ctx context.Context, owner, repo string, opts *ListOptions) (*ArtifactList, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/artifacts", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -62,7 +62,7 @@ func (s *ActionsService) ListArtifacts(ctx context.Context, owner, repo string,
|
|||
|
||||
// ListWorkflowRunArtifacts lists all artifacts that belong to a workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-workflow-run-artifacts
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#list-workflow-run-artifacts
|
||||
func (s *ActionsService) ListWorkflowRunArtifacts(ctx context.Context, owner, repo string, runID int64, opts *ListOptions) (*ArtifactList, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/artifacts", owner, repo, runID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -86,7 +86,7 @@ func (s *ActionsService) ListWorkflowRunArtifacts(ctx context.Context, owner, re
|
|||
|
||||
// GetArtifact gets a specific artifact for a workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-an-artifact
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#get-an-artifact
|
||||
func (s *ActionsService) GetArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Artifact, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID)
|
||||
|
||||
|
|
@ -106,52 +106,31 @@ func (s *ActionsService) GetArtifact(ctx context.Context, owner, repo string, ar
|
|||
|
||||
// DownloadArtifact gets a redirect URL to download an archive for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#download-an-artifact
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#download-an-artifact
|
||||
func (s *ActionsService) DownloadArtifact(ctx context.Context, owner, repo string, artifactID int64, followRedirects bool) (*url.URL, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v/zip", owner, repo, artifactID)
|
||||
|
||||
resp, err := s.getDownloadArtifactFromURL(ctx, u, followRedirects)
|
||||
resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, followRedirects)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status)
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(resp.Header.Get("Location"))
|
||||
if err != nil {
|
||||
return nil, newResponse(resp), err
|
||||
}
|
||||
|
||||
return parsedURL, newResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s *ActionsService) getDownloadArtifactFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) {
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
// Use http.DefaultTransport if no custom Transport is configured
|
||||
req = withContext(ctx, req)
|
||||
if s.client.client.Transport == nil {
|
||||
resp, err = http.DefaultTransport.RoundTrip(req)
|
||||
} else {
|
||||
resp, err = s.client.client.Transport.RoundTrip(req)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// If redirect response is returned, follow it
|
||||
if followRedirects && resp.StatusCode == http.StatusMovedPermanently {
|
||||
u = resp.Header.Get("Location")
|
||||
resp, err = s.getDownloadArtifactFromURL(ctx, u, false)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// DeleteArtifact deletes a workflow run artifact.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-an-artifact
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/artifacts#delete-an-artifact
|
||||
func (s *ActionsService) DeleteArtifact(ctx context.Context, owner, repo string, artifactID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/artifacts/%v", owner, repo, artifactID)
|
||||
|
||||
|
|
@ -61,10 +61,18 @@ type SetRunnerGroupRunnersRequest struct {
|
|||
Runners []int64 `json:"runners"`
|
||||
}
|
||||
|
||||
// ListOrgRunnerGroupOptions extend ListOptions to have the optional parameters VisibleToRepository.
|
||||
type ListOrgRunnerGroupOptions struct {
|
||||
ListOptions
|
||||
|
||||
// Only return runner groups that are allowed to be used by this repository.
|
||||
VisibleToRepository string `url:"visible_to_repository,omitempty"`
|
||||
}
|
||||
|
||||
// ListOrganizationRunnerGroups lists all self-hosted runner groups configured in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-self-hosted-runner-groups-for-an-organization
|
||||
func (s *ActionsService) ListOrganizationRunnerGroups(ctx context.Context, org string, opts *ListOptions) (*RunnerGroups, *Response, error) {
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#list-self-hosted-runner-groups-for-an-organization
|
||||
func (s *ActionsService) ListOrganizationRunnerGroups(ctx context.Context, org string, opts *ListOrgRunnerGroupOptions) (*RunnerGroups, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups", org)
|
||||
u, err := addOptions(u, opts)
|
||||
if err != nil {
|
||||
|
|
@ -87,7 +95,7 @@ func (s *ActionsService) ListOrganizationRunnerGroups(ctx context.Context, org s
|
|||
|
||||
// GetOrganizationRunnerGroup gets a specific self-hosted runner group for an organization using its RunnerGroup ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#get-a-self-hosted-runner-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#get-a-self-hosted-runner-group-for-an-organization
|
||||
func (s *ActionsService) GetOrganizationRunnerGroup(ctx context.Context, org string, groupID int64) (*RunnerGroup, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v", org, groupID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -106,7 +114,7 @@ func (s *ActionsService) GetOrganizationRunnerGroup(ctx context.Context, org str
|
|||
|
||||
// DeleteOrganizationRunnerGroup deletes a self-hosted runner group from an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#delete-a-self-hosted-runner-group-from-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#delete-a-self-hosted-runner-group-from-an-organization
|
||||
func (s *ActionsService) DeleteOrganizationRunnerGroup(ctx context.Context, org string, groupID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v", org, groupID)
|
||||
|
||||
|
|
@ -120,7 +128,7 @@ func (s *ActionsService) DeleteOrganizationRunnerGroup(ctx context.Context, org
|
|||
|
||||
// CreateOrganizationRunnerGroup creates a new self-hosted runner group for an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#create-a-self-hosted-runner-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#create-a-self-hosted-runner-group-for-an-organization
|
||||
func (s *ActionsService) CreateOrganizationRunnerGroup(ctx context.Context, org string, createReq CreateRunnerGroupRequest) (*RunnerGroup, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups", org)
|
||||
req, err := s.client.NewRequest("POST", u, createReq)
|
||||
|
|
@ -139,7 +147,7 @@ func (s *ActionsService) CreateOrganizationRunnerGroup(ctx context.Context, org
|
|||
|
||||
// UpdateOrganizationRunnerGroup updates a self-hosted runner group for an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#update-a-self-hosted-runner-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#update-a-self-hosted-runner-group-for-an-organization
|
||||
func (s *ActionsService) UpdateOrganizationRunnerGroup(ctx context.Context, org string, groupID int64, updateReq UpdateRunnerGroupRequest) (*RunnerGroup, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v", org, groupID)
|
||||
req, err := s.client.NewRequest("PATCH", u, updateReq)
|
||||
|
|
@ -158,7 +166,7 @@ func (s *ActionsService) UpdateOrganizationRunnerGroup(ctx context.Context, org
|
|||
|
||||
// ListRepositoryAccessRunnerGroup lists the repositories with access to a self-hosted runner group configured in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#list-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
func (s *ActionsService) ListRepositoryAccessRunnerGroup(ctx context.Context, org string, groupID int64, opts *ListOptions) (*ListRepositories, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/repositories", org, groupID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -183,7 +191,7 @@ func (s *ActionsService) ListRepositoryAccessRunnerGroup(ctx context.Context, or
|
|||
// SetRepositoryAccessRunnerGroup replaces the list of repositories that have access to a self-hosted runner group configured in an organization
|
||||
// with a new List of repositories.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-repository-access-for-a-self-hosted-runner-group-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#set-repository-access-for-a-self-hosted-runner-group-in-an-organization
|
||||
func (s *ActionsService) SetRepositoryAccessRunnerGroup(ctx context.Context, org string, groupID int64, ids SetRepoAccessRunnerGroupRequest) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/repositories", org, groupID)
|
||||
|
||||
|
|
@ -198,7 +206,7 @@ func (s *ActionsService) SetRepositoryAccessRunnerGroup(ctx context.Context, org
|
|||
// AddRepositoryAccessRunnerGroup adds a repository to the list of selected repositories that can access a self-hosted runner group.
|
||||
// The runner group must have visibility set to 'selected'.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#add-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#add-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
func (s *ActionsService) AddRepositoryAccessRunnerGroup(ctx context.Context, org string, groupID, repoID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/repositories/%v", org, groupID, repoID)
|
||||
|
||||
|
|
@ -213,7 +221,7 @@ func (s *ActionsService) AddRepositoryAccessRunnerGroup(ctx context.Context, org
|
|||
// RemoveRepositoryAccessRunnerGroup removes a repository from the list of selected repositories that can access a self-hosted runner group.
|
||||
// The runner group must have visibility set to 'selected'.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#remove-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#remove-repository-access-to-a-self-hosted-runner-group-in-an-organization
|
||||
func (s *ActionsService) RemoveRepositoryAccessRunnerGroup(ctx context.Context, org string, groupID, repoID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/repositories/%v", org, groupID, repoID)
|
||||
|
||||
|
|
@ -227,7 +235,7 @@ func (s *ActionsService) RemoveRepositoryAccessRunnerGroup(ctx context.Context,
|
|||
|
||||
// ListRunnerGroupRunners lists self-hosted runners that are in a specific organization group.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-self-hosted-runners-in-a-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#list-self-hosted-runners-in-a-group-for-an-organization
|
||||
func (s *ActionsService) ListRunnerGroupRunners(ctx context.Context, org string, groupID int64, opts *ListOptions) (*Runners, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/runners", org, groupID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -252,7 +260,7 @@ func (s *ActionsService) ListRunnerGroupRunners(ctx context.Context, org string,
|
|||
// SetRunnerGroupRunners replaces the list of self-hosted runners that are part of an organization runner group
|
||||
// with a new list of runners.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-self-hosted-runners-in-a-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#set-self-hosted-runners-in-a-group-for-an-organization
|
||||
func (s *ActionsService) SetRunnerGroupRunners(ctx context.Context, org string, groupID int64, ids SetRunnerGroupRunnersRequest) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/runners", org, groupID)
|
||||
|
||||
|
|
@ -266,7 +274,7 @@ func (s *ActionsService) SetRunnerGroupRunners(ctx context.Context, org string,
|
|||
|
||||
// AddRunnerGroupRunners adds a self-hosted runner to a runner group configured in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#add-a-self-hosted-runner-to-a-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#add-a-self-hosted-runner-to-a-group-for-an-organization
|
||||
func (s *ActionsService) AddRunnerGroupRunners(ctx context.Context, org string, groupID, runnerID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/runners/%v", org, groupID, runnerID)
|
||||
|
||||
|
|
@ -281,7 +289,7 @@ func (s *ActionsService) AddRunnerGroupRunners(ctx context.Context, org string,
|
|||
// RemoveRunnerGroupRunners removes a self-hosted runner from a group configured in an organization.
|
||||
// The runner is then returned to the default group.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#remove-a-self-hosted-runner-from-a-group-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runner-groups#remove-a-self-hosted-runner-from-a-group-for-an-organization
|
||||
func (s *ActionsService) RemoveRunnerGroupRunners(ctx context.Context, org string, groupID, runnerID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runner-groups/%v/runners/%v", org, groupID, runnerID)
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ type ActionsEnabledOnOrgRepos struct {
|
|||
|
||||
// ListRunnerApplicationDownloads lists self-hosted runner application binaries that can be downloaded and run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-runner-applications-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-runner-applications-for-a-repository
|
||||
func (s *ActionsService) ListRunnerApplicationDownloads(ctx context.Context, owner, repo string) ([]*RunnerApplicationDownload, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners/downloads", owner, repo)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -53,7 +53,7 @@ type RegistrationToken struct {
|
|||
|
||||
// CreateRegistrationToken creates a token that can be used to add a self-hosted runner.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-registration-token-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-registration-token-for-a-repository
|
||||
func (s *ActionsService) CreateRegistrationToken(ctx context.Context, owner, repo string) (*RegistrationToken, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners/registration-token", owner, repo)
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ type Runners struct {
|
|||
|
||||
// ListRunners lists all the self-hosted runners for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-self-hosted-runners-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-self-hosted-runners-for-a-repository
|
||||
func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, opts *ListOptions) (*Runners, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -120,7 +120,7 @@ func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, op
|
|||
|
||||
// GetRunner gets a specific self-hosted runner for a repository using its runner ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-self-hosted-runner-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#get-a-self-hosted-runner-for-a-repository
|
||||
func (s *ActionsService) GetRunner(ctx context.Context, owner, repo string, runnerID int64) (*Runner, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners/%v", owner, repo, runnerID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -145,7 +145,7 @@ type RemoveToken struct {
|
|||
|
||||
// CreateRemoveToken creates a token that can be used to remove a self-hosted runner from a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-remove-token-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-remove-token-for-a-repository
|
||||
func (s *ActionsService) CreateRemoveToken(ctx context.Context, owner, repo string) (*RemoveToken, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners/remove-token", owner, repo)
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ func (s *ActionsService) CreateRemoveToken(ctx context.Context, owner, repo stri
|
|||
|
||||
// RemoveRunner forces the removal of a self-hosted runner in a repository using the runner id.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-a-self-hosted-runner-from-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#delete-a-self-hosted-runner-from-a-repository
|
||||
func (s *ActionsService) RemoveRunner(ctx context.Context, owner, repo string, runnerID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runners/%v", owner, repo, runnerID)
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ func (s *ActionsService) RemoveRunner(ctx context.Context, owner, repo string, r
|
|||
|
||||
// ListOrganizationRunnerApplicationDownloads lists self-hosted runner application binaries that can be downloaded and run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-runner-applications-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-runner-applications-for-an-organization
|
||||
func (s *ActionsService) ListOrganizationRunnerApplicationDownloads(ctx context.Context, owner string) ([]*RunnerApplicationDownload, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners/downloads", owner)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -198,7 +198,7 @@ func (s *ActionsService) ListOrganizationRunnerApplicationDownloads(ctx context.
|
|||
|
||||
// CreateOrganizationRegistrationToken creates a token that can be used to add a self-hosted runner to an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-registration-token-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-registration-token-for-an-organization
|
||||
func (s *ActionsService) CreateOrganizationRegistrationToken(ctx context.Context, owner string) (*RegistrationToken, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners/registration-token", owner)
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ func (s *ActionsService) CreateOrganizationRegistrationToken(ctx context.Context
|
|||
|
||||
// ListOrganizationRunners lists all the self-hosted runners for an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-self-hosted-runners-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-self-hosted-runners-for-an-organization
|
||||
func (s *ActionsService) ListOrganizationRunners(ctx context.Context, owner string, opts *ListOptions) (*Runners, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners", owner)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -242,7 +242,7 @@ func (s *ActionsService) ListOrganizationRunners(ctx context.Context, owner stri
|
|||
|
||||
// ListEnabledReposInOrg lists the selected repositories that are enabled for GitHub Actions in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-selected-repositories-enabled-for-github-actions-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/permissions#list-selected-repositories-enabled-for-github-actions-in-an-organization
|
||||
func (s *ActionsService) ListEnabledReposInOrg(ctx context.Context, owner string, opts *ListOptions) (*ActionsEnabledOnOrgRepos, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/permissions/repositories", owner)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -266,7 +266,7 @@ func (s *ActionsService) ListEnabledReposInOrg(ctx context.Context, owner string
|
|||
|
||||
// SetEnabledReposInOrg replaces the list of selected repositories that are enabled for GitHub Actions in an organization..
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-selected-repositories-enabled-for-github-actions-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/permissions#set-selected-repositories-enabled-for-github-actions-in-an-organization
|
||||
func (s *ActionsService) SetEnabledReposInOrg(ctx context.Context, owner string, repositoryIDs []int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/permissions/repositories", owner)
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ func (s *ActionsService) SetEnabledReposInOrg(ctx context.Context, owner string,
|
|||
|
||||
// AddEnabledReposInOrg adds a repository to the list of selected repositories that are enabled for GitHub Actions in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#enable-a-selected-repository-for-github-actions-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/permissions#enable-a-selected-repository-for-github-actions-in-an-organization
|
||||
func (s *ActionsService) AddEnabledReposInOrg(ctx context.Context, owner string, repositoryID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/permissions/repositories/%v", owner, repositoryID)
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ func (s *ActionsService) AddEnabledReposInOrg(ctx context.Context, owner string,
|
|||
|
||||
// RemoveEnabledRepoInOrg removes a single repository from the list of enabled repos for GitHub Actions in an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#disable-a-selected-repository-for-github-actions-in-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/permissions#disable-a-selected-repository-for-github-actions-in-an-organization
|
||||
func (s *ActionsService) RemoveEnabledRepoInOrg(ctx context.Context, owner string, repositoryID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/permissions/repositories/%v", owner, repositoryID)
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ func (s *ActionsService) RemoveEnabledRepoInOrg(ctx context.Context, owner strin
|
|||
|
||||
// GetOrganizationRunner gets a specific self-hosted runner for an organization using its runner ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-self-hosted-runner-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#get-a-self-hosted-runner-for-an-organization
|
||||
func (s *ActionsService) GetOrganizationRunner(ctx context.Context, owner string, runnerID int64) (*Runner, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners/%v", owner, runnerID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -344,7 +344,7 @@ func (s *ActionsService) GetOrganizationRunner(ctx context.Context, owner string
|
|||
|
||||
// CreateOrganizationRemoveToken creates a token that can be used to remove a self-hosted runner from an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-remove-token-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-remove-token-for-an-organization
|
||||
func (s *ActionsService) CreateOrganizationRemoveToken(ctx context.Context, owner string) (*RemoveToken, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners/remove-token", owner)
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ func (s *ActionsService) CreateOrganizationRemoveToken(ctx context.Context, owne
|
|||
|
||||
// RemoveOrganizationRunner forces the removal of a self-hosted runner from an organization using the runner id.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-a-self-hosted-runner-from-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#delete-a-self-hosted-runner-from-an-organization
|
||||
func (s *ActionsService) RemoveOrganizationRunner(ctx context.Context, owner string, runnerID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/actions/runners/%v", owner, runnerID)
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ func (s *ActionsService) getPublicKey(ctx context.Context, url string) (*PublicK
|
|||
|
||||
// GetRepoPublicKey gets a public key that should be used for secret encryption.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-repository-public-key
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-a-repository-public-key
|
||||
func (s *ActionsService) GetRepoPublicKey(ctx context.Context, owner, repo string) (*PublicKey, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/actions/secrets/public-key", owner, repo)
|
||||
return s.getPublicKey(ctx, url)
|
||||
|
|
@ -72,7 +72,7 @@ func (s *ActionsService) GetRepoPublicKey(ctx context.Context, owner, repo strin
|
|||
|
||||
// GetOrgPublicKey gets a public key that should be used for secret encryption.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-an-organization-public-key
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-an-organization-public-key
|
||||
func (s *ActionsService) GetOrgPublicKey(ctx context.Context, org string) (*PublicKey, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/public-key", org)
|
||||
return s.getPublicKey(ctx, url)
|
||||
|
|
@ -80,7 +80,7 @@ func (s *ActionsService) GetOrgPublicKey(ctx context.Context, org string) (*Publ
|
|||
|
||||
// GetEnvPublicKey gets a public key that should be used for secret encryption.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#get-an-environment-public-key
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-an-environment-public-key
|
||||
func (s *ActionsService) GetEnvPublicKey(ctx context.Context, repoID int, env string) (*PublicKey, *Response, error) {
|
||||
url := fmt.Sprintf("repositories/%v/environments/%v/secrets/public-key", repoID, env)
|
||||
return s.getPublicKey(ctx, url)
|
||||
|
|
@ -124,7 +124,7 @@ func (s *ActionsService) listSecrets(ctx context.Context, url string, opts *List
|
|||
// ListRepoSecrets lists all secrets available in a repository
|
||||
// without revealing their encrypted values.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-repository-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#list-repository-secrets
|
||||
func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/actions/secrets", owner, repo)
|
||||
return s.listSecrets(ctx, url, opts)
|
||||
|
|
@ -133,7 +133,7 @@ func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string
|
|||
// ListOrgSecrets lists all secrets available in an organization
|
||||
// without revealing their encrypted values.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-organization-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#list-organization-secrets
|
||||
func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *ListOptions) (*Secrets, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets", org)
|
||||
return s.listSecrets(ctx, url, opts)
|
||||
|
|
@ -141,7 +141,7 @@ func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *L
|
|||
|
||||
// ListEnvSecrets lists all secrets available in an environment.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-environment-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#list-environment-secrets
|
||||
func (s *ActionsService) ListEnvSecrets(ctx context.Context, repoID int, env string, opts *ListOptions) (*Secrets, *Response, error) {
|
||||
url := fmt.Sprintf("repositories/%v/environments/%v/secrets", repoID, env)
|
||||
return s.listSecrets(ctx, url, opts)
|
||||
|
|
@ -164,7 +164,7 @@ func (s *ActionsService) getSecret(ctx context.Context, url string) (*Secret, *R
|
|||
|
||||
// GetRepoSecret gets a single repository secret without revealing its encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-repository-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-a-repository-secret
|
||||
func (s *ActionsService) GetRepoSecret(ctx context.Context, owner, repo, name string) (*Secret, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name)
|
||||
return s.getSecret(ctx, url)
|
||||
|
|
@ -172,7 +172,7 @@ func (s *ActionsService) GetRepoSecret(ctx context.Context, owner, repo, name st
|
|||
|
||||
// GetOrgSecret gets a single organization secret without revealing its encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-an-organization-secret
|
||||
func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*Secret, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name)
|
||||
return s.getSecret(ctx, url)
|
||||
|
|
@ -180,13 +180,13 @@ func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*S
|
|||
|
||||
// GetEnvSecret gets a single environment secret without revealing its encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-environment-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#get-an-environment-secret
|
||||
func (s *ActionsService) GetEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Secret, *Response, error) {
|
||||
url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName)
|
||||
return s.getSecret(ctx, url)
|
||||
}
|
||||
|
||||
// SelectedRepoIDs are the repository IDs that have access to the secret.
|
||||
// SelectedRepoIDs are the repository IDs that have access to the actions secrets.
|
||||
type SelectedRepoIDs []int64
|
||||
|
||||
// EncryptedSecret represents a secret that is encrypted using a public key.
|
||||
|
|
@ -213,7 +213,7 @@ func (s *ActionsService) putSecret(ctx context.Context, url string, eSecret *Enc
|
|||
|
||||
// CreateOrUpdateRepoSecret creates or updates a repository secret with an encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-or-update-a-repository-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#create-or-update-a-repository-secret
|
||||
func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, eSecret.Name)
|
||||
return s.putSecret(ctx, url, eSecret)
|
||||
|
|
@ -221,7 +221,7 @@ func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, re
|
|||
|
||||
// CreateOrUpdateOrgSecret creates or updates an organization secret with an encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-or-update-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#create-or-update-an-organization-secret
|
||||
func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, eSecret.Name)
|
||||
return s.putSecret(ctx, url, eSecret)
|
||||
|
|
@ -229,7 +229,7 @@ func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string
|
|||
|
||||
// CreateOrUpdateEnvSecret creates or updates a single environment secret with an encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#create-or-update-an-environment-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#create-or-update-an-environment-secret
|
||||
func (s *ActionsService) CreateOrUpdateEnvSecret(ctx context.Context, repoID int, env string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, eSecret.Name)
|
||||
return s.putSecret(ctx, url, eSecret)
|
||||
|
|
@ -246,7 +246,7 @@ func (s *ActionsService) deleteSecret(ctx context.Context, url string) (*Respons
|
|||
|
||||
// DeleteRepoSecret deletes a secret in a repository using the secret name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-a-repository-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#delete-a-repository-secret
|
||||
func (s *ActionsService) DeleteRepoSecret(ctx context.Context, owner, repo, name string) (*Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name)
|
||||
return s.deleteSecret(ctx, url)
|
||||
|
|
@ -254,7 +254,7 @@ func (s *ActionsService) DeleteRepoSecret(ctx context.Context, owner, repo, name
|
|||
|
||||
// DeleteOrgSecret deletes a secret in an organization using the secret name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#delete-an-organization-secret
|
||||
func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name)
|
||||
return s.deleteSecret(ctx, url)
|
||||
|
|
@ -262,7 +262,7 @@ func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string)
|
|||
|
||||
// DeleteEnvSecret deletes a secret in an environment using the secret name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#delete-an-environment-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#delete-an-environment-secret
|
||||
func (s *ActionsService) DeleteEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Response, error) {
|
||||
url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName)
|
||||
return s.deleteSecret(ctx, url)
|
||||
|
|
@ -296,7 +296,7 @@ func (s *ActionsService) listSelectedReposForSecret(ctx context.Context, url str
|
|||
|
||||
// ListSelectedReposForOrgSecret lists all repositories that have access to a secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-selected-repositories-for-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#list-selected-repositories-for-an-organization-secret
|
||||
func (s *ActionsService) ListSelectedReposForOrgSecret(ctx context.Context, org, name string, opts *ListOptions) (*SelectedReposList, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name)
|
||||
return s.listSelectedReposForSecret(ctx, url, opts)
|
||||
|
|
@ -317,7 +317,7 @@ func (s *ActionsService) setSelectedReposForSecret(ctx context.Context, url stri
|
|||
|
||||
// SetSelectedReposForOrgSecret sets the repositories that have access to a secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#set-selected-repositories-for-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#set-selected-repositories-for-an-organization-secret
|
||||
func (s *ActionsService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids SelectedRepoIDs) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name)
|
||||
return s.setSelectedReposForSecret(ctx, url, ids)
|
||||
|
|
@ -334,7 +334,7 @@ func (s *ActionsService) addSelectedRepoToSecret(ctx context.Context, url string
|
|||
|
||||
// AddSelectedRepoToOrgSecret adds a repository to an organization secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#add-selected-repository-to-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#add-selected-repository-to-an-organization-secret
|
||||
func (s *ActionsService) AddSelectedRepoToOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID)
|
||||
return s.addSelectedRepoToSecret(ctx, url)
|
||||
|
|
@ -351,7 +351,7 @@ func (s *ActionsService) removeSelectedRepoFromSecret(ctx context.Context, url s
|
|||
|
||||
// RemoveSelectedRepoFromOrgSecret removes a repository from an organization secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#remove-selected-repository-from-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/secrets#remove-selected-repository-from-an-organization-secret
|
||||
func (s *ActionsService) RemoveSelectedRepoFromOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID)
|
||||
return s.removeSelectedRepoFromSecret(ctx, url)
|
||||
|
|
@ -66,7 +66,7 @@ type ListWorkflowJobsOptions struct {
|
|||
|
||||
// ListWorkflowJobs lists all jobs for a workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-jobs-for-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-jobs#list-jobs-for-a-workflow-run
|
||||
func (s *ActionsService) ListWorkflowJobs(ctx context.Context, owner, repo string, runID int64, opts *ListWorkflowJobsOptions) (*Jobs, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/actions/runs/%v/jobs", owner, repo, runID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -90,7 +90,7 @@ func (s *ActionsService) ListWorkflowJobs(ctx context.Context, owner, repo strin
|
|||
|
||||
// GetWorkflowJobByID gets a specific job in a workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-job-for-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-jobs#get-a-job-for-a-workflow-run
|
||||
func (s *ActionsService) GetWorkflowJobByID(ctx context.Context, owner, repo string, jobID int64) (*WorkflowJob, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/jobs/%v", owner, repo, jobID)
|
||||
|
||||
|
|
@ -110,45 +110,20 @@ func (s *ActionsService) GetWorkflowJobByID(ctx context.Context, owner, repo str
|
|||
|
||||
// GetWorkflowJobLogs gets a redirect URL to download a plain text file of logs for a workflow job.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#download-job-logs-for-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-jobs#download-job-logs-for-a-workflow-run
|
||||
func (s *ActionsService) GetWorkflowJobLogs(ctx context.Context, owner, repo string, jobID int64, followRedirects bool) (*url.URL, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/jobs/%v/logs", owner, repo, jobID)
|
||||
|
||||
resp, err := s.getWorkflowLogsFromURL(ctx, u, followRedirects)
|
||||
resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, followRedirects)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status)
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(resp.Header.Get("Location"))
|
||||
return parsedURL, newResponse(resp), err
|
||||
}
|
||||
|
||||
func (s *ActionsService) getWorkflowLogsFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) {
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
// Use http.DefaultTransport if no custom Transport is configured
|
||||
req = withContext(ctx, req)
|
||||
if s.client.client.Transport == nil {
|
||||
resp, err = http.DefaultTransport.RoundTrip(req)
|
||||
} else {
|
||||
resp, err = s.client.client.Transport.RoundTrip(req)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// If redirect response is returned, follow it
|
||||
if followRedirects && resp.StatusCode == http.StatusMovedPermanently {
|
||||
u = resp.Header.Get("Location")
|
||||
resp, err = s.getWorkflowLogsFromURL(ctx, u, false)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ type WorkflowRun struct {
|
|||
WorkflowURL *string `json:"workflow_url,omitempty"`
|
||||
Repository *Repository `json:"repository,omitempty"`
|
||||
HeadRepository *Repository `json:"head_repository,omitempty"`
|
||||
Actor *User `json:"actor,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowRuns represents a slice of repository action workflow run.
|
||||
|
|
@ -93,6 +94,14 @@ type WorkflowRunAttemptOptions struct {
|
|||
ExcludePullRequests *bool `url:"exclude_pull_requests,omitempty"`
|
||||
}
|
||||
|
||||
// PendingDeploymentsRequest specifies body parameters to PendingDeployments.
|
||||
type PendingDeploymentsRequest struct {
|
||||
EnvironmentIDs []int64 `json:"environment_ids"`
|
||||
// State can be one of: "approved", "rejected".
|
||||
State string `json:"state"`
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
func (s *ActionsService) listWorkflowRuns(ctx context.Context, endpoint string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) {
|
||||
u, err := addOptions(endpoint, opts)
|
||||
if err != nil {
|
||||
|
|
@ -115,7 +124,7 @@ func (s *ActionsService) listWorkflowRuns(ctx context.Context, endpoint string,
|
|||
|
||||
// ListWorkflowRunsByID lists all workflow runs by workflow ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-workflow-runs
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs
|
||||
func (s *ActionsService) ListWorkflowRunsByID(ctx context.Context, owner, repo string, workflowID int64, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/actions/workflows/%v/runs", owner, repo, workflowID)
|
||||
return s.listWorkflowRuns(ctx, u, opts)
|
||||
|
|
@ -123,7 +132,7 @@ func (s *ActionsService) ListWorkflowRunsByID(ctx context.Context, owner, repo s
|
|||
|
||||
// ListWorkflowRunsByFileName lists all workflow runs by workflow file name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-workflow-runs
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs
|
||||
func (s *ActionsService) ListWorkflowRunsByFileName(ctx context.Context, owner, repo, workflowFileName string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/actions/workflows/%v/runs", owner, repo, workflowFileName)
|
||||
return s.listWorkflowRuns(ctx, u, opts)
|
||||
|
|
@ -131,7 +140,7 @@ func (s *ActionsService) ListWorkflowRunsByFileName(ctx context.Context, owner,
|
|||
|
||||
// ListRepositoryWorkflowRuns lists all workflow runs for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-workflow-runs-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs-for-a-repository
|
||||
func (s *ActionsService) ListRepositoryWorkflowRuns(ctx context.Context, owner, repo string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/actions/runs", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -155,7 +164,7 @@ func (s *ActionsService) ListRepositoryWorkflowRuns(ctx context.Context, owner,
|
|||
|
||||
// GetWorkflowRunByID gets a specific workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run
|
||||
func (s *ActionsService) GetWorkflowRunByID(ctx context.Context, owner, repo string, runID int64) (*WorkflowRun, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v", owner, repo, runID)
|
||||
|
||||
|
|
@ -175,7 +184,7 @@ func (s *ActionsService) GetWorkflowRunByID(ctx context.Context, owner, repo str
|
|||
|
||||
// GetWorkflowRunAttempt gets a specific workflow run attempt.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-workflow-run-attempt
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run-attempt
|
||||
func (s *ActionsService) GetWorkflowRunAttempt(ctx context.Context, owner, repo string, runID int64, attemptNumber int, opts *WorkflowRunAttemptOptions) (*WorkflowRun, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/attempts/%v", owner, repo, runID, attemptNumber)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -199,7 +208,7 @@ func (s *ActionsService) GetWorkflowRunAttempt(ctx context.Context, owner, repo
|
|||
|
||||
// RerunWorkflowByID re-runs a workflow by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#re-run-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#re-run-a-workflow
|
||||
func (s *ActionsService) RerunWorkflowByID(ctx context.Context, owner, repo string, runID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/rerun", owner, repo, runID)
|
||||
|
||||
|
|
@ -211,9 +220,37 @@ func (s *ActionsService) RerunWorkflowByID(ctx context.Context, owner, repo stri
|
|||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RerunFailedJobsByID re-runs all of the failed jobs and their dependent jobs in a workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#re-run-failed-jobs-from-a-workflow-run
|
||||
func (s *ActionsService) RerunFailedJobsByID(ctx context.Context, owner, repo string, runID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/rerun-failed-jobs", owner, repo, runID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// RerunJobByID re-runs a job and its dependent jobs in a workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#re-run-a-job-from-a-workflow-run
|
||||
func (s *ActionsService) RerunJobByID(ctx context.Context, owner, repo string, jobID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/jobs/%v/rerun", owner, repo, jobID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// CancelWorkflowRunByID cancels a workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#cancel-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#cancel-a-workflow-run
|
||||
func (s *ActionsService) CancelWorkflowRunByID(ctx context.Context, owner, repo string, runID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/cancel", owner, repo, runID)
|
||||
|
||||
|
|
@ -227,25 +264,27 @@ func (s *ActionsService) CancelWorkflowRunByID(ctx context.Context, owner, repo
|
|||
|
||||
// GetWorkflowRunLogs gets a redirect URL to download a plain text file of logs for a workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#download-workflow-run-logs
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#download-workflow-run-logs
|
||||
func (s *ActionsService) GetWorkflowRunLogs(ctx context.Context, owner, repo string, runID int64, followRedirects bool) (*url.URL, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/logs", owner, repo, runID)
|
||||
|
||||
resp, err := s.getWorkflowLogsFromURL(ctx, u, followRedirects)
|
||||
resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, followRedirects)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status)
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(resp.Header.Get("Location"))
|
||||
return parsedURL, newResponse(resp), err
|
||||
}
|
||||
|
||||
// DeleteWorkflowRun deletes a workflow run by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/actions#delete-a-workflow-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#delete-a-workflow-run
|
||||
func (s *ActionsService) DeleteWorkflowRun(ctx context.Context, owner, repo string, runID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v", owner, repo, runID)
|
||||
|
||||
|
|
@ -259,7 +298,7 @@ func (s *ActionsService) DeleteWorkflowRun(ctx context.Context, owner, repo stri
|
|||
|
||||
// DeleteWorkflowRunLogs deletes all logs for a workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#delete-workflow-run-logs
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#delete-workflow-run-logs
|
||||
func (s *ActionsService) DeleteWorkflowRunLogs(ctx context.Context, owner, repo string, runID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/logs", owner, repo, runID)
|
||||
|
||||
|
|
@ -273,7 +312,7 @@ func (s *ActionsService) DeleteWorkflowRunLogs(ctx context.Context, owner, repo
|
|||
|
||||
// GetWorkflowRunUsageByID gets a specific workflow usage run by run ID in the unit of billable milliseconds.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-workflow-run-usage
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#get-workflow-run-usage
|
||||
func (s *ActionsService) GetWorkflowRunUsageByID(ctx context.Context, owner, repo string, runID int64) (*WorkflowRunUsage, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/timing", owner, repo, runID)
|
||||
|
||||
|
|
@ -290,3 +329,23 @@ func (s *ActionsService) GetWorkflowRunUsageByID(ctx context.Context, owner, rep
|
|||
|
||||
return workflowRunUsage, resp, nil
|
||||
}
|
||||
|
||||
// PendingDeployments approve or reject pending deployments that are waiting on approval by a required reviewer.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflow-runs#review-pending-deployments-for-a-workflow-run
|
||||
func (s *ActionsService) PendingDeployments(ctx context.Context, owner, repo string, runID int64, request *PendingDeploymentsRequest) ([]*Deployment, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/pending_deployments", owner, repo, runID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var deployments []*Deployment
|
||||
resp, err := s.client.Do(ctx, req, &deployments)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return deployments, resp, nil
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ type CreateWorkflowDispatchEventRequest struct {
|
|||
|
||||
// ListWorkflows lists all workflows in a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#list-repository-workflows
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#list-repository-workflows
|
||||
func (s *ActionsService) ListWorkflows(ctx context.Context, owner, repo string, opts *ListOptions) (*Workflows, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/actions/workflows", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -85,7 +85,7 @@ func (s *ActionsService) ListWorkflows(ctx context.Context, owner, repo string,
|
|||
|
||||
// GetWorkflowByID gets a specific workflow by ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#get-a-workflow
|
||||
func (s *ActionsService) GetWorkflowByID(ctx context.Context, owner, repo string, workflowID int64) (*Workflow, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v", owner, repo, workflowID)
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ func (s *ActionsService) GetWorkflowByID(ctx context.Context, owner, repo string
|
|||
|
||||
// GetWorkflowByFileName gets a specific workflow by file name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#get-a-workflow
|
||||
func (s *ActionsService) GetWorkflowByFileName(ctx context.Context, owner, repo, workflowFileName string) (*Workflow, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v", owner, repo, workflowFileName)
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ func (s *ActionsService) getWorkflow(ctx context.Context, url string) (*Workflow
|
|||
|
||||
// GetWorkflowUsageByID gets a specific workflow usage by ID in the unit of billable milliseconds.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-workflow-usage
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#get-workflow-usage
|
||||
func (s *ActionsService) GetWorkflowUsageByID(ctx context.Context, owner, repo string, workflowID int64) (*WorkflowUsage, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/timing", owner, repo, workflowID)
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ func (s *ActionsService) GetWorkflowUsageByID(ctx context.Context, owner, repo s
|
|||
|
||||
// GetWorkflowUsageByFileName gets a specific workflow usage by file name in the unit of billable milliseconds.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#get-workflow-usage
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#get-workflow-usage
|
||||
func (s *ActionsService) GetWorkflowUsageByFileName(ctx context.Context, owner, repo, workflowFileName string) (*WorkflowUsage, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/timing", owner, repo, workflowFileName)
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ func (s *ActionsService) getWorkflowUsage(ctx context.Context, url string) (*Wor
|
|||
|
||||
// CreateWorkflowDispatchEventByID manually triggers a GitHub Actions workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-workflow-dispatch-event
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event
|
||||
func (s *ActionsService) CreateWorkflowDispatchEventByID(ctx context.Context, owner, repo string, workflowID int64, event CreateWorkflowDispatchEventRequest) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/dispatches", owner, repo, workflowID)
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ func (s *ActionsService) CreateWorkflowDispatchEventByID(ctx context.Context, ow
|
|||
|
||||
// CreateWorkflowDispatchEventByFileName manually triggers a GitHub Actions workflow run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#create-a-workflow-dispatch-event
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event
|
||||
func (s *ActionsService) CreateWorkflowDispatchEventByFileName(ctx context.Context, owner, repo, workflowFileName string, event CreateWorkflowDispatchEventRequest) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/dispatches", owner, repo, workflowFileName)
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ func (s *ActionsService) createWorkflowDispatchEvent(ctx context.Context, url st
|
|||
|
||||
// EnableWorkflowByID enables a workflow and sets the state of the workflow to "active".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#enable-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#enable-a-workflow
|
||||
func (s *ActionsService) EnableWorkflowByID(ctx context.Context, owner, repo string, workflowID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/enable", owner, repo, workflowID)
|
||||
return s.doNewPutRequest(ctx, u)
|
||||
|
|
@ -186,7 +186,7 @@ func (s *ActionsService) EnableWorkflowByID(ctx context.Context, owner, repo str
|
|||
|
||||
// EnableWorkflowByFileName enables a workflow and sets the state of the workflow to "active".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#enable-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#enable-a-workflow
|
||||
func (s *ActionsService) EnableWorkflowByFileName(ctx context.Context, owner, repo, workflowFileName string) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/enable", owner, repo, workflowFileName)
|
||||
return s.doNewPutRequest(ctx, u)
|
||||
|
|
@ -194,7 +194,7 @@ func (s *ActionsService) EnableWorkflowByFileName(ctx context.Context, owner, re
|
|||
|
||||
// DisableWorkflowByID disables a workflow and sets the state of the workflow to "disabled_manually".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#disable-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#disable-a-workflow
|
||||
func (s *ActionsService) DisableWorkflowByID(ctx context.Context, owner, repo string, workflowID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/disable", owner, repo, workflowID)
|
||||
return s.doNewPutRequest(ctx, u)
|
||||
|
|
@ -202,7 +202,7 @@ func (s *ActionsService) DisableWorkflowByID(ctx context.Context, owner, repo st
|
|||
|
||||
// DisableWorkflowByFileName disables a workflow and sets the state of the workflow to "disabled_manually".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions/#disable-a-workflow
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/workflows#disable-a-workflow
|
||||
func (s *ActionsService) DisableWorkflowByFileName(ctx context.Context, owner, repo, workflowFileName string) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/actions/workflows/%v/disable", owner, repo, workflowFileName)
|
||||
return s.doNewPutRequest(ctx, u)
|
||||
|
|
@ -10,7 +10,7 @@ import "context"
|
|||
// ActivityService handles communication with the activity related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/
|
||||
type ActivityService service
|
||||
|
||||
// FeedLink represents a link to a related resource.
|
||||
|
|
@ -45,14 +45,15 @@ type FeedLinks struct {
|
|||
// ListFeeds lists all the feeds available to the authenticated user.
|
||||
//
|
||||
// GitHub provides several timeline resources in Atom format:
|
||||
// Timeline: The GitHub global public timeline
|
||||
// User: The public timeline for any user, using URI template
|
||||
// Current user public: The public timeline for the authenticated user
|
||||
// Current user: The private timeline for the authenticated user
|
||||
// Current user actor: The private timeline for activity created by the
|
||||
// authenticated user
|
||||
// Current user organizations: The private timeline for the organizations
|
||||
// the authenticated user is a member of.
|
||||
//
|
||||
// Timeline: The GitHub global public timeline
|
||||
// User: The public timeline for any user, using URI template
|
||||
// Current user public: The public timeline for the authenticated user
|
||||
// Current user: The private timeline for the authenticated user
|
||||
// Current user actor: The private timeline for activity created by the
|
||||
// authenticated user
|
||||
// Current user organizations: The private timeline for the organizations
|
||||
// the authenticated user is a member of.
|
||||
//
|
||||
// Note: Private feeds are only returned when authenticating via Basic Auth
|
||||
// since current feed URIs use the older, non revocable auth tokens.
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// ListEvents drinks from the firehose of all public events across GitHub.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-public-events
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-public-events
|
||||
func (s *ActivityService) ListEvents(ctx context.Context, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
u, err := addOptions("events", opts)
|
||||
if err != nil {
|
||||
|
|
@ -35,7 +35,7 @@ func (s *ActivityService) ListEvents(ctx context.Context, opts *ListOptions) ([]
|
|||
|
||||
// ListRepositoryEvents lists events for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repository-events
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-repository-events
|
||||
func (s *ActivityService) ListRepositoryEvents(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/events", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -59,7 +59,7 @@ func (s *ActivityService) ListRepositoryEvents(ctx context.Context, owner, repo
|
|||
|
||||
// ListIssueEventsForRepository lists issue events for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/issues/#list-issue-events-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/issues/events#list-issue-events-for-a-repository
|
||||
func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, owner, repo string, opts *ListOptions) ([]*IssueEvent, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -83,7 +83,7 @@ func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, owne
|
|||
|
||||
// ListEventsForRepoNetwork lists public events for a network of repositories.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-public-events-for-a-network-of-repositories
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-public-events-for-a-network-of-repositories
|
||||
func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
u := fmt.Sprintf("networks/%v/%v/events", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -107,7 +107,7 @@ func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, owner, r
|
|||
|
||||
// ListEventsForOrganization lists public events for an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-public-organization-events
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-public-organization-events
|
||||
func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org string, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/events", org)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -132,8 +132,8 @@ func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org str
|
|||
// ListEventsPerformedByUser lists the events performed by a user. If publicOnly is
|
||||
// true, only public events will be returned.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-events-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-public-events-for-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-events-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-public-events-for-a-user
|
||||
func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user string, publicOnly bool, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
var u string
|
||||
if publicOnly {
|
||||
|
|
@ -163,8 +163,8 @@ func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user st
|
|||
// ListEventsReceivedByUser lists the events received by a user. If publicOnly is
|
||||
// true, only public events will be returned.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-events-received-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-public-events-received-by-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-events-received-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-public-events-received-by-a-user
|
||||
func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user string, publicOnly bool, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
var u string
|
||||
if publicOnly {
|
||||
|
|
@ -194,7 +194,7 @@ func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user str
|
|||
// ListUserEventsForOrganization provides the user’s organization dashboard. You
|
||||
// must be authenticated as the user to view this.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-organization-events-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/events#list-organization-events-for-the-authenticated-user
|
||||
func (s *ActivityService) ListUserEventsForOrganization(ctx context.Context, org, user string, opts *ListOptions) ([]*Event, *Response, error) {
|
||||
u := fmt.Sprintf("users/%v/events/orgs/%v", user, org)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -19,7 +19,7 @@ type Notification struct {
|
|||
|
||||
// Reason identifies the event that triggered the notification.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity#notification-reasons
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity#notification-reasons
|
||||
Reason *string `json:"reason,omitempty"`
|
||||
|
||||
Unread *bool `json:"unread,omitempty"`
|
||||
|
|
@ -49,7 +49,7 @@ type NotificationListOptions struct {
|
|||
|
||||
// ListNotifications lists all notifications for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-notifications-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#list-notifications-for-the-authenticated-user
|
||||
func (s *ActivityService) ListNotifications(ctx context.Context, opts *NotificationListOptions) ([]*Notification, *Response, error) {
|
||||
u := "notifications"
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -74,7 +74,7 @@ func (s *ActivityService) ListNotifications(ctx context.Context, opts *Notificat
|
|||
// ListRepositoryNotifications lists all notifications in a given repository
|
||||
// for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repository-notifications-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#list-repository-notifications-for-the-authenticated-user
|
||||
func (s *ActivityService) ListRepositoryNotifications(ctx context.Context, owner, repo string, opts *NotificationListOptions) ([]*Notification, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -102,7 +102,7 @@ type markReadOptions struct {
|
|||
|
||||
// MarkNotificationsRead marks all notifications up to lastRead as read.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity#mark-as-read
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity#mark-as-read
|
||||
func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead time.Time) (*Response, error) {
|
||||
opts := &markReadOptions{
|
||||
LastReadAt: lastRead,
|
||||
|
|
@ -118,7 +118,7 @@ func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead ti
|
|||
// MarkRepositoryNotificationsRead marks all notifications up to lastRead in
|
||||
// the specified repository as read.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#mark-repository-notifications-as-read
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#mark-repository-notifications-as-read
|
||||
func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) {
|
||||
opts := &markReadOptions{
|
||||
LastReadAt: lastRead,
|
||||
|
|
@ -134,7 +134,7 @@ func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, o
|
|||
|
||||
// GetThread gets the specified notification thread.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#get-a-thread
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#get-a-thread
|
||||
func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notification, *Response, error) {
|
||||
u := fmt.Sprintf("notifications/threads/%v", id)
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notificati
|
|||
|
||||
// MarkThreadRead marks the specified thread as read.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#mark-a-thread-as-read
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#mark-a-thread-as-read
|
||||
func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Response, error) {
|
||||
u := fmt.Sprintf("notifications/threads/%v", id)
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Respo
|
|||
// GetThreadSubscription checks to see if the authenticated user is subscribed
|
||||
// to a thread.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#get-a-thread-subscription-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#get-a-thread-subscription-for-the-authenticated-user
|
||||
func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string) (*Subscription, *Response, error) {
|
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string)
|
|||
// SetThreadSubscription sets the subscription for the specified thread for the
|
||||
// authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#set-a-thread-subscription
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#set-a-thread-subscription
|
||||
func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string, subscription *Subscription) (*Subscription, *Response, error) {
|
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string,
|
|||
// DeleteThreadSubscription deletes the subscription for the specified thread
|
||||
// for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#delete-a-thread-subscription
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/notifications#delete-a-thread-subscription
|
||||
func (s *ActivityService) DeleteThreadSubscription(ctx context.Context, id string) (*Response, error) {
|
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
|
|
@ -25,7 +25,7 @@ type Stargazer struct {
|
|||
|
||||
// ListStargazers lists people who have starred the specified repo.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-stargazers
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#list-stargazers
|
||||
func (s *ActivityService) ListStargazers(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Stargazer, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -67,8 +67,8 @@ type ActivityListStarredOptions struct {
|
|||
// ListStarred lists all the repos starred by a user. Passing the empty string
|
||||
// will list the starred repositories for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repositories-starred-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repositories-starred-by-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#list-repositories-starred-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#list-repositories-starred-by-a-user
|
||||
func (s *ActivityService) ListStarred(ctx context.Context, user string, opts *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) {
|
||||
var u string
|
||||
if user != "" {
|
||||
|
|
@ -101,13 +101,14 @@ func (s *ActivityService) ListStarred(ctx context.Context, user string, opts *Ac
|
|||
|
||||
// IsStarred checks if a repository is starred by authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#check-if-a-repository-is-starred-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#check-if-a-repository-is-starred-by-the-authenticated-user
|
||||
func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bool, *Response, error) {
|
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(ctx, req, nil)
|
||||
starred, err := parseBoolResponse(err)
|
||||
return starred, resp, err
|
||||
|
|
@ -115,24 +116,26 @@ func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bo
|
|||
|
||||
// Star a repository as the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#star-a-repository-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#star-a-repository-for-the-authenticated-user
|
||||
func (s *ActivityService) Star(ctx context.Context, owner, repo string) (*Response, error) {
|
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
|
||||
req, err := s.client.NewRequest("PUT", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// Unstar a repository as the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#unstar-a-repository-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/starring#unstar-a-repository-for-the-authenticated-user
|
||||
func (s *ActivityService) Unstar(ctx context.Context, owner, repo string) (*Response, error) {
|
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ type Subscription struct {
|
|||
|
||||
// ListWatchers lists watchers of a particular repo.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-watchers
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#list-watchers
|
||||
func (s *ActivityService) ListWatchers(ctx context.Context, owner, repo string, opts *ListOptions) ([]*User, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -52,8 +52,8 @@ func (s *ActivityService) ListWatchers(ctx context.Context, owner, repo string,
|
|||
// ListWatched lists the repositories the specified user is watching. Passing
|
||||
// the empty string will fetch watched repos for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repositories-watched-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-repositories-watched-by-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#list-repositories-watched-by-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#list-repositories-watched-by-a-user
|
||||
func (s *ActivityService) ListWatched(ctx context.Context, user string, opts *ListOptions) ([]*Repository, *Response, error) {
|
||||
var u string
|
||||
if user != "" {
|
||||
|
|
@ -84,7 +84,7 @@ func (s *ActivityService) ListWatched(ctx context.Context, user string, opts *Li
|
|||
// repository for the authenticated user. If the authenticated user is not
|
||||
// watching the repository, a nil Subscription is returned.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#get-a-repository-subscription
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#get-a-repository-subscription
|
||||
func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner, repo string) (*Subscription, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner,
|
|||
// To ignore notifications made within a repository, set subscription.Ignored to true.
|
||||
// To stop watching a repository, use DeleteRepositorySubscription.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#set-a-repository-subscription
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#set-a-repository-subscription
|
||||
func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner, repo string, subscription *Subscription) (*Subscription, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner,
|
|||
// This is used to stop watching a repository. To control whether or not to
|
||||
// receive notifications from a repository, use SetRepositorySubscription.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#delete-a-repository-subscription
|
||||
// GitHub API docs: https://docs.github.com/en/rest/activity/watching#delete-a-repository-subscription
|
||||
func (s *ActivityService) DeleteRepositorySubscription(ctx context.Context, owner, repo string) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
// GitHub API. These API routes are normally only accessible for GitHub
|
||||
// Enterprise installations.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/enterprise-admin
|
||||
type AdminService service
|
||||
|
||||
// TeamLDAPMapping represents the mapping between a GitHub team and an LDAP group.
|
||||
|
|
@ -82,7 +82,7 @@ func (m Enterprise) String() string {
|
|||
|
||||
// UpdateUserLDAPMapping updates the mapping between a GitHub user and an LDAP user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise/ldap/#update-ldap-mapping-for-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/enterprise-server/rest/enterprise-admin/ldap#update-ldap-mapping-for-a-user
|
||||
func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) {
|
||||
u := fmt.Sprintf("admin/ldap/users/%v/mapping", user)
|
||||
req, err := s.client.NewRequest("PATCH", u, mapping)
|
||||
|
|
@ -101,7 +101,7 @@ func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, m
|
|||
|
||||
// UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise/ldap/#update-ldap-mapping-for-a-team
|
||||
// GitHub API docs: https://docs.github.com/en/rest/enterprise/ldap/#update-ldap-mapping-for-a-team
|
||||
func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int64, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) {
|
||||
u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team)
|
||||
req, err := s.client.NewRequest("PATCH", u, mapping)
|
||||
|
|
@ -153,7 +153,7 @@ func (s RepoStats) String() string {
|
|||
// Please note that this is only available to site administrators,
|
||||
// otherwise it will error with a 404 not found (instead of 401 or 403).
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise-admin/admin_stats/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/enterprise-admin/admin_stats/
|
||||
func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) {
|
||||
u := fmt.Sprintf("enterprise/stats/all")
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
// AppsService provides access to the installation related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/
|
||||
type AppsService service
|
||||
|
||||
// App represents a GitHub App.
|
||||
|
|
@ -59,8 +59,9 @@ type InstallationTokenOptions struct {
|
|||
// InstallationPermissions lists the repository and organization permissions for an installation.
|
||||
//
|
||||
// Permission names taken from:
|
||||
// https://docs.github.com/en/enterprise-server@3.0/rest/reference/apps#create-an-installation-access-token-for-an-app
|
||||
// https://docs.github.com/en/rest/reference/apps#create-an-installation-access-token-for-an-app
|
||||
//
|
||||
// https://docs.github.com/en/enterprise-server@3.0/rest/apps#create-an-installation-access-token-for-an-app
|
||||
// https://docs.github.com/en/rest/apps#create-an-installation-access-token-for-an-app
|
||||
type InstallationPermissions struct {
|
||||
Actions *string `json:"actions,omitempty"`
|
||||
Administration *string `json:"administration,omitempty"`
|
||||
|
|
@ -76,7 +77,9 @@ type InstallationPermissions struct {
|
|||
Metadata *string `json:"metadata,omitempty"`
|
||||
Members *string `json:"members,omitempty"`
|
||||
OrganizationAdministration *string `json:"organization_administration,omitempty"`
|
||||
OrganizationCustomRoles *string `json:"organization_custom_roles,omitempty"`
|
||||
OrganizationHooks *string `json:"organization_hooks,omitempty"`
|
||||
OrganizationPackages *string `json:"organization_packages,omitempty"`
|
||||
OrganizationPlan *string `json:"organization_plan,omitempty"`
|
||||
OrganizationPreReceiveHooks *string `json:"organization_pre_receive_hooks,omitempty"`
|
||||
OrganizationProjects *string `json:"organization_projects,omitempty"`
|
||||
|
|
@ -148,8 +151,8 @@ func (i Installation) String() string {
|
|||
// You can find this on the settings page for your GitHub App
|
||||
// (e.g., https://github.com/settings/apps/:app_slug).
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-an-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-an-app
|
||||
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) {
|
||||
var u string
|
||||
if appSlug != "" {
|
||||
|
|
@ -174,7 +177,7 @@ func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response,
|
|||
|
||||
// ListInstallations lists the installations that the current GitHub App has.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-installations-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#list-installations-for-the-authenticated-app
|
||||
func (s *AppsService) ListInstallations(ctx context.Context, opts *ListOptions) ([]*Installation, *Response, error) {
|
||||
u, err := addOptions("app/installations", opts)
|
||||
if err != nil {
|
||||
|
|
@ -197,14 +200,14 @@ func (s *AppsService) ListInstallations(ctx context.Context, opts *ListOptions)
|
|||
|
||||
// GetInstallation returns the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-an-installation-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-an-installation-for-the-authenticated-app
|
||||
func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) {
|
||||
return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id))
|
||||
}
|
||||
|
||||
// ListUserInstallations lists installations that are accessible to the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-app-installations-accessible-to-the-user-access-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#list-app-installations-accessible-to-the-user-access-token
|
||||
func (s *AppsService) ListUserInstallations(ctx context.Context, opts *ListOptions) ([]*Installation, *Response, error) {
|
||||
u, err := addOptions("user/installations", opts)
|
||||
if err != nil {
|
||||
|
|
@ -229,7 +232,7 @@ func (s *AppsService) ListUserInstallations(ctx context.Context, opts *ListOptio
|
|||
|
||||
// SuspendInstallation suspends the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#suspend-an-app-installation
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#suspend-an-app-installation
|
||||
func (s *AppsService) SuspendInstallation(ctx context.Context, id int64) (*Response, error) {
|
||||
u := fmt.Sprintf("app/installations/%v/suspended", id)
|
||||
|
||||
|
|
@ -243,7 +246,7 @@ func (s *AppsService) SuspendInstallation(ctx context.Context, id int64) (*Respo
|
|||
|
||||
// UnsuspendInstallation unsuspends the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#unsuspend-an-app-installation
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#unsuspend-an-app-installation
|
||||
func (s *AppsService) UnsuspendInstallation(ctx context.Context, id int64) (*Response, error) {
|
||||
u := fmt.Sprintf("app/installations/%v/suspended", id)
|
||||
|
||||
|
|
@ -257,7 +260,7 @@ func (s *AppsService) UnsuspendInstallation(ctx context.Context, id int64) (*Res
|
|||
|
||||
// DeleteInstallation deletes the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#delete-an-installation-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#delete-an-installation-for-the-authenticated-app
|
||||
func (s *AppsService) DeleteInstallation(ctx context.Context, id int64) (*Response, error) {
|
||||
u := fmt.Sprintf("app/installations/%v", id)
|
||||
|
||||
|
|
@ -271,7 +274,7 @@ func (s *AppsService) DeleteInstallation(ctx context.Context, id int64) (*Respon
|
|||
|
||||
// CreateInstallationToken creates a new installation token.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#create-an-installation-access-token-for-an-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app
|
||||
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opts *InstallationTokenOptions) (*InstallationToken, *Response, error) {
|
||||
u := fmt.Sprintf("app/installations/%v/access_tokens", id)
|
||||
|
||||
|
|
@ -291,7 +294,7 @@ func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opt
|
|||
|
||||
// CreateAttachment creates a new attachment on user comment containing a url.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#create-a-content-attachment
|
||||
// TODO: Find GitHub API docs.
|
||||
func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID int64, title, body string) (*Attachment, *Response, error) {
|
||||
u := fmt.Sprintf("content_references/%v/attachments", contentReferenceID)
|
||||
payload := &Attachment{Title: String(title), Body: String(body)}
|
||||
|
|
@ -314,14 +317,14 @@ func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID i
|
|||
|
||||
// FindOrganizationInstallation finds the organization's installation information.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-an-organization-installation-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-an-organization-installation-for-the-authenticated-app
|
||||
func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) {
|
||||
return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org))
|
||||
}
|
||||
|
||||
// FindRepositoryInstallation finds the repository's installation information.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-a-repository-installation-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-a-repository-installation-for-the-authenticated-app
|
||||
func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) {
|
||||
return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo))
|
||||
}
|
||||
|
|
@ -335,7 +338,7 @@ func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int
|
|||
|
||||
// FindUserInstallation finds the user's installation information.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#get-a-user-installation-for-the-authenticated-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#get-a-user-installation-for-the-authenticated-app
|
||||
func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) {
|
||||
return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user))
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
// GetHookConfig returns the webhook configuration for a GitHub App.
|
||||
// The underlying transport must be authenticated as an app.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps#get-a-webhook-configuration-for-an-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#get-a-webhook-configuration-for-an-app
|
||||
func (s *AppsService) GetHookConfig(ctx context.Context) (*HookConfig, *Response, error) {
|
||||
req, err := s.client.NewRequest("GET", "app/hook/config", nil)
|
||||
if err != nil {
|
||||
|
|
@ -31,7 +31,7 @@ func (s *AppsService) GetHookConfig(ctx context.Context) (*HookConfig, *Response
|
|||
// UpdateHookConfig updates the webhook configuration for a GitHub App.
|
||||
// The underlying transport must be authenticated as an app.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps#update-a-webhook-configuration-for-an-app
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#update-a-webhook-configuration-for-an-app
|
||||
func (s *AppsService) UpdateHookConfig(ctx context.Context, config *HookConfig) (*HookConfig, *Response, error) {
|
||||
req, err := s.client.NewRequest("PATCH", "app/hook/config", config)
|
||||
if err != nil {
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// ListHookDeliveries lists deliveries of an App webhook.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/apps#list-deliveries-for-an-app-webhook
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/webhooks#list-deliveries-for-an-app-webhook
|
||||
func (s *AppsService) ListHookDeliveries(ctx context.Context, opts *ListCursorOptions) ([]*HookDelivery, *Response, error) {
|
||||
u, err := addOptions("app/hook/deliveries", opts)
|
||||
if err != nil {
|
||||
|
|
@ -35,7 +35,7 @@ func (s *AppsService) ListHookDeliveries(ctx context.Context, opts *ListCursorOp
|
|||
|
||||
// GetHookDelivery returns the App webhook delivery with the specified ID.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/apps#get-a-delivery-for-an-app-webhook
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/webhooks#get-a-delivery-for-an-app-webhook
|
||||
func (s *AppsService) GetHookDelivery(ctx context.Context, deliveryID int64) (*HookDelivery, *Response, error) {
|
||||
u := fmt.Sprintf("app/hook/deliveries/%v", deliveryID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -54,7 +54,7 @@ func (s *AppsService) GetHookDelivery(ctx context.Context, deliveryID int64) (*H
|
|||
|
||||
// RedeliverHookDelivery redelivers a delivery for an App webhook.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/apps#redeliver-a-delivery-for-an-app-webhook
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/webhooks#redeliver-a-delivery-for-an-app-webhook
|
||||
func (s *AppsService) RedeliverHookDelivery(ctx context.Context, deliveryID int64) (*HookDelivery, *Response, error) {
|
||||
u := fmt.Sprintf("app/hook/deliveries/%v/attempts", deliveryID)
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
|
|
@ -19,7 +19,7 @@ type ListRepositories struct {
|
|||
|
||||
// ListRepos lists the repositories that are accessible to the authenticated installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-repositories-accessible-to-the-app-installation
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#list-repositories-accessible-to-the-app-installation
|
||||
func (s *AppsService) ListRepos(ctx context.Context, opts *ListOptions) (*ListRepositories, *Response, error) {
|
||||
u, err := addOptions("installation/repositories", opts)
|
||||
if err != nil {
|
||||
|
|
@ -52,7 +52,7 @@ func (s *AppsService) ListRepos(ctx context.Context, opts *ListOptions) (*ListRe
|
|||
// ListUserRepos lists repositories that are accessible
|
||||
// to the authenticated user for an installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-repositories-accessible-to-the-user-access-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#list-repositories-accessible-to-the-user-access-token
|
||||
func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opts *ListOptions) (*ListRepositories, *Response, error) {
|
||||
u := fmt.Sprintf("user/installations/%v/repositories", id)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -84,7 +84,7 @@ func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opts *ListOpt
|
|||
|
||||
// AddRepository adds a single repository to an installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#add-a-repository-to-an-app-installation
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#add-a-repository-to-an-app-installation
|
||||
func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (*Repository, *Response, error) {
|
||||
u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID)
|
||||
req, err := s.client.NewRequest("PUT", u, nil)
|
||||
|
|
@ -103,7 +103,7 @@ func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (
|
|||
|
||||
// RemoveRepository removes a single repository from an installation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#remove-a-repository-from-an-app-installation
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#remove-a-repository-from-an-app-installation
|
||||
func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("user/installations/%v/repositories/%v", instID, repoID)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
|
|
@ -116,7 +116,7 @@ func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64
|
|||
|
||||
// RevokeInstallationToken revokes an installation token.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#revoke-an-installation-access-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/installations#revoke-an-installation-access-token
|
||||
func (s *AppsService) RevokeInstallationToken(ctx context.Context) (*Response, error) {
|
||||
u := "installation/token"
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
|
|
@ -31,7 +31,7 @@ type AppConfig struct {
|
|||
// CompleteAppManifest completes the App manifest handshake flow for the given
|
||||
// code.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#create-a-github-app-from-a-manifest
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/apps#create-a-github-app-from-a-manifest
|
||||
func (s *AppsService) CompleteAppManifest(ctx context.Context, code string) (*AppConfig, *Response, error) {
|
||||
u := fmt.Sprintf("app-manifests/%s/conversions", code)
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
// MarketplaceService handles communication with the marketplace related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps#marketplace
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#marketplace
|
||||
type MarketplaceService struct {
|
||||
client *Client
|
||||
// Stubbed controls whether endpoints that return stubbed data are used
|
||||
|
|
@ -21,7 +21,7 @@ type MarketplaceService struct {
|
|||
// for testing your GitHub Apps. Stubbed data is hard-coded and will not
|
||||
// change based on actual subscriptions.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps#testing-with-stubbed-endpoints
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#testing-with-stubbed-endpoints
|
||||
Stubbed bool
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ type MarketplacePlanAccount struct {
|
|||
|
||||
// ListPlans lists all plans for your Marketplace listing.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps#list-plans
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#list-plans
|
||||
func (s *MarketplaceService) ListPlans(ctx context.Context, opts *ListOptions) ([]*MarketplacePlan, *Response, error) {
|
||||
uri := s.marketplaceURI("plans")
|
||||
u, err := addOptions(uri, opts)
|
||||
|
|
@ -101,7 +101,7 @@ func (s *MarketplaceService) ListPlans(ctx context.Context, opts *ListOptions) (
|
|||
|
||||
// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/apps#list-accounts-for-a-plan
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#list-accounts-for-a-plan
|
||||
func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opts *ListOptions) ([]*MarketplacePlanAccount, *Response, error) {
|
||||
uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID))
|
||||
u, err := addOptions(uri, opts)
|
||||
|
|
@ -125,7 +125,7 @@ func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID
|
|||
|
||||
// GetPlanAccountForAccount get GitHub account (user or organization) associated with an account.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/apps#get-a-subscription-plan-for-an-account
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps#get-a-subscription-plan-for-an-account
|
||||
func (s *MarketplaceService) GetPlanAccountForAccount(ctx context.Context, accountID int64) (*MarketplacePlanAccount, *Response, error) {
|
||||
uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID))
|
||||
|
||||
|
|
@ -145,8 +145,8 @@ func (s *MarketplaceService) GetPlanAccountForAccount(ctx context.Context, accou
|
|||
|
||||
// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-subscriptions-for-the-authenticated-user-stubbed
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#list-subscriptions-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/marketplace#list-subscriptions-for-the-authenticated-user-stubbed
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/marketplace#list-subscriptions-for-the-authenticated-user
|
||||
func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opts *ListOptions) ([]*MarketplacePurchase, *Response, error) {
|
||||
uri := "user/marketplace_purchases"
|
||||
if s.Stubbed {
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// Scope models a GitHub authorization scope.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/oauth/#scopes
|
||||
// GitHub API docs: https://docs.github.com/en/rest/oauth/#scopes
|
||||
type Scope string
|
||||
|
||||
// This is the set of scopes for GitHub API V3
|
||||
|
|
@ -50,7 +50,7 @@ const (
|
|||
// This service requires HTTP Basic Authentication; it cannot be accessed using
|
||||
// an OAuth token.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/oauth_authorizations/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/oauth-authorizations
|
||||
type AuthorizationsService service
|
||||
|
||||
// Authorization represents an individual GitHub authorization.
|
||||
|
|
@ -121,7 +121,7 @@ func (a AuthorizationRequest) String() string {
|
|||
// fields. That is, you may provide only one of "Scopes", or "AddScopes", or
|
||||
// "RemoveScopes".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/oauth_authorizations/#update-an-existing-authorization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/oauth-authorizations#update-an-existing-authorization
|
||||
type AuthorizationUpdateRequest struct {
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
AddScopes []string `json:"add_scopes,omitempty"`
|
||||
|
|
@ -143,7 +143,7 @@ func (a AuthorizationUpdateRequest) String() string {
|
|||
//
|
||||
// The returned Authorization.User field will be populated.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#check-a-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/oauth-applications#check-a-token
|
||||
func (s *AuthorizationsService) Check(ctx context.Context, clientID, accessToken string) (*Authorization, *Response, error) {
|
||||
u := fmt.Sprintf("applications/%v/token", clientID)
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ func (s *AuthorizationsService) Check(ctx context.Context, clientID, accessToken
|
|||
//
|
||||
// The returned Authorization.User field will be populated.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#reset-a-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/oauth-applications#reset-a-token
|
||||
func (s *AuthorizationsService) Reset(ctx context.Context, clientID, accessToken string) (*Authorization, *Response, error) {
|
||||
u := fmt.Sprintf("applications/%v/token", clientID)
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ func (s *AuthorizationsService) Reset(ctx context.Context, clientID, accessToken
|
|||
// username is the OAuth application clientID, and the password is its
|
||||
// clientSecret. Invalid tokens will return a 404 Not Found.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#delete-an-app-token
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-token
|
||||
func (s *AuthorizationsService) Revoke(ctx context.Context, clientID, accessToken string) (*Response, error) {
|
||||
u := fmt.Sprintf("applications/%v/token", clientID)
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ func (s *AuthorizationsService) Revoke(ctx context.Context, clientID, accessToke
|
|||
// grant will also delete all OAuth tokens associated with the application for
|
||||
// the user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/apps/#delete-an-app-authorization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization
|
||||
func (s *AuthorizationsService) DeleteGrant(ctx context.Context, clientID, accessToken string) (*Response, error) {
|
||||
u := fmt.Sprintf("applications/%v/grant", clientID)
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
// BillingService provides access to the billing related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing
|
||||
type BillingService service
|
||||
|
||||
// ActionBilling represents a GitHub Action billing.
|
||||
|
|
@ -65,7 +65,7 @@ type AdvancedSecurityCommittersBreakdown struct {
|
|||
|
||||
// GetActionsBillingOrg returns the summary of the free and paid GitHub Actions minutes used for an Org.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-actions-billing-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-github-actions-billing-for-an-organization
|
||||
func (s *BillingService) GetActionsBillingOrg(ctx context.Context, org string) (*ActionBilling, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/settings/billing/actions", org)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -79,12 +79,12 @@ func (s *BillingService) GetActionsBillingOrg(ctx context.Context, org string) (
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return actionsOrgBilling, resp, err
|
||||
return actionsOrgBilling, resp, nil
|
||||
}
|
||||
|
||||
// GetPackagesBillingOrg returns the free and paid storage used for GitHub Packages in gigabytes for an Org.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-packages-billing-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-github-packages-billing-for-an-organization
|
||||
func (s *BillingService) GetPackagesBillingOrg(ctx context.Context, org string) (*PackageBilling, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/settings/billing/packages", org)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -98,13 +98,13 @@ func (s *BillingService) GetPackagesBillingOrg(ctx context.Context, org string)
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return packagesOrgBilling, resp, err
|
||||
return packagesOrgBilling, resp, nil
|
||||
}
|
||||
|
||||
// GetStorageBillingOrg returns the estimated paid and estimated total storage used for GitHub Actions
|
||||
// and GitHub Packages in gigabytes for an Org.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-shared-storage-billing-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-shared-storage-billing-for-an-organization
|
||||
func (s *BillingService) GetStorageBillingOrg(ctx context.Context, org string) (*StorageBilling, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/settings/billing/shared-storage", org)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -118,12 +118,12 @@ func (s *BillingService) GetStorageBillingOrg(ctx context.Context, org string) (
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return storageOrgBilling, resp, err
|
||||
return storageOrgBilling, resp, nil
|
||||
}
|
||||
|
||||
// GetAdvancedSecurityActiveCommittersOrg returns the GitHub Advanced Security active committers for an organization per repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-advanced-security-active-committers-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-github-advanced-security-active-committers-for-an-organization
|
||||
func (s *BillingService) GetAdvancedSecurityActiveCommittersOrg(ctx context.Context, org string) (*ActiveCommitters, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/settings/billing/advanced-security", org)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -137,12 +137,12 @@ func (s *BillingService) GetAdvancedSecurityActiveCommittersOrg(ctx context.Cont
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return activeOrgCommitters, resp, err
|
||||
return activeOrgCommitters, resp, nil
|
||||
}
|
||||
|
||||
// GetActionsBillingUser returns the summary of the free and paid GitHub Actions minutes used for a user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-actions-billing-for-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-github-actions-billing-for-a-user
|
||||
func (s *BillingService) GetActionsBillingUser(ctx context.Context, user string) (*ActionBilling, *Response, error) {
|
||||
u := fmt.Sprintf("users/%v/settings/billing/actions", user)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -156,12 +156,12 @@ func (s *BillingService) GetActionsBillingUser(ctx context.Context, user string)
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return actionsUserBilling, resp, err
|
||||
return actionsUserBilling, resp, nil
|
||||
}
|
||||
|
||||
// GetPackagesBillingUser returns the free and paid storage used for GitHub Packages in gigabytes for a user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-packages-billing-for-an-organization
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-github-packages-billing-for-a-user
|
||||
func (s *BillingService) GetPackagesBillingUser(ctx context.Context, user string) (*PackageBilling, *Response, error) {
|
||||
u := fmt.Sprintf("users/%v/settings/billing/packages", user)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -175,13 +175,13 @@ func (s *BillingService) GetPackagesBillingUser(ctx context.Context, user string
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return packagesUserBilling, resp, err
|
||||
return packagesUserBilling, resp, nil
|
||||
}
|
||||
|
||||
// GetStorageBillingUser returns the estimated paid and estimated total storage used for GitHub Actions
|
||||
// and GitHub Packages in gigabytes for a user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-shared-storage-billing-for-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/billing#get-shared-storage-billing-for-a-user
|
||||
func (s *BillingService) GetStorageBillingUser(ctx context.Context, user string) (*StorageBilling, *Response, error) {
|
||||
u := fmt.Sprintf("users/%v/settings/billing/shared-storage", user)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -195,5 +195,5 @@ func (s *BillingService) GetStorageBillingUser(ctx context.Context, user string)
|
|||
return nil, resp, err
|
||||
}
|
||||
|
||||
return storageUserBilling, resp, err
|
||||
return storageUserBilling, resp, nil
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
// ChecksService provides access to the Checks API in the
|
||||
// GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/
|
||||
type ChecksService service
|
||||
|
||||
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
|
||||
|
|
@ -98,7 +98,7 @@ func (c CheckSuite) String() string {
|
|||
|
||||
// GetCheckRun gets a check-run for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#get-a-check-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#get-a-check-run
|
||||
func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -119,7 +119,7 @@ func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, che
|
|||
|
||||
// GetCheckSuite gets a single check suite.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#get-a-check-suite
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/suites#get-a-check-suite
|
||||
func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -161,7 +161,7 @@ type CheckRunAction struct {
|
|||
|
||||
// CreateCheckRun creates a check run for repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#create-a-check-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#create-a-check-run
|
||||
func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opts CreateCheckRunOptions) (*CheckRun, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo)
|
||||
req, err := s.client.NewRequest("POST", u, opts)
|
||||
|
|
@ -194,7 +194,7 @@ type UpdateCheckRunOptions struct {
|
|||
|
||||
// UpdateCheckRun updates a check run for a specific commit in a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#update-a-check-run
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#update-a-check-run
|
||||
func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opts UpdateCheckRunOptions) (*CheckRun, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
|
||||
req, err := s.client.NewRequest("PATCH", u, opts)
|
||||
|
|
@ -215,7 +215,7 @@ func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string,
|
|||
|
||||
// ListCheckRunAnnotations lists the annotations for a check run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#list-check-run-annotations
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#list-check-run-annotations
|
||||
func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opts *ListOptions) ([]*CheckRunAnnotation, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -257,7 +257,7 @@ type ListCheckRunsResults struct {
|
|||
|
||||
// ListCheckRunsForRef lists check runs for a specific ref.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#list-check-runs-for-a-git-reference
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#list-check-runs-for-a-git-reference
|
||||
func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opts *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, refURLEscape(ref))
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -283,7 +283,7 @@ func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, re
|
|||
|
||||
// ListCheckRunsCheckSuite lists check runs for a check suite.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#list-check-runs-in-a-check-suite
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#list-check-runs-in-a-check-suite
|
||||
func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opts *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -307,6 +307,22 @@ func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo
|
|||
return checkRunResults, resp, nil
|
||||
}
|
||||
|
||||
// ReRequestCheckRun triggers GitHub to rerequest an existing check run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/runs#rerequest-a-check-run
|
||||
func (s *ChecksService) ReRequestCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v/rerequest", owner, repo, checkRunID)
|
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// ListCheckSuiteOptions represents parameters to list check suites.
|
||||
type ListCheckSuiteOptions struct {
|
||||
CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run.
|
||||
|
|
@ -323,7 +339,7 @@ type ListCheckSuiteResults struct {
|
|||
|
||||
// ListCheckSuitesForRef lists check suite for a specific ref.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#list-check-suites-for-a-git-reference
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/suites#list-check-suites-for-a-git-reference
|
||||
func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opts *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, refURLEscape(ref))
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -371,7 +387,7 @@ type PreferenceList struct {
|
|||
|
||||
// SetCheckSuitePreferences changes the default automatic flow when creating check suites.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#update-repository-preferences-for-check-suites
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/suites#update-repository-preferences-for-check-suites
|
||||
func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opts CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo)
|
||||
req, err := s.client.NewRequest("PATCH", u, opts)
|
||||
|
|
@ -398,7 +414,7 @@ type CreateCheckSuiteOptions struct {
|
|||
|
||||
// CreateCheckSuite manually creates a check suite for a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#create-a-check-suite
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/suites#create-a-check-suite
|
||||
func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opts CreateCheckSuiteOptions) (*CheckSuite, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo)
|
||||
req, err := s.client.NewRequest("POST", u, opts)
|
||||
|
|
@ -419,7 +435,7 @@ func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string
|
|||
|
||||
// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/checks/#rerequest-a-check-suite
|
||||
// GitHub API docs: https://docs.github.com/en/rest/checks/suites#rerequest-a-check-suite
|
||||
func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID)
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ import (
|
|||
// CodeScanningService handles communication with the code scanning related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/code-scanning/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning
|
||||
type CodeScanningService service
|
||||
|
||||
// Rule represents the complete details of GitHub Code Scanning alert type.
|
||||
|
|
@ -65,24 +65,29 @@ type Tool struct {
|
|||
|
||||
// Alert represents an individual GitHub Code Scanning Alert on a single repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#list-code-scanning-alerts-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning
|
||||
type Alert struct {
|
||||
RuleID *string `json:"rule_id,omitempty"`
|
||||
RuleSeverity *string `json:"rule_severity,omitempty"`
|
||||
RuleDescription *string `json:"rule_description,omitempty"`
|
||||
Rule *Rule `json:"rule,omitempty"`
|
||||
Tool *Tool `json:"tool,omitempty"`
|
||||
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
ClosedBy *User `json:"closed_by,omitempty"`
|
||||
ClosedAt *Timestamp `json:"closed_at,omitempty"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
HTMLURL *string `json:"html_url,omitempty"`
|
||||
MostRecentInstance *MostRecentInstance `json:"most_recent_instance,omitempty"`
|
||||
DismissedBy *User `json:"dismissed_by,omitempty"`
|
||||
DismissedAt *Timestamp `json:"dismissed_at,omitempty"`
|
||||
DismissedReason *string `json:"dismissed_reason,omitempty"`
|
||||
InstancesURL *string `json:"instances_url,omitempty"`
|
||||
Number *int `json:"number,omitempty"`
|
||||
Repository *Repository `json:"repository,omitempty"`
|
||||
RuleID *string `json:"rule_id,omitempty"`
|
||||
RuleSeverity *string `json:"rule_severity,omitempty"`
|
||||
RuleDescription *string `json:"rule_description,omitempty"`
|
||||
Rule *Rule `json:"rule,omitempty"`
|
||||
Tool *Tool `json:"tool,omitempty"`
|
||||
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
||||
FixedAt *Timestamp `json:"fixed_at,omitempty"`
|
||||
State *string `json:"state,omitempty"`
|
||||
ClosedBy *User `json:"closed_by,omitempty"`
|
||||
ClosedAt *Timestamp `json:"closed_at,omitempty"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
HTMLURL *string `json:"html_url,omitempty"`
|
||||
MostRecentInstance *MostRecentInstance `json:"most_recent_instance,omitempty"`
|
||||
Instances []*MostRecentInstance `json:"instances,omitempty"`
|
||||
DismissedBy *User `json:"dismissed_by,omitempty"`
|
||||
DismissedAt *Timestamp `json:"dismissed_at,omitempty"`
|
||||
DismissedReason *string `json:"dismissed_reason,omitempty"`
|
||||
InstancesURL *string `json:"instances_url,omitempty"`
|
||||
}
|
||||
|
||||
// ID returns the ID associated with an alert. It is the number at the end of the security alert's URL.
|
||||
|
|
@ -132,7 +137,7 @@ type AnalysesListOptions struct {
|
|||
|
||||
// ScanningAnalysis represents an individual GitHub Code Scanning ScanningAnalysis on a single repository.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#list-code-scanning-analyses-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning
|
||||
type ScanningAnalysis struct {
|
||||
ID *int64 `json:"id,omitempty"`
|
||||
Ref *string `json:"ref,omitempty"`
|
||||
|
|
@ -153,7 +158,7 @@ type ScanningAnalysis struct {
|
|||
|
||||
// SarifAnalysis specifies the results of a code scanning job.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning
|
||||
type SarifAnalysis struct {
|
||||
CommitSHA *string `json:"commit_sha,omitempty"`
|
||||
Ref *string `json:"ref,omitempty"`
|
||||
|
|
@ -165,19 +170,46 @@ type SarifAnalysis struct {
|
|||
|
||||
// SarifID identifies a sarif analysis upload.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning
|
||||
type SarifID struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// ListAlertsForOrg lists code scanning alerts for an org.
|
||||
//
|
||||
// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events
|
||||
// read permission to use this endpoint.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#list-code-scanning-alerts-for-an-organization
|
||||
func (s *CodeScanningService) ListAlertsForOrg(ctx context.Context, org string, opts *AlertListOptions) ([]*Alert, *Response, error) {
|
||||
u := fmt.Sprintf("orgs/%v/code-scanning/alerts", org)
|
||||
u, err := addOptions(u, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var alerts []*Alert
|
||||
resp, err := s.client.Do(ctx, req, &alerts)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return alerts, resp, nil
|
||||
}
|
||||
|
||||
// ListAlertsForRepo lists code scanning alerts for a repository.
|
||||
//
|
||||
// Lists all open code scanning alerts for the default branch (usually master) and protected branches in a repository.
|
||||
// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events
|
||||
// read permission to use this endpoint.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/code-scanning/#list-code-scanning-alerts-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#list-code-scanning-alerts-for-a-repository
|
||||
func (s *CodeScanningService) ListAlertsForRepo(ctx context.Context, owner, repo string, opts *AlertListOptions) ([]*Alert, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -206,7 +238,7 @@ func (s *CodeScanningService) ListAlertsForRepo(ctx context.Context, owner, repo
|
|||
//
|
||||
// The security alert_id is the number at the end of the security alert's URL.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/code-scanning/#get-a-code-scanning-alert
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#get-a-code-scanning-alert
|
||||
func (s *CodeScanningService) GetAlert(ctx context.Context, owner, repo string, id int64) (*Alert, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts/%v", owner, repo, id)
|
||||
|
||||
|
|
@ -230,7 +262,7 @@ func (s *CodeScanningService) GetAlert(ctx context.Context, owner, repo string,
|
|||
// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events
|
||||
// write permission to use this endpoint.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#upload-an-analysis-as-sarif-data
|
||||
func (s *CodeScanningService) UploadSarif(ctx context.Context, owner, repo string, sarif *SarifAnalysis) (*SarifID, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/code-scanning/sarifs", owner, repo)
|
||||
|
||||
|
|
@ -254,7 +286,7 @@ func (s *CodeScanningService) UploadSarif(ctx context.Context, owner, repo strin
|
|||
// You must use an access token with the security_events scope to use this endpoint.
|
||||
// GitHub Apps must have the security_events read permission to use this endpoint.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#list-code-scanning-analyses-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#list-code-scanning-analyses-for-a-repository
|
||||
func (s *CodeScanningService) ListAnalysesForRepo(ctx context.Context, owner, repo string, opts *AnalysesListOptions) ([]*ScanningAnalysis, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/code-scanning/analyses", owner, repo)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -283,7 +315,7 @@ func (s *CodeScanningService) ListAnalysesForRepo(ctx context.Context, owner, re
|
|||
//
|
||||
// The security analysis_id is the ID of the analysis, as returned from the ListAnalysesForRepo operation.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/code-scanning#get-a-code-scanning-analysis-for-a-repository
|
||||
// GitHub API docs: https://docs.github.com/en/rest/code-scanning#get-a-code-scanning-analysis-for-a-repository
|
||||
func (s *CodeScanningService) GetAnalysis(ctx context.Context, owner, repo string, id int64) (*ScanningAnalysis, *Response, error) {
|
||||
u := fmt.Sprintf("repos/%v/%v/code-scanning/analyses/%v", owner, repo, id)
|
||||
|
||||
|
|
@ -8,5 +8,5 @@ package github
|
|||
// DependabotService handles communication with the Dependabot related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/dependabot/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/
|
||||
type DependabotService service
|
||||
|
|
@ -27,7 +27,7 @@ func (s *DependabotService) getPublicKey(ctx context.Context, url string) (*Publ
|
|||
|
||||
// GetRepoPublicKey gets a public key that should be used for Dependabot secret encryption.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#get-a-repository-public-key
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#get-a-repository-public-key
|
||||
func (s *DependabotService) GetRepoPublicKey(ctx context.Context, owner, repo string) (*PublicKey, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/dependabot/secrets/public-key", owner, repo)
|
||||
return s.getPublicKey(ctx, url)
|
||||
|
|
@ -35,7 +35,7 @@ func (s *DependabotService) GetRepoPublicKey(ctx context.Context, owner, repo st
|
|||
|
||||
// GetOrgPublicKey gets a public key that should be used for Dependabot secret encryption.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#get-an-organization-public-key
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#get-an-organization-public-key
|
||||
func (s *DependabotService) GetOrgPublicKey(ctx context.Context, org string) (*PublicKey, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/public-key", org)
|
||||
return s.getPublicKey(ctx, url)
|
||||
|
|
@ -64,7 +64,7 @@ func (s *DependabotService) listSecrets(ctx context.Context, url string, opts *L
|
|||
// ListRepoSecrets lists all Dependabot secrets available in a repository
|
||||
// without revealing their encrypted values.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#list-repository-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#list-repository-secrets
|
||||
func (s *DependabotService) ListRepoSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/dependabot/secrets", owner, repo)
|
||||
return s.listSecrets(ctx, url, opts)
|
||||
|
|
@ -73,7 +73,7 @@ func (s *DependabotService) ListRepoSecrets(ctx context.Context, owner, repo str
|
|||
// ListOrgSecrets lists all Dependabot secrets available in an organization
|
||||
// without revealing their encrypted values.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#list-organization-secrets
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#list-organization-secrets
|
||||
func (s *DependabotService) ListOrgSecrets(ctx context.Context, org string, opts *ListOptions) (*Secrets, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets", org)
|
||||
return s.listSecrets(ctx, url, opts)
|
||||
|
|
@ -96,7 +96,7 @@ func (s *DependabotService) getSecret(ctx context.Context, url string) (*Secret,
|
|||
|
||||
// GetRepoSecret gets a single repository Dependabot secret without revealing its encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#get-a-repository-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#get-a-repository-secret
|
||||
func (s *DependabotService) GetRepoSecret(ctx context.Context, owner, repo, name string) (*Secret, *Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/dependabot/secrets/%v", owner, repo, name)
|
||||
return s.getSecret(ctx, url)
|
||||
|
|
@ -104,13 +104,26 @@ func (s *DependabotService) GetRepoSecret(ctx context.Context, owner, repo, name
|
|||
|
||||
// GetOrgSecret gets a single organization Dependabot secret without revealing its encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#get-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#get-an-organization-secret
|
||||
func (s *DependabotService) GetOrgSecret(ctx context.Context, org, name string) (*Secret, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v", org, name)
|
||||
return s.getSecret(ctx, url)
|
||||
}
|
||||
|
||||
func (s *DependabotService) putSecret(ctx context.Context, url string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
// DependabotEncryptedSecret represents a secret that is encrypted using a public key for Dependabot.
|
||||
//
|
||||
// The value of EncryptedValue must be your secret, encrypted with
|
||||
// LibSodium (see documentation here: https://libsodium.gitbook.io/doc/bindings_for_other_languages)
|
||||
// using the public key retrieved using the GetPublicKey method.
|
||||
type DependabotEncryptedSecret struct {
|
||||
Name string `json:"-"`
|
||||
KeyID string `json:"key_id"`
|
||||
EncryptedValue string `json:"encrypted_value"`
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
SelectedRepositoryIDs DependabotSecretsSelectedRepoIDs `json:"selected_repository_ids,omitempty"`
|
||||
}
|
||||
|
||||
func (s *DependabotService) putSecret(ctx context.Context, url string, eSecret *DependabotEncryptedSecret) (*Response, error) {
|
||||
req, err := s.client.NewRequest("PUT", url, eSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -121,16 +134,16 @@ func (s *DependabotService) putSecret(ctx context.Context, url string, eSecret *
|
|||
|
||||
// CreateOrUpdateRepoSecret creates or updates a repository Dependabot secret with an encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#create-or-update-a-repository-secret
|
||||
func (s *DependabotService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#create-or-update-a-repository-secret
|
||||
func (s *DependabotService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, eSecret *DependabotEncryptedSecret) (*Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/dependabot/secrets/%v", owner, repo, eSecret.Name)
|
||||
return s.putSecret(ctx, url, eSecret)
|
||||
}
|
||||
|
||||
// CreateOrUpdateOrgSecret creates or updates an organization Dependabot secret with an encrypted value.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#create-or-update-an-organization-secret
|
||||
func (s *DependabotService) CreateOrUpdateOrgSecret(ctx context.Context, org string, eSecret *EncryptedSecret) (*Response, error) {
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#create-or-update-an-organization-secret
|
||||
func (s *DependabotService) CreateOrUpdateOrgSecret(ctx context.Context, org string, eSecret *DependabotEncryptedSecret) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v", org, eSecret.Name)
|
||||
return s.putSecret(ctx, url, eSecret)
|
||||
}
|
||||
|
|
@ -146,7 +159,7 @@ func (s *DependabotService) deleteSecret(ctx context.Context, url string) (*Resp
|
|||
|
||||
// DeleteRepoSecret deletes a Dependabot secret in a repository using the secret name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#delete-a-repository-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#delete-a-repository-secret
|
||||
func (s *DependabotService) DeleteRepoSecret(ctx context.Context, owner, repo, name string) (*Response, error) {
|
||||
url := fmt.Sprintf("repos/%v/%v/dependabot/secrets/%v", owner, repo, name)
|
||||
return s.deleteSecret(ctx, url)
|
||||
|
|
@ -154,7 +167,7 @@ func (s *DependabotService) DeleteRepoSecret(ctx context.Context, owner, repo, n
|
|||
|
||||
// DeleteOrgSecret deletes a Dependabot secret in an organization using the secret name.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#delete-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#delete-an-organization-secret
|
||||
func (s *DependabotService) DeleteOrgSecret(ctx context.Context, org, name string) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v", org, name)
|
||||
return s.deleteSecret(ctx, url)
|
||||
|
|
@ -162,7 +175,7 @@ func (s *DependabotService) DeleteOrgSecret(ctx context.Context, org, name strin
|
|||
|
||||
// ListSelectedReposForOrgSecret lists all repositories that have access to a Dependabot secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#list-selected-repositories-for-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#list-selected-repositories-for-an-organization-secret
|
||||
func (s *DependabotService) ListSelectedReposForOrgSecret(ctx context.Context, org, name string, opts *ListOptions) (*SelectedReposList, *Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v/repositories", org, name)
|
||||
u, err := addOptions(url, opts)
|
||||
|
|
@ -184,13 +197,16 @@ func (s *DependabotService) ListSelectedReposForOrgSecret(ctx context.Context, o
|
|||
return result, resp, nil
|
||||
}
|
||||
|
||||
// DependabotSecretsSelectedRepoIDs are the repository IDs that have access to the dependabot secrets.
|
||||
type DependabotSecretsSelectedRepoIDs []string
|
||||
|
||||
// SetSelectedReposForOrgSecret sets the repositories that have access to a Dependabot secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#set-selected-repositories-for-an-organization-secret
|
||||
func (s *DependabotService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids SelectedRepoIDs) (*Response, error) {
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#set-selected-repositories-for-an-organization-secret
|
||||
func (s *DependabotService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids DependabotSecretsSelectedRepoIDs) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v/repositories", org, name)
|
||||
type repoIDs struct {
|
||||
SelectedIDs SelectedRepoIDs `json:"selected_repository_ids"`
|
||||
SelectedIDs DependabotSecretsSelectedRepoIDs `json:"selected_repository_ids"`
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("PUT", url, repoIDs{SelectedIDs: ids})
|
||||
|
|
@ -203,7 +219,7 @@ func (s *DependabotService) SetSelectedReposForOrgSecret(ctx context.Context, or
|
|||
|
||||
// AddSelectedRepoToOrgSecret adds a repository to an organization Dependabot secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#add-selected-repository-to-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#add-selected-repository-to-an-organization-secret
|
||||
func (s *DependabotService) AddSelectedRepoToOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v/repositories/%v", org, name, *repo.ID)
|
||||
req, err := s.client.NewRequest("PUT", url, nil)
|
||||
|
|
@ -216,7 +232,7 @@ func (s *DependabotService) AddSelectedRepoToOrgSecret(ctx context.Context, org,
|
|||
|
||||
// RemoveSelectedRepoFromOrgSecret removes a repository from an organization Dependabot secret.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/dependabot#remove-selected-repository-from-an-organization-secret
|
||||
// GitHub API docs: https://docs.github.com/en/rest/dependabot/secrets#remove-selected-repository-from-an-organization-secret
|
||||
func (s *DependabotService) RemoveSelectedRepoFromOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
|
||||
url := fmt.Sprintf("orgs/%v/dependabot/secrets/%v/repositories/%v", org, name, *repo.ID)
|
||||
req, err := s.client.NewRequest("DELETE", url, nil)
|
||||
|
|
@ -8,7 +8,7 @@ Package github provides a client for using the GitHub API.
|
|||
|
||||
Usage:
|
||||
|
||||
import "github.com/google/go-github/v43/github" // with go modules enabled (GO111MODULE=on or outside GOPATH)
|
||||
import "github.com/google/go-github/v48/github" // with go modules enabled (GO111MODULE=on or outside GOPATH)
|
||||
import "github.com/google/go-github/github" // with go modules disabled
|
||||
|
||||
Construct a new GitHub client, then use the various services on the client to
|
||||
|
|
@ -29,7 +29,7 @@ Some API methods have optional parameters that can be passed. For example:
|
|||
|
||||
The services of a client divide the API into logical chunks and correspond to
|
||||
the structure of the GitHub API documentation at
|
||||
https://docs.github.com/en/free-pro-team@latest/rest/reference/.
|
||||
https://docs.github.com/en/rest .
|
||||
|
||||
NOTE: Using the https://godoc.org/context package, one can easily
|
||||
pass cancelation signals and deadlines to various services of the client for
|
||||
|
|
@ -38,7 +38,7 @@ can be used as a starting point.
|
|||
|
||||
For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory.
|
||||
|
||||
Authentication
|
||||
# Authentication
|
||||
|
||||
The go-github library does not directly handle authentication. Instead, when
|
||||
creating a new client, pass an http.Client that can handle authentication for
|
||||
|
|
@ -110,7 +110,7 @@ To authenticate as an app, using a JWT:
|
|||
// Use client...
|
||||
}
|
||||
|
||||
Rate Limiting
|
||||
# Rate Limiting
|
||||
|
||||
GitHub imposes a rate limit on all API clients. Unauthenticated clients are
|
||||
limited to 60 requests per hour, while authenticated clients can make up to
|
||||
|
|
@ -137,9 +137,9 @@ For secondary rate limits, you can check if its type is *github.AbuseRateLimitEr
|
|||
}
|
||||
|
||||
Learn more about GitHub rate limiting at
|
||||
https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#rate-limiting.
|
||||
https://docs.github.com/en/rest/rate-limit .
|
||||
|
||||
Accepted Status
|
||||
# Accepted Status
|
||||
|
||||
Some endpoints may return a 202 Accepted status code, meaning that the
|
||||
information required is not yet ready and was scheduled to be gathered on
|
||||
|
|
@ -154,7 +154,7 @@ To detect this condition of error, you can check if its type is
|
|||
log.Println("scheduled on GitHub side")
|
||||
}
|
||||
|
||||
Conditional Requests
|
||||
# Conditional Requests
|
||||
|
||||
The GitHub API has good support for conditional requests which will help
|
||||
prevent you from burning through your rate limit, as well as help speed up your
|
||||
|
|
@ -163,9 +163,9 @@ instead designed to work with a caching http.Transport. We recommend using
|
|||
https://github.com/gregjones/httpcache for that.
|
||||
|
||||
Learn more about GitHub conditional requests at
|
||||
https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#conditional-requests.
|
||||
https://docs.github.com/en/rest/overview/resources-in-the-rest-api#conditional-requests.
|
||||
|
||||
Creating and Updating Resources
|
||||
# Creating and Updating Resources
|
||||
|
||||
All structs for GitHub resources use pointer values for all non-repeated fields.
|
||||
This allows distinguishing between unset fields and those set to a zero-value.
|
||||
|
|
@ -181,7 +181,7 @@ bool, and int values. For example:
|
|||
|
||||
Users who have worked with protocol buffers should find this pattern familiar.
|
||||
|
||||
Pagination
|
||||
# Pagination
|
||||
|
||||
All requests for resource collections (repos, pull requests, issues, etc.)
|
||||
support pagination. Pagination options are described in the
|
||||
|
|
@ -208,6 +208,5 @@ github.Response struct.
|
|||
}
|
||||
opt.Page = resp.NextPage
|
||||
}
|
||||
|
||||
*/
|
||||
package github
|
||||
|
|
@ -8,5 +8,5 @@ package github
|
|||
// EnterpriseService provides access to the enterprise related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise-admin/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/enterprise-admin/
|
||||
type EnterpriseService service
|
||||
|
|
@ -10,9 +10,28 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// ListRunnerApplicationDownloads lists self-hosted runner application binaries that can be downloaded and run.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-runner-applications-for-an-enterprise
|
||||
func (s *EnterpriseService) ListRunnerApplicationDownloads(ctx context.Context, enterprise string) ([]*RunnerApplicationDownload, *Response, error) {
|
||||
u := fmt.Sprintf("enterprises/%v/actions/runners/downloads", enterprise)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var rads []*RunnerApplicationDownload
|
||||
resp, err := s.client.Do(ctx, req, &rads)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return rads, resp, nil
|
||||
}
|
||||
|
||||
// CreateRegistrationToken creates a token that can be used to add a self-hosted runner.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise-admin/#create-a-registration-token-for-an-enterprise
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#create-a-registration-token-for-an-enterprise
|
||||
func (s *EnterpriseService) CreateRegistrationToken(ctx context.Context, enterprise string) (*RegistrationToken, *Response, error) {
|
||||
u := fmt.Sprintf("enterprises/%v/actions/runners/registration-token", enterprise)
|
||||
|
||||
|
|
@ -32,7 +51,7 @@ func (s *EnterpriseService) CreateRegistrationToken(ctx context.Context, enterpr
|
|||
|
||||
// ListRunners lists all the self-hosted runners for a enterprise.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise-admin/#list-self-hosted-runners-for-an-enterprise
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#list-self-hosted-runners-for-an-enterprise
|
||||
func (s *EnterpriseService) ListRunners(ctx context.Context, enterprise string, opts *ListOptions) (*Runners, *Response, error) {
|
||||
u := fmt.Sprintf("enterprises/%v/actions/runners", enterprise)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -56,7 +75,7 @@ func (s *EnterpriseService) ListRunners(ctx context.Context, enterprise string,
|
|||
|
||||
// RemoveRunner forces the removal of a self-hosted runner from an enterprise using the runner id.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/enterprise-admin/#delete-a-self-hosted-runner-from-an-enterprise
|
||||
// GitHub API docs: https://docs.github.com/en/rest/actions/self-hosted-runners#delete-a-self-hosted-runner-from-an-enterprise
|
||||
func (s *EnterpriseService) RemoveRunner(ctx context.Context, enterprise string, runnerID int64) (*Response, error) {
|
||||
u := fmt.Sprintf("enterprises/%v/actions/runners/%v", enterprise, runnerID)
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// GetAuditLog gets the audit-log entries for an organization.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/rest/reference/enterprise-admin#get-the-audit-log-for-an-enterprise
|
||||
// GitHub API docs: https://docs.github.com/en/rest/enterprise-admin/audit-log#get-the-audit-log-for-an-enterprise
|
||||
func (s *EnterpriseService) GetAuditLog(ctx context.Context, enterprise string, opts *GetAuditLogOptions) ([]*AuditEntry, *Response, error) {
|
||||
u := fmt.Sprintf("enterprises/%v/audit-log", enterprise)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -36,6 +36,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
|
|||
payload = &CheckRunEvent{}
|
||||
case "CheckSuiteEvent":
|
||||
payload = &CheckSuiteEvent{}
|
||||
case "CodeScanningAlertEvent":
|
||||
payload = &CodeScanningAlertEvent{}
|
||||
case "CommitCommentEvent":
|
||||
payload = &CommitCommentEvent{}
|
||||
case "ContentReferenceEvent":
|
||||
|
|
@ -102,6 +104,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
|
|||
payload = &PullRequestReviewEvent{}
|
||||
case "PullRequestReviewCommentEvent":
|
||||
payload = &PullRequestReviewCommentEvent{}
|
||||
case "PullRequestReviewThreadEvent":
|
||||
payload = &PullRequestReviewThreadEvent{}
|
||||
case "PullRequestTargetEvent":
|
||||
payload = &PullRequestTargetEvent{}
|
||||
case "PushEvent":
|
||||
|
|
@ -112,6 +116,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
|
|||
payload = &RepositoryEvent{}
|
||||
case "RepositoryDispatchEvent":
|
||||
payload = &RepositoryDispatchEvent{}
|
||||
case "RepositoryImportEvent":
|
||||
payload = &RepositoryImportEvent{}
|
||||
case "RepositoryVulnerabilityAlertEvent":
|
||||
payload = &RepositoryVulnerabilityAlertEvent{}
|
||||
case "SecretScanningAlertEvent":
|
||||
|
|
@ -106,10 +106,11 @@ type CreateEvent struct {
|
|||
RefType *string `json:"ref_type,omitempty"`
|
||||
MasterBranch *string `json:"master_branch,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
PusherType *string `json:"pusher_type,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
PusherType *string `json:"pusher_type,omitempty"`
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
|
@ -493,13 +494,14 @@ type IssuesEvent struct {
|
|||
type LabelEvent struct {
|
||||
// Action is the action that was performed. Possible values are:
|
||||
// "created", "edited", "deleted"
|
||||
Action *string `json:"action,omitempty"`
|
||||
Label *Label `json:"label,omitempty"`
|
||||
Action *string `json:"action,omitempty"`
|
||||
Label *Label `json:"label,omitempty"`
|
||||
Changes *EditChange `json:"changes,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Changes *EditChange `json:"changes,omitempty"`
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -574,6 +576,9 @@ type MetaEvent struct {
|
|||
Hook *Hook `json:"hook,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -682,7 +687,12 @@ type PingEvent struct {
|
|||
// The ID of the webhook that triggered the ping.
|
||||
HookID *int64 `json:"hook_id,omitempty"`
|
||||
// The webhook configuration.
|
||||
Hook *Hook `json:"hook,omitempty"`
|
||||
Hook *Hook `json:"hook,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -830,12 +840,30 @@ type PullRequestReviewCommentEvent struct {
|
|||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
// PullRequestReviewThreadEvent is triggered when a comment made as part of a
|
||||
// review of a pull request is marked resolved or unresolved.
|
||||
// The Webhook event name is "pull_request_review_thread".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#pull_request_review_thread
|
||||
type PullRequestReviewThreadEvent struct {
|
||||
// Action is the action that was performed on the comment.
|
||||
// Possible values are: "resolved", "unresolved".
|
||||
Action *string `json:"action,omitempty"`
|
||||
Thread *PullRequestThread `json:"thread,omitempty"`
|
||||
PullRequest *PullRequest `json:"pull_request,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
// PullRequestTargetEvent is triggered when a pull request is assigned, unassigned, labeled,
|
||||
// unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review,
|
||||
// locked, unlocked, a pull request review is requested, or a review request is removed.
|
||||
// The Webhook event name is "pull_request_target".
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target
|
||||
// GitHub API docs: https://docs.github.com/en/actions/events-that-trigger-workflows#pull_request_target
|
||||
type PullRequestTargetEvent struct {
|
||||
// Action is the action that was performed. Possible values are:
|
||||
// "assigned", "unassigned", "labeled", "unlabeled", "opened", "edited", "closed", "reopened",
|
||||
|
|
@ -885,6 +913,7 @@ type PushEvent struct {
|
|||
DistinctSize *int `json:"distinct_size,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Action *string `json:"action,omitempty"`
|
||||
After *string `json:"after,omitempty"`
|
||||
Created *bool `json:"created,omitempty"`
|
||||
Deleted *bool `json:"deleted,omitempty"`
|
||||
|
|
@ -926,8 +955,8 @@ type HeadCommit struct {
|
|||
Modified []string `json:"modified,omitempty"`
|
||||
}
|
||||
|
||||
func (p HeadCommit) String() string {
|
||||
return Stringify(p)
|
||||
func (h HeadCommit) String() string {
|
||||
return Stringify(h)
|
||||
}
|
||||
|
||||
// PushEventRepository represents the repo object in a PushEvent payload.
|
||||
|
|
@ -1032,6 +1061,17 @@ type RepositoryDispatchEvent struct {
|
|||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
// RepositoryImportEvent represents the activity related to a repository being imported to GitHub.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#repository_import
|
||||
type RepositoryImportEvent struct {
|
||||
// Status represents the final state of the import. This can be one of "success", "cancelled", or "failure".
|
||||
Status *string `json:"status,omitempty"`
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
}
|
||||
|
||||
// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#repository_vulnerability_alert
|
||||
|
|
@ -1039,14 +1079,17 @@ type RepositoryVulnerabilityAlertEvent struct {
|
|||
// Action is the action that was performed. Possible values are: "create", "dismiss", "resolve".
|
||||
Action *string `json:"action,omitempty"`
|
||||
|
||||
//The security alert of the vulnerable dependency.
|
||||
// The security alert of the vulnerable dependency.
|
||||
Alert *RepositoryVulnerabilityAlert `json:"alert,omitempty"`
|
||||
|
||||
//The repository of the vulnerable dependency.
|
||||
// The repository of the vulnerable dependency.
|
||||
Repository *Repository `json:"repository,omitempty"`
|
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
|
||||
// The user that triggered the event.
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
}
|
||||
|
||||
// RepositoryVulnerabilityAlert represents a repository security alert.
|
||||
|
|
@ -1248,3 +1291,71 @@ type WorkflowRunEvent struct {
|
|||
Sender *User `json:"sender,omitempty"`
|
||||
Installation *Installation `json:"installation,omitempty"`
|
||||
}
|
||||
|
||||
// SecurityAdvisory represents the advisory object in SecurityAdvisoryEvent payload.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#security_advisory
|
||||
type SecurityAdvisory struct {
|
||||
GHSAID *string `json:"ghsa_id,omitempty"`
|
||||
Summary *string `json:"summary,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Severity *string `json:"severity,omitempty"`
|
||||
Identifiers []*AdvisoryIdentifier `json:"identifiers,omitempty"`
|
||||
References []*AdvisoryReference `json:"references,omitempty"`
|
||||
PublishedAt *Timestamp `json:"published_at,omitempty"`
|
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
||||
WithdrawnAt *Timestamp `json:"withdrawn_at,omitempty"`
|
||||
Vulnerabilities []*AdvisoryVulnerability `json:"vulnerabilities,omitempty"`
|
||||
}
|
||||
|
||||
// AdvisoryIdentifier represents the identifier for a Security Advisory.
|
||||
type AdvisoryIdentifier struct {
|
||||
Value *string `json:"value,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// AdvisoryReference represents the reference url for the security advisory.
|
||||
type AdvisoryReference struct {
|
||||
URL *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// AdvisoryVulnerability represents the vulnerability object for a Security Advisory.
|
||||
type AdvisoryVulnerability struct {
|
||||
Package *VulnerabilityPackage `json:"package,omitempty"`
|
||||
Severity *string `json:"severity,omitempty"`
|
||||
VulnerableVersionRange *string `json:"vulnerable_version_range,omitempty"`
|
||||
FirstPatchedVersion *FirstPatchedVersion `json:"first_patched_version,omitempty"`
|
||||
}
|
||||
|
||||
// VulnerabilityPackage represents the package object for an Advisory Vulnerability.
|
||||
type VulnerabilityPackage struct {
|
||||
Ecosystem *string `json:"ecosystem,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// FirstPatchedVersion represents the identifier for the first patched version of that vulnerability.
|
||||
type FirstPatchedVersion struct {
|
||||
Identifier *string `json:"identifier,omitempty"`
|
||||
}
|
||||
|
||||
// SecurityAdvisoryEvent is triggered when a security-related vulnerability is found in software on GitHub.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#security_advisory
|
||||
type SecurityAdvisoryEvent struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
SecurityAdvisory *SecurityAdvisory `json:"security_advisory,omitempty"`
|
||||
}
|
||||
|
||||
// CodeScanningAlertEvent is triggered when a code scanning finds a potential vulnerability or error in your code.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#code_scanning_alert
|
||||
type CodeScanningAlertEvent struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
Alert *Alert `json:"alert,omitempty"`
|
||||
Ref *string `json:"ref,omitempty"`
|
||||
// CommitOID is the commit SHA of the code scanning alert
|
||||
CommitOID *string `json:"commit_oid,omitempty"`
|
||||
Repo *Repository `json:"repository,omitempty"`
|
||||
Org *Organization `json:"organization,omitempty"`
|
||||
Sender *User `json:"sender,omitempty"`
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
// GistsService handles communication with the Gist related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists
|
||||
type GistsService service
|
||||
|
||||
// Gist represents a GitHub's gist.
|
||||
|
|
@ -96,8 +96,8 @@ type GistListOptions struct {
|
|||
// is authenticated, it will returns all gists for the authenticated
|
||||
// user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-gists-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-gists-for-a-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-gists-for-the-authenticated-user
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-gists-for-a-user
|
||||
func (s *GistsService) List(ctx context.Context, user string, opts *GistListOptions) ([]*Gist, *Response, error) {
|
||||
var u string
|
||||
if user != "" {
|
||||
|
|
@ -126,7 +126,7 @@ func (s *GistsService) List(ctx context.Context, user string, opts *GistListOpti
|
|||
|
||||
// ListAll lists all public gists.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-public-gists
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-public-gists
|
||||
func (s *GistsService) ListAll(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) {
|
||||
u, err := addOptions("gists/public", opts)
|
||||
if err != nil {
|
||||
|
|
@ -149,7 +149,7 @@ func (s *GistsService) ListAll(ctx context.Context, opts *GistListOptions) ([]*G
|
|||
|
||||
// ListStarred lists starred gists of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-starred-gists
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-starred-gists
|
||||
func (s *GistsService) ListStarred(ctx context.Context, opts *GistListOptions) ([]*Gist, *Response, error) {
|
||||
u, err := addOptions("gists/starred", opts)
|
||||
if err != nil {
|
||||
|
|
@ -172,7 +172,7 @@ func (s *GistsService) ListStarred(ctx context.Context, opts *GistListOptions) (
|
|||
|
||||
// Get a single gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#get-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#get-a-gist
|
||||
func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v", id)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -191,7 +191,7 @@ func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, er
|
|||
|
||||
// GetRevision gets a specific revision of a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#get-a-gist-revision
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#get-a-gist-revision
|
||||
func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/%v", id, sha)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
|
|
@ -210,7 +210,7 @@ func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist,
|
|||
|
||||
// Create a gist for authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#create-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#create-a-gist
|
||||
func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) {
|
||||
u := "gists"
|
||||
req, err := s.client.NewRequest("POST", u, gist)
|
||||
|
|
@ -229,7 +229,7 @@ func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response
|
|||
|
||||
// Edit a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#update-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#update-a-gist
|
||||
func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v", id)
|
||||
req, err := s.client.NewRequest("PATCH", u, gist)
|
||||
|
|
@ -248,7 +248,7 @@ func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist,
|
|||
|
||||
// ListCommits lists commits of a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-gist-commits
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-gist-commits
|
||||
func (s *GistsService) ListCommits(ctx context.Context, id string, opts *ListOptions) ([]*GistCommit, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/commits", id)
|
||||
u, err := addOptions(u, opts)
|
||||
|
|
@ -272,49 +272,53 @@ func (s *GistsService) ListCommits(ctx context.Context, id string, opts *ListOpt
|
|||
|
||||
// Delete a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#delete-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#delete-a-gist
|
||||
func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) {
|
||||
u := fmt.Sprintf("gists/%v", id)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// Star a gist on behalf of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#star-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#star-a-gist
|
||||
func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/star", id)
|
||||
req, err := s.client.NewRequest("PUT", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// Unstar a gist on a behalf of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#unstar-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#unstar-a-gist
|
||||
func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/star", id)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(ctx, req, nil)
|
||||
}
|
||||
|
||||
// IsStarred checks if a gist is starred by authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#check-if-a-gist-is-starred
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#check-if-a-gist-is-starred
|
||||
func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/star", id)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(ctx, req, nil)
|
||||
starred, err := parseBoolResponse(err)
|
||||
return starred, resp, err
|
||||
|
|
@ -322,7 +326,7 @@ func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Respons
|
|||
|
||||
// Fork a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#fork-a-gist
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#fork-a-gist
|
||||
func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/forks", id)
|
||||
req, err := s.client.NewRequest("POST", u, nil)
|
||||
|
|
@ -341,7 +345,7 @@ func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, e
|
|||
|
||||
// ListForks lists forks of a gist.
|
||||
//
|
||||
// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/gists/#list-gist-forks
|
||||
// GitHub API docs: https://docs.github.com/en/rest/gists/gists#list-gist-forks
|
||||
func (s *GistsService) ListForks(ctx context.Context, id string, opts *ListOptions) ([]*GistFork, *Response, error) {
|
||||
u := fmt.Sprintf("gists/%v/forks", id)
|
||||
u, err := addOptions(u, opts)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue