Add support for enterprise runners (#290)
* Add support for enterprise runners * update docs
This commit is contained in:
		
							parent
							
								
									831db9ee2a
								
							
						
					
					
						commit
						28e80a2d28
					
				
							
								
								
									
										44
									
								
								README.md
								
								
								
								
							
							
						
						
									
										44
									
								
								README.md
								
								
								
								
							|  | @ -32,13 +32,53 @@ helm upgrade --install -n actions-runner-system actions-runner-controller/action | |||
| 
 | ||||
| ### Github Enterprise support | ||||
| 
 | ||||
| If you use either Github Enterprise Cloud or Server (and have recent enought version supporting Actions), you can use **actions-runner-controller**  with those, too. Authentication works same way as with public Github (repo and organization level). | ||||
| If you use either Github Enterprise Cloud or Server, you can use **actions-runner-controller**  with those, too. | ||||
| Authentication works same way as with public Github (repo and organization level). | ||||
| The minimum version of Github Enterprise Server is 3.0.0 (or rc1/rc2). | ||||
| In most cases maintainers do not have environment where to test changes and are reliant on the community for testing. | ||||
| 
 | ||||
| 
 | ||||
| ```shell | ||||
| kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL> --namespace actions-runner-system | ||||
| ``` | ||||
| 
 | ||||
| [Enterprise level](https://docs.github.com/en/enterprise-server@2.22/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-an-enterprise) runners are not working yet as there's no API definition for those. | ||||
| #### Enterprise runners usage | ||||
| 
 | ||||
| In order to use enterprise runners you must have Admin access to Github Enterprise and you should do Personal Access Token (PAT) | ||||
| with `enterprise:admin` access. Enterprise runners are not possible to run with Github APP or any other permission. | ||||
| 
 | ||||
| When you use enterprise runners those will get access to Github Organisations. However, access to the repositories is **NOT** | ||||
| allowed by default. Each Github Organisation must allow Enterprise runner groups to be used in repositories. | ||||
| This is needed only one time and is permanent after that. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| ```yaml | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: RunnerDeployment | ||||
| metadata: | ||||
|   name: ghe-runner-deployment | ||||
| spec: | ||||
|   replicas: 2 | ||||
|   template: | ||||
|     spec: | ||||
|       enterprise: your-enterprise-name | ||||
|       dockerdWithinRunnerContainer: true | ||||
|       resources: | ||||
|         limits: | ||||
|           cpu: "4000m" | ||||
|           memory: "2Gi" | ||||
|         requests: | ||||
|           cpu: "200m" | ||||
|           memory: "200Mi" | ||||
|       volumeMounts: | ||||
|       - mountPath: /runner | ||||
|         name: runner | ||||
|       volumes: | ||||
|       - name: runner | ||||
|         emptyDir: {} | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| ## Setting up authentication with GitHub API | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,6 +25,10 @@ import ( | |||
| 
 | ||||
| // RunnerSpec defines the desired state of Runner
 | ||||
| type RunnerSpec struct { | ||||
| 	// +optional
 | ||||
| 	// +kubebuilder:validation:Pattern=`^[^/]+$`
 | ||||
| 	Enterprise string `json:"enterprise,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	// +kubebuilder:validation:Pattern=`^[^/]+$`
 | ||||
| 	Organization string `json:"organization,omitempty"` | ||||
|  | @ -92,12 +96,22 @@ type RunnerSpec struct { | |||
| 
 | ||||
| // ValidateRepository validates repository field.
 | ||||
| func (rs *RunnerSpec) ValidateRepository() error { | ||||
| 	// Organization and repository are both exclusive.
 | ||||
| 	if len(rs.Organization) == 0 && len(rs.Repository) == 0 { | ||||
| 		return errors.New("Spec needs organization or repository") | ||||
| 	// Enterprise, Organization and repository are both exclusive.
 | ||||
| 	foundCount := 0 | ||||
| 	if len(rs.Organization) > 0 { | ||||
| 		foundCount += 1 | ||||
| 	} | ||||
| 	if len(rs.Organization) > 0 && len(rs.Repository) > 0 { | ||||
| 		return errors.New("Spec cannot have both organization and repository") | ||||
| 	if len(rs.Repository) > 0 { | ||||
| 		foundCount += 1 | ||||
| 	} | ||||
| 	if len(rs.Enterprise) > 0 { | ||||
| 		foundCount += 1 | ||||
| 	} | ||||
| 	if foundCount == 0 { | ||||
| 		return errors.New("Spec needs enterprise, organization or repository") | ||||
| 	} | ||||
| 	if foundCount > 1 { | ||||
| 		return errors.New("Spec cannot have many fields defined enterprise, organization and repository") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
|  | @ -113,6 +127,7 @@ type RunnerStatus struct { | |||
| 
 | ||||
| // RunnerStatusRegistration contains runner registration status
 | ||||
| type RunnerStatusRegistration struct { | ||||
| 	Enterprise   string      `json:"enterprise,omitempty"` | ||||
| 	Organization string      `json:"organization,omitempty"` | ||||
| 	Repository   string      `json:"repository,omitempty"` | ||||
| 	Labels       []string    `json:"labels,omitempty"` | ||||
|  | @ -122,6 +137,7 @@ type RunnerStatusRegistration struct { | |||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.enterprise",name=Enterprise,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.organization",name=Organization,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.repository",name=Repository,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.labels",name=Labels,type=string
 | ||||
|  |  | |||
|  | @ -426,6 +426,9 @@ spec: | |||
|                       type: object | ||||
|                     dockerdWithinRunnerContainer: | ||||
|                       type: boolean | ||||
|                     enterprise: | ||||
|                       pattern: ^[^/]+$ | ||||
|                       type: string | ||||
|                     env: | ||||
|                       items: | ||||
|                         description: EnvVar represents an environment variable present in a Container. | ||||
|  |  | |||
|  | @ -426,6 +426,9 @@ spec: | |||
|                       type: object | ||||
|                     dockerdWithinRunnerContainer: | ||||
|                       type: boolean | ||||
|                     enterprise: | ||||
|                       pattern: ^[^/]+$ | ||||
|                       type: string | ||||
|                     env: | ||||
|                       items: | ||||
|                         description: EnvVar represents an environment variable present in a Container. | ||||
|  |  | |||
|  | @ -7,6 +7,9 @@ metadata: | |||
|   name: runners.actions.summerwind.dev | ||||
| spec: | ||||
|   additionalPrinterColumns: | ||||
|     - JSONPath: .spec.enterprise | ||||
|       name: Enterprise | ||||
|       type: string | ||||
|     - JSONPath: .spec.organization | ||||
|       name: Organization | ||||
|       type: string | ||||
|  | @ -419,6 +422,9 @@ spec: | |||
|               type: object | ||||
|             dockerdWithinRunnerContainer: | ||||
|               type: boolean | ||||
|             enterprise: | ||||
|               pattern: ^[^/]+$ | ||||
|               type: string | ||||
|             env: | ||||
|               items: | ||||
|                 description: EnvVar represents an environment variable present in a Container. | ||||
|  | @ -1541,6 +1547,8 @@ spec: | |||
|             registration: | ||||
|               description: RunnerStatusRegistration contains runner registration status | ||||
|               properties: | ||||
|                 enterprise: | ||||
|                   type: string | ||||
|                 expiresAt: | ||||
|                   format: date-time | ||||
|                   type: string | ||||
|  |  | |||
|  | @ -426,6 +426,9 @@ spec: | |||
|                       type: object | ||||
|                     dockerdWithinRunnerContainer: | ||||
|                       type: boolean | ||||
|                     enterprise: | ||||
|                       pattern: ^[^/]+$ | ||||
|                       type: string | ||||
|                     env: | ||||
|                       items: | ||||
|                         description: EnvVar represents an environment variable present in a Container. | ||||
|  |  | |||
|  | @ -426,6 +426,9 @@ spec: | |||
|                       type: object | ||||
|                     dockerdWithinRunnerContainer: | ||||
|                       type: boolean | ||||
|                     enterprise: | ||||
|                       pattern: ^[^/]+$ | ||||
|                       type: string | ||||
|                     env: | ||||
|                       items: | ||||
|                         description: EnvVar represents an environment variable present in a Container. | ||||
|  |  | |||
|  | @ -7,6 +7,9 @@ metadata: | |||
|   name: runners.actions.summerwind.dev | ||||
| spec: | ||||
|   additionalPrinterColumns: | ||||
|     - JSONPath: .spec.enterprise | ||||
|       name: Enterprise | ||||
|       type: string | ||||
|     - JSONPath: .spec.organization | ||||
|       name: Organization | ||||
|       type: string | ||||
|  | @ -419,6 +422,9 @@ spec: | |||
|               type: object | ||||
|             dockerdWithinRunnerContainer: | ||||
|               type: boolean | ||||
|             enterprise: | ||||
|               pattern: ^[^/]+$ | ||||
|               type: string | ||||
|             env: | ||||
|               items: | ||||
|                 description: EnvVar represents an environment variable present in a Container. | ||||
|  | @ -1541,6 +1547,8 @@ spec: | |||
|             registration: | ||||
|               description: RunnerStatusRegistration contains runner registration status | ||||
|               properties: | ||||
|                 enterprise: | ||||
|                   type: string | ||||
|                 expiresAt: | ||||
|                   format: date-time | ||||
|                   type: string | ||||
|  |  | |||
|  | @ -204,7 +204,7 @@ func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByPercentageRunn | |||
| 	} | ||||
| 
 | ||||
| 	// ListRunners will return all runners managed by GitHub - not restricted to ns
 | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, orgName, "") | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, "", orgName, "") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  |  | |||
|  | @ -95,7 +95,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { | |||
| 
 | ||||
| 		if removed { | ||||
| 			if len(runner.Status.Registration.Token) > 0 { | ||||
| 				ok, err := r.unregisterRunner(ctx, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 				ok, err := r.unregisterRunner(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 				if err != nil { | ||||
| 					log.Error(err, "Failed to unregister runner") | ||||
| 					return ctrl.Result{}, err | ||||
|  | @ -194,7 +194,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { | |||
| 			return ctrl.Result{}, err | ||||
| 		} | ||||
| 
 | ||||
| 		runnerBusy, err := r.isRunnerBusy(ctx, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 		runnerBusy, err := r.isRunnerBusy(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 		if err != nil { | ||||
| 			log.Error(err, "Failed to check if runner is busy") | ||||
| 			return ctrl.Result{}, nil | ||||
|  | @ -227,8 +227,8 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { | |||
| 	return ctrl.Result{}, nil | ||||
| } | ||||
| 
 | ||||
| func (r *RunnerReconciler) isRunnerBusy(ctx context.Context, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, org, repo) | ||||
| func (r *RunnerReconciler) isRunnerBusy(ctx context.Context, enterprise, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, enterprise, org, repo) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | @ -242,8 +242,8 @@ func (r *RunnerReconciler) isRunnerBusy(ctx context.Context, org, repo, name str | |||
| 	return false, fmt.Errorf("runner not found") | ||||
| } | ||||
| 
 | ||||
| func (r *RunnerReconciler) unregisterRunner(ctx context.Context, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, org, repo) | ||||
| func (r *RunnerReconciler) unregisterRunner(ctx context.Context, enterprise, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, enterprise, org, repo) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | @ -263,7 +263,7 @@ func (r *RunnerReconciler) unregisterRunner(ctx context.Context, org, repo, name | |||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	if err := r.GitHubClient.RemoveRunner(ctx, org, repo, id); err != nil { | ||||
| 	if err := r.GitHubClient.RemoveRunner(ctx, enterprise, org, repo, id); err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 
 | ||||
|  | @ -277,7 +277,7 @@ func (r *RunnerReconciler) updateRegistrationToken(ctx context.Context, runner v | |||
| 
 | ||||
| 	log := r.Log.WithValues("runner", runner.Name) | ||||
| 
 | ||||
| 	rt, err := r.GitHubClient.GetRegistrationToken(ctx, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 	rt, err := r.GitHubClient.GetRegistrationToken(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 	if err != nil { | ||||
| 		r.Recorder.Event(&runner, corev1.EventTypeWarning, "FailedUpdateRegistrationToken", "Updating registration token failed") | ||||
| 		log.Error(err, "Failed to get new registration token") | ||||
|  | @ -339,6 +339,10 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) { | |||
| 			Name:  "RUNNER_REPO", | ||||
| 			Value: runner.Spec.Repository, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:  "RUNNER_ENTERPRISE", | ||||
| 			Value: runner.Spec.Enterprise, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:  "RUNNER_LABELS", | ||||
| 			Value: strings.Join(runner.Spec.Labels, ","), | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ func (r *RunnerReplicaSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, e | |||
| 		// get runners that are currently not busy
 | ||||
| 		var notBusy []v1alpha1.Runner | ||||
| 		for _, runner := range myRunners { | ||||
| 			busy, err := r.isRunnerBusy(ctx, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 			busy, err := r.isRunnerBusy(ctx, runner.Spec.Enterprise, runner.Spec.Organization, runner.Spec.Repository, runner.Name) | ||||
| 			if err != nil { | ||||
| 				log.Error(err, "Failed to check if runner is busy") | ||||
| 				return ctrl.Result{}, err | ||||
|  | @ -187,8 +187,8 @@ func (r *RunnerReplicaSetReconciler) SetupWithManager(mgr ctrl.Manager) error { | |||
| 		Complete(r) | ||||
| } | ||||
| 
 | ||||
| func (r *RunnerReplicaSetReconciler) isRunnerBusy(ctx context.Context, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, org, repo) | ||||
| func (r *RunnerReplicaSetReconciler) isRunnerBusy(ctx context.Context, enterprise, org, repo, name string) (bool, error) { | ||||
| 	runners, err := r.GitHubClient.ListRunners(ctx, enterprise, org, repo) | ||||
| 	r.Log.Info("runners", "github", runners) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ func (c *Config) NewClient() (*Client, error) { | |||
| } | ||||
| 
 | ||||
| // GetRegistrationToken returns a registration token tied with the name of repository and runner.
 | ||||
| func (c *Client) GetRegistrationToken(ctx context.Context, org, repo, name string) (*github.RegistrationToken, error) { | ||||
| func (c *Client) GetRegistrationToken(ctx context.Context, enterprise, org, repo, name string) (*github.RegistrationToken, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
|  | @ -89,13 +89,13 @@ func (c *Client) GetRegistrationToken(ctx context.Context, org, repo, name strin | |||
| 		return rt, nil | ||||
| 	} | ||||
| 
 | ||||
| 	owner, repo, err := getOwnerAndRepo(org, repo) | ||||
| 	enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return rt, err | ||||
| 	} | ||||
| 
 | ||||
| 	rt, res, err := c.createRegistrationToken(ctx, owner, repo) | ||||
| 	rt, res, err := c.createRegistrationToken(ctx, enterprise, owner, repo) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to create registration token: %v", err) | ||||
|  | @ -114,14 +114,14 @@ func (c *Client) GetRegistrationToken(ctx context.Context, org, repo, name strin | |||
| } | ||||
| 
 | ||||
| // RemoveRunner removes a runner with specified runner ID from repository.
 | ||||
| func (c *Client) RemoveRunner(ctx context.Context, org, repo string, runnerID int64) error { | ||||
| 	owner, repo, err := getOwnerAndRepo(org, repo) | ||||
| func (c *Client) RemoveRunner(ctx context.Context, enterprise, org, repo string, runnerID int64) error { | ||||
| 	enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := c.removeRunner(ctx, owner, repo, runnerID) | ||||
| 	res, err := c.removeRunner(ctx, enterprise, owner, repo, runnerID) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to remove runner: %v", err) | ||||
|  | @ -135,8 +135,8 @@ func (c *Client) RemoveRunner(ctx context.Context, org, repo string, runnerID in | |||
| } | ||||
| 
 | ||||
| // ListRunners returns a list of runners of specified owner/repository name.
 | ||||
| func (c *Client) ListRunners(ctx context.Context, org, repo string) ([]*github.Runner, error) { | ||||
| 	owner, repo, err := getOwnerAndRepo(org, repo) | ||||
| func (c *Client) ListRunners(ctx context.Context, enterprise, org, repo string) ([]*github.Runner, error) { | ||||
| 	enterprise, owner, repo, err := getEnterpriseOrganisationAndRepo(enterprise, org, repo) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -146,7 +146,7 @@ func (c *Client) ListRunners(ctx context.Context, org, repo string) ([]*github.R | |||
| 
 | ||||
| 	opts := github.ListOptions{PerPage: 10} | ||||
| 	for { | ||||
| 		list, res, err := c.listRunners(ctx, owner, repo, &opts) | ||||
| 		list, res, err := c.listRunners(ctx, enterprise, owner, repo, &opts) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			return runners, fmt.Errorf("failed to list runners: %v", err) | ||||
|  | @ -174,42 +174,52 @@ func (c *Client) cleanup() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // wrappers for github functions (switch between organization/repository mode)
 | ||||
| // wrappers for github functions (switch between enterprise/organization/repository mode)
 | ||||
| // so the calling functions don't need to switch and their code is a bit cleaner
 | ||||
| 
 | ||||
| func (c *Client) createRegistrationToken(ctx context.Context, owner, repo string) (*github.RegistrationToken, *github.Response, error) { | ||||
| func (c *Client) createRegistrationToken(ctx context.Context, enterprise, org, repo string) (*github.RegistrationToken, *github.Response, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return c.Client.Actions.CreateRegistrationToken(ctx, owner, repo) | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Client.Actions.CreateOrganizationRegistrationToken(ctx, owner) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) removeRunner(ctx context.Context, owner, repo string, runnerID int64) (*github.Response, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return c.Client.Actions.RemoveRunner(ctx, owner, repo, runnerID) | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Client.Actions.RemoveOrganizationRunner(ctx, owner, runnerID) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) listRunners(ctx context.Context, owner, repo string, opts *github.ListOptions) (*github.Runners, *github.Response, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return c.Client.Actions.ListRunners(ctx, owner, repo, opts) | ||||
| 	} | ||||
| 
 | ||||
| 	return c.Client.Actions.ListOrganizationRunners(ctx, owner, opts) | ||||
| } | ||||
| 
 | ||||
| // Validates owner and repo arguments. Both are optional, but at least one should be specified
 | ||||
| func getOwnerAndRepo(org, repo string) (string, string, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return splitOwnerAndRepo(repo) | ||||
| 		return c.Client.Actions.CreateRegistrationToken(ctx, org, repo) | ||||
| 	} | ||||
| 	if len(org) > 0 { | ||||
| 		return org, "", nil | ||||
| 		return c.Client.Actions.CreateOrganizationRegistrationToken(ctx, org) | ||||
| 	} | ||||
| 	return "", "", fmt.Errorf("organization and repository are both empty") | ||||
| 	return c.Client.Enterprise.CreateRegistrationToken(ctx, enterprise) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) removeRunner(ctx context.Context, enterprise, org, repo string, runnerID int64) (*github.Response, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return c.Client.Actions.RemoveRunner(ctx, org, repo, runnerID) | ||||
| 	} | ||||
| 	if len(org) > 0 { | ||||
| 		return c.Client.Actions.RemoveOrganizationRunner(ctx, org, runnerID) | ||||
| 	} | ||||
| 	return c.Client.Enterprise.RemoveRunner(ctx, enterprise, runnerID) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) listRunners(ctx context.Context, enterprise, org, repo string, opts *github.ListOptions) (*github.Runners, *github.Response, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		return c.Client.Actions.ListRunners(ctx, org, repo, opts) | ||||
| 	} | ||||
| 	if len(org) > 0 { | ||||
| 		return c.Client.Actions.ListOrganizationRunners(ctx, org, opts) | ||||
| 	} | ||||
| 	return c.Client.Enterprise.ListRunners(ctx, enterprise, opts) | ||||
| } | ||||
| 
 | ||||
| // Validates enterprise, organisation and repo arguments. Both are optional, but at least one should be specified
 | ||||
| func getEnterpriseOrganisationAndRepo(enterprise, org, repo string) (string, string, string, error) { | ||||
| 	if len(repo) > 0 { | ||||
| 		owner, repository, err := splitOwnerAndRepo(repo) | ||||
| 		return "", owner, repository, err | ||||
| 	} | ||||
| 	if len(org) > 0 { | ||||
| 		return "", org, "", nil | ||||
| 	} | ||||
| 	if len(enterprise) > 0 { | ||||
| 		return enterprise, "", "", nil | ||||
| 	} | ||||
| 	return "", "", "", fmt.Errorf("enterprise, organization and repository are all empty") | ||||
| } | ||||
| 
 | ||||
| func getRegistrationKey(org, repo string) string { | ||||
|  |  | |||
|  | @ -39,22 +39,26 @@ func TestMain(m *testing.M) { | |||
| 
 | ||||
| func TestGetRegistrationToken(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		enterprise string | ||||
| 		org        string | ||||
| 		repo       string | ||||
| 		token      string | ||||
| 		err        bool | ||||
| 	}{ | ||||
| 		{org: "", repo: "test/valid", token: fake.RegistrationToken, err: false}, | ||||
| 		{org: "", repo: "test/invalid", token: "", err: true}, | ||||
| 		{org: "", repo: "test/error", token: "", err: true}, | ||||
| 		{org: "test", repo: "", token: fake.RegistrationToken, err: false}, | ||||
| 		{org: "invalid", repo: "", token: "", err: true}, | ||||
| 		{org: "error", repo: "", token: "", err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/valid", token: fake.RegistrationToken, err: false}, | ||||
| 		{enterprise: "", org: "", repo: "test/invalid", token: "", err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/error", token: "", err: true}, | ||||
| 		{enterprise: "", org: "test", repo: "", token: fake.RegistrationToken, err: false}, | ||||
| 		{enterprise: "", org: "invalid", repo: "", token: "", err: true}, | ||||
| 		{enterprise: "", org: "error", repo: "", token: "", err: true}, | ||||
| 		{enterprise: "test", org: "", repo: "", token: fake.RegistrationToken, err: false}, | ||||
| 		{enterprise: "invalid", org: "", repo: "", token: "", err: true}, | ||||
| 		{enterprise: "error", org: "", repo: "", token: "", err: true}, | ||||
| 	} | ||||
| 
 | ||||
| 	client := newTestClient() | ||||
| 	for i, tt := range tests { | ||||
| 		rt, err := client.GetRegistrationToken(context.Background(), tt.org, tt.repo, "test") | ||||
| 		rt, err := client.GetRegistrationToken(context.Background(), tt.enterprise, tt.org, tt.repo, "test") | ||||
| 		if !tt.err && err != nil { | ||||
| 			t.Errorf("[%d] unexpected error: %v", i, err) | ||||
| 		} | ||||
|  | @ -66,22 +70,26 @@ func TestGetRegistrationToken(t *testing.T) { | |||
| 
 | ||||
| func TestListRunners(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		enterprise string | ||||
| 		org        string | ||||
| 		repo       string | ||||
| 		length     int | ||||
| 		err        bool | ||||
| 	}{ | ||||
| 		{org: "", repo: "test/valid", length: 2, err: false}, | ||||
| 		{org: "", repo: "test/invalid", length: 0, err: true}, | ||||
| 		{org: "", repo: "test/error", length: 0, err: true}, | ||||
| 		{org: "test", repo: "", length: 2, err: false}, | ||||
| 		{org: "invalid", repo: "", length: 0, err: true}, | ||||
| 		{org: "error", repo: "", length: 0, err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/valid", length: 2, err: false}, | ||||
| 		{enterprise: "", org: "", repo: "test/invalid", length: 0, err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/error", length: 0, err: true}, | ||||
| 		{enterprise: "", org: "test", repo: "", length: 2, err: false}, | ||||
| 		{enterprise: "", org: "invalid", repo: "", length: 0, err: true}, | ||||
| 		{enterprise: "", org: "error", repo: "", length: 0, err: true}, | ||||
| 		{enterprise: "test", org: "", repo: "", length: 2, err: false}, | ||||
| 		{enterprise: "invalid", org: "", repo: "", length: 0, err: true}, | ||||
| 		{enterprise: "error", org: "", repo: "", length: 0, err: true}, | ||||
| 	} | ||||
| 
 | ||||
| 	client := newTestClient() | ||||
| 	for i, tt := range tests { | ||||
| 		runners, err := client.ListRunners(context.Background(), tt.org, tt.repo) | ||||
| 		runners, err := client.ListRunners(context.Background(), tt.enterprise, tt.org, tt.repo) | ||||
| 		if !tt.err && err != nil { | ||||
| 			t.Errorf("[%d] unexpected error: %v", i, err) | ||||
| 		} | ||||
|  | @ -93,21 +101,25 @@ func TestListRunners(t *testing.T) { | |||
| 
 | ||||
| func TestRemoveRunner(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		enterprise string | ||||
| 		org        string | ||||
| 		repo       string | ||||
| 		err        bool | ||||
| 	}{ | ||||
| 		{org: "", repo: "test/valid", err: false}, | ||||
| 		{org: "", repo: "test/invalid", err: true}, | ||||
| 		{org: "", repo: "test/error", err: true}, | ||||
| 		{org: "test", repo: "", err: false}, | ||||
| 		{org: "invalid", repo: "", err: true}, | ||||
| 		{org: "error", repo: "", err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/valid", err: false}, | ||||
| 		{enterprise: "", org: "", repo: "test/invalid", err: true}, | ||||
| 		{enterprise: "", org: "", repo: "test/error", err: true}, | ||||
| 		{enterprise: "", org: "test", repo: "", err: false}, | ||||
| 		{enterprise: "", org: "invalid", repo: "", err: true}, | ||||
| 		{enterprise: "", org: "error", repo: "", err: true}, | ||||
| 		{enterprise: "test", org: "", repo: "", err: false}, | ||||
| 		{enterprise: "invalid", org: "", repo: "", err: true}, | ||||
| 		{enterprise: "error", org: "", repo: "", err: true}, | ||||
| 	} | ||||
| 
 | ||||
| 	client := newTestClient() | ||||
| 	for i, tt := range tests { | ||||
| 		err := client.RemoveRunner(context.Background(), tt.org, tt.repo, int64(1)) | ||||
| 		err := client.RemoveRunner(context.Background(), tt.enterprise, tt.org, tt.repo, int64(1)) | ||||
| 		if !tt.err && err != nil { | ||||
| 			t.Errorf("[%d] unexpected error: %v", i, err) | ||||
| 		} | ||||
|  |  | |||
							
								
								
									
										5
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										5
									
								
								go.mod
								
								
								
								
							|  | @ -6,10 +6,7 @@ require ( | |||
| 	github.com/bradleyfalzon/ghinstallation v1.1.1 | ||||
| 	github.com/davecgh/go-spew v1.1.1 | ||||
| 	github.com/go-logr/logr v0.1.0 | ||||
| 	github.com/google/go-github v17.0.0+incompatible // indirect | ||||
| 	github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04 | ||||
| 	github.com/google/go-github/v33 v33.0.0 | ||||
| 	github.com/google/go-querystring v1.0.0 | ||||
| 	github.com/google/go-github/v33 v33.0.1-0.20210204004227-319dcffb518a | ||||
| 	github.com/gorilla/mux v1.8.0 | ||||
| 	github.com/kelseyhightower/envconfig v1.4.0 | ||||
| 	github.com/onsi/ginkgo v1.8.0 | ||||
|  |  | |||
							
								
								
									
										8
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										8
									
								
								go.sum
								
								
								
								
							|  | @ -116,14 +116,10 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= | |||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||
| github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= | ||||
| github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||
| github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= | ||||
| github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= | ||||
| github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= | ||||
| github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= | ||||
| github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04 h1:wEYk2h/GwOhImcVjiTIceP88WxVbXw2F+ARYUQMEsfg= | ||||
| github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= | ||||
| github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM= | ||||
| github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= | ||||
| github.com/google/go-github/v33 v33.0.1-0.20210204004227-319dcffb518a h1:Z9Nzq8ntvvXCLnFGOkzzcD8HDOzOo+obuwE5oK85vNQ= | ||||
| github.com/google/go-github/v33 v33.0.1-0.20210204004227-319dcffb518a/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= | ||||
| github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= | ||||
| github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||||
| github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= | ||||
|  |  | |||
|  | @ -16,14 +16,16 @@ if [ -z "${RUNNER_NAME}" ]; then | |||
|   exit 1 | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${RUNNER_ORG}" ] && [ -n "${RUNNER_REPO}" ]; then | ||||
| if [ -n "${RUNNER_ORG}" ] && [ -n "${RUNNER_REPO}" ] && [ -n "${RUNNER_ENTERPRISE}" ]; then | ||||
|   ATTACH="${RUNNER_ORG}/${RUNNER_REPO}" | ||||
| elif [ -n "${RUNNER_ORG}" ]; then | ||||
|   ATTACH="${RUNNER_ORG}" | ||||
| elif [ -n "${RUNNER_REPO}" ]; then | ||||
|   ATTACH="${RUNNER_REPO}" | ||||
| elif [ -n "${RUNNER_ENTERPRISE}" ]; then | ||||
|   ATTACH="enterprises/${RUNNER_ENTERPRISE}" | ||||
| else | ||||
|   echo "At least one of RUNNER_ORG or RUNNER_REPO must be set" 1>&2 | ||||
|   echo "At least one of RUNNER_ORG or RUNNER_REPO or RUNNER_ENTERPRISE must be set" 1>&2 | ||||
|   exit 1 | ||||
| fi | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue