mirror of
https://github.com/kjanat/articulate-parser.git
synced 2026-01-16 07:42:09 +01:00
chore(build): introduce go-task for project automation
Adds a comprehensive Taskfile.yml to centralize all project scripts for building, testing, linting, and Docker image management. The GitHub Actions CI workflow is refactored to utilize these `task` commands, resulting in a cleaner, more readable, and maintainable configuration. This approach ensures consistency between local development and CI environments.
This commit is contained in:
114
.github/workflows/ci.yml
vendored
114
.github/workflows/ci.yml
vendored
@ -37,47 +37,17 @@ jobs:
|
||||
go-version: ${{ matrix.go }}
|
||||
check-latest: true
|
||||
|
||||
- name: Download dependencies with retry
|
||||
run: |
|
||||
set -e
|
||||
echo "Downloading Go dependencies..."
|
||||
- name: Install Task
|
||||
uses: go-task/setup-task@v1
|
||||
|
||||
# Function to download with retry
|
||||
download_with_retry() {
|
||||
local attempt=1
|
||||
local max_attempts=3
|
||||
- name: Show build info
|
||||
run: task info
|
||||
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
echo "Attempt $attempt of $max_attempts"
|
||||
|
||||
if go mod download; then
|
||||
echo "Download successful on attempt $attempt"
|
||||
return 0
|
||||
else
|
||||
echo "Download failed on attempt $attempt"
|
||||
if [ $attempt -lt $max_attempts ]; then
|
||||
echo "Cleaning cache and retrying..."
|
||||
go clean -modcache
|
||||
go clean -cache
|
||||
sleep 2
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "All download attempts failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Try download with retry logic
|
||||
download_with_retry
|
||||
|
||||
echo "Verifying module dependencies..."
|
||||
go mod verify
|
||||
echo "Dependencies verified successfully"
|
||||
- name: Download dependencies
|
||||
run: task deps
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
run: task build
|
||||
|
||||
- name: Run tests with enhanced reporting
|
||||
id: test
|
||||
@ -89,7 +59,7 @@ jobs:
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo "Running tests with coverage..."
|
||||
go test -v -race -coverprofile=coverage.out ./... 2>&1 | tee test-output.log
|
||||
task test:coverage 2>&1 | tee test-output.log
|
||||
|
||||
# Extract test results for summary
|
||||
TEST_STATUS=$?
|
||||
@ -151,9 +121,8 @@ jobs:
|
||||
- name: Generate coverage report
|
||||
if: always()
|
||||
run: |
|
||||
if [ -f coverage.out ]; then
|
||||
go tool cover -html=coverage.out -o coverage.html
|
||||
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}')
|
||||
if [ -f coverage/coverage.out ]; then
|
||||
COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}')
|
||||
|
||||
echo "## 📊 Code Coverage (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
@ -171,7 +140,7 @@ jobs:
|
||||
temp_coverage=$(mktemp)
|
||||
|
||||
# Extract package-level coverage data
|
||||
go tool cover -func=coverage.out | grep -v total | while read line; do
|
||||
go tool cover -func=coverage/coverage.out | grep -v total | while read line; do
|
||||
if [[ $line == *".go:"* ]]; then
|
||||
# Extract package path from file path (everything before the filename)
|
||||
filepath=$(echo "$line" | awk '{print $1}')
|
||||
@ -217,16 +186,16 @@ jobs:
|
||||
name: test-results-go-${{ matrix.go }}
|
||||
path: |
|
||||
test-output.log
|
||||
coverage.out
|
||||
coverage.html
|
||||
coverage/
|
||||
retention-days: 7
|
||||
|
||||
- name: Run go vet
|
||||
- name: Run linters
|
||||
run: |
|
||||
echo "## 🔍 Static Analysis (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
VET_OUTPUT=$(go vet ./... 2>&1 || echo "")
|
||||
# Run go vet
|
||||
VET_OUTPUT=$(task lint:vet 2>&1 || echo "")
|
||||
VET_STATUS=$?
|
||||
|
||||
if [ $VET_STATUS -eq 0 ]; then
|
||||
@ -240,13 +209,11 @@ jobs:
|
||||
fi
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
exit $VET_STATUS
|
||||
# Run go fmt check
|
||||
FMT_OUTPUT=$(task lint:fmt 2>&1 || echo "")
|
||||
FMT_STATUS=$?
|
||||
|
||||
- name: Run go fmt
|
||||
run: |
|
||||
FMT_OUTPUT=$(gofmt -s -l . 2>&1 || echo "")
|
||||
|
||||
if [ -z "$FMT_OUTPUT" ]; then
|
||||
if [ $FMT_STATUS -eq 0 ]; then
|
||||
echo "✅ **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "❌ **go fmt:** Files need formatting" >> $GITHUB_STEP_SUMMARY
|
||||
@ -254,7 +221,10 @@ jobs:
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
# Exit with error if any linter failed
|
||||
if [ $VET_STATUS -ne 0 ] || [ $FMT_STATUS -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -276,6 +246,7 @@ jobs:
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./coverage/coverage.out
|
||||
flags: Go ${{ matrix.go }}
|
||||
slug: kjanat/articulate-parser
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@ -297,40 +268,37 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
- name: Install Task
|
||||
uses: go-task/setup-task@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Capture build date
|
||||
run: echo "BUILD_TIME=$(git log -1 --format=%cd --date=iso-strict)" >> $GITHUB_ENV
|
||||
- name: Build Docker image using Task
|
||||
run: task docker:build
|
||||
|
||||
- name: Build Docker image (test)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
load: true
|
||||
tags: test:latest
|
||||
build-args: |
|
||||
VERSION=test
|
||||
BUILD_TIME=${{ env.BUILD_TIME }}
|
||||
GIT_COMMIT=${{ github.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Test Docker image
|
||||
- name: Test Docker image using Task
|
||||
run: |
|
||||
echo "## 🧪 Docker Image Tests" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# Test that the image runs and shows help
|
||||
# Run Task docker test
|
||||
task docker:test
|
||||
|
||||
echo "**Testing help command:**" >> $GITHUB_STEP_SUMMARY
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
docker run --rm test:latest --help >> $GITHUB_STEP_SUMMARY
|
||||
docker run --rm articulate-parser:latest --help >> $GITHUB_STEP_SUMMARY
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# Test image size
|
||||
IMAGE_SIZE=$(docker image inspect test:latest --format='{{.Size}}' | numfmt --to=iec-i --suffix=B)
|
||||
IMAGE_SIZE=$(docker image inspect articulate-parser:latest --format='{{.Size}}' | numfmt --to=iec-i --suffix=B)
|
||||
echo "**Image size:** $IMAGE_SIZE" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -69,3 +69,5 @@ main_coverage
|
||||
# Editors
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
.task/
|
||||
|
||||
@ -49,7 +49,7 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
|
||||
RUN file /app/articulate-parser || echo "file command not available"
|
||||
|
||||
# Development stage - uses Alpine for shell access
|
||||
FROM alpine:3.22.1
|
||||
FROM alpine:3
|
||||
|
||||
# Install minimal dependencies
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
|
||||
571
Taskfile.yml
Normal file
571
Taskfile.yml
Normal file
@ -0,0 +1,571 @@
|
||||
# yaml-language-server: $schema=https://taskfile.dev/schema.json
|
||||
# Articulate Parser - Task Automation
|
||||
# https://taskfile.dev
|
||||
version: '3'
|
||||
|
||||
# Global output settings
|
||||
output: prefixed
|
||||
|
||||
# Shell settings (only applied on Unix-like systems)
|
||||
# Note: These are ignored on Windows where PowerShell/cmd is used
|
||||
set: [errexit, pipefail]
|
||||
shopt: [globstar]
|
||||
|
||||
# Watch mode interval
|
||||
interval: 500ms
|
||||
|
||||
# Global variables
|
||||
vars:
|
||||
APP_NAME: articulate-parser
|
||||
MAIN_FILE: main.go
|
||||
OUTPUT_DIR: bin
|
||||
COVERAGE_DIR: coverage
|
||||
TEST_TIMEOUT: 5m
|
||||
|
||||
# Version info
|
||||
VERSION:
|
||||
sh: git describe --tags --always --dirty 2>/dev/null || echo "dev"
|
||||
GIT_COMMIT:
|
||||
sh: git rev-parse --short HEAD 2>/dev/null || echo "unknown"
|
||||
BUILD_TIME: '{{now | date "2006-01-02T15:04:05Z07:00"}}'
|
||||
|
||||
# Go settings
|
||||
CGO_ENABLED: 0
|
||||
GO_FLAGS: -v
|
||||
LDFLAGS: >-
|
||||
-s -w
|
||||
-X github.com/kjanat/articulate-parser/internal/version.Version={{.VERSION}}
|
||||
-X github.com/kjanat/articulate-parser/internal/version.BuildTime={{.BUILD_TIME}}
|
||||
-X github.com/kjanat/articulate-parser/internal/version.GitCommit={{.GIT_COMMIT}}
|
||||
|
||||
# Platform detection (using Task built-in variables)
|
||||
GOOS:
|
||||
sh: go env GOOS
|
||||
GOARCH:
|
||||
sh: go env GOARCH
|
||||
EXE_EXT: '{{if eq OS "windows"}}.exe{{end}}'
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
CGO_ENABLED: '{{.CGO_ENABLED}}'
|
||||
GO111MODULE: on
|
||||
|
||||
# Load .env files if present
|
||||
dotenv: ['.env', '.env.local']
|
||||
|
||||
# Task definitions
|
||||
tasks:
|
||||
# Default task - show help
|
||||
default:
|
||||
desc: Show available tasks
|
||||
cmds:
|
||||
- task --list
|
||||
silent: true
|
||||
|
||||
# Development tasks
|
||||
dev:
|
||||
desc: Run the application in development mode (with hot reload)
|
||||
aliases: [run, start]
|
||||
interactive: true
|
||||
watch: true
|
||||
sources:
|
||||
- '**/*.go'
|
||||
- go.mod
|
||||
- go.sum
|
||||
cmds:
|
||||
- task: build
|
||||
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} --help'
|
||||
|
||||
# Build tasks
|
||||
build:
|
||||
desc: Build the application binary
|
||||
aliases: [b]
|
||||
deps: [clean-bin]
|
||||
sources:
|
||||
- '**/*.go'
|
||||
- go.mod
|
||||
- go.sum
|
||||
generates:
|
||||
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}}'
|
||||
cmds:
|
||||
- task: mkdir
|
||||
vars: { DIR: '{{.OUTPUT_DIR}}' }
|
||||
- go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o {{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} {{.MAIN_FILE}}
|
||||
method: checksum
|
||||
|
||||
build:all:
|
||||
desc: Build binaries for all major platforms
|
||||
aliases: [build-all, cross-compile]
|
||||
deps: [clean-bin]
|
||||
cmds:
|
||||
- task: mkdir
|
||||
vars: { DIR: '{{.OUTPUT_DIR}}' }
|
||||
- for:
|
||||
matrix:
|
||||
GOOS: [linux, darwin, windows]
|
||||
GOARCH: [amd64, arm64]
|
||||
task: build:platform
|
||||
vars:
|
||||
TARGET_GOOS: '{{.ITEM.GOOS}}'
|
||||
TARGET_GOARCH: '{{.ITEM.GOARCH}}'
|
||||
- echo "Built binaries for all platforms in {{.OUTPUT_DIR}}/"
|
||||
|
||||
build:platform:
|
||||
internal: true
|
||||
vars:
|
||||
TARGET_EXT: '{{if eq .TARGET_GOOS "windows"}}.exe{{end}}'
|
||||
OUTPUT_FILE: '{{.OUTPUT_DIR}}/{{.APP_NAME}}-{{.TARGET_GOOS}}-{{.TARGET_GOARCH}}{{.TARGET_EXT}}'
|
||||
env:
|
||||
GOOS: '{{.TARGET_GOOS}}'
|
||||
GOARCH: '{{.TARGET_GOARCH}}'
|
||||
cmds:
|
||||
- echo "Building {{.OUTPUT_FILE}}..."
|
||||
- go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o "{{.OUTPUT_FILE}}" {{.MAIN_FILE}}
|
||||
|
||||
# Install task
|
||||
install:
|
||||
desc: Install the binary to $GOPATH/bin
|
||||
deps: [test]
|
||||
cmds:
|
||||
- go install -ldflags="{{.LDFLAGS}}" {{.MAIN_FILE}}
|
||||
- echo "Installed {{.APP_NAME}} to $(go env GOPATH)/bin"
|
||||
|
||||
# Testing tasks
|
||||
test:
|
||||
desc: Run all tests
|
||||
aliases: [t]
|
||||
cmds:
|
||||
- go test {{.GO_FLAGS}} -race -timeout {{.TEST_TIMEOUT}} ./...
|
||||
|
||||
test:coverage:
|
||||
desc: Run tests with coverage report
|
||||
aliases: [cover, cov]
|
||||
deps: [clean-coverage]
|
||||
cmds:
|
||||
- task: mkdir
|
||||
vars: { DIR: '{{.COVERAGE_DIR}}' }
|
||||
- go test {{.GO_FLAGS}} -race -coverprofile={{.COVERAGE_DIR}}/coverage.out -covermode=atomic -timeout {{.TEST_TIMEOUT}} ./...
|
||||
- go tool cover -html={{.COVERAGE_DIR}}/coverage.out -o {{.COVERAGE_DIR}}/coverage.html
|
||||
- go tool cover -func={{.COVERAGE_DIR}}/coverage.out
|
||||
- echo "Coverage report generated at {{.COVERAGE_DIR}}/coverage.html"
|
||||
|
||||
test:verbose:
|
||||
desc: Run tests with verbose output
|
||||
aliases: [tv]
|
||||
cmds:
|
||||
- go test -v -race -timeout {{.TEST_TIMEOUT}} ./...
|
||||
|
||||
test:watch:
|
||||
desc: Run tests in watch mode
|
||||
aliases: [tw]
|
||||
watch: true
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- task: test
|
||||
|
||||
test:bench:
|
||||
desc: Run benchmark tests
|
||||
aliases: [bench]
|
||||
cmds:
|
||||
- go test -bench=. -benchmem -timeout {{.TEST_TIMEOUT}} ./...
|
||||
|
||||
test:integration:
|
||||
desc: Run integration tests
|
||||
status:
|
||||
- '{{if eq OS "windows"}}if not exist "main_test.go" exit 1{{else}}test ! -f "main_test.go"{{end}}'
|
||||
cmds:
|
||||
- go test -v -race -tags=integration -timeout {{.TEST_TIMEOUT}} ./...
|
||||
|
||||
# Code quality tasks
|
||||
lint:
|
||||
desc: Run all linters
|
||||
aliases: [l]
|
||||
cmds:
|
||||
- task: lint:vet
|
||||
- task: lint:fmt
|
||||
- task: lint:staticcheck
|
||||
|
||||
lint:vet:
|
||||
desc: Run go vet
|
||||
cmds:
|
||||
- go vet ./...
|
||||
|
||||
lint:fmt:
|
||||
desc: Check code formatting
|
||||
vars:
|
||||
UNFORMATTED:
|
||||
sh: gofmt -s -l .
|
||||
cmds:
|
||||
- |
|
||||
{{if ne .UNFORMATTED ""}}
|
||||
echo "❌ The following files need formatting:"
|
||||
echo "{{.UNFORMATTED}}"
|
||||
exit 1
|
||||
{{else}}
|
||||
echo "All files are properly formatted"
|
||||
{{end}}
|
||||
|
||||
lint:staticcheck:
|
||||
desc: Run staticcheck (install if needed)
|
||||
vars:
|
||||
HAS_STATICCHECK:
|
||||
sh: '{{if eq OS "windows"}}where staticcheck 2>NUL{{else}}command -v staticcheck 2>/dev/null{{end}}'
|
||||
cmds:
|
||||
- '{{if eq .HAS_STATICCHECK ""}}echo "Installing staticcheck..." && go install honnef.co/go/tools/cmd/staticcheck@latest{{end}}'
|
||||
- staticcheck ./...
|
||||
ignore_error: true
|
||||
|
||||
fmt:
|
||||
desc: Format all Go files
|
||||
aliases: [format]
|
||||
cmds:
|
||||
- gofmt -s -w .
|
||||
- echo "Formatted all Go files"
|
||||
|
||||
modernize:
|
||||
desc: Modernize Go code to use modern idioms
|
||||
aliases: [modern]
|
||||
cmds:
|
||||
- go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
|
||||
- echo "Code modernized"
|
||||
|
||||
# Dependency management
|
||||
deps:
|
||||
desc: Download and verify dependencies
|
||||
aliases: [mod]
|
||||
cmds:
|
||||
- go mod download
|
||||
- go mod verify
|
||||
- echo "Dependencies downloaded and verified"
|
||||
|
||||
deps:tidy:
|
||||
desc: Tidy go.mod and go.sum
|
||||
aliases: [tidy]
|
||||
cmds:
|
||||
- go mod tidy
|
||||
- echo "Dependencies tidied"
|
||||
|
||||
deps:update:
|
||||
desc: Update all dependencies to latest versions
|
||||
aliases: [update]
|
||||
cmds:
|
||||
- go get -u ./...
|
||||
- go mod tidy
|
||||
- echo "Dependencies updated"
|
||||
|
||||
deps:graph:
|
||||
desc: Display dependency graph
|
||||
cmds:
|
||||
- go mod graph
|
||||
|
||||
# Docker tasks
|
||||
docker:build:
|
||||
desc: Build Docker image
|
||||
aliases: [db]
|
||||
cmds:
|
||||
- |
|
||||
docker build \
|
||||
--build-arg VERSION={{.VERSION}} \
|
||||
--build-arg BUILD_TIME={{.BUILD_TIME}} \
|
||||
--build-arg GIT_COMMIT={{.GIT_COMMIT}} \
|
||||
-t {{.APP_NAME}}:{{.VERSION}} \
|
||||
-t {{.APP_NAME}}:latest \
|
||||
.
|
||||
- >
|
||||
echo "Docker image built: {{.APP_NAME}}:{{.VERSION}}"
|
||||
|
||||
docker:build:dev:
|
||||
desc: Build development Docker image
|
||||
cmds:
|
||||
- docker build -f Dockerfile.dev -t {{.APP_NAME}}:dev .
|
||||
- >
|
||||
echo "Development Docker image built: {{.APP_NAME}}:dev"
|
||||
|
||||
docker:run:
|
||||
desc: Run Docker container
|
||||
aliases: [dr]
|
||||
deps: [docker:build]
|
||||
cmds:
|
||||
- docker run --rm {{.APP_NAME}}:{{.VERSION}} --help
|
||||
|
||||
docker:test:
|
||||
desc: Test Docker image
|
||||
deps: [docker:build]
|
||||
cmds:
|
||||
- docker run --rm {{.APP_NAME}}:{{.VERSION}} --version
|
||||
- echo "Docker image tested successfully"
|
||||
|
||||
docker:compose:up:
|
||||
desc: Start services with docker-compose
|
||||
cmds:
|
||||
- docker-compose up -d
|
||||
|
||||
docker:compose:down:
|
||||
desc: Stop services with docker-compose
|
||||
cmds:
|
||||
- docker-compose down
|
||||
|
||||
# Cleanup tasks
|
||||
clean:
|
||||
desc: Clean all generated files
|
||||
aliases: [c]
|
||||
cmds:
|
||||
- task: clean-bin
|
||||
- task: clean-coverage
|
||||
- task: clean-cache
|
||||
- echo "All generated files cleaned"
|
||||
|
||||
clean-bin:
|
||||
desc: Remove built binaries
|
||||
internal: true
|
||||
cmds:
|
||||
- task: rmdir
|
||||
vars: { DIR: '{{.OUTPUT_DIR}}' }
|
||||
|
||||
clean-coverage:
|
||||
desc: Remove coverage files
|
||||
internal: true
|
||||
cmds:
|
||||
- task: rmdir
|
||||
vars: { DIR: '{{.COVERAGE_DIR}}' }
|
||||
|
||||
clean-cache:
|
||||
desc: Clean Go build and test cache
|
||||
cmds:
|
||||
- go clean -cache -testcache -modcache
|
||||
- echo "Go caches cleaned"
|
||||
|
||||
# CI/CD tasks
|
||||
ci:
|
||||
desc: Run all CI checks (test, lint, build)
|
||||
cmds:
|
||||
- task: deps
|
||||
- task: lint
|
||||
- task: test:coverage
|
||||
- task: build
|
||||
- echo "All CI checks passed"
|
||||
|
||||
ci:local:
|
||||
desc: Run CI checks locally with detailed output
|
||||
cmds:
|
||||
- echo "🔍 Running local CI checks..."
|
||||
- echo ""
|
||||
- echo "📦 Checking dependencies..."
|
||||
- task: deps
|
||||
- echo ""
|
||||
- echo "🔧 Running linters..."
|
||||
- task: lint
|
||||
- echo ""
|
||||
- echo "🧪 Running tests with coverage..."
|
||||
- task: test:coverage
|
||||
- echo ""
|
||||
- echo "🏗️ Building application..."
|
||||
- task: build:all
|
||||
- echo ""
|
||||
- echo "All CI checks completed successfully!"
|
||||
|
||||
# Release tasks
|
||||
release:check:
|
||||
desc: Check if ready for release
|
||||
cmds:
|
||||
- task: ci
|
||||
- git diff --exit-code
|
||||
- git diff --cached --exit-code
|
||||
- echo "Ready for release"
|
||||
|
||||
release:tag:
|
||||
desc: Tag a new release (requires VERSION env var)
|
||||
requires:
|
||||
vars: [VERSION]
|
||||
preconditions:
|
||||
- sh: 'git diff --exit-code'
|
||||
msg: 'Working directory is not clean'
|
||||
- sh: 'git diff --cached --exit-code'
|
||||
msg: 'Staging area is not clean'
|
||||
cmds:
|
||||
- git tag -a v{{.VERSION}} -m "Release v{{.VERSION}}"
|
||||
- echo "Tagged v{{.VERSION}}"
|
||||
- >
|
||||
echo "Push with: git push origin v{{.VERSION}}"
|
||||
|
||||
# Documentation tasks
|
||||
docs:serve:
|
||||
desc: Serve documentation locally
|
||||
vars:
|
||||
HAS_GODOC:
|
||||
sh: '{{if eq OS "windows"}}where godoc 2>NUL{{else}}command -v godoc 2>/dev/null{{end}}'
|
||||
cmds:
|
||||
- '{{if eq .HAS_GODOC ""}}echo "Installing godoc..." && go install golang.org/x/tools/cmd/godoc@latest{{end}}'
|
||||
- echo "📚 Serving documentation at http://localhost:6060"
|
||||
- godoc -http=:6060
|
||||
interactive: true
|
||||
|
||||
docs:coverage:
|
||||
desc: Open coverage report in browser
|
||||
deps: [test:coverage]
|
||||
cmds:
|
||||
- '{{if eq OS "darwin"}}open {{.COVERAGE_DIR}}/coverage.html{{else if eq OS "windows"}}start {{.COVERAGE_DIR}}/coverage.html{{else}}xdg-open {{.COVERAGE_DIR}}/coverage.html 2>/dev/null || echo "Please open {{.COVERAGE_DIR}}/coverage.html in your browser"{{end}}'
|
||||
|
||||
# Info tasks
|
||||
info:
|
||||
desc: Display build information
|
||||
vars:
|
||||
GO_VERSION:
|
||||
sh: go version
|
||||
cmds:
|
||||
- task: info:print
|
||||
silent: true
|
||||
|
||||
info:print:
|
||||
internal: true
|
||||
silent: true
|
||||
vars:
|
||||
GO_VERSION:
|
||||
sh: go version
|
||||
cmds:
|
||||
- echo "Application Info:"
|
||||
- echo " Name{{":"}} {{.APP_NAME}}"
|
||||
- echo " Version{{":"}} {{.VERSION}}"
|
||||
- echo " Git Commit{{":"}} {{.GIT_COMMIT}}"
|
||||
- echo " Build Time{{":"}} {{.BUILD_TIME}}"
|
||||
- echo ""
|
||||
- echo "Go Environment{{":"}}"
|
||||
- echo " Go Version{{":"}} {{.GO_VERSION}}"
|
||||
- echo " GOOS{{":"}} {{.GOOS}}"
|
||||
- echo " GOARCH{{":"}} {{.GOARCH}}"
|
||||
- echo " CGO{{":"}} {{.CGO_ENABLED}}"
|
||||
- echo ""
|
||||
- echo "Paths{{":"}}"
|
||||
- echo " Output Dir{{":"}} {{.OUTPUT_DIR}}"
|
||||
- echo " Coverage{{":"}} {{.COVERAGE_DIR}}"
|
||||
|
||||
# Security tasks
|
||||
security:check:
|
||||
desc: Run security checks with gosec
|
||||
vars:
|
||||
HAS_GOSEC:
|
||||
sh: '{{if eq OS "windows"}}where gosec 2>NUL{{else}}command -v gosec 2>/dev/null{{end}}'
|
||||
cmds:
|
||||
- '{{if eq .HAS_GOSEC ""}}echo "Installing gosec..." && go install github.com/securego/gosec/v2/cmd/gosec@latest{{end}}'
|
||||
- gosec ./...
|
||||
ignore_error: true
|
||||
|
||||
security:audit:
|
||||
desc: Audit dependencies for vulnerabilities
|
||||
vars:
|
||||
HAS_GOVULNCHECK:
|
||||
sh: '{{if eq OS "windows"}}where govulncheck 2>NUL{{else}}command -v govulncheck 2>/dev/null{{end}}'
|
||||
cmds:
|
||||
- '{{if eq .HAS_GOVULNCHECK ""}}echo "Installing govulncheck..." && go install golang.org/x/vuln/cmd/govulncheck@latest{{end}}'
|
||||
- govulncheck ./...
|
||||
|
||||
# Example/Demo tasks
|
||||
demo:markdown:
|
||||
desc: Demo - Convert sample to Markdown
|
||||
status:
|
||||
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
|
||||
deps: [build]
|
||||
cmds:
|
||||
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json md output-demo.md'
|
||||
- echo "Demo Markdown created{{:}} output-demo.md"
|
||||
- defer:
|
||||
task: rmfile
|
||||
vars: { FILE: 'output-demo.md' }
|
||||
|
||||
demo:html:
|
||||
desc: Demo - Convert sample to HTML
|
||||
status:
|
||||
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
|
||||
deps: [build]
|
||||
cmds:
|
||||
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json html output-demo.html'
|
||||
- echo "Demo HTML created{{:}} output-demo.html"
|
||||
- defer:
|
||||
task: rmfile
|
||||
vars: { FILE: 'output-demo.html' }
|
||||
|
||||
demo:docx:
|
||||
desc: Demo - Convert sample to DOCX
|
||||
status:
|
||||
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
|
||||
deps: [build]
|
||||
cmds:
|
||||
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json docx output-demo.docx'
|
||||
- echo "Demo DOCX created{{:}} output-demo.docx"
|
||||
- defer:
|
||||
task: rmfile
|
||||
vars: { FILE: 'output-demo.docx' }
|
||||
|
||||
# Performance profiling
|
||||
profile:cpu:
|
||||
desc: Run CPU profiling
|
||||
cmds:
|
||||
- go test -cpuprofile=cpu.prof -bench=. ./...
|
||||
- go tool pprof -http=:8080 cpu.prof
|
||||
- defer:
|
||||
task: rmfile
|
||||
vars: { FILE: 'cpu.prof' }
|
||||
|
||||
profile:mem:
|
||||
desc: Run memory profiling
|
||||
cmds:
|
||||
- go test -memprofile=mem.prof -bench=. ./...
|
||||
- go tool pprof -http=:8080 mem.prof
|
||||
- defer:
|
||||
task: rmfile
|
||||
vars: { FILE: 'mem.prof' }
|
||||
|
||||
# Git hooks
|
||||
hooks:install:
|
||||
desc: Install git hooks
|
||||
cmds:
|
||||
- task: mkdir
|
||||
vars: { DIR: '.git/hooks' }
|
||||
- '{{if eq OS "windows"}}echo "#!/bin/sh" > .git/hooks/pre-commit && echo "task lint:fmt" >> .git/hooks/pre-commit{{else}}cat > .git/hooks/pre-commit << ''EOF''{{printf "\n"}}#!/bin/sh{{printf "\n"}}task lint:fmt{{printf "\n"}}EOF{{printf "\n"}}chmod +x .git/hooks/pre-commit{{end}}'
|
||||
- echo "Git hooks installed"
|
||||
|
||||
# Quick shortcuts
|
||||
qa:
|
||||
desc: Quick quality assurance (fmt + lint + test)
|
||||
aliases: [q, quick]
|
||||
cmds:
|
||||
- task: fmt
|
||||
- task: lint
|
||||
- task: test
|
||||
- echo "Quick QA passed"
|
||||
|
||||
all:
|
||||
desc: Build everything (clean + deps + test + build:all + docker:build)
|
||||
cmds:
|
||||
- task: clean
|
||||
- task: deps:tidy
|
||||
- task: test:coverage
|
||||
- task: build:all
|
||||
- task: docker:build
|
||||
- echo "Full build completed!"
|
||||
|
||||
# Cross-platform helper tasks
|
||||
mkdir:
|
||||
internal: true
|
||||
requires:
|
||||
vars: [DIR]
|
||||
cmds:
|
||||
- '{{if eq OS "windows"}}powershell -Command "New-Item -ItemType Directory -Force -Path ''{{.DIR}}'' | Out-Null"{{else}}mkdir -p "{{.DIR}}"{{end}}'
|
||||
silent: true
|
||||
|
||||
rmdir:
|
||||
internal: true
|
||||
requires:
|
||||
vars: [DIR]
|
||||
cmds:
|
||||
- '{{if eq OS "windows"}}powershell -Command "if (Test-Path ''{{.DIR}}'') { Remove-Item -Recurse -Force ''{{.DIR}}'' }"{{else}}rm -rf "{{.DIR}}" 2>/dev/null || true{{end}}'
|
||||
silent: true
|
||||
|
||||
rmfile:
|
||||
internal: true
|
||||
requires:
|
||||
vars: [FILE]
|
||||
cmds:
|
||||
- '{{if eq OS "windows"}}powershell -Command "if (Test-Path ''{{.FILE}}'') { Remove-Item -Force ''{{.FILE}}'' }"{{else}}rm -f "{{.FILE}}"{{end}}'
|
||||
silent: true
|
||||
2
go.sum
2
go.sum
@ -2,7 +2,5 @@ github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b h1:/mxSugRc4SgN7Xg
|
||||
github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b/go.mod h1:ssRF0IaB1hCcKIObp3FkZOsjTcAHpgii70JelNb4H8M=
|
||||
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
|
||||
github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
||||
|
||||
@ -615,8 +615,7 @@ func BenchmarkDocxExporter_Export(b *testing.B) {
|
||||
// Create temporary directory
|
||||
tempDir := b.TempDir()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
outputPath := filepath.Join(tempDir, "benchmark-course.docx")
|
||||
_ = exporter.Export(course, outputPath)
|
||||
// Clean up for next iteration
|
||||
@ -641,7 +640,7 @@ func BenchmarkDocxExporter_ComplexCourse(b *testing.B) {
|
||||
}
|
||||
|
||||
// Fill with test data
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := range 10 {
|
||||
lesson := models.Lesson{
|
||||
ID: "lesson-" + string(rune(i)),
|
||||
Title: "Lesson " + string(rune(i)),
|
||||
@ -649,13 +648,13 @@ func BenchmarkDocxExporter_ComplexCourse(b *testing.B) {
|
||||
Items: make([]models.Item, 5), // 5 items per lesson
|
||||
}
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
for j := range 5 {
|
||||
item := models.Item{
|
||||
Type: "text",
|
||||
Items: make([]models.SubItem, 3), // 3 sub-items per item
|
||||
}
|
||||
|
||||
for k := 0; k < 3; k++ {
|
||||
for k := range 3 {
|
||||
item.Items[k] = models.SubItem{
|
||||
Heading: "<h3>Heading " + string(rune(k)) + "</h3>",
|
||||
Paragraph: "<p>Paragraph content with <strong>formatting</strong> for performance testing.</p>",
|
||||
@ -670,8 +669,7 @@ func BenchmarkDocxExporter_ComplexCourse(b *testing.B) {
|
||||
|
||||
tempDir := b.TempDir()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
outputPath := filepath.Join(tempDir, "benchmark-complex.docx")
|
||||
_ = exporter.Export(course, outputPath)
|
||||
os.Remove(outputPath)
|
||||
|
||||
@ -449,8 +449,7 @@ func BenchmarkFactory_CreateExporter(b *testing.B) {
|
||||
htmlCleaner := services.NewHTMLCleaner()
|
||||
factory := NewFactory(htmlCleaner)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_, _ = factory.CreateExporter("markdown")
|
||||
}
|
||||
}
|
||||
@ -460,8 +459,7 @@ func BenchmarkFactory_CreateExporter_Docx(b *testing.B) {
|
||||
htmlCleaner := services.NewHTMLCleaner()
|
||||
factory := NewFactory(htmlCleaner)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_, _ = factory.CreateExporter("docx")
|
||||
}
|
||||
}
|
||||
@ -471,8 +469,7 @@ func BenchmarkFactory_GetSupportedFormats(b *testing.B) {
|
||||
htmlCleaner := services.NewHTMLCleaner()
|
||||
factory := NewFactory(htmlCleaner)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_ = factory.GetSupportedFormats()
|
||||
}
|
||||
}
|
||||
|
||||
@ -841,8 +841,7 @@ func BenchmarkHTMLExporter_Export(b *testing.B) {
|
||||
// Create temporary directory
|
||||
tempDir := b.TempDir()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
outputPath := filepath.Join(tempDir, "benchmark-course.html")
|
||||
_ = exporter.Export(course, outputPath)
|
||||
// Clean up for next iteration
|
||||
@ -865,8 +864,7 @@ func BenchmarkHTMLExporter_ProcessTextItem(b *testing.B) {
|
||||
},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
var buf bytes.Buffer
|
||||
exporter.processTextItem(&buf, item)
|
||||
}
|
||||
@ -889,7 +887,7 @@ func BenchmarkHTMLExporter_ComplexCourse(b *testing.B) {
|
||||
}
|
||||
|
||||
// Fill with test data
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := range 10 {
|
||||
lesson := models.Lesson{
|
||||
ID: "lesson-" + string(rune(i)),
|
||||
Title: "Lesson " + string(rune(i)),
|
||||
@ -897,13 +895,13 @@ func BenchmarkHTMLExporter_ComplexCourse(b *testing.B) {
|
||||
Items: make([]models.Item, 5), // 5 items per lesson
|
||||
}
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
for j := range 5 {
|
||||
item := models.Item{
|
||||
Type: "text",
|
||||
Items: make([]models.SubItem, 3), // 3 sub-items per item
|
||||
}
|
||||
|
||||
for k := 0; k < 3; k++ {
|
||||
for k := range 3 {
|
||||
item.Items[k] = models.SubItem{
|
||||
Heading: "<h3>Heading " + string(rune(k)) + "</h3>",
|
||||
Paragraph: "<p>Paragraph content with <strong>formatting</strong> for performance testing.</p>",
|
||||
@ -918,8 +916,7 @@ func BenchmarkHTMLExporter_ComplexCourse(b *testing.B) {
|
||||
|
||||
tempDir := b.TempDir()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
outputPath := filepath.Join(tempDir, "benchmark-complex.html")
|
||||
_ = exporter.Export(course, outputPath)
|
||||
os.Remove(outputPath)
|
||||
|
||||
@ -661,8 +661,7 @@ func BenchmarkMarkdownExporter_Export(b *testing.B) {
|
||||
// Create temporary directory
|
||||
tempDir := b.TempDir()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
outputPath := filepath.Join(tempDir, "benchmark-course.md")
|
||||
_ = exporter.Export(course, outputPath)
|
||||
// Clean up for next iteration
|
||||
@ -685,8 +684,7 @@ func BenchmarkMarkdownExporter_ProcessTextItem(b *testing.B) {
|
||||
},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
var buf bytes.Buffer
|
||||
exporter.processTextItem(&buf, item, "###")
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ type Lesson struct {
|
||||
// Items is an ordered array of content items within the lesson
|
||||
Items []Item `json:"items"`
|
||||
// Position stores the ordering information for the lesson
|
||||
Position interface{} `json:"position"`
|
||||
Position any `json:"position"`
|
||||
// Ready indicates whether the lesson is marked as complete
|
||||
Ready bool `json:"ready"`
|
||||
// CreatedAt is the timestamp when the lesson was created
|
||||
@ -41,9 +41,9 @@ type Item struct {
|
||||
// Items contains the actual content elements (sub-items) of this item
|
||||
Items []SubItem `json:"items"`
|
||||
// Settings contains configuration options specific to this item type
|
||||
Settings interface{} `json:"settings"`
|
||||
Settings any `json:"settings"`
|
||||
// Data contains additional structured data for the item
|
||||
Data interface{} `json:"data"`
|
||||
Data any `json:"data"`
|
||||
// Media contains any associated media for the item
|
||||
Media *Media `json:"media,omitempty"`
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@ func TestLesson_JSONMarshalUnmarshal(t *testing.T) {
|
||||
Ready: true,
|
||||
CreatedAt: "2023-06-01T12:00:00Z",
|
||||
UpdatedAt: "2023-06-01T13:00:00Z",
|
||||
Position: map[string]interface{}{"x": 1, "y": 2},
|
||||
Position: map[string]any{"x": 1, "y": 2},
|
||||
Items: []Item{
|
||||
{
|
||||
ID: "item-test",
|
||||
@ -154,8 +154,8 @@ func TestLesson_JSONMarshalUnmarshal(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Settings: map[string]interface{}{"autoplay": false},
|
||||
Data: map[string]interface{}{"metadata": "test"},
|
||||
Settings: map[string]any{"autoplay": false},
|
||||
Data: map[string]any{"metadata": "test"},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -197,11 +197,11 @@ func TestItem_JSONMarshalUnmarshal(t *testing.T) {
|
||||
Feedback: "Well done!",
|
||||
},
|
||||
},
|
||||
Settings: map[string]interface{}{
|
||||
Settings: map[string]any{
|
||||
"allowRetry": true,
|
||||
"showAnswer": true,
|
||||
},
|
||||
Data: map[string]interface{}{
|
||||
Data: map[string]any{
|
||||
"points": 10,
|
||||
"weight": 1.5,
|
||||
},
|
||||
@ -475,7 +475,7 @@ func TestLabelSet_JSONMarshalUnmarshal(t *testing.T) {
|
||||
func TestEmptyStructures(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
data interface{}
|
||||
data any
|
||||
}{
|
||||
{"Empty Course", Course{}},
|
||||
{"Empty CourseInfo", CourseInfo{}},
|
||||
@ -626,8 +626,7 @@ func BenchmarkCourse_JSONMarshal(b *testing.B) {
|
||||
},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_, _ = json.Marshal(course)
|
||||
}
|
||||
}
|
||||
@ -660,17 +659,16 @@ func BenchmarkCourse_JSONUnmarshal(b *testing.B) {
|
||||
|
||||
jsonData, _ := json.Marshal(course)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
var result Course
|
||||
_ = json.Unmarshal(jsonData, &result)
|
||||
}
|
||||
}
|
||||
|
||||
// compareMaps compares two interface{} values that should be maps
|
||||
func compareMaps(original, unmarshaled interface{}) bool {
|
||||
origMap, origOk := original.(map[string]interface{})
|
||||
unMap, unOk := unmarshaled.(map[string]interface{})
|
||||
func compareMaps(original, unmarshaled any) bool {
|
||||
origMap, origOk := original.(map[string]any)
|
||||
unMap, unOk := unmarshaled.(map[string]any)
|
||||
|
||||
if !origOk || !unOk {
|
||||
// If not maps, use deep equal
|
||||
|
||||
@ -168,7 +168,7 @@ func TestHTMLCleaner_CleanHTML_LargeContent(t *testing.T) {
|
||||
// Create a large HTML string
|
||||
var builder strings.Builder
|
||||
builder.WriteString("<html><body>")
|
||||
for i := 0; i < 1000; i++ {
|
||||
for i := range 1000 {
|
||||
builder.WriteString("<p>Paragraph ")
|
||||
builder.WriteString(string(rune('0' + i%10)))
|
||||
builder.WriteString(" with some content & entities.</p>")
|
||||
@ -299,8 +299,7 @@ func BenchmarkHTMLCleaner_CleanHTML(b *testing.B) {
|
||||
cleaner := NewHTMLCleaner()
|
||||
input := "<div class=\"content\"><h1>Course Title</h1><p>This is a <em>great</em> course about & HTML entities like and "quotes".</p><ul><li>Item 1</li><li>Item 2</li></ul></div>"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
cleaner.CleanHTML(input)
|
||||
}
|
||||
}
|
||||
@ -311,15 +310,14 @@ func BenchmarkHTMLCleaner_CleanHTML_Large(b *testing.B) {
|
||||
|
||||
// Create a large HTML string
|
||||
var builder strings.Builder
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
builder.WriteString("<p>Paragraph ")
|
||||
builder.WriteString(string(rune('0' + i%10)))
|
||||
builder.WriteString(" with some content & entities <test>.</p>")
|
||||
}
|
||||
input := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
cleaner.CleanHTML(input)
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,8 +420,7 @@ func BenchmarkExtractShareID(b *testing.B) {
|
||||
parser := &ArticulateParser{}
|
||||
uri := "https://rise.articulate.com/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO#/"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_, _ = parser.extractShareID(uri)
|
||||
}
|
||||
}
|
||||
@ -433,8 +432,7 @@ func BenchmarkBuildAPIURL(b *testing.B) {
|
||||
}
|
||||
shareID := "N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
_ = parser.buildAPIURL(shareID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,8 +89,7 @@ func TestIsURI(t *testing.T) {
|
||||
func BenchmarkIsURI(b *testing.B) {
|
||||
testStr := "https://rise.articulate.com/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO#/"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for b.Loop() {
|
||||
isURI(testStr)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user