Skip to content

Commit 6d40371

Browse files
committed
Create a wonderful report
1 parent cf55a8e commit 6d40371

File tree

10 files changed

+185
-50
lines changed

10 files changed

+185
-50
lines changed

Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
build:
2-
go build -o bin/gowordlytics cmd/root.go
2+
@go build -o bin/gowordlytics cmd/root.go
33

44
test:
5-
go test -v ./...
5+
@go test -v ./...
66

77
install:
8-
go install
8+
@go install

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
![WordPress](https://img.shields.io/badge/WordPress-%23117AC9.svg?style=for-the-badge&logo=WordPress&logoColor=white)
33
![Go](https://img.shields.io/badge/go-%2300ADD8.svg?style=for-the-badge&logo=go&logoColor=white)
44

5+
56
GoWordlytics is a simple CLI tool to analyze a WordPress Website for Plugins, Themes, and other details.
67

8+
![Picture of the CLI](./assets/example-output.png)
9+
710
## Installation
811

912
To install the CLI tool, run the following command:

assets/example-output.png

362 KB
Loading

cmd/root.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var rootCmd = &cobra.Command{
3131
os.Exit(1)
3232
}
3333

34-
report.Output()
34+
report.Render()
3535
},
3636
}
3737

go.mod

+13-4
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@ go 1.21.0
55
require (
66
github.com/PuerkitoBio/goquery v1.8.1
77
golang.org/x/net v0.20.0
8+
golang.org/x/term v0.17.0
9+
)
10+
11+
require (
12+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
13+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
14+
github.com/mattn/go-runewidth v0.0.15 // indirect
15+
github.com/muesli/reflow v0.3.0 // indirect
16+
github.com/muesli/termenv v0.15.2 // indirect
17+
github.com/rivo/uniseg v0.2.0 // indirect
818
)
919

1020
require (
1121
github.com/andybalholm/cascadia v1.3.1 // indirect
12-
github.com/fatih/color v1.16.0 // indirect
22+
github.com/charmbracelet/lipgloss v0.9.1
1323
github.com/inconshreveable/mousetrap v1.1.0 // indirect
14-
github.com/mattn/go-colorable v0.1.13 // indirect
1524
github.com/mattn/go-isatty v0.0.20 // indirect
16-
github.com/spf13/cobra v1.8.0 // indirect
25+
github.com/spf13/cobra v1.8.0
1726
github.com/spf13/pflag v1.0.5 // indirect
18-
golang.org/x/sys v0.16.0 // indirect
27+
golang.org/x/sys v0.17.0 // indirect
1928
)

go.sum

+20-8
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,27 @@ github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAc
22
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
33
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
44
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
5+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
6+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
7+
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
8+
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
59
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6-
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
7-
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
810
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
911
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
10-
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
11-
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
12-
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
12+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
13+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
1314
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
1415
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
16+
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
17+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
18+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
19+
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
20+
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
21+
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
22+
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
23+
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
24+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
25+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
1526
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
1627
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
1728
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
@@ -36,14 +47,15 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
3647
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3748
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3849
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39-
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4050
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4151
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42-
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
43-
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
52+
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
53+
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
4454
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
4555
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
4656
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
57+
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
58+
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
4759
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
4860
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
4961
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

internal/analyze/theme.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ func (a *Analyze) getThemeData(name string) report.Theme {
4141

4242
themeMap := a.parseCSSThemeString(response)
4343

44-
return a.getThemeDetials(themeMap)
44+
return a.getThemeDetials(themeMap, name)
4545
}
4646

