Skip to content

Commit

Permalink
ci: add golangci linter rules
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoliwa committed Dec 28, 2024
1 parent f737ea4 commit fa0eddc
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 61 deletions.
23 changes: 18 additions & 5 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
name: go
on: [push, pull_request]
jobs:
build:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "stable"
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: "v1.60"

test:
strategy:
matrix:
go: [stable]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.21"
- name: Install richgo
run: |
go install github.com/kyoh86/richgo@latest
go-version: ${{ matrix.go }}
- name: Run tests and generate coverage data
run: |
make test-go-coverage
Expand Down
17 changes: 17 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# https://golangci-lint.run/usage/configuration/
linters:
enable-all: true
disable:
# keep-sorted start
- copyloopvar
- depguard
- exportloopref
- forbidigo
- gci
- gochecknoinits
- godox
- intrange
- ireturn
- paralleltest
- testpackage
# keep-sorted end
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@

Logseq Doctor: heal your flat old Markdown files before importing them.

**NOTE:** This project is still alpha, so it\'s very rough on the edges
(documentation and feature-wise).

At the moment, it has a Python package shipped with a Rust module, plus
an external Go executable with recent additions.

The long-term plan is to convert it to Go and slowly remove Rust and
Python. New features will be added to the Go executable only.
> [!NOTE]
> This project is still alpha, so it\'s very rough on the edges
> (documentation and feature-wise).
>
> At the moment, it has a Python package shipped with a Rust extension, plus
> an external Go executable with recent additions.
>
> The long-term plan is to convert it to Go and slowly remove Rust and
> Python. New features will be added to the Go executable only.
## Installation

