chore: bump actions, reflow configs, fix examples

Bump codecov/codecov-action to v7 and docker/metadata-action
to v6 in the CI and release workflows.

Reflow .golangci.yml and html_styles.css under
the prettier plugin dprint now loads.

Exporter examples hand their export to the temp-dir helper instead of
pairing defer cleanup with log.Fatal. log.Fatal exits the process, so
the deferred cleanup never ran and a failed export left its temp dir
behind. gocritic reported it as exitAfterDefer.
This commit is contained in:
2026-09-21 10:10:40 +02:00
parent 7d3487312f
commit 76f8017ea7
5 changed files with 140 additions and 150 deletions
+2 -2
View File
@@ -286,7 +286,7 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY" } >> "$GITHUB_STEP_SUMMARY"
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v7
with: with:
files: ./coverage/coverage.out files: ./coverage/coverage.out
flags: Go ${{ env.GO_VERSION }} flags: Go ${{ env.GO_VERSION }}
@@ -401,7 +401,7 @@ jobs:
- name: Extract metadata - name: Extract metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
images: | images: |
${{ env.IMAGE_NAME }} ${{ env.IMAGE_NAME }}
+1 -1
View File
@@ -111,7 +111,7 @@ jobs:
- name: Extract metadata - name: Extract metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
images: | images: |
${{ env.IMAGE_NAME }} ${{ env.IMAGE_NAME }}
+10 -9
View File
@@ -346,15 +346,16 @@ linters:
# stylecheck settings # stylecheck settings
staticcheck: staticcheck:
checks: [ checks:
"all", [
"-ST1000", "all",
"-ST1003", "-ST1000",
"-ST1016", "-ST1003",
"-ST1020", "-ST1016",
"-ST1021", "-ST1020",
"-ST1022", "-ST1021",
] "-ST1022",
]
# maintidx settings # maintidx settings
maintidx: maintidx:
+18 -23
View File
@@ -12,15 +12,19 @@ import (
"github.com/kjanat/articulate-parser/internal/services" "github.com/kjanat/articulate-parser/internal/services"
) )
// tempOutput returns a path inside a fresh temp dir plus a cleanup func, so // exportToTemp runs export against a path in a fresh temp dir and removes the
// example exports don't pollute the package source tree. Example functions // dir afterwards. Example functions can't take *testing.T, so t.TempDir is
// can't take *testing.T, so t.TempDir is unavailable here. // unavailable here.
func tempOutput(name string) (path string, cleanup func()) { func exportToTemp(name string, export func(path string) error) {
dir, err := os.MkdirTemp("", "exporters-example-*") dir, err := os.MkdirTemp("", "exporters-example-*")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
return filepath.Join(dir, name), func() { _ = os.RemoveAll(dir) } err = export(filepath.Join(dir, name))
_ = os.RemoveAll(dir)
if err != nil {
log.Fatal(err)
}
} }
// ExampleNewFactory demonstrates creating an exporter factory. // ExampleNewFactory demonstrates creating an exporter factory.
@@ -82,12 +86,9 @@ func ExampleMarkdownExporter_Export() {
} }
// Export to markdown file // Export to markdown file
out, cleanup := tempOutput("output.md") exportToTemp("output.md", func(path string) error {
defer cleanup() return exporter.Export(course, path)
err := exporter.Export(course, out) })
if err != nil {
log.Fatal(err)
}
fmt.Println("Export complete") fmt.Println("Export complete")
// Output: Export complete // Output: Export complete
@@ -106,12 +107,9 @@ func ExampleDocxExporter_Export() {
} }
// Export to Word document // Export to Word document
out, cleanup := tempOutput("output.docx") exportToTemp("output.docx", func(path string) error {
defer cleanup() return exporter.Export(course, path)
err := exporter.Export(course, out) })
if err != nil {
log.Fatal(err)
}
fmt.Println("DOCX export complete") fmt.Println("DOCX export complete")
// Output: DOCX export complete // Output: DOCX export complete
@@ -138,12 +136,9 @@ func ExampleHTMLExporter_Export() {
} }
// Export to HTML file // Export to HTML file
out, cleanup := tempOutput("output.html") exportToTemp("output.html", func(path string) error {
defer cleanup() return exporter.Export(course, path)
err := exporter.Export(course, out) })
if err != nil {
log.Fatal(err)
}
fmt.Println("HTML export complete") fmt.Println("HTML export complete")
// Output: HTML export complete // Output: HTML export complete
+109 -115
View File
@@ -1,181 +1,175 @@
body { body {
font-family: font-family:
-apple-system, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
BlinkMacSystemFont, Cantarell, sans-serif;
"Segoe UI", line-height: 1.6;
Roboto, color: #333;
Oxygen, max-width: 800px;
Ubuntu, margin: 0 auto;
Cantarell, padding: 20px;
sans-serif; background-color: #f9f9f9;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f9f9f9;
} }
header { header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; color: white;
padding: 2rem; padding: 2rem;
border-radius: 10px; border-radius: 10px;
margin-bottom: 2rem; margin-bottom: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
} }
header h1 { header h1 {
margin: 0; margin: 0;
font-size: 2.5rem; font-size: 2.5rem;
font-weight: 300; font-weight: 300;
} }
.course-description { .course-description {
margin-top: 1rem; margin-top: 1rem;
font-size: 1.1rem; font-size: 1.1rem;
opacity: 0.9; opacity: 0.9;
} }
.course-info { .course-info {
background: white; background: white;
padding: 1.5rem; padding: 1.5rem;
border-radius: 8px; border-radius: 8px;
margin-bottom: 2rem; margin-bottom: 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
} }
.course-info h2 { .course-info h2 {
margin-top: 0; margin-top: 0;
color: #4a5568; color: #4a5568;
border-bottom: 2px solid #e2e8f0; border-bottom: 2px solid #e2e8f0;
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
.course-info ul { .course-info ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
} }
.course-info li { .course-info li {
margin: 0.5rem 0; margin: 0.5rem 0;
padding: 0.5rem; padding: 0.5rem;
background: #f7fafc; background: #f7fafc;
border-radius: 4px; border-radius: 4px;
} }
.course-section { .course-section {
background: #4299e1; background: #4299e1;
color: white; color: white;
padding: 1.5rem; padding: 1.5rem;
border-radius: 8px; border-radius: 8px;
margin: 2rem 0; margin: 2rem 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
} }
.course-section h2 { .course-section h2 {
margin: 0; margin: 0;
font-weight: 400; font-weight: 400;
} }
.lesson { .lesson {
background: white; background: white;
padding: 2rem; padding: 2rem;
border-radius: 8px; border-radius: 8px;
margin: 2rem 0; margin: 2rem 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-left: 4px solid #4299e1; border-left: 4px solid #4299e1;
} }
.lesson h3 { .lesson h3 {
margin-top: 0; margin-top: 0;
color: #2d3748; color: #2d3748;
font-size: 1.5rem; font-size: 1.5rem;
} }
.lesson-description { .lesson-description {
margin: 1rem 0; margin: 1rem 0;
padding: 1rem; padding: 1rem;
background: #f7fafc; background: #f7fafc;
border-radius: 4px; border-radius: 4px;
border-left: 3px solid #4299e1; border-left: 3px solid #4299e1;
} }
.item { .item {
margin: 1.5rem 0; margin: 1.5rem 0;
padding: 1rem; padding: 1rem;
border-radius: 6px; border-radius: 6px;
background: #fafafa; background: #fafafa;
border: 1px solid #e2e8f0; border: 1px solid #e2e8f0;
} }
.item h4 { .item h4 {
margin-top: 0; margin-top: 0;
color: #4a5568; color: #4a5568;
font-size: 1.2rem; font-size: 1.2rem;
text-transform: capitalize; text-transform: capitalize;
} }
.text-item { .text-item {
background: #f0fff4; background: #f0fff4;
border-left: 3px solid #48bb78; border-left: 3px solid #48bb78;
} }
.list-item { .list-item {
background: #fffaf0; background: #fffaf0;
border-left: 3px solid #ed8936; border-left: 3px solid #ed8936;
} }
.knowledge-check { .knowledge-check {
background: #e6fffa; background: #e6fffa;
border-left: 3px solid #38b2ac; border-left: 3px solid #38b2ac;
} }
.multimedia-item { .multimedia-item {
background: #faf5ff; background: #faf5ff;
border-left: 3px solid #9f7aea; border-left: 3px solid #9f7aea;
} }
.interactive-item { .interactive-item {
background: #fff5f5; background: #fff5f5;
border-left: 3px solid #f56565; border-left: 3px solid #f56565;
} }
.unknown-item { .unknown-item {
background: #f7fafc; background: #f7fafc;
border-left: 3px solid #a0aec0; border-left: 3px solid #a0aec0;
} }
.answers { .answers {
margin: 1rem 0; margin: 1rem 0;
} }
.answers h5 { .answers h5 {
margin: 0.5rem 0; margin: 0.5rem 0;
color: #4a5568; color: #4a5568;
} }
.answers ol { .answers ol {
margin: 0.5rem 0; margin: 0.5rem 0;
padding-left: 1.5rem; padding-left: 1.5rem;
} }
.answers li { .answers li {
margin: 0.3rem 0; margin: 0.3rem 0;
padding: 0.3rem; padding: 0.3rem;
} }
.correct-answer { .correct-answer {
background: #c6f6d5; background: #c6f6d5;
border-radius: 3px; border-radius: 3px;
font-weight: bold; font-weight: bold;
} }
.correct-answer::after { .correct-answer::after {
content: " ✓"; content: " ✓";
color: #38a169; color: #38a169;
} }
.feedback { .feedback {
margin: 1rem 0; margin: 1rem 0;
padding: 1rem; padding: 1rem;
background: #edf2f7; background: #edf2f7;
border-radius: 4px; border-radius: 4px;
border-left: 3px solid #4299e1; border-left: 3px solid #4299e1;
font-style: italic; font-style: italic;
} }
.media-info { .media-info {
background: #edf2f7; background: #edf2f7;
padding: 1rem; padding: 1rem;
border-radius: 4px; border-radius: 4px;
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.media-info strong { .media-info strong {
color: #4a5568; color: #4a5568;
} }
hr { hr {
border: none; border: none;
height: 2px; height: 2px;
background: linear-gradient(to right, #667eea, #764ba2); background: linear-gradient(to right, #667eea, #764ba2);
margin: 2rem 0; margin: 2rem 0;
border-radius: 1px; border-radius: 1px;
} }
ul { ul {
padding-left: 1.5rem; padding-left: 1.5rem;
} }
li { li {
margin: 0.5rem 0; margin: 0.5rem 0;
} }