47-
func (a *Analyze) getThemeDetials(themeMap map[string]string) report.Theme {
47+
func (a *Analyze) getThemeDetials(themeMap map[string]string, name string) report.Theme {
4848
themeDetails := report.Theme{}
4949

5050
fields := map[string]func(string){
@@ -72,6 +72,10 @@ func (a *Analyze) getThemeDetials(themeMap map[string]string) report.Theme {
7272
}
7373
}
7474

75+
if len(themeDetails.Name) == 0 {
76+
themeDetails.Name = name
77+
}
78+
7579
return themeDetails
7680
}
7781

internal/render/size.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package render
2+
3+
import (
4+
"golang.org/x/term"
5+
)
6+
7+
func getWidth(fallback int) int {
8+
if !term.IsTerminal(0) {
9+
return fallback
10+
}
11+
12+
width, _, err := term.GetSize(0)
13+
14+
if err != nil {
15+
return fallback
16+
}
17+
18+
return width
19+
}

internal/render/table.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package render
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/charmbracelet/lipgloss"
7+
"github.com/charmbracelet/lipgloss/table"
8+
)
9+
10+
func Table(header []string, rows [][]string) {
11+
t := table.New().Width(getWidth(80)).StyleFunc(rowStyle)
12+
13+
t.Headers(header...)
14+
t.Rows(addBreakToColumns(rows)...)
15+
16+
fmt.Print(t)
17+
}
18+
19+
func rowStyle(row, col int) lipgloss.Style {
20+
switch {
21+
case row == 0:
22+
return lipgloss.NewStyle().Foreground(lipgloss.Color("#0FE11A"))
23+
case row%2 == 0:
24+
return lipgloss.NewStyle().Foreground(lipgloss.Color("#A4C3E4"))
25+
default:
26+
return lipgloss.NewStyle().Foreground(lipgloss.Color("#AF9BEA"))
27+
}
28+
}
29+
30+
func addBreakToColumns(rows [][]string) [][]string {
31+
width := getWidth(80) / 3
32+
33+
colStyle := lipgloss.NewStyle().MaxWidth(width)
34+
35+
for i, row := range rows {
36+
for index, col := range row {
37+
row[index] = colStyle.Render(breakLines(col, width))
38+
}
39+
40+
rows[i] = row
41+
}
42+
43+
return rows
44+
}
45+
46+
func breakLines(input string, count int) string {
47+
var out = []rune{}
48+
49+
for i, char := range input {
50+
out = append(out, char)
51+
52+
if i%count == 0 && i != 0 {
53+
out = append(out, '\n')
54+
}
55+
}
56+
57+
return string(out)
58+
}

internal/report/main.go

+62-32
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import (
55
"html"
66
"strings"
77

8-
"github.com/fatih/color"
8+
"github.com/charmbracelet/lipgloss"
99
"github.com/fschuermeyer/GoWordlytics/internal/format"
10+
"github.com/fschuermeyer/GoWordlytics/internal/render"
1011
)
1112

