mirror of
https://github.com/kjanat/articulate-parser.git
synced 2026-01-16 11:42:09 +01:00
chore: update actions/checkout to v6, improve AGENTS.md
This commit is contained in:
8
.github/workflows/autofix.yml
vendored
8
.github/workflows/autofix.yml
vendored
@ -2,7 +2,7 @@ name: autofix.ci
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches: [ "master" ]
|
branches: ["master"]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
@ -11,13 +11,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install Task
|
- name: Install Task
|
||||||
uses: go-task/setup-task@v1
|
uses: go-task/setup-task@v1
|
||||||
|
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with: { go-version-file: 'go.mod' }
|
with: { go-version-file: "go.mod" }
|
||||||
|
|
||||||
- name: Setup go deps
|
- name: Setup go deps
|
||||||
run: |
|
run: |
|
||||||
@ -34,7 +34,7 @@ jobs:
|
|||||||
run: golangci-lint run --fix
|
run: golangci-lint run --fix
|
||||||
|
|
||||||
- name: Run golangci-lint format
|
- name: Run golangci-lint format
|
||||||
run: golangci-lint format
|
run: golangci-lint fmt
|
||||||
|
|
||||||
- name: Run go mod tidy
|
- name: Run go mod tidy
|
||||||
run: go mod tidy
|
run: go mod tidy
|
||||||
|
|||||||
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@ -2,7 +2,7 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ['master', 'develop']
|
branches: ["master", "develop"]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@ -21,12 +21,12 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
pull-requests: read
|
pull-requests: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: stable
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v8
|
uses: golangci/golangci-lint-action@v9
|
||||||
with: { version: latest }
|
with: { version: latest }
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@ -45,7 +45,7 @@ jobs:
|
|||||||
- 1.25.x
|
- 1.25.x
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up Go ${{ matrix.go }}
|
- name: Set up Go ${{ matrix.go }}
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
@ -206,7 +206,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload test artifacts
|
- name: Upload test artifacts
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: test-results-go-${{ matrix.go }}
|
name: test-results-go-${{ matrix.go }}
|
||||||
path: |
|
path: |
|
||||||
@ -297,7 +297,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v6
|
uses: actions/setup-go@v6
|
||||||
@ -342,10 +342,10 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: "Checkout Repository"
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: 'Dependency Review'
|
- name: "Dependency Review"
|
||||||
uses: actions/dependency-review-action@v4
|
uses: actions/dependency-review-action@v4
|
||||||
with:
|
with:
|
||||||
fail-on-severity: moderate
|
fail-on-severity: moderate
|
||||||
@ -364,7 +364,7 @@ jobs:
|
|||||||
startsWith(github.ref, 'refs/heads/feature/docker'))
|
startsWith(github.ref, 'refs/heads/feature/docker'))
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -61,7 +61,7 @@ jobs:
|
|||||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||||
|
|||||||
2
.github/workflows/dependency-review.yml
vendored
2
.github/workflows/dependency-review.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: 'Dependency Review'
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@v4
|
uses: actions/dependency-review-action@v4
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
158
AGENTS.md
158
AGENTS.md
@ -1,56 +1,178 @@
|
|||||||
# Agent Guidelines for articulate-parser
|
# Agent Guidelines for articulate-parser
|
||||||
|
|
||||||
|
A Go CLI tool that parses Articulate Rise courses from URLs or local JSON files and exports them to Markdown, HTML, or DOCX formats.
|
||||||
|
|
||||||
## Build/Test Commands
|
## Build/Test Commands
|
||||||
- **Build**: `task build` or `go build -o bin/articulate-parser main.go`
|
|
||||||
- **Run tests**: `task test` or `go test -race -timeout 5m ./...`
|
### Primary Commands (using Taskfile)
|
||||||
- **Run single test**: `go test -v -race -run ^TestName$ ./path/to/package`
|
|
||||||
- **Test with coverage**:
|
```bash
|
||||||
- `task test:coverage` or
|
task build # Build binary to bin/articulate-parser
|
||||||
- `go test -race -coverprofile=coverage/coverage.out -covermode=atomic ./...`
|
task test # Run all tests with race detection
|
||||||
- **Lint**: `task lint` (runs vet, fmt check, staticcheck, golangci-lint)
|
task lint # Run all linters (vet, fmt, staticcheck, golangci-lint)
|
||||||
- **Format**: `task fmt` or `gofmt -s -w .`
|
task fmt # Format all Go files
|
||||||
- **CI checks**: `task ci` (deps, lint, test with coverage, build)
|
task ci # Full CI pipeline: deps, lint, test with coverage, build
|
||||||
|
task qa # Quick QA: fmt + lint + test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Direct Go Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build
|
||||||
|
go build -o bin/articulate-parser main.go
|
||||||
|
|
||||||
|
# Run all tests
|
||||||
|
go test -race -timeout 5m ./...
|
||||||
|
|
||||||
|
# Run single test by name
|
||||||
|
go test -v -race -run ^TestMarkdownExporter_Export$ ./internal/exporters
|
||||||
|
|
||||||
|
# Run tests in specific package
|
||||||
|
go test -v -race ./internal/services
|
||||||
|
|
||||||
|
# Run tests matching pattern
|
||||||
|
go test -v -race -run "TestParser" ./...
|
||||||
|
|
||||||
|
# Test with coverage
|
||||||
|
go test -race -coverprofile=coverage/coverage.out -covermode=atomic ./...
|
||||||
|
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
|
||||||
|
|
||||||
|
# Benchmarks
|
||||||
|
go test -bench=. -benchmem ./...
|
||||||
|
go test -bench=BenchmarkMarkdownExporter ./internal/exporters
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security & Auditing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
task security:check # Run gosec security scanner
|
||||||
|
task security:audit # Run govulncheck for vulnerabilities
|
||||||
|
```
|
||||||
|
|
||||||
## Code Style Guidelines
|
## Code Style Guidelines
|
||||||
|
|
||||||
### Imports
|
### Imports
|
||||||
|
|
||||||
- Use `goimports` with local prefix: `github.com/kjanat/articulate-parser`
|
- Use `goimports` with local prefix: `github.com/kjanat/articulate-parser`
|
||||||
- Order: stdlib, external, internal packages
|
- Order: stdlib, blank line, external packages, blank line, internal packages
|
||||||
- Group related imports together
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fumiama/go-docx"
|
||||||
|
|
||||||
|
"github.com/kjanat/articulate-parser/internal/interfaces"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
### Formatting
|
### Formatting
|
||||||
|
|
||||||
- Use `gofmt -s` (simplify) and `gofumpt` with extra rules
|
- Use `gofmt -s` (simplify) and `gofumpt` with extra rules
|
||||||
- Function length: max 100 lines, 50 statements
|
- Function length: max 100 lines, 50 statements
|
||||||
- Cyclomatic complexity: max 15
|
- Cyclomatic complexity: max 15; Cognitive complexity: max 20
|
||||||
- Cognitive complexity: max 20
|
|
||||||
|
|
||||||
### Types & Naming
|
### Types & Naming
|
||||||
|
|
||||||
- Use interface-based design (see `internal/interfaces/`)
|
- Use interface-based design (see `internal/interfaces/`)
|
||||||
- Export types/functions with clear godoc comments ending with period
|
- Exported types/functions require godoc comments ending with period
|
||||||
- Use descriptive names: `ArticulateParser`, `MarkdownExporter`
|
- Use descriptive names: `ArticulateParser`, `MarkdownExporter`
|
||||||
- Receiver names: short (1-2 chars), consistent per type
|
- Receiver names: short (1-2 chars), consistent per type
|
||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
- Always wrap errors with context: `fmt.Errorf("operation failed: %w", err)`
|
- Always wrap errors with context: `fmt.Errorf("operation failed: %w", err)`
|
||||||
- Use `%w` verb for error wrapping to preserve error chain
|
- Use `%w` verb for error wrapping to preserve error chain
|
||||||
- Check all error returns (enforced by `errcheck`)
|
- Check all error returns (enforced by `errcheck`)
|
||||||
- Document error handling rationale in defer blocks when ignoring close errors
|
- Document error handling rationale in defer blocks when ignoring close errors
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Good: Error wrapping with context
|
||||||
|
if err := json.Unmarshal(body, &course); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good: Documented defer with error handling
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
p.Logger.Warn("failed to close response body", "error", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
```
|
||||||
|
|
||||||
### Comments
|
### Comments
|
||||||
|
|
||||||
- All exported types/functions require godoc comments
|
- All exported types/functions require godoc comments
|
||||||
- End sentences with periods (`godot` linter enforced)
|
- End sentences with periods (`godot` linter enforced)
|
||||||
- Mark known issues with TODO/FIXME/HACK/BUG/XXX
|
- Mark known issues with TODO/FIXME/HACK/BUG/XXX
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Use `#nosec` with justification for deliberate security exceptions (G304 for CLI file paths, G306 for export file permissions)
|
|
||||||
- Run `gosec` and `govulncheck` for security audits
|
- Use `#nosec` with justification for deliberate security exceptions
|
||||||
|
- G304: File paths from CLI args; G306: Export file permissions
|
||||||
|
|
||||||
|
```go
|
||||||
|
// #nosec G304 - File path provided by user via CLI argument
|
||||||
|
data, err := os.ReadFile(filePath)
|
||||||
|
```
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
- Enable race detection: `-race` flag
|
|
||||||
|
- Enable race detection: `-race` flag always
|
||||||
- Use table-driven tests where applicable
|
- Use table-driven tests where applicable
|
||||||
- Mark test helpers with `t.Helper()`
|
- Mark test helpers with `t.Helper()`
|
||||||
|
- Use `t.TempDir()` for temporary files
|
||||||
- Benchmarks in `*_bench_test.go`, examples in `*_example_test.go`
|
- Benchmarks in `*_bench_test.go`, examples in `*_example_test.go`
|
||||||
|
- Test naming: `Test<Type>_<Method>` or `Test<Function>`
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TestMarkdownExporter_ProcessItemToMarkdown_AllTypes(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name, itemType, expectedText string
|
||||||
|
}{
|
||||||
|
{"text item", "text", ""},
|
||||||
|
{"divider item", "divider", "---"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// test implementation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
- Minimal external dependencies (currently: go-docx, golang.org/x/net, golang.org/x/text)
|
|
||||||
|
- Minimal external dependencies (go-docx, golang.org/x/net, golang.org/x/text)
|
||||||
- Run `task deps:tidy` after adding/removing dependencies
|
- Run `task deps:tidy` after adding/removing dependencies
|
||||||
|
- CGO disabled by default (`CGO_ENABLED=0`)
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
articulate-parser/
|
||||||
|
internal/
|
||||||
|
config/ # Configuration loading
|
||||||
|
exporters/ # Export implementations (markdown, html, docx)
|
||||||
|
interfaces/ # Core interfaces (Exporter, CourseParser, Logger)
|
||||||
|
models/ # Data models (Course, Lesson, Item, Media)
|
||||||
|
services/ # Core services (parser, html cleaner, app, logger)
|
||||||
|
version/ # Version information
|
||||||
|
main.go # Application entry point
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Creating a new exporter
|
||||||
|
|
||||||
|
1. Implement `interfaces.Exporter` interface
|
||||||
|
2. Add factory method to `internal/exporters/factory.go`
|
||||||
|
3. Register format in `NewFactory()`
|
||||||
|
4. Add tests following existing patterns
|
||||||
|
|
||||||
|
### Adding configuration options
|
||||||
|
|
||||||
|
1. Add field to `Config` struct in `internal/config/config.go`
|
||||||
|
2. Load from environment variable with sensible default
|
||||||
|
3. Document in config struct comments
|
||||||
|
|||||||
Reference in New Issue
Block a user