Skip to content

Commit

Permalink
Merge branch 'feature/report' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
obcode committed Oct 28, 2022
2 parents b9afedc + d466540 commit ec16188
Show file tree
Hide file tree
Showing 7 changed files with 525 additions and 0 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Available Commands:
delete Delete repositories.
generate Generate repositories.
help Help about any command
report generate activity report
setaccess Set access level for exisiting repositories.
show Show config of an assignment
version Print the version number of Glabs
Expand All @@ -168,6 +169,33 @@ Before generating check whether all students exist or not using the command
glabs check [course]
```

## Generating Reports of Assignments

It is possible to generate reports in plain text (by default), HTML or JSON via the
`report` command:

```
Generate activity report
Usage:
glabs report course assignment [flags]
Flags:
-e, --export-default-template export the default HTML template
-h, --help help for report
--html generate HTML
--json generate JSON
-o, --output string output to <file>
-t, --tmpl string use template for HTML
```

If you do not like the default plain text or HTML template feel free to use your
own template via `-t`. You can simply export the default template via `-e` and adapt
it to your needs.

All available report information which can be used in the templates, can be found
[here](https://github.com/obcode/glabs/blob/master/gitlab/report/types.go).

## Cloning Repos

```
Expand Down
81 changes: 81 additions & 0 deletions cmd/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cmd

import (
"errors"
"fmt"
"os"

"github.com/obcode/glabs/config"
"github.com/obcode/glabs/gitlab"
"github.com/obcode/glabs/gitlab/report"
"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(reportCmd)
reportCmd.Flags().BoolVar(&Html, "html", false, "generate HTML")
reportCmd.Flags().BoolVar(&Json, "json", false, "generate JSON")
reportCmd.Flags().StringVarP(&Template, "tmpl", "t", "", "use template for HTML")
reportCmd.Flags().BoolVarP(&ExportTemplate, "export-default-template", "e", false, "export the default HTML template")
reportCmd.Flags().StringVarP(&OutPut, "output", "o", "", "output to <file>")
}

