(ctx context.Context, remote, branch string, user *database.User)
| 1148 | } |
| 1149 | |
| 1150 | func (s *Server) createRepo(ctx context.Context, remote, branch string, user *database.User) (string, error) { |
| 1151 | org, repo, ok := gitutil.SplitGithubRemote(remote) |
| 1152 | if !ok { |
| 1153 | return "", status.Error(codes.InvalidArgument, fmt.Sprintf("invalid remote: %q", remote)) |
| 1154 | } |
| 1155 | |
| 1156 | var err error |
| 1157 | var token, ghAcct string |
| 1158 | var client *github.Client |
| 1159 | if org == user.GithubUsername { |
| 1160 | // if expectation is to create in user's personal account then we need to use user access token |
| 1161 | token, err = s.userAccessToken(ctx, user) |
| 1162 | if err != nil { |
| 1163 | return "", err |
| 1164 | } |
| 1165 | // We need to pass empty org if the org to be created in is same as the authenticated user. |
| 1166 | ghAcct = "" |
| 1167 | client = github.NewTokenClient(ctx, token) |
| 1168 | } else { |
| 1169 | // get the installation access token for that org |
| 1170 | token, _, err = s.admin.Github.InstallationTokenForOrg(ctx, org) |
| 1171 | if err != nil { |
| 1172 | return "", err |
| 1173 | } |
| 1174 | ghAcct = org |
| 1175 | client = github.NewTokenClient(ctx, token) |
| 1176 | // check user should be a member of the org to create a repo |
| 1177 | ok, _, err := client.Organizations.IsMember(ctx, ghAcct, user.GithubUsername) |
| 1178 | if err != nil { |
| 1179 | return "", err |
| 1180 | } |
| 1181 | if !ok { |
| 1182 | return "", status.Errorf(codes.PermissionDenied, "user is not a member of the organization %q", org) |
| 1183 | } |
| 1184 | } |
| 1185 | |
| 1186 | _, _, err = client.Repositories.Create(ctx, ghAcct, &github.Repository{ |
| 1187 | Name: &repo, |
| 1188 | DefaultBranch: &branch, |
| 1189 | Private: github.Ptr(true), |
| 1190 | }) |
| 1191 | if err != nil { |
| 1192 | return "", fmt.Errorf("failed to create repo: %w", err) |
| 1193 | } |
| 1194 | |
| 1195 | // github.Repositories.Create returns before actually creating the repo. So do an exponential backoff check |
| 1196 | err = retrier.New(retrier.ExponentialBackoff(createRetries, time.Second), nil).RunCtx(ctx, func(ctx context.Context) error { |
| 1197 | _, _, err := client.Repositories.Get(ctx, org, repo) |
| 1198 | if err != nil { |
| 1199 | return err |
| 1200 | } |
| 1201 | return nil |
| 1202 | }) |
| 1203 | if err != nil { |
| 1204 | return "", fmt.Errorf("failed to verify repo creation: %w", err) |
| 1205 | } |
| 1206 | |
| 1207 | return token, nil |
no test coverage detected