mirror of
https://github.com/kjanat/articulate-parser.git
synced 2026-08-05 23:24:07 +02:00
fix: resolve golangci-lint CI failures, simplify CI, tidy docs (#29)
* fix(lint): resolve golangci-lint failures and modernize string handling
CI's golangci-lint (v2.12.2) job was failing with 14 issues, which blocked
the dependent test job. This addresses all of them:
- goconst: extract repeated string literals into constants
- format aliases ("md", "word", "htm") in the exporter factory
- "section" lesson type shared by markdown and HTML exporters
- default Articulate Rise base URL and host in the parser
- reuse existing itemType* constants in the markdown switch
- staticcheck (QF1012): replace buf.WriteString(fmt.Sprintf(...)) with
fmt.Fprintf(...) in the markdown exporter
Also drop the hardcoded `go: "1.24"` from .golangci.yml so the target Go
version is autodetected from go.mod.
* ci: drop test matrix, run a single Go version from go.mod
The test job ran a 1.24.x/1.25.x matrix, but go.mod requires go 1.25.0, so the
1.24 entry just auto-downloaded the 1.25 toolchain and tested the same thing
twice. Replace the matrix with a single job that sources its Go version from
go.mod via go-version-file, and reference the resolved version through the
setup-go step output in summaries, artifact names, and Codecov flags.
* docs: remove emojis from README
* ci: pin modernize tool to gopls v0.21.x for Go 1.25 compatibility
The autofix workflow's `task modernize` step installed the modernize
analyzer from gopls@latest, which as of v0.22.0 requires Go 1.26. The
project targets Go 1.25 (go.mod) and CI runs with GOTOOLCHAIN=local, so
the install failed. Pin to the v0.21.x line, which supports Go >= 1.25.
* ci: keep modernize@latest, fetch its toolchain via GOTOOLCHAIN=auto
Replaces the earlier v0.21.0 pin. The modernize analyzer (gopls v0.22+)
requires Go 1.26, which the project doesn't target yet — and bumping the
module to 1.26 isn't viable because the current golangci-lint release is
built with Go 1.25 and refuses to lint a newer target. Instead, let the
modernize task fetch the toolchain it needs on demand via GOTOOLCHAIN=auto
(setup-go pins GOTOOLCHAIN=local in CI), so we stay on the latest analyzer
without touching the module's Go version.
Also bump golang.org/x/image v0.34.0 -> v0.42.0 via `go get -u ./...`.
* ci: set GOTOOLCHAIN=auto inline for the modernize task
A task-level env: entry does not override GOTOOLCHAIN when setup-go has
already exported GOTOOLCHAIN=local job-wide, so the autofix job still
failed. Set GOTOOLCHAIN=auto inline on the modernize command itself, which
reliably overrides the inherited value and lets Go fetch the toolchain the
modernize analyzer requires.
* ci: bump to Go 1.26 and address PR review feedback
The autofix failure is fixed properly by moving to Go 1.26 instead of the
GOTOOLCHAIN workaround. The official golangci-lint v2.12.2 binary is built
with go1.26.2 and lints a Go 1.26 target fine (the earlier "not ready"
claim was from a locally go-installed binary compiled with Go 1.25), and
the Dockerfiles already use golang:1.26-alpine, so this also aligns the
module with the images.
- go.mod: go 1.25.0 -> 1.26.0, drop the toolchain pin (keeps the lint
target at the go directive).
- Taskfile: revert modernize to plain modernize@latest; on Go 1.26 the
GOTOOLCHAIN dance and its comments are unnecessary.
- ci.yml: pass the resolved Go version through an env var (GO_VERSION)
instead of interpolating steps.setup-go.outputs.go-version directly into
shell scripts (script-injection hygiene); grant the dependency-review job
pull-requests: write so it can post its summary.
- parser.go: derive defaultBaseURL from riseHost instead of duplicating the
host string; drop the redundant per-const comments.
- .golangci.yml: remove the redundant go-version comment.
- regenerate internal/exporters/output.docx.
This commit is contained in:
@@ -13,6 +13,11 @@ const (
|
||||
FormatMarkdown = "markdown"
|
||||
FormatDocx = "docx"
|
||||
FormatHTML = "html"
|
||||
|
||||
// Format aliases accepted by CreateExporter.
|
||||
formatAliasMarkdown = "md"
|
||||
formatAliasDocx = "word"
|
||||
formatAliasHTML = "htm"
|
||||
)
|
||||
|
||||
// Factory implements the ExporterFactory interface.
|
||||
@@ -41,11 +46,11 @@ func NewFactory(htmlCleaner *services.HTMLCleaner) interfaces.ExporterFactory {
|
||||
// Format strings are case-insensitive (e.g., "markdown", "DOCX").
|
||||
func (f *Factory) CreateExporter(format string) (interfaces.Exporter, error) {
|
||||
switch strings.ToLower(format) {
|
||||
case FormatMarkdown, "md":
|
||||
case FormatMarkdown, formatAliasMarkdown:
|
||||
return NewMarkdownExporter(f.htmlCleaner), nil
|
||||
case FormatDocx, "word":
|
||||
case FormatDocx, formatAliasDocx:
|
||||
return NewDocxExporter(f.htmlCleaner), nil
|
||||
case FormatHTML, "htm":
|
||||
case FormatHTML, formatAliasHTML:
|
||||
return NewHTMLExporter(f.htmlCleaner), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported export format: %s", format)
|
||||
@@ -55,5 +60,9 @@ func (f *Factory) CreateExporter(format string) (interfaces.Exporter, error) {
|
||||
// SupportedFormats returns a list of all supported export formats,
|
||||
// including both primary format names and their aliases.
|
||||
func (f *Factory) SupportedFormats() []string {
|
||||
return []string{FormatMarkdown, "md", FormatDocx, "word", FormatHTML, "htm"}
|
||||
return []string{
|
||||
FormatMarkdown, formatAliasMarkdown,
|
||||
FormatDocx, formatAliasDocx,
|
||||
FormatHTML, formatAliasHTML,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ const (
|
||||
itemTypeDivider = "divider"
|
||||
)
|
||||
|
||||
// lessonTypeSection identifies a lesson that acts as a section header.
|
||||
const lessonTypeSection = "section"
|
||||
|
||||
// templateData represents the data structure passed to the HTML template.
|
||||
type templateData struct {
|
||||
Course models.CourseInfo
|
||||
@@ -74,7 +77,7 @@ func prepareTemplateData(course *models.Course, htmlCleaner *services.HTMLCleane
|
||||
Description: lesson.Description,
|
||||
}
|
||||
|
||||
if lesson.Type != "section" {
|
||||
if lesson.Type != lessonTypeSection {
|
||||
lessonCounter++
|
||||
section.Number = lessonCounter
|
||||
section.Items = prepareItems(lesson.Items, htmlCleaner)
|
||||
|
||||
@@ -40,35 +40,35 @@ func (e *MarkdownExporter) Export(course *models.Course, outputPath string) erro
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Write course header
|
||||
buf.WriteString(fmt.Sprintf("# %s\n\n", course.Course.Title))
|
||||
fmt.Fprintf(&buf, "# %s\n\n", course.Course.Title)
|
||||
|
||||
if course.Course.Description != "" {
|
||||
buf.WriteString(fmt.Sprintf("%s\n\n", e.htmlCleaner.CleanHTML(course.Course.Description)))
|
||||
fmt.Fprintf(&buf, "%s\n\n", e.htmlCleaner.CleanHTML(course.Course.Description))
|
||||
}
|
||||
|
||||
// Add metadata
|
||||
buf.WriteString("## Course Information\n\n")
|
||||
buf.WriteString(fmt.Sprintf("- **Course ID**: %s\n", course.Course.ID))
|
||||
buf.WriteString(fmt.Sprintf("- **Share ID**: %s\n", course.ShareID))
|
||||
buf.WriteString(fmt.Sprintf("- **Navigation Mode**: %s\n", course.Course.NavigationMode))
|
||||
fmt.Fprintf(&buf, "- **Course ID**: %s\n", course.Course.ID)
|
||||
fmt.Fprintf(&buf, "- **Share ID**: %s\n", course.ShareID)
|
||||
fmt.Fprintf(&buf, "- **Navigation Mode**: %s\n", course.Course.NavigationMode)
|
||||
if course.Course.ExportSettings != nil {
|
||||
buf.WriteString(fmt.Sprintf("- **Export Format**: %s\n", course.Course.ExportSettings.Format))
|
||||
fmt.Fprintf(&buf, "- **Export Format**: %s\n", course.Course.ExportSettings.Format)
|
||||
}
|
||||
buf.WriteString("\n---\n\n")
|
||||
|
||||
// Process lessons
|
||||
lessonCounter := 0
|
||||
for _, lesson := range course.Course.Lessons {
|
||||
if lesson.Type == "section" {
|
||||
buf.WriteString(fmt.Sprintf("# %s\n\n", lesson.Title))
|
||||
if lesson.Type == lessonTypeSection {
|
||||
fmt.Fprintf(&buf, "# %s\n\n", lesson.Title)
|
||||
continue
|
||||
}
|
||||
|
||||
lessonCounter++
|
||||
buf.WriteString(fmt.Sprintf("## Lesson %d: %s\n\n", lessonCounter, lesson.Title))
|
||||
fmt.Fprintf(&buf, "## Lesson %d: %s\n\n", lessonCounter, lesson.Title)
|
||||
|
||||
if lesson.Description != "" {
|
||||
buf.WriteString(fmt.Sprintf("%s\n\n", e.htmlCleaner.CleanHTML(lesson.Description)))
|
||||
fmt.Fprintf(&buf, "%s\n\n", e.htmlCleaner.CleanHTML(lesson.Description))
|
||||
}
|
||||
|
||||
// Process lesson items
|
||||
@@ -100,19 +100,19 @@ func (e *MarkdownExporter) processItemToMarkdown(buf *bytes.Buffer, item models.
|
||||
itemType := strings.ToLower(item.Type)
|
||||
|
||||
switch itemType {
|
||||
case "text":
|
||||
case itemTypeText:
|
||||
e.processTextItem(buf, item, headingPrefix)
|
||||
case "list":
|
||||
case itemTypeList:
|
||||
e.processListItem(buf, item)
|
||||
case "multimedia":
|
||||
case itemTypeMultimedia:
|
||||
e.processMultimediaItem(buf, item, headingPrefix)
|
||||
case "image":
|
||||
case itemTypeImage:
|
||||
e.processImageItem(buf, item, headingPrefix)
|
||||
case "knowledgecheck":
|
||||
case itemTypeKnowledgeCheck:
|
||||
e.processKnowledgeCheckItem(buf, item, headingPrefix)
|
||||
case "interactive":
|
||||
case itemTypeInteractive:
|
||||
e.processInteractiveItem(buf, item, headingPrefix)
|
||||
case "divider":
|
||||
case itemTypeDivider:
|
||||
e.processDividerItem(buf)
|
||||
default:
|
||||
e.processUnknownItem(buf, item, headingPrefix)
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user