• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-server / 1899590412

01 Jul 2025 09:26AM UTC coverage: 65.694% (-0.04%) from 65.731%
1899590412

push

gitlab-ci

bahaa-ghazal
refactor: Remove unused ant0ine/go-json-rest utilities from deployments

Signed-off-by: Bahaa Aldeen Ghazal <bahaa.ghazal@northern.tech>

32420 of 49350 relevant lines covered (65.69%)

1.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.83
/backend/services/deployments/api/http/api_deployments_releases.go
1
// Copyright 2024 Northern.tech AS
2
//
3
//        Licensed under the Apache License, Version 2.0 (the "License");
4
//        you may not use this file except in compliance with the License.
5
//        You may obtain a copy of the License at
6
//
7
//            http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//        Unless required by applicable law or agreed to in writing, software
10
//        distributed under the License is distributed on an "AS IS" BASIS,
11
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//        See the License for the specific language governing permissions and
13
//        limitations under the License.
14

15
package http
16

17
import (
18
        "encoding/json"
19
        "net/http"
20
        "strconv"
21

22
        "github.com/gin-gonic/gin"
23
        "github.com/pkg/errors"
24

25
        "github.com/mendersoftware/mender-server/pkg/requestid"
26
        "github.com/mendersoftware/mender-server/pkg/rest.utils"
27

28
        "github.com/mendersoftware/mender-server/services/deployments/app"
29
        "github.com/mendersoftware/mender-server/services/deployments/model"
30
)
31

32
type listReleasesVersion int64
33

34
const (
35
        listReleasesV1 listReleasesVersion = iota
36
        listReleasesV2
37
)
38

39
// Errors
40
var (
41
        ErrReleaseNameNotProvided        = errors.New("at least one release name has to be provided")
42
        ErrReleaseUsedInActiveDeployment = errors.New("release(s) used in active deployment")
43
)
44

45
func redactReleaseName(r *http.Request) {
3✔
46
        q := r.URL.Query()
3✔
47
        if q.Get(ParamName) != "" {
6✔
48
                q.Set(ParamName, Redacted)
3✔
49
                r.URL.RawQuery = q.Encode()
3✔
50
        }
3✔
51
}
52

53
func (d *DeploymentsApiHandlers) GetReleases(c *gin.Context) {
2✔
54

2✔
55
        defer redactReleaseName(c.Request)
2✔
56
        filter := getReleaseOrImageFilter(c.Request, listReleasesV1, false)
2✔
57
        releases, _, err := d.store.GetReleases(c.Request.Context(), filter)
2✔
58
        if err != nil {
3✔
59
                d.view.RenderInternalError(c, err)
1✔
60
                return
1✔
61
        }
1✔
62

63
        d.view.RenderSuccessGet(c, model.ConvertReleasesToV1(releases))
2✔
64
}
65

66
func (d *DeploymentsApiHandlers) listReleases(c *gin.Context,
67
        version listReleasesVersion) {
2✔
68

2✔
69
        defer redactReleaseName(c.Request)
2✔
70
        filter := getReleaseOrImageFilter(c.Request, version, true)
2✔
71
        releases, totalCount, err := d.store.GetReleases(c.Request.Context(), filter)
2✔
72
        if err != nil {
3✔
73
                d.view.RenderInternalError(c, err)
1✔
74
                return
1✔
75
        }
1✔
76

77
        hasNext := totalCount > int(filter.Page*filter.PerPage)
2✔
78

2✔
79
        hints := rest.NewPagingHints().
2✔
80
                SetPage(int64(filter.Page)).
2✔
81
                SetPerPage(int64(filter.PerPage)).
2✔
82
                SetHasNext(hasNext).
2✔
83
                SetTotalCount(int64(totalCount))
2✔
84

2✔
85
        links, err := rest.MakePagingHeaders(c.Request, hints)
2✔
86
        if err != nil {
2✔
87
                d.view.RenderInternalError(c, err)
×
88
                return
×
89
        }
×
90

91
        for _, l := range links {
4✔
92
                c.Writer.Header().Add("Link", l)
2✔
93
        }
2✔
94
        c.Writer.Header().Add(hdrTotalCount, strconv.Itoa(totalCount))
2✔
95

2✔
96
        if version == listReleasesV1 {
4✔
97
                d.view.RenderSuccessGet(c, model.ConvertReleasesToV1(releases))
2✔
98
        } else {
3✔
99
                d.view.RenderSuccessGet(c, releases)
1✔
100
        }
1✔
101
}
102

