Add blueprint workspace diff

The list of changes between the committed blueprint and its workspace
are returned when a user requests the diff. Each change includes the
new(added) or the old(removed) package.
This commit is contained in:
Jacob Kozol 2019-09-24 19:44:21 +02:00 committed by Lars Karlitski
parent e14c48ff61
commit e24bfcf7d0
3 changed files with 88 additions and 5 deletions

View file

@ -462,13 +462,72 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
})
}
func (api *API) blueprintsDiffHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
var reply struct {
Diff []interface{} `json:"diff"`
func (api *API) blueprintsDiffHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
type pack struct {
Package blueprintPackage `json:"Package"`
}
reply.Diff = make([]interface{}, 0)
json.NewEncoder(writer).Encode(reply)
type diff struct {
New *pack `json:"new"`
Old *pack `json:"old"`
}
type reply struct {
Diffs []diff `json:"diff"`
}
name := params.ByName("blueprint")
if len(name) == 0 {
statusResponseError(writer, http.StatusNotFound, "no blueprint name given")
return
}
fromCommit := params.ByName("from")
if len(fromCommit) == 0 || fromCommit != "NEWEST" {
statusResponseError(writer, http.StatusNotFound, "invalid from commit ID given")
return
}
toCommit := params.ByName("to")
if len(toCommit) == 0 || toCommit != "WORKSPACE" {
statusResponseError(writer, http.StatusNotFound, "invalid to commit ID given")
return
}
// Fetch old and new blueprint details from store and return error if not found
var oldBlueprint, newBlueprint blueprint
if !api.store.getBlueprintCommitted(name, &oldBlueprint) || !api.store.getBlueprint(name, &newBlueprint, nil) {
statusResponseError(writer, http.StatusNotFound)
return
}
newSlice := newBlueprint.Packages
oldMap := make(map[string]blueprintPackage)
diffs := []diff{}
for _, oldPackage := range oldBlueprint.Packages {
oldMap[oldPackage.Name] = oldPackage
}
// For each package in new blueprint check if the old one contains it
for _, newPackage := range newSlice {
oldPackage, found := oldMap[newPackage.Name]
// If found remove from old packages map but otherwise create a diff with the added package
if found {
delete(oldMap, oldPackage.Name)
// Create a diff if the versions changed
if oldPackage.Version != newPackage.Version {
diffs = append(diffs, diff{Old: &pack{oldPackage}, New: &pack{newPackage}})
}
} else {
diffs = append(diffs, diff{Old: nil, New: &pack{newPackage}})
}
}
// All packages remaining in the old packages map have been removed in the new blueprint so create a diff
for _, oldPackage := range oldMap {
diffs = append(diffs, diff{Old: &pack{oldPackage}, New: nil})
}
json.NewEncoder(writer).Encode(reply{diffs})
}
func (api *API) blueprintsNewHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {

View file

@ -135,6 +135,9 @@ func TestBlueprints(t *testing.T) {
testRoute(t, api, "GET", "/api/v0/blueprints/info/test", ``,
http.StatusOK, `{"blueprints":[{"name":"test","description":"Test","modules":[],"packages":[{"name":"systemd","version":"123"}],"version":"0"}],
"changes":[{"name":"test","changed":true}], "errors":[]}`)
testRoute(t, api, "GET", "/api/v0/blueprints/diff/test/NEWEST/WORKSPACE", ``,
http.StatusOK, `{"diff":[{"new":{"Package":{"name":"systemd","version":"123"}},"old":null},{"new":null,"old":{"Package":{"name":"httpd","version":"2.4.*"}}}]}`)
}
func TestCompose(t *testing.T) {

View file

@ -109,6 +109,27 @@ func (s *store) getBlueprint(name string, bp *blueprint, changed *bool) bool {
return true
}
func (s *store) getBlueprintCommitted(name string, bp *blueprint) bool {
s.mu.RLock()
defer s.mu.RUnlock()
var ok bool
*bp, ok = s.Blueprints[name]
if !ok {
return false
}
// cockpit-composer cannot deal with missing "packages" or "modules"
if bp.Packages == nil {
bp.Packages = []blueprintPackage{}
}
if bp.Modules == nil {
bp.Modules = []blueprintPackage{}
}
return true
}
func (s *store) pushBlueprint(bp blueprint) {
s.change(func() {
delete(s.Workspace, bp.Name)