diff --git a/AUTHORS b/AUTHORS index 70a75464b..2a42fb9a4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -63,3 +63,4 @@ List of contributors, in chronological order: * Ramón N.Rodriguez (https://github.com/runitonmetal) * Golf Hu (https://github.com/hudeng-go) * Cookie Fei (https://github.com/wuhuang26) +* Andrey Loukhnov (https://github.com/aol-nnov) diff --git a/api/repos.go b/api/repos.go index bc55dd9f0..25de579ba 100644 --- a/api/repos.go +++ b/api/repos.go @@ -69,25 +69,32 @@ func apiReposList(c *gin.Context) { c.JSON(200, result) } +type repoCreateParams struct { + // Name of repository to create + Name string `binding:"required" json:"Name" example:"repo1"` + // Text describing the repository (optional) + Comment string ` json:"Comment" example:"this is a repo"` + // Default distribution when publishing from this local repo + DefaultDistribution string ` json:"DefaultDistribution" example:"stable"` + // Default component when publishing from this local repo + DefaultComponent string ` json:"DefaultComponent" example:"main"` + // Snapshot name to create repoitory from (optional) + FromSnapshot string ` json:"FromSnapshot" example:"snapshot1"` +} + // @Summary Create repository // @Description Create a local repository. // @Tags Repos // @Produce json // @Consume json -// @Param Name query string false "Name of repository to be created." -// @Param Comment query string false "Text describing local repository, for the user" -// @Param DefaultDistribution query string false "Default distribution when publishing from this local repo" -// @Param DefaultComponent query string false "Default component when publishing from this local repo" +// @Param request body repoCreateParams true "Parameters" // @Success 201 {object} deb.LocalRepo -// @Failure 400 {object} Error "Repository already exists" +// @Failure 404 {object} Error "Source snapshot not found" +// @Failure 409 {object} Error "Local repo already exists" +// @Failure 500 {object} Error "Internal error" // @Router /api/repos [post] func apiReposCreate(c *gin.Context) { - var b struct { - Name string `binding:"required"` - Comment string - DefaultDistribution string - DefaultComponent string - } + var b repoCreateParams if c.Bind(&b) != nil { return @@ -98,14 +105,41 @@ func apiReposCreate(c *gin.Context) { repo.DefaultDistribution = b.DefaultDistribution collectionFactory := context.NewCollectionFactory() - collection := collectionFactory.LocalRepoCollection() - err := collection.Add(repo) + + if b.FromSnapshot != "" { + var snapshot *deb.Snapshot + + snapshotCollection := collectionFactory.SnapshotCollection() + + snapshot, err := snapshotCollection.ByName(b.FromSnapshot) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("source snapshot not found: %s", err)) + return + } + + err = snapshotCollection.LoadComplete(snapshot) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, fmt.Errorf("unable to load source snapshot: %s", err)) + return + } + + repo.UpdateRefList(snapshot.RefList()) + } + + localRepoCollection := collectionFactory.LocalRepoCollection() + + if _, err := localRepoCollection.ByName(b.Name); err == nil { + AbortWithJSONError(c, http.StatusConflict, fmt.Errorf("local repo with name %s already exists", b.Name)) + return + } + + err := localRepoCollection.Add(repo) if err != nil { - AbortWithJSONError(c, 400, err) + AbortWithJSONError(c, http.StatusInternalServerError, err) return } - c.JSON(201, repo) + c.JSON(http.StatusCreated, repo) } // PUT /api/repos/:name diff --git a/system/t12_api/repos.py b/system/t12_api/repos.py index 8cc8e4e56..424f9f49f 100644 --- a/system/t12_api/repos.py +++ b/system/t12_api/repos.py @@ -28,6 +28,51 @@ def check(self): self.check_equal(self.get("/api/repos/" + self.random_name()).status_code, 404) +class ReposAPITestCreateFromSnapshot(APITest): + """ + Create repo from snapshot + """ + def check(self): + initial_repo = self.random_name() + self.check_equal(self.post("/api/repos", json={"Name": initial_repo}).status_code, 201) + + d = self.random_name() + self.check_equal(self.upload("/api/files/" + d, + "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) + + task = self.post_task("/api/repos/" + initial_repo + "/file/" + d) + self.check_task(task) + + snapshot_name = self.random_name() + task = self.post_task("/api/repos/" + initial_repo + '/snapshots', json={'Name': snapshot_name}) + self.check_task(task) + self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200) + + repo_from_snapshot = self.random_name() + new_repo = {'Name': repo_from_snapshot, + 'FromSnapshot': snapshot_name} + + resp = self.post("/api/repos", json=new_repo) + self.check_equal(resp.status_code, 201) + + self.check_equal(self.get("/api/repos/" + repo_from_snapshot + "/packages").json(), + ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378']) + + +class ReposAPITestCreateFromWrongSnapshot(APITest): + """ + Create repo from snapshot + """ + def check(self): + snapshot_name = self.random_name() # non-existing snapshot + repo_from_snapshot = self.random_name() + new_repo = {'Name': repo_from_snapshot, + 'FromSnapshot': snapshot_name} + + resp = self.post("/api/repos", json=new_repo) + self.check_equal(resp.status_code, 404) + + class ReposAPITestCreateIndexDelete(APITest): """ GET /api/repos, POST /api/repos, DELETE /api/repos/:name