var (
reportCmd = &cobra.Command{
Use: "report course assignment",
Short: "generate activity report",
Long: `Generate activity report`,
Args: func(cmd *cobra.Command, args []string) error {
if !ExportTemplate {
if len(args) < 2 {
return errors.New("requires at least two args")
}
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
if Html && Json {
panic(fmt.Errorf("error: do not use --html and --json together"))
}

var output *string
if len(OutPut) > 0 {
output = &OutPut
}
var template *string
if len(Template) > 0 {
template = &Template
}
if ExportTemplate {
tmpl := ""
if Html {
tmpl = report.HTMLTemplate
} else {
tmpl = report.TextTemplate
}
if output != nil {
err := os.WriteFile(*output, []byte(tmpl), 0644)
if err != nil {
panic(err)
}
} else {
fmt.Println(tmpl)
}
return
}
assignmentConfig := config.GetAssignmentConfig(args[0], args[1], args[2:]...)
c := gitlab.NewClient()
if Json {
c.ReportJSON(assignmentConfig, output)
} else if Html {
c.ReportHTML(assignmentConfig, template, output)
} else {
c.Report(assignmentConfig, template, output)
}
}}
Html bool
Json bool
Template string
ExportTemplate bool
OutPut string
)
102 changes: 102 additions & 0 deletions gitlab/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package gitlab

import (
"encoding/json"
"fmt"
htmlTemplate "html/template"
"os"
"text/template"

"github.com/obcode/glabs/config"
r "github.com/obcode/glabs/gitlab/report"
)

func (c *Client) Report(assignmentCfg *config.AssignmentConfig, templateFile *string, output *string) {
report := c.report(assignmentCfg)

var (
tmpl *template.Template
err error
)
if templateFile != nil {
tmpl, err = template.ParseFiles(*templateFile)
} else {
tmpl, err = template.New("text").Parse(r.TextTemplate)
}

if err != nil {
panic(err)
}

if output != nil {
os.Remove(*output)
f, err := os.Create(*output)
if err != nil {
panic(err)
}
defer f.Close()
err = tmpl.Execute(f, report)
if err != nil {
panic(err)
}
} else {
err = tmpl.Execute(os.Stdout, report)
if err != nil {
panic(err)
}
}

}

func (c *Client) ReportHTML(assignmentCfg *config.AssignmentConfig, templateFile *string, output *string) {
report := c.report(assignmentCfg)

var (
tmpl *htmlTemplate.Template
err error
)
if templateFile != nil {
tmpl, err = htmlTemplate.ParseFiles(*templateFile)
} else {
tmpl, err = htmlTemplate.New("html").Parse(r.HTMLTemplate)
}
if err != nil {
panic(err)
}

if output != nil {
os.Remove(*output)
f, err := os.Create(*output)
if err != nil {
panic(err)
}
defer f.Close()
err = tmpl.Execute(f, report)
if err != nil {
panic(err)
}
} else {
err = tmpl.Execute(os.Stdout, report)
if err != nil {
panic(err)
}
}
}

func (c *Client) ReportJSON(assignmentCfg *config.AssignmentConfig, output *string) {
report := c.report(assignmentCfg)

json, err := json.MarshalIndent(report, "", " ")
if err != nil {
panic(err)
}

if output != nil {
err := os.WriteFile(*output, json, 0644)
if err != nil {
panic(err)
}
} else {
fmt.Println(string(json))
}
}
74 changes: 74 additions & 0 deletions gitlab/report/html.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package report

var HTMLTemplate = `
<!DOCTYPE html>
<html data-theme="cupcake">
<head>
<meta charset="UTF-8">
<title>glabs {{ .Course }} / {{ .Assignment }}</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="p-8">
<div class="text-center m-2">
<div class="text-4xl text-center mt-8">
Report <a href="{{ .URL }}">{{ .Course }} / {{ .Assignment }} </a>
</div>
<div class="text-xl text-center m-8">{{ .Description }}</div>
<div class="text-xl text-center m-8">Generated: {{ .Generated.Format "02.01.06, 15:04 MST" }}</div>
</div>
<table class="table table-compact w-full">
<thead>
<tr>
<th>Name</th>
<th>Member</th>
<th>Last Commit</th>
<th>Open Issues</th>
<th>Open Merge Requests</th>
</tr>
</thead>
<tbody>
{{range .Projects -}}
{{if and .IsActive (gt .Commits 0) }}<tr class="active">
{{else}} <tr>
{{end}}
<td><a href="{{ .WebURL}}">{{ .Name}}</a></td>
<td>
{{range .Members}}
<a href="{{ .WebURL }}">{{ .Name}}</a>,
{{end}}
</td>
<td>
{{if .LastCommit -}}
<a href="{{ .LastCommit.WebURL}}">last commit</a>
{{- end}}
</td>
<td>
{{if eq .OpenIssuesCount 1 -}}
<a href="{{ .WebURL }}/-/issues">{{ .OpenIssuesCount }} open issue</a>
{{else}}
{{if gt .OpenIssuesCount 1 -}}
<a href="{{ .WebURL }}/-/issues">{{ .OpenIssuesCount }} open issues</a>
{{- end}}
{{- end}}
</td>
<td>
{{if gt .OpenMergeRequestsCount 0 -}}
<a href="{{ .WebURL }}/-/merge_requests">{{ .OpenMergeRequestsCount }} open merge requests</a>
{{- end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<footer class="footer footer-center p-4 bg-base-300 text-base-content">
<div>
<p>Generated with <a href="https://github.com/obcode/glabs">glabs</a>, {{ .Generated.Format "02.01.06, 15:04 MST" }}</p>
</div>
</footer>
</body>
</html>
`
16 changes: 16 additions & 0 deletions gitlab/report/text.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package report

var TextTemplate = `
Report {{ .Course }} / {{ .Assignment}}
{{range .Projects -}}
{{ .Name -}}:
{{- if .IsActive -}}
{{- if eq .Commits 0 }} --- no commits found ---
{{- else }} {{ .WebURL -}}
{{- end -}}
{{- else }} --- no activity found ---
{{- end}}
{{end}}
`
37 changes: 37 additions & 0 deletions gitlab/report/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package report

import (
"time"

"github.com/xanzy/go-gitlab"
)

type Reports struct {
Course string `json:"course"`
Assignment string `json:"assignment"`
URL string `json:"url"`
Description string `json:"description"`
Projects []*ProjectReport `json:"projects"`
Generated *time.Time `json:"generated"`
}

type ProjectReport struct {
Name string `json:"name"`
IsActive bool `json:"active"`
IsEmpty bool `json:"emptyRepo"`
Commits int `json:"commits"`
CreatedAt *time.Time `json:"createdAt"`
LastActivity *time.Time `json:"lastActivity"`
LastCommit *Commit `json:"commit"`
OpenIssuesCount int `json:"openIssuesCount"`
OpenMergeRequestsCount int `json:"openMergeRequestsCount"`
WebURL string `json:"webURL"`
Members []*gitlab.ProjectMember `json:"members"`
}

type Commit struct {
Title string `json:"title"`
CommitterName string `json:"committerName"`
CommittedDate *time.Time `json:"committedDate"`
WebURL string `json:"webURL"`
}
Loading

0 comments on commit ec16188

Please sign in to comment.