Skip to content

Commit

Permalink
Added indented JSON if desktop, mobile, tablet, or curl (#158)
Browse files Browse the repository at this point in the history
* Added indented JSON if desktop, mobile, tablet, or curl

* go mod tidy

* Updated CHANGELOG.md
  • Loading branch information
applejag authored Mar 4, 2022
1 parent 7353fa2 commit 2cd15f6
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 37 deletions.
15 changes: 10 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ This project tries to follow [SemVer 2.0.0](https://semver.org/).
much quicker as it can skip applying migrations that are already
applied. (#144)

- Added automatic JSON indentation in HTTP responses based on the user agent, if
they are a desktop, mobile, or tablet device, or specifically cURL. Can be
disabled by the new query parameter `?pretty=false`. (#158)

- Changed query parameter `?status` and `?statusId` in `GET /api/build` to
support multiple values, where it will respond with builds matching any of the
supplied statuses. (#150)
Expand All @@ -59,19 +63,20 @@ This project tries to follow [SemVer 2.0.0](https://semver.org/).
the Sqlite database driver. The HTTP response model still uses the field name
`"token"`. (#144)

- Added numerous dependencies:
- Added dependencies:

- `github.com/alta/protopatch` v0.5.0 (#147)
- `github.com/go-gormigrate/gormigrate/v2` v2.0.0. (#144)
- `github.com/go-gormigrate/gormigrate/v2` v2.0.0 (#144)
- `github.com/mileusna/useragent` v1.0.2 (#158)
- `github.com/soheilhy/cmux` v0.1.5 (#147)
- `google.golang.org/grpc` v1.44.0 (#147)
- `google.golang.org/protobuf` v1.27.1 (#147)

- Changed version of numerous dependencies:

- `github.com/gin-gonic/gin` from v1.7.4 to v1.7.7. (#151)
- `github.com/swaggo/gin-swagger` from v1.3.1 to v1.4.1. (#151)
- `github.com/swaggo/swag` from v1.7.1 to v1.8.0. (#151)
- `github.com/gin-gonic/gin` from v1.7.4 to v1.7.7 (#151)
- `github.com/swaggo/gin-swagger` from v1.3.1 to v1.4.1 (#151)
- `github.com/swaggo/swag` from v1.7.1 to v1.8.0 (#151)
- `gorm.io/driver/postgres` from v1.1.1 to v1.2.3 (#144)
- `gorm.io/driver/sqlite` from v1.1.5 to v1.2.6 (#144)
- `gorm.io/gorm` from v1.21.15 to v1.22.5 (#144)
Expand Down
10 changes: 8 additions & 2 deletions artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var defaultGetArtifactsOrderBy = orderby.Column{Name: database.ArtifactColumns.A
// @description while the matching filters are meant for searches by humans where it tries to find soft matches and is therefore inaccurate by nature.
// @description Added in v5.0.0.
// @tags artifact
// @produce json
// @param buildId path uint true "Build ID" minimum(0)
// @param limit query int false "Number of results to return. No limiting is applied if empty (`?limit=`) or non-positive (`?limit=0`). Required if `offset` is used." default(100)
// @param offset query int false "Skipped results, where 0 means from the start." minimum(0) default(0)
Expand All @@ -56,6 +57,7 @@ var defaultGetArtifactsOrderBy = orderby.Column{Name: database.ArtifactColumns.A
// @param nameMatch query string false "Filter by matching artifact name. Cannot be used with `name`."
// @param fileNameMatch query string false "Filter by matching artifact file name. Cannot be used with `fileName`."
// @param match query string false "Filter by matching on any supported fields."
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.PaginatedArtifacts
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -120,7 +122,7 @@ func (m artifactModule) getBuildArtifactListHandler(c *gin.Context) {
return
}

c.JSON(http.StatusOK, response.PaginatedArtifacts{
renderJSON(c, http.StatusOK, response.PaginatedArtifacts{
List: modelconv.DBArtifactsToResponses(dbArtifacts),
TotalCount: totalCount,
})
Expand All @@ -131,6 +133,7 @@ func (m artifactModule) getBuildArtifactListHandler(c *gin.Context) {
// @summary Get build artifact
// @description Added in v0.7.1.
// @tags artifact
// @produce multipart/form-data
// @param buildId path uint true "Build ID" minimum(0)
// @param artifactId path uint true "Artifact ID" minimum(0)
// @success 200 {file} string "OK"
Expand Down Expand Up @@ -193,6 +196,7 @@ func (m artifactModule) getBuildArtifactHandler(c *gin.Context) {
// @failure 502 {object} problem.Response "Database is unreachable"
// @router /build/{buildId}/artifact [post]
func (m artifactModule) createBuildArtifactHandler(c *gin.Context) {
log.Debug().Message("Start of createBuildArtifactHandler")
buildID, ok := ginutil.ParseParamUint(c, "buildId")
if !ok {
return
Expand Down Expand Up @@ -221,7 +225,9 @@ func (m artifactModule) createBuildArtifactHandler(c *gin.Context) {
// @description Deprecated, /build/{buildid}/test-result/list-summary should be used instead.
// @description Added in v0.7.0.
// @tags artifact
// @produce json
// @param buildId path uint true "Build ID" minimum(0)
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.TestsResults
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -264,7 +270,7 @@ func (m artifactModule) getBuildTestResultListHandler(c *gin.Context) {
resResults.Status = response.TestStatusFailed
}

c.JSON(http.StatusOK, resResults)
renderJSON(c, http.StatusOK, resResults)
}

func createArtifacts(c *gin.Context, db *gorm.DB, files []ctxparser.File, buildID uint) ([]database.Artifact, bool) {
Expand Down
10 changes: 7 additions & 3 deletions branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ func (m branchModule) Register(g *gin.RouterGroup) {
// @summary Get list of branches.
// @description Added in v5.0.0.
// @tags branch
// @produce json
// @param projectId path uint true "project ID" minimum(0)
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.PaginatedBranches "Branches"
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand All @@ -58,7 +60,7 @@ func (m branchModule) getProjectBranchListHandler(c *gin.Context) {
return
}
dbDefaultBranch := findDefaultDBBranch(dbBranches)
c.JSON(http.StatusOK, modelconv.DBBranchListToPaginatedResponse(dbBranches, int64(len(dbBranches)), dbDefaultBranch))
renderJSON(c, http.StatusOK, modelconv.DBBranchListToPaginatedResponse(dbBranches, int64(len(dbBranches)), dbDefaultBranch))
}

// createProjectBranchHandler godoc
Expand All @@ -72,6 +74,7 @@ func (m branchModule) getProjectBranchListHandler(c *gin.Context) {
// @produce json
// @param projectId path uint true "project ID" minimum(0)
// @param branch body request.Branch true "Branch object"
// @param pretty query bool false "Pretty indented JSON output"
// @success 201 {object} response.Branch "Created branch"
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -121,7 +124,7 @@ func (m branchModule) createProjectBranchHandler(c *gin.Context) {
projectID))
return
}
c.JSON(http.StatusCreated, modelconv.DBBranchToResponse(dbBranch))
renderJSON(c, http.StatusCreated, modelconv.DBBranchToResponse(dbBranch))
}

// updateProjectBranchListHandler godoc
Expand All @@ -137,6 +140,7 @@ func (m branchModule) createProjectBranchHandler(c *gin.Context) {
// @produce json
// @param projectId path uint true "project ID" minimum(0)
// @param branches body request.BranchListUpdate true "Branch update"
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.BranchList "Updated branches"
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -164,7 +168,7 @@ func (m branchModule) updateProjectBranchListHandler(c *gin.Context) {
return
}
resBranchList := modelconv.DBBranchListToResponse(dbBranchList.branches, dbBranchList.defaultBranch)
c.JSON(http.StatusOK, resBranchList)
renderJSON(c, http.StatusOK, resBranchList)
}

type databaseBranchList struct {
Expand Down
20 changes: 17 additions & 3 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ func build(buildID uint) broadcast.Broadcaster {
// @summary Finds build by build ID
// @description Added in v0.3.5.
// @tags build
// @produce json
// @param buildId path uint true "build id" minimum(0)
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.Build
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand All @@ -117,7 +119,7 @@ func (m buildModule) getBuildHandler(c *gin.Context) {
}

resBuild := modelconv.DBBuildToResponse(dbBuild, m.engineLookup)
c.JSON(http.StatusOK, resBuild)
renderJSON(c, http.StatusOK, resBuild)
}

var buildJSONToColumns = map[string]database.SafeSQLName{
Expand All @@ -141,6 +143,7 @@ var defaultGetBuildsOrderBy = orderby.Column{Name: database.BuildColumns.BuildID
// @description while the matching filters are meant for searches by humans where it tries to find soft matches and is therefore inaccurate by nature.
// @description Added in v5.0.0.
// @tags build
// @produce json
// @param limit query int false "Number of results to return. No limiting is applied if empty (`?limit=`) or non-positive (`?limit=0`). Required if `offset` is used." default(100)
// @param offset query int false "Skipped results, where 0 means from the start." minimum(0) default(0)
// @param orderby query []string false "Sorting orders. Takes the property name followed by either 'asc' or 'desc'. Can be specified multiple times for more granular sorting. Defaults to `?orderby=buildId desc`"
Expand All @@ -160,6 +163,7 @@ var defaultGetBuildsOrderBy = orderby.Column{Name: database.BuildColumns.BuildID
// @param gitBranchMatch query string false "Filter by matching build Git branch. Cannot be used with `gitBranch`."
// @param stageMatch query string false "Filter by matching build stage. Cannot be used with `stage`."
// @param match query string false "Filter by matching on any supported fields."
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.PaginatedBuilds
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -272,7 +276,7 @@ func (m buildModule) getBuildListHandler(c *gin.Context) {
return
}

c.JSON(http.StatusOK, response.PaginatedBuilds{
renderJSON(c, http.StatusOK, response.PaginatedBuilds{
List: modelconv.DBBuildsToResponses(dbBuilds, m.engineLookup),
TotalCount: totalCount,
})
Expand All @@ -294,7 +298,9 @@ func parseBuildStatusOrWriteError(c *gin.Context, str, paramName string) (databa
// @summary Finds logs for build with selected build ID
// @description Added in v0.3.8.
// @tags build
// @produce json
// @param buildId path uint true "build id" minimum(0)
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} []response.Log "logs from selected build"
// @failure 400 {object} problem.Response "Bad request"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -324,14 +330,15 @@ func (m buildModule) getBuildLogListHandler(c *gin.Context) {
}
}

c.JSON(http.StatusOK, resLogs)
renderJSON(c, http.StatusOK, resLogs)
}

// streamBuildLogHandler godoc
// @id streamBuildLog
// @summary Opens stream listener
// @description Added in v0.3.8.
// @tags build
// @produce json-stream
// @param buildId path uint true "build id" minimum(0)
// @success 200 "Open stream"
// @failure 400 {object} problem.Response "Bad request"
Expand Down Expand Up @@ -363,6 +370,7 @@ func (m buildModule) streamBuildLogHandler(c *gin.Context) {
// @summary Post a log to selected build
// @description Added in v0.1.0.
// @tags build
// @accept json
// @param buildId path uint true "build id" minimum(0)
// @param data body request.LogOrStatusUpdate true "data"
// @success 201 "Created"
Expand Down Expand Up @@ -502,6 +510,7 @@ func createLogBatchSqliteQuery(db *gorm.DB, dbLogs []database.Log) *gorm.DB {
// @summary Update a build's status.
// @description Added in v5.0.0.
// @tags build
// @accept json
// @param buildId path uint true "Build ID" minimum(0)
// @param data body request.BuildStatusUpdate true "Status update"
// @success 204 "Updated"
Expand Down Expand Up @@ -626,11 +635,13 @@ func (m buildModule) getLogs(buildID uint) ([]database.Log, error) {
// @description Added in v0.2.4.
// @tags project
// @accept json
// @produce json
// @param projectId path uint true "project ID" minimum(0)
// @param stage path string true "name of stage to run, or specify ALL to run everything"
// @param branch query string false "branch name, uses default branch if omitted"
// @param environment query string false "environment name"
// @param inputs body string _ "user inputs" example(foo:bar)
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.BuildReferenceWrapper "Build scheduled"
// @failure 400 {object} problem.Response "Bad request, such as invalid body JSON"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand All @@ -655,12 +666,14 @@ func (m buildModule) oldStartProjectBuildHandler(c *gin.Context) {
// @description Added in v5.0.0.
// @tags build
// @accept json
// @produce json
// @param projectId path uint true "Project ID" minimum(0)
// @param stage query string false "Name of stage to run, or specify `ALL` to run all stages." default(ALL)
// @param branch query string false "Branch name. Uses project's default branch if omitted"
// @param environment query string false "Environment name filter. If left empty it will run all stages without any environment filters."
// @param engine query string false "Execution engine ID"
// @param inputs body request.BuildInputs _ "Input variable values. Map of variable names (as defined in the project's `.wharf-ci.yml` file) as keys paired with their string, boolean, or numeric value."
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.BuildReferenceWrapper "Build scheduled"
// @failure 400 {object} problem.Response "Bad request, such as invalid body JSON"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
Expand Down Expand Up @@ -822,6 +835,7 @@ func (m buildModule) startBuildHandler(c *gin.Context, projectID uint, stageName
}
}

renderJSON(c, http.StatusOK, modelconv.DBBuildToResponseBuildReferenceWrapper(dbBuild))
c.JSON(http.StatusOK, modelconv.DBBuildToResponseBuildReferenceWrapper(dbBuild))
}

Expand Down
4 changes: 3 additions & 1 deletion engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func (m engineModule) Register(r *gin.RouterGroup) {
// @summary Get list of engines.
// @description Added in v5.1.0.
// @tags engine
// @produce json
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.EngineList "Engines"
// @failure 401 {object} problem.Response "Unauthorized or missing jwt token"
// @router /engine [get]
Expand All @@ -36,7 +38,7 @@ func (m engineModule) getEngineList(c *gin.Context) {
}
engines := getEnginesFromConfig(conf)
res.List = convCIEnginesToResponses(engines)
c.JSON(200, res)
renderJSON(c, 200, res)
}

func getEnginesFromConfig(ciConf CIConfig) []CIEngineConfig {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/go-gormigrate/gormigrate/v2 v2.0.0
github.com/golang-jwt/jwt/v4 v4.1.0
github.com/iver-wharf/wharf-core v1.3.0
github.com/mileusna/useragent v1.0.2
github.com/stretchr/testify v1.7.0
github.com/swaggo/gin-swagger v1.4.1
github.com/swaggo/swag v1.8.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsF
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mileusna/useragent v1.0.2 h1:DgVKtiPnjxlb73z9bCwgdUvU2nQNQ97uhgfO8l9uz/w=
github.com/mileusna/useragent v1.0.2/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
Expand Down
6 changes: 4 additions & 2 deletions ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ func (m healthModule) DeprecatedRegister(e *gin.Engine) {
// @description Added in v4.2.0.
// @tags health
// @produce json
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.Ping
// @router /ping [get]
func (m healthModule) pingHandler(c *gin.Context) {
c.JSON(200, response.Ping{Message: "pong"})
renderJSON(c, 200, response.Ping{Message: "pong"})
}

// healthHandler godoc
Expand All @@ -41,8 +42,9 @@ func (m healthModule) pingHandler(c *gin.Context) {
// @description Added in v0.7.1.
// @tags health
// @produce json
// @param pretty query bool false "Pretty indented JSON output"
// @success 200 {object} response.HealthStatus
// @router /health [get]
func (m healthModule) healthHandler(c *gin.Context) {
c.JSON(200, response.HealthStatus{Message: "API is healthy.", IsHealthy: true})
renderJSON(c, 200, response.HealthStatus{Message: "API is healthy.", IsHealthy: true})
}
Loading

0 comments on commit 2cd15f6

Please sign in to comment.