- Best Suited for README.md
+ Best Suited for README.md. Mini charts for each type.
@@ -228,7 +214,7 @@ const baseURL = import.meta.env.PUBLIC_BASE_URL;
-
+
![](https:///chart?org=&repo=&branch=
-
+
-
@@ -259,7 +245,7 @@ const baseURL = import.meta.env.PUBLIC_BASE_URL;
:src="`//${url}/chart?org=${org}&repo=${repo}&branch=${branch}&type=${t.name}&theme=dark&line=fill`"
/>
-
+
![](https:///chart?org=&repo=&branch=
+
+
+ # Comparison Charts for Types
+
+
+ Visualize comparison charts for types for latest scores for same metrics
+
+
+
+
+
+
-
+
+
-
+
+
![Chart]()
+
+
+ ![](https:///chart?org=&repo=&branch=&types=)
+
+
+
+
+
+
+
+
@@ -291,7 +310,7 @@ const baseURL = import.meta.env.PUBLIC_BASE_URL;
:src="`//${url}/chart?org=${org}&repo=${repo}&branches=all&type=${t.name}&theme=dark&line=fill`"
/>
-
+
![](https:///chart?org=&repo=&branches=all&type=
Visualize comparison charts for users over time for a specific type
-
+
-
@@ -323,7 +342,7 @@ const baseURL = import.meta.env.PUBLIC_BASE_URL;
:src="`//${url}/chart?org=${org}&repo=${repo}&users=all&type=${t.name}&theme=dark&line=fill`"
/>
-
+
![](https:///chart?org=&repo=&branch= {
+ return types.reduce((acc, type) => {
+ const metric = type.metric;
+ if (!acc[metric]) {
+ acc[metric] = [];
+ }
+ acc[metric].push(type);
+ return acc;
+ }, {});
+ };
const currentURL = window.location.origin;
@@ -370,6 +399,8 @@ const baseURL = import.meta.env.PUBLIC_BASE_URL;
branch = data.branch;
updateBranch();
}
+
+ data.groupedTypes = groupByMetric(data.types);
data.url = baseURL.replace("https://", "").replace("http://", "");
data.org = org;
data.repo = repo;
diff --git a/app/pkg/badge_handler_test.go b/app/pkg/badge_handler_test.go
index c3ddb4e..082677e 100644
--- a/app/pkg/badge_handler_test.go
+++ b/app/pkg/badge_handler_test.go
@@ -39,25 +39,25 @@ func TestGetBadgeErrors(t *testing.T) {
{
Name: "422",
Query: `?repo=repo&branch=branch&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&branch=branch&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&repo=repo&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&repo=repo&branch=branch`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
}
diff --git a/app/pkg/chart.go b/app/pkg/chart.go
index b71ffe2..b57513b 100644
--- a/app/pkg/chart.go
+++ b/app/pkg/chart.go
@@ -157,6 +157,36 @@ func (e *Chart) GetInstaChartForUser(req *ChartRequest, t *models.Type) ([]byte,
return line.Get(xData, yyData, names, cReq)
}
+// bar chart for all types with type names on x-axis and scores on y-axis
+func (e *Chart) GetInstaChartForTypes(req *ChartRequest, branch string, types []*models.Type) ([]byte, error) {
+ cReq := e.makeChartRequest(req, types[0])
+ bar := instachart.NewBarChart()
+
+ xData := []string{}
+ yData := []float64{}
+ zData := []float64{}
+ names := []string{}
+ var hasErr error
+ for _, t := range types {
+ ret, err := e.coverageModel.GetLatestBranchScore(req.Org, req.Repo, branch, t.Name)
+ if err != nil {
+ hasErr = err
+ break
+ }
+ xData = append(xData, t.Name)
+ yData = append(yData, ret.Score)
+ zData = append(zData, ret.Score)
+ names = append(names, t.Name)
+ }
+ if hasErr != nil {
+ return nil, hasErr
+ }
+ yyData := [][]float64{yData}
+ zzData := [][]float64{zData}
+
+ return bar.GetStacked(xData, yyData, zzData, names, cReq)
+}
+
// bar chart with branch names on x-axis and scores on y-axis
func (e *Chart) GetInstaChartForBranches(req *ChartRequest, t *models.Type) ([]byte, error) {
cReq := e.makeChartRequest(req, t)
diff --git a/app/pkg/chart_handler.go b/app/pkg/chart_handler.go
index f7b0031..5d093a9 100644
--- a/app/pkg/chart_handler.go
+++ b/app/pkg/chart_handler.go
@@ -2,7 +2,9 @@ package pkg
import (
"net/http"
+ "strings"
+ "github.com/kevincobain2000/action-coveritup/models"
"github.com/labstack/echo/v4"
"github.com/mcuadros/go-defaults"
)
@@ -23,7 +25,8 @@ type ChartRequest struct {
Branch string `json:"branch" query:"branch" validate:"ascii" message:"ascii branch is required"`
User string `json:"user" query:"user" validate:"ascii,excludes=/" message:"ascii user is required"`
BaseBranch string `json:"base_branch" query:"base_branch" validate:"ascii" message:"ascii base_branch is required"`
- Type string `json:"type" query:"type" validate:"ascii,required,excludes=/" message:"ascii type is required"`
+ Type string `json:"type" query:"type" validate:"ascii,excludes=/" message:"ascii type is required"`
+ Types string `json:"types" query:"types" validate:"ascii,excludes=/" message:"ascii types are required"`
Branches string `json:"branches" query:"branches" validate:"ascii" message:"ascii branches is required"`
Users string `json:"users" query:"users" validate:"ascii" message:"ascii users is required"`
PRNum int `json:"pr_num" query:"pr_num"`
@@ -49,6 +52,35 @@ func (h *ChartHandler) Get(c echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusUnprocessableEntity, msgs)
}
+ if req.Types == "" && req.Type == "" {
+ return echo.NewHTTPError(http.StatusUnprocessableEntity, "types or type is required")
+ }
+ if req.Types != "" {
+ if req.Branch == "" {
+ return echo.NewHTTPError(http.StatusUnprocessableEntity, "branch for types is required")
+ }
+ types := []*models.Type{}
+ for _, t := range strings.Split(req.Types, ",") {
+ tt, err := h.Chart.GetType(t)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error())
+ }
+ if tt.ID == 0 {
+ return echo.NewHTTPError(http.StatusNotFound, "type from types not found")
+ }
+ types = append(types, tt)
+ }
+ for i := 1; i < len(types); i++ {
+ if types[i].Metric != types[0].Metric {
+ return echo.NewHTTPError(http.StatusUnprocessableEntity, "types must have same metric")
+ }
+ }
+ buf, err := h.Chart.GetInstaChartForTypes(req, req.Branch, types)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusInternalServerError, err)
+ }
+ return ResponseMedia(c, buf, req.Output)
+ }
t, err := h.Chart.GetType(req.Type)
if err != nil {
diff --git a/app/pkg/chart_handler_test.go b/app/pkg/chart_handler_test.go
index 33b03b4..77cff84 100644
--- a/app/pkg/chart_handler_test.go
+++ b/app/pkg/chart_handler_test.go
@@ -33,24 +33,24 @@ func TestGetChartErrors(t *testing.T) {
Name: "404",
Query: `?org=org&repo=repo&branch=branch&type=type`,
Status: http.StatusNotFound,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
},
{
Name: "422",
Query: `?repo=repo&branch=branch&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&branch=branch&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&repo=repo&branch=branch`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
}
diff --git a/app/pkg/pr_handler_test.go b/app/pkg/pr_handler_test.go
index bede2a2..a00eaaa 100644
--- a/app/pkg/pr_handler_test.go
+++ b/app/pkg/pr_handler_test.go
@@ -32,25 +32,25 @@ func TestPRErrors(t *testing.T) {
{
Name: "409",
Query: `?org=org&repo=repo&branch=branch&base_branch=master&pr_num=2&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusConflict,
},
{
Name: "422",
Query: `?org=org&branch=branch&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&repo=repo&type=type`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
{
Name: "422",
Query: `?org=org&repo=repo&branch=branch`,
- ContentType: "application/json; charset=UTF-8",
+ ContentType: "application/json",
Status: http.StatusUnprocessableEntity,
},
}
diff --git a/app/pkg/readme_handler.go b/app/pkg/readme_handler.go
index 09d3057..b530ed1 100644
--- a/app/pkg/readme_handler.go
+++ b/app/pkg/readme_handler.go
@@ -49,6 +49,7 @@ func (h *ReadmeHandler) Get(c echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
+
res := &ReadmeResponse{
Types: types,
Branches: branches,
diff --git a/app/pkg/upload_handler.go b/app/pkg/upload_handler.go
index d06309d..f5de701 100644
--- a/app/pkg/upload_handler.go
+++ b/app/pkg/upload_handler.go
@@ -3,6 +3,7 @@ package pkg
import (
"net/http"
"os"
+ "strings"
"github.com/labstack/echo/v4"
"github.com/mcuadros/go-defaults"
@@ -43,6 +44,9 @@ func (h *UploadHandler) Post(c echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusUnprocessableEntity, msgs)
}
+ if strings.Contains(req.Type, ",") {
+ return echo.NewHTTPError(http.StatusUnprocessableEntity, "type cannot contain comma")
+ }
// set by default to api.github and "" on tests
if os.Getenv("GITHUB_API") != "" {
diff --git a/app/build.sh b/build.sh
similarity index 80%
rename from app/build.sh
rename to build.sh
index cc56ecd..2511d25 100755
--- a/app/build.sh
+++ b/build.sh
@@ -1,6 +1,6 @@
#! /bin/bash
-cd frontend
+cd app/frontend
npm install
npm run build
cd ..