feat(redmine): partial UpdateVersion and GetVersion with fake endpoints
UpdateVersion issues PUT /versions/N.json sending only the fields the
caller set (untouched attributes never travel), and never parses the
empty 204 body Redmine answers with. GetVersion backs re-fetching one
milestone. The fake serves both endpoints with Redmine's semantics
(partial apply, 204 empty, 404 for unknown ids), and table tests pin
the exact request bodies, partiality, and error mapping.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@@ -215,6 +215,14 @@ func (s *Server) AddVersion(v Version) int {
|
||||
return v.ID
|
||||
}
|
||||
|
||||
// Version returns a copy of a stored version (for assertions).
|
||||
func (s *Server) Version(id int) (Version, bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
v, ok := s.versions[id]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (s *Server) AddCategory(name string) int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -274,8 +282,14 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
|
||||
respStatus, respBody = s.createRelation(from, body)
|
||||
case r.Method == http.MethodGet && strings.HasPrefix(path, "/projects/") && strings.HasSuffix(path, "/versions.json"):
|
||||
respStatus, respBody = s.listVersions()
|
||||
case r.Method == http.MethodPost && strings.HasPrefix(path, "/projects/") && strings.HasSuffix(path, "/versions.json"):
|
||||
case r.Method == http.MethodPost && strings.HasSuffix(path, "/versions.json") && strings.HasPrefix(path, "/projects/"):
|
||||
respStatus, respBody = s.createVersion(body)
|
||||
case r.Method == http.MethodGet && strings.HasPrefix(path, "/versions/") && strings.HasSuffix(path, ".json"):
|
||||
id, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(path, "/versions/"), ".json"))
|
||||
respStatus, respBody = s.getVersion(id)
|
||||
case r.Method == http.MethodPut && strings.HasPrefix(path, "/versions/") && strings.HasSuffix(path, ".json"):
|
||||
id, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(path, "/versions/"), ".json"))
|
||||
respStatus, respBody = s.updateVersion(id, body)
|
||||
case r.Method == http.MethodGet && strings.HasPrefix(path, "/projects/") && strings.HasSuffix(path, "/issue_categories.json"):
|
||||
respStatus, respBody = s.listCategories()
|
||||
case r.Method == http.MethodPost && strings.HasPrefix(path, "/projects/") && strings.HasSuffix(path, "/issue_categories.json"):
|
||||
@@ -501,6 +515,43 @@ func (s *Server) createVersion(body []byte) (int, string) {
|
||||
return http.StatusCreated, `{"version":` + mustJSON(v) + `}`
|
||||
}
|
||||
|
||||
// updateVersion applies a PARTIAL update (only provided fields move) and
|
||||
// answers 204 with an empty body, exactly like the real tracker.
|
||||
func (s *Server) updateVersion(id int, body []byte) (int, string) {
|
||||
v, ok := s.versions[id]
|
||||
if !ok {
|
||||
return http.StatusNotFound, `{"errors":["Version not found"]}`
|
||||
}
|
||||
var p struct {
|
||||
Version Version `json:"version"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &p); err != nil {
|
||||
return http.StatusBadRequest, `{"errors":["bad json"]}`
|
||||
}
|
||||
if p.Version.Name != "" {
|
||||
v.Name = p.Version.Name
|
||||
}
|
||||
if p.Version.DueDate != "" {
|
||||
v.DueDate = p.Version.DueDate
|
||||
}
|
||||
if p.Version.Status != "" {
|
||||
v.Status = p.Version.Status
|
||||
}
|
||||
if p.Version.Sharing != "" {
|
||||
v.Sharing = p.Version.Sharing
|
||||
}
|
||||
s.versions[id] = v
|
||||
return http.StatusNoContent, ""
|
||||
}
|
||||
|
||||
func (s *Server) getVersion(id int) (int, string) {
|
||||
v, ok := s.versions[id]
|
||||
if !ok {
|
||||
return http.StatusNotFound, `{"errors":["Version not found"]}`
|
||||
}
|
||||
return jsonReply(map[string]any{"version": v})
|
||||
}
|
||||
|
||||
func (s *Server) listCategories() (int, string) {
|
||||
var cs []Category
|
||||
for _, c := range s.categories {
|
||||
|
||||
Reference in New Issue
Block a user