Skip to content

Commit

Permalink
Merge pull request #1375 from aol-nnov/api-create-repo-from-snapshot
Browse files Browse the repository at this point in the history
Update create repo API to support snapshots
  • Loading branch information
neolynx authored Oct 22, 2024
2 parents ae0fa20 + 0666f87 commit 037da55
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 15 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -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)
64 changes: 49 additions & 15 deletions api/repos.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
45 changes: 45 additions & 0 deletions system/t12_api/repos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 037da55

Please sign in to comment.