1213
type Report struct {
@@ -65,57 +66,86 @@ func (r *Report) HasWordPress() bool {
6566
return r.hasWordPress
6667
}
6768

68-
func (r *Report) Output() {
69-
color.White("\nGoWordlytics Report")
70-
color.Blue("Report for %s", r.GetUrl())
71-
fmt.Println("------------------------")
69+
// Render renders the report by calling the RenderOverview, RenderPlugins, and RenderThemes methods.
70+
// It applies the provided headline style to the rendered sections.
71+
func (r *Report) Render() {
72+
var headline = lipgloss.NewStyle().Foreground(lipgloss.Color("#E7D617")).Bold(true)
7273

73-
c := color.New(color.FgGreen)
74+
r.renderOverview(headline)
7475

75-
c.Print("Has WordPress: ")
76-
fmt.Println(r.hasWordPress)
76+
if len(r.pluginDetails) > 0 {
77+
r.renderPlugins(headline)
78+
}
7779

78-
c.Print("Has readme.html: ")
79-
fmt.Println(r.hasReadme)
80+
if len(r.themes) > 0 {
81+
r.renderThemes(headline)
82+
}
83+
}
84+
85+
// RenderOverview renders the overview of the GoWordlytics report.
86+
// It takes a headline lipgloss.Style as a parameter and prints the report to the console.
87+
// The report includes the URL and whether it is a WordPress site.
88+
// If the site is a WordPress site, it also includes whether it has a readme file.
89+
// If the report includes version information, it also includes the version number, version status, and current version.
90+
// The report is displayed in a table format.
91+
func (r *Report) renderOverview(headline lipgloss.Style) {
92+
fmt.Printf("%s\n", headline.Render("GoWordlytics Report"))
93+
94+
headers := []string{"URL", "WordPress?"}
95+
values := []string{r.GetUrl(), fmt.Sprintf("%t", r.HasWordPress())}
96+
97+
if r.HasWordPress() {
98+
headers = append(headers, "Readme?")
99+
values = append(values, fmt.Sprintf("%t", r.hasReadme))
100+
}
80101

81102
if len(r.version) > 0 {
82-
c.Print("Version: ")
83-
fmt.Printf("%s ", r.version)
103+
headers = append(headers, "Version")
104+
values = append(values, r.version)
84105

85106
if len(r.versionStatus) > 0 && r.versionStatus != "error" && r.versionStatus != "latest" {
86-
text := color.RedString("(%s to %s)", r.versionStatus, r.versionCurrent)
87-
88-
fmt.Print(text)
89-
}
107+
headers = append(headers, "Version Status")
90108

91-
fmt.Println()
92-
}
109+
if r.versionStatus == "upgrade" {
110+
r.versionStatus = lipgloss.NewStyle().Foreground(lipgloss.Color("#F16208")).Render(r.versionStatus)
111+
}
93112

94-
if len(r.pluginDetails) > 0 {
95-
r.OutputPlugins()
96-
}
113+
values = append(values, r.versionStatus)
97114

98-
if len(r.themes) > 0 {
99-
r.OutputThemes()
115+
headers = append(headers, "Current")
116+
values = append(values, r.versionCurrent)
117+
}
100118
}
101119

102-
fmt.Print("------------------------\n\n")
120+
render.Table(headers, [][]string{values})
103121
}
104122

105-
func (r *Report) OutputPlugins() {
106-
fmt.Println("------------------------")
107-
color.Blue("Plugins")
123+
// RenderPlugins renders the plugins report with the given headline style.
124+
// It prints the headline and then displays a table with the plugin details,
125+
// including the name, slug, version, number of downloads, and homepage link.
126+
func (r *Report) renderPlugins(headline lipgloss.Style) {
127+
fmt.Printf("%s\n", headline.Render("Plugins Report"))
128+
129+
rows := [][]string{}
108130

109131
for _, plugin := range r.pluginDetails {
110-
fmt.Printf("%s (%s) - Version: %s - Downloaded: %s | %s \n", html.UnescapeString(plugin.Name), plugin.Slug, plugin.Version, format.InsertThousandSeparator(plugin.Downloaded, '.'), plugin.Homepage)
132+
rows = append(rows, []string{html.UnescapeString(plugin.Name), plugin.Slug, plugin.Version, format.InsertThousandSeparator(plugin.Downloaded, '.'), plugin.Homepage})
111133
}
134+
135+
render.Table([]string{"Name", "Slug", "Version", "Downloads", "Link"}, rows)
112136
}
113137

114-
func (r *Report) OutputThemes() {
115-
fmt.Println("------------------------")
116-
color.Blue("Themes")
138+
// RenderThemes renders a report of the themes.
139+
// It takes a headline style as input and prints the themes' information in a table format.
140+
// The themes' information includes the name, description, text domain, author, author URI, and version.
141+
func (r *Report) renderThemes(headline lipgloss.Style) {
142+
143+
rows := [][]string{}
117144

118145
for _, theme := range r.themes {
119-
fmt.Printf("(%s)\n- %s %s - %s %s\n", theme.Description, theme.TextDomain, theme.Author, theme.AuthorURI, theme.Version)
146+
rows = append(rows, []string{theme.Name, theme.Description, theme.TextDomain, theme.Author, theme.AuthorURI, theme.Version})
120147
}
148+
149+
fmt.Printf("%s\n", headline.Render("Themes Report"))
150+
render.Table([]string{"Name", "Description", "TextDomain", "Author", "AuthorURI", "Version"}, rows)
121151
}

0 commit comments

Comments
 (0)