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  }