From 0d96e4b21c680a228ee66ab05af6a5220a4ad91b Mon Sep 17 00:00:00 2001 From: Christoph Fiehe Date: Wed, 2 Oct 2024 12:04:47 +0200 Subject: [PATCH] Allow to add/switch components of a published local repository This commit modifies the behavior of the publish switch method in the way, that it can also be used to add/switch components of a published local repository. Furthermore, the commit ensures that the sources returned by a published repository are ordered by their component names. Signed-off-by: Christoph Fiehe --- api/publish.go | 131 +++++++++++-- api/router.go | 1 + cmd/publish_show.go | 3 +- cmd/publish_switch.go | 73 +++---- deb/publish.go | 25 ++- man/aptly.1 | 8 +- system/t06_publish/PublishSwitch13Test_gold | 8 +- system/t06_publish/PublishSwitch14Test_gold | 1 + ...Test_binary => PublishSwitch15Test_binary} | 0 system/t06_publish/PublishSwitch15Test_gold | 1 - ...st_release => PublishSwitch15Test_release} | 0 system/t06_publish/PublishSwitch16Test_gold | 8 + system/t06_publish/switch.py | 34 +++- system/t12_api/publish.py | 178 +++++++++++++++++- 14 files changed, 391 insertions(+), 80 deletions(-) rename system/t06_publish/{PublishSwitch14Test_binary => PublishSwitch15Test_binary} (100%) rename system/t06_publish/{PublishSwitch14Test_release => PublishSwitch15Test_release} (100%) create mode 100644 system/t06_publish/PublishSwitch16Test_gold diff --git a/api/publish.go b/api/publish.go index e3de9b4c7..9cd55059b 100644 --- a/api/publish.go +++ b/api/publish.go @@ -52,10 +52,10 @@ func parseEscapedPath(path string) string { return result } -// @Summary Get publish points -// @Description Get list of available publish points. Each publish point is returned as in “show” API. +// @Summary Get published repositories +// @Description Get a list of published repositories. Each published repository is returned as in "show" API. // @Tags Publish -// @Produce json +// @Produce json // @Success 200 {array} deb.PublishedRepo // @Router /api/publish [get] func apiPublishList(c *gin.Context) { @@ -83,7 +83,50 @@ func apiPublishList(c *gin.Context) { c.JSON(200, result) } -// POST /publish/:prefix +// @Summary Show published repository +// @Description Get published repository by name. +// @Tags Publish +// @Consume json +// @Produce json +// @Param prefix path string true "publishing prefix, use ':.' instead of '.' because it is ambigious in URLs" +// @Param distribution path string true "distribution name" +// @Success 200 {object} deb.RemoteRepo +// @Failure 404 {object} Error "Published repository not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [get] +func apiPublishShow(c *gin.Context) { + param := parseEscapedPath(c.Params.ByName("prefix")) + storage, prefix := deb.ParsePrefix(param) + distribution := parseEscapedPath(c.Params.ByName("distribution")) + + collectionFactory := context.NewCollectionFactory() + collection := collectionFactory.PublishedRepoCollection() + + published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) + if err != nil { + AbortWithJSONError(c, 404, fmt.Errorf("unable to show: %s", err)) + return + } + err = collection.LoadComplete(published, collectionFactory) + if err != nil { + AbortWithJSONError(c, 500, fmt.Errorf("unable to show: %s", err)) + return + } + + c.JSON(200, published) +} + +// @Summary Create published repository +// @Description Create a published repository with specified parameters. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Success 200 {object} deb.RemoteRepo +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Source not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix} [post] func apiPublishRepoOrSnapshot(c *gin.Context) { param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) @@ -245,11 +288,22 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { }) } -// PUT /publish/:prefix/:distribution +// @Summary Update published repository +// @Description Update a published repository. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Param distribution path string true "distribution name" +// @Success 200 {object} deb.RemoteRepo +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Published repository or source not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [put] func apiPublishUpdateSwitch(c *gin.Context) { param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) - distribution := c.Params.ByName("distribution") + distribution := parseEscapedPath(c.Params.ByName("distribution")) var b struct { ForceOverwrite bool @@ -261,6 +315,10 @@ func apiPublishUpdateSwitch(c *gin.Context) { Component string `binding:"required"` Name string `binding:"required"` } + Sources []struct { + Component string `binding:"required"` + Name string `binding:"required"` + } AcquireByHash *bool MultiDist bool } @@ -290,7 +348,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { } var updatedComponents []string - var updatedSnapshots []string + var updatedSources []string var resources []string if published.SourceKind == deb.SourceLocalRepo { @@ -298,14 +356,36 @@ func apiPublishUpdateSwitch(c *gin.Context) { AbortWithJSONError(c, 400, fmt.Errorf("snapshots shouldn't be given when updating local repo")) return } - updatedComponents = published.Components() - for _, component := range updatedComponents { - published.UpdateLocalRepo(component) + + localRepoCollection := collectionFactory.LocalRepoCollection() + if len(b.Sources) > 0 { + for _, source := range b.Sources { + localRepo, err2 := localRepoCollection.ByName(source.Name) + if err2 != nil { + AbortWithJSONError(c, 404, err2) + return + } + + err2 = localRepoCollection.LoadComplete(localRepo) + if err2 != nil { + AbortWithJSONError(c, 500, err2) + return + } + + published.SwitchLocalRepo(source.Component, localRepo) + updatedComponents = append(updatedComponents, source.Component) + updatedSources = append(updatedSources, localRepo.Name) + } + } else { + updatedComponents = published.Components() + for _, component := range updatedComponents { + published.UpdateLocalRepo(component) + } } } else if published.SourceKind == "snapshot" { - for _, snapshotInfo := range b.Snapshots { - snapshotCollection := collectionFactory.SnapshotCollection() - snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name) + snapshotCollection := collectionFactory.SnapshotCollection() + for _, source := range b.Snapshots { + snapshot, err2 := snapshotCollection.ByName(source.Name) if err2 != nil { AbortWithJSONError(c, 404, err2) return @@ -317,9 +397,9 @@ func apiPublishUpdateSwitch(c *gin.Context) { return } - published.UpdateSnapshot(snapshotInfo.Component, snapshot) - updatedComponents = append(updatedComponents, snapshotInfo.Component) - updatedSnapshots = append(updatedSnapshots, snapshot.Name) + published.SwitchSnapshot(source.Component, snapshot) + updatedComponents = append(updatedComponents, source.Component) + updatedSources = append(updatedSources, snapshot.Name) } } else { AbortWithJSONError(c, 500, fmt.Errorf("unknown published repository type")) @@ -339,7 +419,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { } resources = append(resources, string(published.Key())) - taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", ")) + taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSources, ", ")) maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite, b.MultiDist) if err != nil { @@ -363,14 +443,27 @@ func apiPublishUpdateSwitch(c *gin.Context) { }) } -// DELETE /publish/:prefix/:distribution +// @Summary Delete published repository +// @Description Delete a published repository. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Param distribution path string true "distribution name" +// @Param force query int true "force: 1 to enable" +// @Param skipCleanup query int true "skipCleanup: 1 to enable" +// @Success 200 {object} task.ProcessReturnValue +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Published repository not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [delete] func apiPublishDrop(c *gin.Context) { force := c.Request.URL.Query().Get("force") == "1" skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1" param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) - distribution := c.Params.ByName("distribution") + distribution := parseEscapedPath(c.Params.ByName("distribution")) collectionFactory := context.NewCollectionFactory() collection := collectionFactory.PublishedRepoCollection() diff --git a/api/router.go b/api/router.go index 148b0f4af..932fbf84e 100644 --- a/api/router.go +++ b/api/router.go @@ -185,6 +185,7 @@ func Router(c *ctx.AptlyContext) http.Handler { { api.GET("/publish", apiPublishList) + api.GET("/publish/:prefix/:distribution", apiPublishShow) api.POST("/publish", apiPublishRepoOrSnapshot) api.POST("/publish/:prefix", apiPublishRepoOrSnapshot) api.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) diff --git a/cmd/publish_show.go b/cmd/publish_show.go index d943df3fa..a0af446b1 100644 --- a/cmd/publish_show.go +++ b/cmd/publish_show.go @@ -52,7 +52,8 @@ func aptlyPublishShowTxt(_ *commander.Command, args []string) error { fmt.Printf("Architectures: %s\n", strings.Join(repo.Architectures, " ")) fmt.Printf("Sources:\n") - for component, sourceID := range repo.Sources { + for _, component := range repo.Components() { + sourceID := repo.Sources[component] var name string if repo.SourceKind == deb.SourceSnapshot { source, e := collectionFactory.SnapshotCollection().ByUUID(sourceID) diff --git a/cmd/publish_switch.go b/cmd/publish_switch.go index a55347475..f66b03880 100644 --- a/cmd/publish_switch.go +++ b/cmd/publish_switch.go @@ -10,12 +10,15 @@ import ( ) func aptlyPublishSwitch(cmd *commander.Command, args []string) error { - var err error + var ( + err error + names []string + ) components := strings.Split(context.Flags().Lookup("component").Value.String(), ",") multiDist := context.Flags().Lookup("multi-dist").Value.Get().(bool) - if len(args) < len(components)+1 || len(args) > len(components)+2 { + if len(args) < len(components) + 1 || len(args) > len(components) + 2 { cmd.Usage() return commander.ErrCommandError } @@ -23,12 +26,7 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { distribution := args[0] param := "." - var ( - names []string - snapshot *deb.Snapshot - ) - - if len(args) == len(components)+2 { + if len(args) == len(components) + 2 { param = args[1] names = args[2:] } else { @@ -45,36 +43,47 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to update: %s", err) } - if published.SourceKind != deb.SourceSnapshot { - return fmt.Errorf("unable to update: not a snapshot publish") - } - err = collectionFactory.PublishedRepoCollection().LoadComplete(published, collectionFactory) if err != nil { return fmt.Errorf("unable to update: %s", err) } - publishedComponents := published.Components() - if len(components) == 1 && len(publishedComponents) == 1 && components[0] == "" { - components = publishedComponents - } - if len(names) != len(components) { - return fmt.Errorf("mismatch in number of components (%d) and snapshots (%d)", len(components), len(names)) + return fmt.Errorf("mismatch in number of components (%d) and sources (%d)", len(components), len(names)) } - for i, component := range components { - snapshot, err = collectionFactory.SnapshotCollection().ByName(names[i]) - if err != nil { - return fmt.Errorf("unable to switch: %s", err) - } + if published.SourceKind == deb.SourceLocalRepo { + localRepoCollection := collectionFactory.LocalRepoCollection() + for i, component := range components { + localRepo, err := localRepoCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } - err = collectionFactory.SnapshotCollection().LoadComplete(snapshot) - if err != nil { - return fmt.Errorf("unable to switch: %s", err) - } + err = localRepoCollection.LoadComplete(localRepo) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } - published.UpdateSnapshot(component, snapshot) + published.SwitchLocalRepo(component, localRepo) + } + } else if published.SourceKind == "snapshot" { + snapshotCollection := collectionFactory.SnapshotCollection() + for i, component := range components { + snapshot, err := snapshotCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } + + err = snapshotCollection.LoadComplete(snapshot) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } + + published.SwitchSnapshot(component, snapshot) + } + } else { + return fmt.Errorf("unknown published repository type") } signer, err := getSigner(context.Flags()) @@ -115,7 +124,7 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { } } - context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String()) + context.Progress().Printf("\nPublish %s has been successfully switched to new source.\n", published.String()) return err } @@ -123,10 +132,10 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { func makeCmdPublishSwitch() *commander.Command { cmd := &commander.Command{ Run: aptlyPublishSwitch, - UsageLine: "switch [[:]] ", - Short: "update published repository by switching to new snapshot", + UsageLine: "switch [[:]] ", + Short: "update published repository by switching to new source", Long: ` -Command switches in-place published snapshots with new snapshot contents. All +Command switches in-place published snapshots with new source contents. All publishing parameters are preserved (architecture list, distribution, component). diff --git a/deb/publish.go b/deb/publish.go index 2bdd608de..07a2e5fe6 100644 --- a/deb/publish.go +++ b/deb/publish.go @@ -284,7 +284,8 @@ func (p *PublishedRepo) MarshalJSON() ([]byte, error) { } sources := []sourceInfo{} - for component, item := range p.sourceItems { + for _, component := range p.Components() { + item := p.sourceItems[component] name := "" if item.snapshot != nil { name = item.snapshot.Name @@ -452,8 +453,26 @@ func (p *PublishedRepo) UpdateLocalRepo(component string) { p.rePublishing = true } -// UpdateSnapshot switches snapshot for component -func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) { +// SwitchLocalRepo switches local repo for component +func (p *PublishedRepo) SwitchLocalRepo(component string, localRepo *LocalRepo) { + if p.SourceKind != SourceLocalRepo { + panic("not local repo publish") + } + + item, exists := p.sourceItems[component] + if !exists { + item = repoSourceItem{} + } + item.localRepo = localRepo + item.packageRefs = localRepo.RefList() + p.sourceItems[component] = item + + p.Sources[component] = localRepo.UUID + p.rePublishing = true +} + +// SwitchSnapshot switches snapshot for component +func (p *PublishedRepo) SwitchSnapshot(component string, snapshot *Snapshot) { if p.SourceKind != SourceSnapshot { panic("not snapshot publish") } diff --git a/man/aptly.1 b/man/aptly.1 index fe986f0ff..4ab370468 100644 --- a/man/aptly.1 +++ b/man/aptly.1 @@ -1616,14 +1616,14 @@ suite to publish (defaults to distribution) \-\fBcodename\fR= codename to publish (defaults to distribution) . -.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SNAPSHOT" -\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [[\fIendpoint\fR:]\fIprefix\fR] \fInew\-snapshot\fR +.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SOURCE" +\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [[\fIendpoint\fR:]\fIprefix\fR] \fInew\-source\fR . .P -Command switches in\-place published snapshots with new snapshot contents\. All publishing parameters are preserved (architecture list, distribution, component)\. +Command switches in\-place published sources with new source contents\. All publishing parameters are preserved (architecture list, distribution, component)\. . .P -For multiple component repositories, flag \-component should be given with list of components to update\. Corresponding snapshots should be given in the same order, e\.g\.: +For multiple component repositories, flag \-component should be given with list of components to update\. Corresponding sources should be given in the same order, e\.g\.: . .IP "" 4 . diff --git a/system/t06_publish/PublishSwitch13Test_gold b/system/t06_publish/PublishSwitch13Test_gold index 3f440f06d..150c54a71 100644 --- a/system/t06_publish/PublishSwitch13Test_gold +++ b/system/t06_publish/PublishSwitch13Test_gold @@ -1,8 +1,6 @@ -Loading packages... -Generating metadata files and linking package files... Finalizing metadata files... Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: -Cleaning up prefix "." components main... - -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Cleaning up prefix "." components a, c... + +Publish ./maverick [i386] publishes {a: [local-repo2]}, {b: [local-repo2]}, {c: [local-repo3]} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch14Test_gold b/system/t06_publish/PublishSwitch14Test_gold index 9b8ce8f1c..3f440f06d 100644 --- a/system/t06_publish/PublishSwitch14Test_gold +++ b/system/t06_publish/PublishSwitch14Test_gold @@ -3,5 +3,6 @@ Generating metadata files and linking package files... Finalizing metadata files... Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. diff --git a/system/t06_publish/PublishSwitch14Test_binary b/system/t06_publish/PublishSwitch15Test_binary similarity index 100% rename from system/t06_publish/PublishSwitch14Test_binary rename to system/t06_publish/PublishSwitch15Test_binary diff --git a/system/t06_publish/PublishSwitch15Test_gold b/system/t06_publish/PublishSwitch15Test_gold index 3f440f06d..9b8ce8f1c 100644 --- a/system/t06_publish/PublishSwitch15Test_gold +++ b/system/t06_publish/PublishSwitch15Test_gold @@ -3,6 +3,5 @@ Generating metadata files and linking package files... Finalizing metadata files... Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: -Cleaning up prefix "." components main... Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. diff --git a/system/t06_publish/PublishSwitch14Test_release b/system/t06_publish/PublishSwitch15Test_release similarity index 100% rename from system/t06_publish/PublishSwitch14Test_release rename to system/t06_publish/PublishSwitch15Test_release diff --git a/system/t06_publish/PublishSwitch16Test_gold b/system/t06_publish/PublishSwitch16Test_gold new file mode 100644 index 000000000..3f440f06d --- /dev/null +++ b/system/t06_publish/PublishSwitch16Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... + +Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. diff --git a/system/t06_publish/switch.py b/system/t06_publish/switch.py index 933e08c15..607692507 100644 --- a/system/t06_publish/switch.py +++ b/system/t06_publish/switch.py @@ -424,7 +424,7 @@ def check(self): class PublishSwitch12Test(BaseTest): """ - publish switch: add new component to publish + publish switch: add new component to snapshot publish """ fixtureCmds = [ "aptly snapshot create snap1 empty", @@ -439,10 +439,32 @@ def check(self): super(PublishSwitch12Test, self).check() self.check_exists('public/dists/maverick/a/binary-i386/Packages') + self.check_not_exists('public/dists/maverick/b/binary-i386/Packages') self.check_exists('public/dists/maverick/c/binary-i386/Packages') class PublishSwitch13Test(BaseTest): + """ + publish switch: add new component to local repo publish + """ + fixtureCmds = [ + "aptly repo create local-repo1", + "aptly repo create local-repo2", + "aptly repo create local-repo3", + "aptly publish repo -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b local-repo1 local-repo2", + ] + runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=a,c maverick local-repo2 local-repo3" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishSwitch13Test, self).check() + + self.check_exists('public/dists/maverick/a/binary-i386/Packages') + self.check_not_exists('public/dists/maverick/b/binary-i386/Packages') + self.check_exists('public/dists/maverick/c/binary-i386/Packages') + + +class PublishSwitch14Test(BaseTest): """ publish switch: -skip-contents """ @@ -458,7 +480,7 @@ class PublishSwitch13Test(BaseTest): gold_processor = BaseTest.expand_environ def check(self): - super(PublishSwitch13Test, self).check() + super(PublishSwitch14Test, self).check() self.check_exists('public/dists/maverick/Release') @@ -468,7 +490,7 @@ def check(self): self.check_not_exists('public/dists/maverick/main/Contents-amd64.gz') -class PublishSwitch14Test(BaseTest): +class PublishSwitch15Test(BaseTest): """ publish switch: removed some packages skipping cleanup """ @@ -484,7 +506,7 @@ class PublishSwitch14Test(BaseTest): gold_processor = BaseTest.expand_environ def check(self): - super(PublishSwitch14Test, self).check() + super(PublishSwitch15Test, self).check() self.check_exists('public/dists/maverick/InRelease') self.check_exists('public/dists/maverick/Release') @@ -554,7 +576,7 @@ def check(self): raise Exception("path seen wrong: %r" % (pathsSeen, )) -class PublishSwitch15Test(BaseTest): +class PublishSwitch16Test(BaseTest): """ publish switch: -skip-bz2 """ @@ -570,7 +592,7 @@ class PublishSwitch15Test(BaseTest): gold_processor = BaseTest.expand_environ def check(self): - super(PublishSwitch15Test, self).check() + super(PublishSwitch16Test, self).check() self.check_exists('public/dists/maverick/Release') diff --git a/system/t12_api/publish.py b/system/t12_api/publish.py index 4ecffbc1c..d90903e90 100644 --- a/system/t12_api/publish.py +++ b/system/t12_api/publish.py @@ -493,9 +493,9 @@ class PublishSwitchAPITestRepo(APITest): fixtureGpg = True def check(self): - repo_name = self.random_name() + repo1_name = self.random_name() self.check_equal(self.post( - "/api/repos", json={"Name": repo_name, "DefaultDistribution": "wheezy"}).status_code, 201) + "/api/repos", json={"Name": repo1_name, "DefaultDistribution": "wheezy"}).status_code, 201) d = self.random_name() self.check_equal( @@ -503,11 +503,11 @@ def check(self): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + task = self.post_task("/api/repos/" + repo1_name + "/file/" + d) self.check_task(task) snapshot1_name = self.random_name() - task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot1_name}) + task = self.post_task("/api/repos/" + repo1_name + '/snapshots', json={'Name': snapshot1_name}) self.check_task(task) prefix = self.random_name() @@ -549,21 +549,21 @@ def check(self): 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/" + repo_name + "/file/" + d) + task = self.post_task("/api/repos/" + repo1_name + "/file/" + d) self.check_task(task) - task = self.delete_task("/api/repos/" + repo_name + "/packages/", + task = self.delete_task("/api/repos/" + repo1_name + "/packages/", json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) self.check_task(task) snapshot2_name = self.random_name() - task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot2_name}) + task = self.post_task("/api/repos/" + repo1_name + '/snapshots', json={'Name': snapshot2_name}) self.check_task(task) task = self.put_task( "/api/publish/" + prefix + "/wheezy", json={ - "Snapshots": [{"Component": "main", "Name": snapshot2_name}], + "Sources": [{"Component": "main", "Name": snapshot2_name}], "Signing": DefaultSigningOptions, "SkipContents": True, }) @@ -598,6 +598,79 @@ def check(self): self.check_task(task) self.check_not_exists("public/" + prefix + "dists/") + repo2_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo2_name, "DefaultDistribution": "wheezy"}).status_code, 201) + + prefix = self.random_name() + task = self.post_task( + "/api/publish/" + prefix, + json={ + "Architectures": ["i386", "source"], + "SourceKind": "local", + "Sources": [{"Component": "A", "Name": repo1_name}], + "Signing": DefaultSigningOptions, + }) + self.check_task(task) + + task = self.put_task( + "/api/publish/" + prefix + "/wheezy", + json={ + "Sources": [{"Component": "A", "Name": repo2_name}], + "Signing": DefaultSigningOptions, + "SkipContents": True, + }) + self.check_task(task) + repo_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'wheezy', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'wheezy', + 'Prefix': prefix, + 'SkipContents': True, + 'SourceKind': 'local', + 'Sources': [{'Component': 'A', 'Name': repo2_name}], + 'Storage': '', + 'Suite': ''} + + all_repos = self.get("/api/publish") + self.check_equal(all_repos.status_code, 200) + self.check_in(repo_expected, all_repos.json()) + + task = self.put_task( + "/api/publish/" + prefix + "/wheezy", + json={ + "Sources": [{"Component": "B", "Name": repo1_name}], + "Signing": DefaultSigningOptions, + "SkipContents": True, + }) + self.check_task(task) + repo_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'wheezy', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'wheezy', + 'Prefix': prefix, + 'SkipContents': True, + 'SourceKind': 'local', + 'Sources': [{'Component': 'A', 'Name': repo2_name}, {'Component': 'B', 'Name': repo1_name}], + 'Storage': '', + 'Suite': ''} + + all_repos = self.get("/api/publish") + self.check_equal(all_repos.status_code, 200) + self.check_in(repo_expected, all_repos.json()) + class PublishSwitchAPISkipCleanupTestRepo(APITest): """ @@ -744,7 +817,7 @@ def check(self): class ServePublishedListTestRepo(APITest): """ - GET /repos + POST /api/mirrors, GET /api/mirrors/:name/packages """ def check(self): @@ -787,6 +860,93 @@ def check(self): raise Exception(f"Expected content {excepted_content} was not: {get.content}") +class ServePublishedShowTestRepo(APITest): + """ + GET /publish/:prefix/:distribution + """ + + def check(self): + repo1_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo1_name, "DefaultDistribution": "wheezy"}).status_code, 201) + + repo2_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo2_name, "DefaultDistribution": "jessie"}).status_code, 201) + + d = self.random_name() + self.check_equal( + self.upload("/api/files/" + d, + "pyspi_0.6.1-1.3.dsc", + "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", + "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) + task = self.post_task("/api/repos/" + repo1_name + "/file/" + d) + self.check_task(task) + + prefix = self.random_name() + task = self.post_task( + "/api/publish/" + prefix, + json={ + "Architectures": ["i386", "source"], + "SourceKind": "local", + "Sources": [{"Name": repo1_name}], + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + + task = self.post_task( + "/api/publish/" + prefix, + json={ + "Architectures": ["i386", "source"], + "SourceKind": "local", + "Sources": [{"Name": repo2_name}], + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + + repo1_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'wheezy', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'wheezy', + 'Prefix': prefix, + 'SkipContents': False, + 'SourceKind': 'local', + 'Sources': [{'Component': 'main', 'Name': repo1_name}], + 'Storage': '', + 'Suite': ''} + repo1 = self.get("/api/publish/" + prefix + "/wheezy") + self.check_equal(repo1.status_code, 200) + self.check_equal(repo1_expected, repo1.json()) + + repo2_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'jessie', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'jessie', + 'Prefix': prefix, + 'SkipContents': False, + 'SourceKind': 'local', + 'Sources': [{'Component': 'main', 'Name': repo2_name}], + 'Storage': '', + 'Suite': ''} + repo2 = self.get("/api/publish/" + prefix + "/jessie") + self.check_equal(repo2.status_code, 200) + self.check_equal(repo2_expected, repo2.json()) + + class ServePublishedTestRepo(APITest): """ GET /repos/:storage/*pkgPath