github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/routers/api/repo/repo.go (about) 1 package repo 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/covergates/covergates/config" 8 "github.com/covergates/covergates/core" 9 "github.com/covergates/covergates/routers/api/request" 10 "github.com/gin-gonic/gin" 11 "golang.org/x/net/context" 12 ) 13 14 // HandleCreate a repository 15 // @Summary Create new repository for code coverage 16 // @Tags Repository 17 // @Param repo body core.Repo true "repository to create" 18 // @Success 200 {object} core.Repo "Created repository" 19 // @Router /repos [post] 20 func HandleCreate(store core.RepoStore, service core.SCMService) gin.HandlerFunc { 21 return func(c *gin.Context) { 22 user, ok := request.UserFrom(c) 23 if !ok { 24 c.String(403, "user not found") 25 return 26 } 27 repo := &core.Repo{} 28 if err := c.BindJSON(repo); err != nil { 29 c.String(400, err.Error()) 30 return 31 } 32 33 if repo.Branch == "" { 34 client, err := service.Client(repo.SCM) 35 if err != nil { 36 c.String(500, err.Error()) 37 } 38 scmRepo, err := client.Repositories().Find(c.Request.Context(), user, repo.FullName()) 39 if err != nil { 40 c.String(500, err.Error()) 41 return 42 } 43 repo.Branch = scmRepo.Branch 44 } 45 46 if err := store.Create(repo); err != nil { 47 c.String(400, err.Error()) 48 return 49 } 50 c.JSON(200, repo) 51 } 52 } 53 54 // HandleReportIDRenew generates a new report id for the repository 55 // @Summary renew repository report id 56 // @Tags Repository 57 // @Param scm path string true "SCM" 58 // @Param namespace path string true "Namespace" 59 // @Param name path string true "name" 60 // @Success 200 {object} core.Repo "updated repository" 61 // @Router /repos/{scm}/{namespace}/{name}/report [patch] 62 func HandleReportIDRenew(store core.RepoStore, service core.SCMService) gin.HandlerFunc { 63 return func(c *gin.Context) { 64 user := request.MustGetUserFrom(c) 65 scm := core.SCMProvider(c.Param("scm")) 66 repo, err := store.Find(&core.Repo{ 67 Name: c.Param("name"), 68 NameSpace: c.Param("namespace"), 69 SCM: scm, 70 }) 71 if err != nil { 72 c.String(500, err.Error()) 73 return 74 } 75 client, err := service.Client(scm) 76 if err != nil { 77 c.Error(err) 78 c.String(500, err.Error()) 79 return 80 } 81 repo.ReportID = client.Repositories().NewReportID(repo) 82 if err := store.Update(repo); err != nil { 83 c.Error(err) 84 c.String(500, err.Error()) 85 return 86 } 87 if err := store.UpdateCreator(repo, user); err != nil { 88 c.Error(err) 89 c.String(500, err.Error()) 90 return 91 } 92 c.JSON(200, repo) 93 return 94 } 95 } 96 97 // HandleGet repository 98 // @Summary get repository 99 // @Tags Repository 100 // @Param scm path string true "SCM" 101 // @Param namespace path string true "Namespace" 102 // @Param name path string true "name" 103 // @Success 200 {object} core.Repo found repository 104 // @Router /repos/{scm}/{namespace}/{name} [get] 105 func HandleGet(store core.RepoStore) gin.HandlerFunc { 106 return func(c *gin.Context) { 107 repo, err := store.Find(&core.Repo{ 108 NameSpace: c.Param("namespace"), 109 Name: c.Param("name"), 110 SCM: core.SCMProvider(c.Param("scm")), 111 }) 112 if err != nil { 113 c.JSON(404, &core.Repo{}) 114 return 115 } 116 if repo.Private { 117 if _, ok := request.UserFrom(c); !ok { 118 c.JSON(401, &core.Repo{}) 119 return 120 } 121 } 122 c.JSON(200, repo) 123 } 124 } 125 126 // HandleSync repository information with SCM 127 // @Summary sync repository information with SCM 128 // @Tags Repository 129 // @Param scm path string true "SCM" 130 // @Param namespace path string true "Namespace" 131 // @Param name path string true "name" 132 // @Success 200 {object} core.Repo updated repository 133 // @Router /repos/{scm}/{namespace}/{name} [patch] 134 func HandleSync(service core.SCMService, store core.RepoStore) gin.HandlerFunc { 135 return func(c *gin.Context) { 136 ctx := c.Request.Context() 137 repo := &core.Repo{} 138 provider := core.SCMProvider(c.Param("scm")) 139 nameSpace := c.Param("namespace") 140 name := c.Param("name") 141 user, ok := request.UserFrom(c) 142 if !ok { 143 c.JSON(403, repo) 144 return 145 } 146 client, err := service.Client(provider) 147 if err != nil { 148 c.JSON(500, repo) 149 return 150 } 151 repo, err = client.Repositories().Find(ctx, user, fmt.Sprintf("%s/%s", nameSpace, name)) 152 if err != nil { 153 c.JSON(500, repo) 154 return 155 } 156 storeRepo, err := store.Find(&core.Repo{ 157 URL: repo.URL, 158 }) 159 if err != nil { 160 c.JSON(500, repo) 161 return 162 } 163 storeRepo.Branch = repo.Branch 164 if err := store.Update(storeRepo); err != nil { 165 c.JSON(500, repo) 166 return 167 } 168 c.JSON(200, storeRepo) 169 } 170 } 171 172 // HandleListAll repositories from remote SCM. 173 // To list repository for user, using API /user/repos instead for fatser response. 174 // @Summary List repositories for all available SCM providers 175 // @Tags Repository 176 // @Success 200 {object} []core.Repo "repositories" 177 // @Router /repos [get] 178 func HandleListAll(config *config.Config, service core.SCMService, store core.RepoStore) gin.HandlerFunc { 179 return func(c *gin.Context) { 180 repositories := make([]*core.Repo, 0) 181 user, ok := request.UserFrom(c) 182 if !ok { 183 c.JSON(401, repositories) 184 return 185 } 186 ctx := c.Request.Context() 187 for _, provider := range config.Providers() { 188 client, err := service.Client(provider) 189 if err != nil { 190 continue 191 } 192 result, err := getRepositories(ctx, user, client, store) 193 if err != nil { 194 continue 195 } 196 repositories = append(repositories, result...) 197 } 198 c.JSON(200, repositories) 199 } 200 } 201 202 // HandleListSCM repositories 203 // @Summary List repositories 204 // @Tags Repository 205 // @Param scm path string true "SCM source (github, gitea)" 206 // @Success 200 {object} []core.Repo "repositories" 207 // @Router /repos/{scm} [get] 208 func HandleListSCM(service core.SCMService, store core.RepoStore) gin.HandlerFunc { 209 return func(c *gin.Context) { 210 scm := core.SCMProvider(c.Param("scm")) 211 user, ok := request.UserFrom(c) 212 if !ok { 213 c.JSON(401, []*core.Repo{}) 214 return 215 } 216 ctx := c.Request.Context() 217 client, err := service.Client(scm) 218 if err != nil { 219 c.Error(err) 220 c.JSON(500, []*core.Repo{}) 221 return 222 } 223 repositories, err := getRepositories(ctx, user, client, store) 224 if err != nil { 225 c.JSON(500, []*core.Repo{}) 226 return 227 } 228 c.JSON(200, repositories) 229 } 230 } 231 232 // HandleGetFiles from the repository 233 // @Summary List all files in repository 234 // @Tags Repository 235 // @Param scm path string true "SCM" 236 // @Param namespace path string true "Namespace" 237 // @Param name path string true "name" 238 // @Param ref query string false "specify git ref, default main branch" 239 // @Success 200 {object} []string "files" 240 // @Router /repos/{scm}/{namespace}/{name}/files [get] 241 func HandleGetFiles(service core.SCMService) gin.HandlerFunc { 242 return func(c *gin.Context) { 243 scm := core.SCMProvider(c.Param("scm")) 244 repoName := fmt.Sprintf("%s/%s", c.Param("namespace"), c.Param("name")) 245 user, ok := request.UserFrom(c) 246 ctx := c.Request.Context() 247 if !ok { 248 c.JSON(401, []string{}) 249 return 250 } 251 client, err := service.Client(scm) 252 if err != nil { 253 c.Error(err) 254 c.JSON(500, []string{}) 255 return 256 } 257 ref, err := getRef(c, client, user) 258 if err != nil { 259 c.Error(err) 260 c.JSON(500, []string{}) 261 return 262 } 263 files, err := client.Contents().ListAllFiles(ctx, user, repoName, ref) 264 if err != nil { 265 c.Error(err) 266 c.JSON(500, []string{}) 267 return 268 } 269 c.JSON(200, files) 270 } 271 } 272 273 // HandleGetFileContent for a file from repository 274 // @Summary Get a file content 275 // @Tags Repository 276 // @Param scm path string true "SCM" 277 // @Param namespace path string true "Namespace" 278 // @Param name path string true "name" 279 // @Param path path string true "file path" 280 // @Param ref query string false "specify git ref, default main branch" 281 // @Success 200 {string} string "file content" 282 // @Router /repos/{scm}/{namespace}/{name}/content/{path} [get] 283 func HandleGetFileContent(service core.SCMService) gin.HandlerFunc { 284 return func(c *gin.Context) { 285 scm := core.SCMProvider(c.Param("scm")) 286 repoName := fmt.Sprintf("%s/%s", c.Param("namespace"), c.Param("name")) 287 filePath := strings.TrimLeft(c.Param("path"), "/") 288 user, ok := request.UserFrom(c) 289 ctx := c.Request.Context() 290 if !ok { 291 c.String(401, "") 292 return 293 } 294 client, err := service.Client(scm) 295 if err != nil { 296 c.Error(err) 297 c.String(500, "") 298 return 299 } 300 ref, err := getRef(c, client, user) 301 if err != nil { 302 c.Error(err) 303 c.String(500, "") 304 return 305 } 306 content, err := client.Contents().Find(ctx, user, repoName, filePath, ref) 307 c.Data(200, "text/plain", content) 308 } 309 } 310 311 // HandleGetSetting for the repository 312 // @Summary get repository setting 313 // @Tags Repository 314 // @Param scm path string true "SCM" 315 // @Param namespace path string true "Namespace" 316 // @Param name path string true "name" 317 // @Success 200 {object} core.RepoSetting repository setting 318 // @Router /repos/{scm}/{namespace}/{name}/setting [get] 319 func HandleGetSetting(store core.RepoStore) gin.HandlerFunc { 320 return func(c *gin.Context) { 321 repo, err := store.Find(&core.Repo{ 322 NameSpace: c.Param("namespace"), 323 Name: c.Param("name"), 324 SCM: core.SCMProvider(c.Param("scm")), 325 }) 326 if err != nil { 327 c.JSON(404, &core.RepoSetting{}) 328 return 329 } 330 setting, err := store.Setting(repo) 331 if err != nil { 332 if err != nil { 333 c.JSON(404, &core.RepoSetting{}) 334 return 335 } 336 } 337 c.JSON(200, setting) 338 } 339 } 340 341 // HandleUpdateSetting for the repository 342 // @Summary update repository setting 343 // @Tags Repository 344 // @Param scm path string true "SCM" 345 // @Param namespace path string true "Namespace" 346 // @Param name path string true "name" 347 // @Param setting body core.RepoSetting true "repository setting" 348 // @Success 200 {object} core.RepoSetting repository setting 349 // @Router /repos/{scm}/{namespace}/{name}/setting [post] 350 func HandleUpdateSetting(store core.RepoStore, service core.SCMService) gin.HandlerFunc { 351 return func(c *gin.Context) { 352 ctx := c.Request.Context() 353 repo := c.MustGet(keyRepo).(*core.Repo) 354 setting := &core.RepoSetting{} 355 user, ok := request.UserFrom(c) 356 if !ok { 357 c.JSON(401, setting) 358 return 359 } 360 creator, err := store.Creator(repo) 361 if err != nil { 362 c.JSON(500, setting) 363 return 364 } 365 client, err := service.Client(repo.SCM) 366 if err != nil { 367 c.JSON(500, setting) 368 } 369 if !client.Repositories().IsAdmin(ctx, user, repo.FullName()) && user.Login != creator.Login { 370 c.JSON(401, setting) 371 return 372 } 373 if err := c.BindJSON(setting); err != nil { 374 c.JSON(400, setting) 375 return 376 } 377 if err := store.UpdateSetting(repo, setting); err != nil { 378 c.JSON(500, setting) 379 return 380 } 381 c.JSON(200, setting) 382 } 383 } 384 385 // HandleListCommits for repository recent builds 386 // @Summary list recent commits 387 // @Tags Repository 388 // @Param scm path string true "SCM" 389 // @Param namespace path string true "Namespace" 390 // @Param name path string true "name" 391 // @Param ref query string false "branch to list commits from" 392 // @Success 200 {object} []core.Commit commits 393 // @Router /repos/{scm}/{namespace}/{name}/commits [get] 394 func HandleListCommits(service core.SCMService) gin.HandlerFunc { 395 return func(c *gin.Context) { 396 repo := c.MustGet(keyRepo).(*core.Repo) 397 user, ok := request.UserFrom(c) 398 if !ok { 399 c.JSON(401, []*core.Commit{}) 400 return 401 } 402 client, err := service.Client(repo.SCM) 403 if err != nil { 404 c.JSON(500, []*core.Commit{}) 405 return 406 } 407 ctx := c.Request.Context() 408 var commits []*core.Commit 409 if c.Query("ref") == "" { 410 commits, err = client.Git().ListCommits(ctx, user, repo.FullName()) 411 } else { 412 commits, err = client.Git().ListCommitsByRef(ctx, user, repo.FullName(), c.Query("ref")) 413 } 414 if err != nil { 415 c.Error(err) 416 c.JSON(500, []*core.Commit{}) 417 } 418 c.JSON(200, commits) 419 } 420 } 421 422 // HandleListBranches for the repository 423 // @Summary list repository branches 424 // @Tags Repository 425 // @Param scm path string true "SCM" 426 // @Param namespace path string true "Namespace" 427 // @Param name path string true "name" 428 // @Success 200 {object} []string branch names 429 // @Router /repos/{scm}/{namespace}/{name}/branches [get] 430 func HandleListBranches(service core.SCMService) gin.HandlerFunc { 431 return func(c *gin.Context) { 432 repo := c.MustGet(keyRepo).(*core.Repo) 433 user := request.MustGetUserFrom(c) 434 client, err := service.Client(repo.SCM) 435 if err != nil { 436 c.Error(err) 437 c.JSON(500, []string{}) 438 return 439 } 440 ctx := c.Request.Context() 441 branches, err := client.Git().ListBranches(ctx, user, repo.FullName()) 442 if err != nil { 443 c.Error(err) 444 c.JSON(500, []string{}) 445 return 446 } 447 c.JSON(200, branches) 448 } 449 } 450 451 func getRef(c *gin.Context, client core.Client, user *core.User) (string, error) { 452 repoName := fmt.Sprintf("%s/%s", c.Param("namespace"), c.Param("name")) 453 ref := c.Query("ref") 454 if ref == "" { 455 repo, err := client.Repositories().Find(c.Request.Context(), user, repoName) 456 if err != nil { 457 return "", err 458 } 459 ref = repo.Branch 460 } 461 return ref, nil 462 } 463 464 func getRepositories( 465 ctx context.Context, 466 user *core.User, 467 client core.Client, 468 store core.RepoStore, 469 ) ([]*core.Repo, error) { 470 repositories, err := client.Repositories().List(ctx, user) 471 if err != nil { 472 return nil, err 473 } 474 urls := make([]string, len(repositories)) 475 for i, repo := range repositories { 476 urls[i] = repo.URL 477 } 478 storeRepositories, err := store.Finds(urls...) 479 if err != nil { 480 return repositories, nil 481 } 482 reportsMap := make(map[string]string) 483 for _, repo := range storeRepositories { 484 reportsMap[repo.URL] = repo.ReportID 485 } 486 for _, repo := range repositories { 487 report, ok := reportsMap[repo.URL] 488 if ok { 489 repo.ReportID = report 490 } 491 } 492 return repositories, nil 493 }