103
func (d *DeploymentsApiHandlers) ListReleases(c *gin.Context) {
2✔
104
        d.listReleases(c, listReleasesV1)
2✔
105
}
2✔
106

107
func (d *DeploymentsApiHandlers) ListReleasesV2(c *gin.Context) {
1✔
108
        d.listReleases(c, listReleasesV2)
1✔
109
}
1✔
110

111
func (d *DeploymentsApiHandlers) GetRelease(c *gin.Context) {
2✔
112
        ctx := c.Request.Context()
2✔
113

2✔
114
        releaseName := c.Param(ParamName)
2✔
115
        if releaseName == "" {
2✔
116
                err := errors.New("path parameter 'release_name' cannot be empty")
×
117
                d.view.RenderError(c, err, http.StatusNotFound)
×
118
                return
×
119
        }
×
120

121
        release, err := d.app.GetRelease(ctx, releaseName)
2✔
122
        if err != nil {
3✔
123
                status := http.StatusInternalServerError
1✔
124
                if errors.Is(err, app.ErrReleaseNotFound) {
2✔
125
                        status = http.StatusNotFound
1✔
126
                }
1✔
127
                d.view.RenderError(c, err, status)
1✔
128
                return
1✔
129
        }
130

131
        d.view.RenderSuccessGet(c, release)
2✔
132
}
133

134
func (d *DeploymentsApiHandlers) PatchRelease(c *gin.Context) {
2✔
135
        ctx := c.Request.Context()
2✔
136

2✔
137
        releaseName := c.Param(ParamName)
2✔
138
        if releaseName == "" {
2✔
139
                err := errors.New("path parameter 'release_name' cannot be empty")
×
140
                d.view.RenderError(c, err, http.StatusNotFound)
×
141
                return
×
142
        }
×
143

144
        var release model.ReleasePatch
2✔
145
        dec := json.NewDecoder(c.Request.Body)
2✔
146
        if err := dec.Decode(&release); err != nil {
2✔
147
                d.view.RenderError(c,
×
148
                        errors.WithMessage(err,
×
149
                                "malformed JSON in request body"),
×
150
                        http.StatusBadRequest)
×
151
                return
×
152
        }
×
153
        if err := release.Validate(); err != nil {
3✔
154
                d.view.RenderError(c,
1✔
155
                        errors.WithMessage(err,
1✔
156
                                "invalid request body"),
1✔
157
                        http.StatusBadRequest)
1✔
158
                return
1✔
159
        }
1✔
160

161
        err := d.app.UpdateRelease(ctx, releaseName, release)
2✔
162
        if err != nil {
3✔
163
                status := http.StatusInternalServerError
1✔
164
                if errors.Is(err, app.ErrReleaseNotFound) {
1✔
165
                        status = http.StatusNotFound
×
166
                } else if errors.Is(err, model.ErrTooManyUniqueTags) {
1✔
167
                        status = http.StatusConflict
×
168
                }
×
169
                d.view.RenderError(c, err, status)
1✔
170
                return
1✔
171
        }
172

173
        c.Status(http.StatusNoContent)
2✔
174
}
175