Expand Down
6 changes: 3 additions & 3 deletions cmd/lsdg.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
// rootCmd represents the base command when called without any subcommands.
var rootCmd = &cobra.Command{ //nolint:exhaustruct,gochecknoglobals
Use: "lsdg",
Short: "Logseq Doctor (Go) heals your Markdown files for Logseq",
Long: `Logseq Doctor (Go) heals your Markdown files for Logseq.
Expand Down Expand Up @@ -40,5 +40,5 @@ func init() {

// Cobra also supports local flags, which will only run
// when this action is called directly.
//rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
83 changes: 45 additions & 38 deletions cmd/tidy_up.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package cmd
import (
"context"
"fmt"
"github.com/andreoliwa/logseq-go"
"github.com/andreoliwa/logseq-go/content"
"github.com/spf13/cobra"
"log"
"os"
"sort"
"strings"

"github.com/andreoliwa/logseq-go"
"github.com/andreoliwa/logseq-go/content"
"github.com/spf13/cobra"
)

// tidyUpCmd represents the tidyUp command
var tidyUpCmd = &cobra.Command{
// tidyUpCmd represents the tidyUp command.
var tidyUpCmd = &cobra.Command{ //nolint:exhaustruct,gochecknoglobals
Use: "tidy-up",
Short: "Tidy up your Markdown files.",
Long: `Tidy up your Markdown files, checking for invalid content and fixing some of them automatically.
Expand All @@ -22,7 +23,7 @@ var tidyUpCmd = &cobra.Command{
- Check for running tasks (DOING)
- Check for double spaces`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, args []string) {
dir := os.Getenv("LOGSEQ_GRAPH_PATH")
if dir == "" {
log.Fatalln("LOGSEQ_GRAPH_PATH environment variable is not set.")
Expand All @@ -32,7 +33,6 @@ var tidyUpCmd = &cobra.Command{
graph, err := logseq.Open(ctx, dir)
if err != nil {
log.Fatalln("error opening graph: %w", err)
return
}

exitCode := 0
Expand All @@ -43,11 +43,9 @@ var tidyUpCmd = &cobra.Command{
page, err := graph.OpenViaPath(path)
if err != nil {
log.Fatalf("%s: error opening file via path: %s\n", path, err)
return
}
if page == nil {
log.Fatalf("%s: error opening file via path: page is nil\n", path)
return
}

changes := make([]string, 0)
Expand All @@ -73,16 +71,6 @@ var tidyUpCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(tidyUpCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// tidyUpCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// tidyUpCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// isValidMarkdownFile checks if a file is a Markdown file, by looking at its extension, not its content.
Expand All @@ -106,34 +94,40 @@ func isValidMarkdownFile(filePath string) bool {
// checkForbiddenReferences checks if a page has forbidden references to other pages or tags.
func checkForbiddenReferences(page logseq.Page) string {
all := make([]string, 0)

for _, block := range page.Blocks() {
block.Children().FilterDeep(func(n content.Node) bool {
var to string
var reference string
if pageLink, ok := n.(*content.PageLink); ok {
to = pageLink.To
reference = pageLink.To
} else if tag, ok := n.(*content.Hashtag); ok {
to = tag.To
reference = tag.To
}

// TODO: these values should be read from a config file or env var
forbidden := false
switch strings.ToLower(to) {

switch strings.ToLower(reference) {
case "quick capture":
forbidden = true
case "inbox":
forbidden = true
}

if forbidden {
all = append(all, to)
all = append(all, reference)
}

return false
})
}
count := len(all)
if count > 0 {

if count := len(all); count > 0 {
unique := sortAndRemoveDuplicates(all)

return fmt.Sprintf("remove %d forbidden references to pages/tags: %s", count, strings.Join(unique, ", "))
}

return ""
}

Expand All @@ -144,9 +138,11 @@ func sortAndRemoveDuplicates(elements []string) []string {
for _, element := range elements {
if !seen[element] {
seen[element] = true

uniqueElements = append(uniqueElements, element)
}
}

sort.Strings(uniqueElements)

return uniqueElements
Expand All @@ -155,51 +151,62 @@ func sortAndRemoveDuplicates(elements []string) []string {
// checkRunningTasks checks if a page has running tasks (DOING, etc.).
func checkRunningTasks(page logseq.Page) string {
all := make([]string, 0)

for _, block := range page.Blocks() {
block.Children().FilterDeep(func(n content.Node) bool {
if task, ok := n.(*content.TaskMarker); ok {
s := task.Status
// TODO: the conversion from a task status to the "DOING"/"IN-PROGRESS" strings should be done in logseq-go
if s == content.TaskStatusDoing {
status := task.Status
// TODO: convert to strings "DOING"/"IN-PROGRESS" in logseq-go
if status == content.TaskStatusDoing {
all = append(all, "DOING")
}
if s == content.TaskStatusInProgress {

if status == content.TaskStatusInProgress {
all = append(all, "IN-PROGRESS")
}
}

return false
})
}
count := len(all)
if count > 0 {

if count := len(all); count > 0 {
unique := sortAndRemoveDuplicates(all)

return fmt.Sprintf("stop %d running task(s): %s", count, strings.Join(unique, ", "))
}

return ""
}

func checkDoubleSpaces(page logseq.Page) string {
all := make([]string, 0)

for _, block := range page.Blocks() {
block.Children().FilterDeep(func(n content.Node) bool {
block.Children().FilterDeep(func(node content.Node) bool {
var value string
if text, ok := n.(*content.Text); ok {

if text, ok := node.(*content.Text); ok {
value = text.Value
} else if pageLink, ok := n.(*content.PageLink); ok {
} else if pageLink, ok := node.(*content.PageLink); ok {
value = pageLink.To
} else if tag, ok := n.(*content.Hashtag); ok {
} else if tag, ok := node.(*content.Hashtag); ok {
value = tag.To
}

if strings.Contains(value, " ") {
all = append(all, fmt.Sprintf("'%s'", value))
}

return false
})
}
count := len(all)
if count > 0 {

if count := len(all); count > 0 {
unique := sortAndRemoveDuplicates(all)

return fmt.Sprintf("%d double spaces: %s", count, strings.Join(unique, ", "))
}

return ""
}
24 changes: 17 additions & 7 deletions cmd/tidy_up_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package cmd

import (
"context"
"github.com/andreoliwa/logseq-go"
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/andreoliwa/logseq-go"
"github.com/stretchr/testify/assert"
)

func TestSortAndRemoveDuplicates(t *testing.T) {
Expand All @@ -20,7 +21,11 @@ func TestSortAndRemoveDuplicates(t *testing.T) {
{"one element", []string{"apple"}, []string{"apple"}},
{"duplicates", []string{"orange", "apple", "banana", "apple"}, []string{"apple", "banana", "orange"}},
{"sorted unique", []string{"orange", "banana", "apple"}, []string{"apple", "banana", "orange"}},
{"unsorted with duplicates", []string{"orange", "banana", "apple", "apple", "orange"}, []string{"apple", "banana", "orange"}},
{
"unsorted with duplicates",
[]string{"orange", "banana", "apple", "apple", "orange"},
[]string{"apple", "banana", "orange"},
},
}

for _, test := range tests {
Expand Down Expand Up @@ -51,8 +56,7 @@ func TestIsValidMarkdownFile(t *testing.T) {

// Create a valid markdown file
validFilePath := filepath.Join(dir, "valid_markdown_file.md")
err := os.WriteFile(validFilePath, []byte("# Test"), 0644)
if err != nil {
if err := os.WriteFile(validFilePath, []byte("# Test"), 0o600); err != nil {
t.Fatalf("Failed to create test file: %v", err)
}

Expand All @@ -70,7 +74,10 @@ func TestIsValidMarkdownFile(t *testing.T) {
}

func setupPage(t *testing.T, name string) logseq.Page {
t.Helper()

ctx := context.Background()

graph, err := logseq.Open(ctx, filepath.Join("testdata", "graph"))
if err != nil {
t.Fatal(err)
Expand All @@ -86,7 +93,8 @@ func setupPage(t *testing.T, name string) logseq.Page {

func TestCheckForbiddenReferences(t *testing.T) {
invalid := setupPage(t, "forbidden")
assert.Equal(t, "remove 4 forbidden references to pages/tags: Inbox, quick capture", checkForbiddenReferences(invalid))
assert.Equal(t, "remove 4 forbidden references to pages/tags: Inbox, quick capture",
checkForbiddenReferences(invalid))

valid := setupPage(t, "valid")
assert.Equal(t, "", checkForbiddenReferences(valid))
Expand All @@ -102,7 +110,9 @@ func TestCheckRunningTasks(t *testing.T) {

func TestCheckDoubleSpaces(t *testing.T) {
invalid := setupPage(t, "spaces")
assert.Equal(t, "3 double spaces: 'Link With Spaces ', 'Regular text with spaces', 'some tag with spaces'", checkDoubleSpaces(invalid))
assert.Equal(t,
"3 double spaces: 'Link With Spaces ', 'Regular text with spaces', 'some tag with spaces'",
checkDoubleSpaces(invalid))

valid := setupPage(t, "valid")
assert.Equal(t, "", checkDoubleSpaces(valid))
Expand Down

0 comments on commit fa0eddc

Please sign in to comment.