176
func (d *DeploymentsApiHandlers) PutReleaseTags(
177
        c *gin.Context,
178
) {
1✔
179

1✔
180
        ctx := c.Request.Context()
1✔
181

1✔
182
        releaseName := c.Param(ParamName)
1✔
183
        if releaseName == "" {
2✔
184
                err := errors.New("path parameter 'release_name' cannot be empty")
1✔
185
                d.view.RenderError(c, err, http.StatusNotFound)
1✔
186
                return
1✔
187
        }
1✔
188

189
        var tags model.Tags
1✔
190
        dec := json.NewDecoder(c.Request.Body)
1✔
191
        if err := dec.Decode(&tags); err != nil {
2✔
192
                d.view.RenderError(c,
1✔
193
                        errors.WithMessage(err,
1✔
194
                                "malformed JSON in request body"),
1✔
195
                        http.StatusBadRequest)
1✔
196
                return
1✔
197
        }
1✔
198
        if err := tags.Validate(); err != nil {
2✔
199
                d.view.RenderError(c,
1✔
200
                        errors.WithMessage(err,
1✔
201
                                "invalid request body"),
1✔
202
                        http.StatusBadRequest)
1✔
203
                return
1✔
204
        }
1✔
205

206
        err := d.app.ReplaceReleaseTags(ctx, releaseName, tags)
1✔
207
        if err != nil {
2✔
208
                status := http.StatusInternalServerError
1✔
209
                if errors.Is(err, app.ErrReleaseNotFound) {
2✔
210
                        status = http.StatusNotFound
1✔
211
                } else if errors.Is(err, model.ErrTooManyUniqueTags) {
3✔
212
                        status = http.StatusConflict
1✔
213
                }
1✔
214
                d.view.RenderError(c, err, status)
1✔
215
                return
1✔
216
        }
217

218
        c.Status(http.StatusNoContent)
1✔
219
}
220

221
func (d *DeploymentsApiHandlers) GetReleaseTagKeys(
222
        c *gin.Context,
223
) {
1✔
224
        ctx := c.Request.Context()
1✔
225

1✔
226
        tags, err := d.app.ListReleaseTags(ctx)
1✔
227
        if err != nil {
2✔
228
                d.view.RenderError(c, err, http.StatusInternalServerError)
1✔
229
                return
1✔
230
        }
1✔
231

232
        c.JSON(http.StatusOK, tags)
1✔
233
}
234

235
func (d *DeploymentsApiHandlers) GetReleasesUpdateTypes(
236
        c *gin.Context,
237
) {
2✔
238
        ctx := c.Request.Context()
2✔
239

2✔
240
        updateTypes, err := d.app.GetReleasesUpdateTypes(ctx)
2✔
241
        if err != nil {
3✔
242
                d.view.RenderError(c, err, http.StatusInternalServerError)
1✔
243
                return
1✔
244
        }
1✔
245

246
        c.JSON(http.StatusOK, updateTypes)
2✔
247
}
248

249
func (d *DeploymentsApiHandlers) DeleteReleases(
250
        c *gin.Context,
251
) {
1✔
252
        ctx := c.Request.Context()
1✔
253

1✔
254
        names := c.Request.URL.Query()[ParamName]
1✔
255

1✔
256
        if len(names) == 0 {
2✔
257
                d.view.RenderError(c,
1✔
258
                        ErrReleaseNameNotProvided,
1✔
259
                        http.StatusBadRequest)
1✔
260
                return
1✔
261
        }
1✔
262

263
        ids, err := d.app.DeleteReleases(ctx, names)
1✔
264
        if err != nil {
1✔
265
                d.view.RenderError(c, err, http.StatusInternalServerError)
×
266
                return
×
267
        }
×
268

269
        if len(ids) > 0 {
2✔
270
                deleteErr := model.ReleasesDeleteError{
1✔
271
                        Error:             ErrReleaseUsedInActiveDeployment.Error(),
1✔
272
                        RequestID:         requestid.GetReqId(c.Request),
1✔
273
                        ActiveDeployments: ids,
1✔
274
                }
1✔
275
                c.JSON(http.StatusConflict, deleteErr)
1✔
276
                return
1✔
277
        }
1✔
278

279
        c.Status(http.StatusNoContent)
1✔
280
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc