mirror of
https://github.com/kjanat/articulate-parser.git
synced 2026-01-16 13:02:08 +01:00
Compare commits
3 Commits
33673d661b
...
94a7924bed
| Author | SHA1 | Date | |
|---|---|---|---|
|
94a7924bed
|
|||
|
90b9d557d8
|
|||
|
33ff267644
|
42
.dprint.jsonc
Normal file
42
.dprint.jsonc
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"typescript": {
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
},
|
||||||
|
"markdown": {
|
||||||
|
},
|
||||||
|
"toml": {
|
||||||
|
},
|
||||||
|
"dockerfile": {
|
||||||
|
},
|
||||||
|
"oxc": {
|
||||||
|
},
|
||||||
|
"ruff": {
|
||||||
|
},
|
||||||
|
"jupyter": {
|
||||||
|
},
|
||||||
|
"malva": {
|
||||||
|
},
|
||||||
|
"markup": {
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
},
|
||||||
|
"excludes": [
|
||||||
|
"**/node_modules",
|
||||||
|
"**/*-lock.json",
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"https://plugins.dprint.dev/typescript-0.95.13.wasm",
|
||||||
|
"https://plugins.dprint.dev/json-0.21.1.wasm",
|
||||||
|
"https://plugins.dprint.dev/markdown-0.20.0.wasm",
|
||||||
|
"https://plugins.dprint.dev/toml-0.7.0.wasm",
|
||||||
|
"https://plugins.dprint.dev/dockerfile-0.3.3.wasm",
|
||||||
|
"https://plugins.dprint.dev/oxc-0.1.0.wasm",
|
||||||
|
"https://plugins.dprint.dev/ruff-0.6.11.wasm",
|
||||||
|
"https://plugins.dprint.dev/jupyter-0.2.1.wasm",
|
||||||
|
"https://plugins.dprint.dev/g-plane/malva-v0.15.1.wasm",
|
||||||
|
"https://plugins.dprint.dev/g-plane/markup_fmt-v0.25.3.wasm",
|
||||||
|
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm",
|
||||||
|
"https://plugins.dprint.dev/exec-0.6.0.json@a054130d458f124f9b5c91484833828950723a5af3f8ff2bd1523bd47b83b364",
|
||||||
|
],
|
||||||
|
}
|
||||||
22
.github/CONTRIBUTING.md
vendored
22
.github/CONTRIBUTING.md
vendored
@ -45,23 +45,23 @@ Enhancement suggestions are welcome! Please use the feature request template and
|
|||||||
|
|
||||||
2. **Clone and setup:**
|
2. **Clone and setup:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/your-username/articulate-parser.git
|
git clone https://github.com/your-username/articulate-parser.git
|
||||||
cd articulate-parser
|
cd articulate-parser
|
||||||
go mod download
|
go mod download
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Run tests:**
|
3. **Run tests:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Build:**
|
4. **Build:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build main.go
|
go build main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
## Coding Standards
|
## Coding Standards
|
||||||
|
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,7 +1,7 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Create a report to help us improve
|
description: Create a report to help us improve
|
||||||
title: '[BUG] '
|
title: "[BUG] "
|
||||||
labels: ['bug', 'triage']
|
labels: ["bug", "triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -5,11 +5,13 @@
|
|||||||
## Related Issue
|
## Related Issue
|
||||||
|
|
||||||
<!-- Link to the issue this PR addresses using the syntax: Fixes #issue_number -->
|
<!-- Link to the issue this PR addresses using the syntax: Fixes #issue_number -->
|
||||||
|
|
||||||
Fixes #
|
Fixes #
|
||||||
|
|
||||||
## Type of Change
|
## Type of Change
|
||||||
|
|
||||||
<!-- Mark the appropriate option with an "x" -->
|
<!-- Mark the appropriate option with an "x" -->
|
||||||
|
|
||||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||||
- [ ] New feature (non-breaking change which adds functionality)
|
- [ ] New feature (non-breaking change which adds functionality)
|
||||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||||
@ -21,6 +23,7 @@ Fixes #
|
|||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
<!-- Mark the items you've completed with an "x" -->
|
<!-- Mark the items you've completed with an "x" -->
|
||||||
|
|
||||||
- [ ] My code follows the style guidelines of this project
|
- [ ] My code follows the style guidelines of this project
|
||||||
- [ ] I have performed a self-review of my code
|
- [ ] I have performed a self-review of my code
|
||||||
- [ ] I have added comments to complex logic
|
- [ ] I have added comments to complex logic
|
||||||
@ -42,6 +45,7 @@ Fixes #
|
|||||||
## Testing Instructions
|
## Testing Instructions
|
||||||
|
|
||||||
<!-- Provide steps to test the changes, if applicable -->
|
<!-- Provide steps to test the changes, if applicable -->
|
||||||
|
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
3.
|
3.
|
||||||
|
|||||||
98
.github/dependabot.yml
vendored
98
.github/dependabot.yml
vendored
@ -1,86 +1,86 @@
|
|||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
# Check for updates to GitHub Actions
|
# Check for updates to GitHub Actions
|
||||||
- package-ecosystem: 'github-actions'
|
- package-ecosystem: "github-actions"
|
||||||
directory: '/'
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'weekly'
|
interval: "weekly"
|
||||||
day: 'monday'
|
day: "monday"
|
||||||
time: '07:00'
|
time: "07:00"
|
||||||
timezone: 'Europe/Amsterdam'
|
timezone: "Europe/Amsterdam"
|
||||||
open-pull-requests-limit: 2
|
open-pull-requests-limit: 2
|
||||||
labels:
|
labels:
|
||||||
- 'dependencies'
|
- "dependencies"
|
||||||
- 'dependencies/github-actions'
|
- "dependencies/github-actions"
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: 'ci'
|
prefix: "ci"
|
||||||
include: 'scope'
|
include: "scope"
|
||||||
|
|
||||||
# Check for updates to Docker
|
# Check for updates to Docker
|
||||||
- package-ecosystem: 'docker'
|
- package-ecosystem: "docker"
|
||||||
directory: '/'
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'weekly'
|
interval: "weekly"
|
||||||
day: 'monday'
|
day: "monday"
|
||||||
time: '07:00'
|
time: "07:00"
|
||||||
timezone: 'Europe/Amsterdam'
|
timezone: "Europe/Amsterdam"
|
||||||
open-pull-requests-limit: 2
|
open-pull-requests-limit: 2
|
||||||
labels:
|
labels:
|
||||||
- 'dependencies'
|
- "dependencies"
|
||||||
- 'dependencies/docker'
|
- "dependencies/docker"
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: 'docker'
|
prefix: "docker"
|
||||||
include: 'scope'
|
include: "scope"
|
||||||
groups:
|
groups:
|
||||||
docker:
|
docker:
|
||||||
patterns:
|
patterns:
|
||||||
- '*'
|
- "*"
|
||||||
update-types:
|
update-types:
|
||||||
- 'minor'
|
- "minor"
|
||||||
- 'patch'
|
- "patch"
|
||||||
|
|
||||||
# Check for updates to Docker Compose
|
# Check for updates to Docker Compose
|
||||||
- package-ecosystem: 'docker-compose'
|
- package-ecosystem: "docker-compose"
|
||||||
directory: '/'
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'weekly'
|
interval: "weekly"
|
||||||
day: 'monday'
|
day: "monday"
|
||||||
time: '07:00'
|
time: "07:00"
|
||||||
timezone: 'Europe/Amsterdam'
|
timezone: "Europe/Amsterdam"
|
||||||
open-pull-requests-limit: 2
|
open-pull-requests-limit: 2
|
||||||
labels:
|
labels:
|
||||||
- 'dependencies'
|
- "dependencies"
|
||||||
- 'dependencies/docker-compose'
|
- "dependencies/docker-compose"
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: 'docker'
|
prefix: "docker"
|
||||||
include: 'scope'
|
include: "scope"
|
||||||
groups:
|
groups:
|
||||||
docker:
|
docker:
|
||||||
patterns:
|
patterns:
|
||||||
- '*'
|
- "*"
|
||||||
update-types:
|
update-types:
|
||||||
- 'minor'
|
- "minor"
|
||||||
- 'patch'
|
- "patch"
|
||||||
|
|
||||||
# Check for updates to Go modules
|
# Check for updates to Go modules
|
||||||
- package-ecosystem: 'gomod'
|
- package-ecosystem: "gomod"
|
||||||
directory: '/'
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'weekly'
|
interval: "weekly"
|
||||||
day: 'monday'
|
day: "monday"
|
||||||
time: '07:00'
|
time: "07:00"
|
||||||
timezone: 'Europe/Amsterdam'
|
timezone: "Europe/Amsterdam"
|
||||||
open-pull-requests-limit: 2
|
open-pull-requests-limit: 2
|
||||||
labels:
|
labels:
|
||||||
- 'dependencies'
|
- "dependencies"
|
||||||
- 'dependencies/go'
|
- "dependencies/go"
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: 'deps'
|
prefix: "deps"
|
||||||
include: 'scope'
|
include: "scope"
|
||||||
groups:
|
groups:
|
||||||
go-modules:
|
go-modules:
|
||||||
patterns:
|
patterns:
|
||||||
- '*'
|
- "*"
|
||||||
update-types:
|
update-types:
|
||||||
- 'minor'
|
- "minor"
|
||||||
- 'patch'
|
- "patch"
|
||||||
|
|||||||
105
.github/workflows/ci.yml
vendored
105
.github/workflows/ci.yml
vendored
@ -64,14 +64,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Run tests with enhanced reporting
|
- name: Run tests with enhanced reporting
|
||||||
id: test
|
id: test
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 1
|
||||||
run: |
|
run: |
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
{
|
||||||
|
cat << EOF
|
||||||
## 🔧 Test Environment
|
## 🔧 Test Environment
|
||||||
- **Go Version:** ${{ matrix.go }}
|
- **Go Version:** ${{ matrix.go }}
|
||||||
- **OS:** ubuntu-latest
|
- **OS:** ubuntu-latest
|
||||||
- **Timestamp:** $(date -u)
|
- **Timestamp:** $(date -u)
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
echo "Running tests with coverage..."
|
echo "Running tests with coverage..."
|
||||||
task test:coverage 2>&1 | tee test-output.log
|
task test:coverage 2>&1 | tee test-output.log
|
||||||
@ -84,16 +88,17 @@ jobs:
|
|||||||
SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0")
|
SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0")
|
||||||
|
|
||||||
# Generate test summary
|
# Generate test summary
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
{
|
||||||
|
cat << EOF
|
||||||
## 🧪 Test Results (Go ${{ matrix.go }})
|
## 🧪 Test Results (Go ${{ matrix.go }})
|
||||||
|
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
| ----------- | ----------------------------------------------------------- |
|
| ----------- | ------------------------------------------------------------- |
|
||||||
| Total Tests | $TOTAL_TESTS |
|
| Total Tests | $TOTAL_TESTS |
|
||||||
| Passed | $PASSED_TESTS |
|
| Passed | $PASSED_TESTS |
|
||||||
| Failed | $FAILED_TESTS |
|
| Failed | $FAILED_TESTS |
|
||||||
| Skipped | $SKIPPED_TESTS |
|
| Skipped | $SKIPPED_TESTS |
|
||||||
| Status | $([ $TEST_STATUS -eq 0 ] && echo "PASSED" || echo "FAILED") |
|
| Status | $([ "$TEST_STATUS" -eq 0 ] && echo "PASSED" || echo "FAILED") |
|
||||||
|
|
||||||
### 📦 Package Test Results
|
### 📦 Package Test Results
|
||||||
|
|
||||||
@ -105,38 +110,39 @@ jobs:
|
|||||||
grep "^ok\|^FAIL" test-output.log | while read -r line; do
|
grep "^ok\|^FAIL" test-output.log | while read -r line; do
|
||||||
if [[ $line == ok* ]]; then
|
if [[ $line == ok* ]]; then
|
||||||
pkg=$(echo "$line" | awk '{print $2}')
|
pkg=$(echo "$line" | awk '{print $2}')
|
||||||
echo "| $pkg | ✅ PASS |" >> $GITHUB_STEP_SUMMARY
|
echo "| $pkg | ✅ PASS |"
|
||||||
elif [[ $line == FAIL* ]]; then
|
elif [[ $line == FAIL* ]]; then
|
||||||
pkg=$(echo "$line" | awk '{print $2}')
|
pkg=$(echo "$line" | awk '{print $2}')
|
||||||
echo "| $pkg | ❌ FAIL |" >> $GITHUB_STEP_SUMMARY
|
echo "| $pkg | ❌ FAIL |"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo ""
|
||||||
|
|
||||||
# Add detailed results if tests failed
|
# Add detailed results if tests failed
|
||||||
if [ $TEST_STATUS -ne 0 ]; then
|
if [ "$TEST_STATUS" -ne 0 ]; then
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat << 'EOF'
|
||||||
### ❌ Failed Tests Details
|
### ❌ Failed Tests Details
|
||||||
```
|
```
|
||||||
EOF
|
EOF
|
||||||
grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY
|
grep -A 10 -- "--- FAIL:" test-output.log | head -100
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat << 'EOF'
|
||||||
```
|
```
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
# Set outputs for other steps
|
# Set outputs for other steps
|
||||||
cat >> $GITHUB_OUTPUT << EOF
|
{
|
||||||
test-status=$TEST_STATUS
|
echo "test-status=$TEST_STATUS"
|
||||||
total-tests=$TOTAL_TESTS
|
echo "total-tests=$TOTAL_TESTS"
|
||||||
passed-tests=$PASSED_TESTS
|
echo "passed-tests=$PASSED_TESTS"
|
||||||
failed-tests=$FAILED_TESTS
|
echo "failed-tests=$FAILED_TESTS"
|
||||||
EOF
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Exit with the original test status
|
# Exit with the original test status
|
||||||
exit $TEST_STATUS
|
exit "$TEST_STATUS"
|
||||||
|
|
||||||
- name: Generate coverage report
|
- name: Generate coverage report
|
||||||
if: always()
|
if: always()
|
||||||
@ -144,7 +150,8 @@ jobs:
|
|||||||
if [ -f coverage/coverage.out ]; then
|
if [ -f coverage/coverage.out ]; then
|
||||||
COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}')
|
COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}')
|
||||||
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
{
|
||||||
|
cat << EOF
|
||||||
## 📊 Code Coverage (Go ${{ matrix.go }})
|
## 📊 Code Coverage (Go ${{ matrix.go }})
|
||||||
|
|
||||||
**Total Coverage: $COVERAGE**
|
**Total Coverage: $COVERAGE**
|
||||||
@ -184,17 +191,18 @@ jobs:
|
|||||||
avg = packages[pkg] / counts[pkg]
|
avg = packages[pkg] / counts[pkg]
|
||||||
printf "| %s | %.1f%% |\n", pkg, avg
|
printf "| %s | %.1f%% |\n", pkg, avg
|
||||||
}
|
}
|
||||||
}' "$temp_coverage" | sort >> $GITHUB_STEP_SUMMARY
|
}' "$temp_coverage" | sort
|
||||||
|
|
||||||
rm -f "$temp_coverage"
|
rm -f "$temp_coverage"
|
||||||
|
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat << 'EOF'
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
else
|
else
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat >> "$GITHUB_STEP_SUMMARY" << 'EOF'
|
||||||
## ⚠️ Coverage Report
|
## ⚠️ Coverage Report
|
||||||
No coverage file generated
|
No coverage file generated
|
||||||
|
|
||||||
@ -213,8 +221,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Run linters
|
- name: Run linters
|
||||||
run: |
|
run: |
|
||||||
# Initialize summary
|
{
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
cat << EOF
|
||||||
## 🔍 Static Analysis (Go ${{ matrix.go }})
|
## 🔍 Static Analysis (Go ${{ matrix.go }})
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
@ -223,42 +231,43 @@ jobs:
|
|||||||
VET_OUTPUT=$(task lint:vet 2>&1 || echo "")
|
VET_OUTPUT=$(task lint:vet 2>&1 || echo "")
|
||||||
VET_STATUS=$?
|
VET_STATUS=$?
|
||||||
|
|
||||||
if [ $VET_STATUS -eq 0 ]; then
|
if [ "$VET_STATUS" -eq 0 ]; then
|
||||||
echo "✅ **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY
|
echo "✅ **go vet:** No issues found"
|
||||||
else
|
else
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat << 'EOF'
|
||||||
❌ **go vet:** Issues found
|
❌ **go vet:** Issues found
|
||||||
|
|
||||||
```
|
```
|
||||||
EOF
|
EOF
|
||||||
echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY
|
echo "$VET_OUTPUT"
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo '```'
|
||||||
fi
|
fi
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo ""
|
||||||
|
|
||||||
# Run go fmt check
|
# Run go fmt check
|
||||||
FMT_OUTPUT=$(task lint:fmt 2>&1 || echo "")
|
FMT_OUTPUT=$(task lint:fmt 2>&1 || echo "")
|
||||||
FMT_STATUS=$?
|
FMT_STATUS=$?
|
||||||
|
|
||||||
if [ $FMT_STATUS -eq 0 ]; then
|
if [ "$FMT_STATUS" -eq 0 ]; then
|
||||||
echo "✅ **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY
|
echo "✅ **go fmt:** All files properly formatted"
|
||||||
else
|
else
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat << 'EOF'
|
||||||
❌ **go fmt:** Files need formatting
|
❌ **go fmt:** Files need formatting
|
||||||
|
|
||||||
```
|
```
|
||||||
EOF
|
EOF
|
||||||
echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY
|
echo "$FMT_OUTPUT"
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo '```'
|
||||||
fi
|
fi
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
# Exit with error if any linter failed
|
# Exit with error if any linter failed
|
||||||
[ $VET_STATUS -eq 0 ] && [ $FMT_STATUS -eq 0 ] || exit 1
|
[ "$VET_STATUS" -eq 0 ] && [ "$FMT_STATUS" -eq 0 ] || exit 1
|
||||||
|
|
||||||
- name: Job Summary
|
- name: Job Summary
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat >> "$GITHUB_STEP_SUMMARY" << 'EOF'
|
||||||
## 📋 Job Summary (Go ${{ matrix.go }})
|
## 📋 Job Summary (Go ${{ matrix.go }})
|
||||||
|
|
||||||
| Step | Status |
|
| Step | Status |
|
||||||
@ -313,7 +322,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Test Docker image using Task
|
- name: Test Docker image using Task
|
||||||
run: |
|
run: |
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
{
|
||||||
|
cat << 'EOF'
|
||||||
## 🧪 Docker Image Tests
|
## 🧪 Docker Image Tests
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
@ -321,16 +331,17 @@ jobs:
|
|||||||
# Run Task docker test
|
# Run Task docker test
|
||||||
task docker:test
|
task docker:test
|
||||||
|
|
||||||
echo "**Testing help command:**" >> $GITHUB_STEP_SUMMARY
|
echo "**Testing help command:**"
|
||||||
echo '```terminaloutput' >> $GITHUB_STEP_SUMMARY
|
echo '```terminaloutput'
|
||||||
docker run --rm articulate-parser:latest --help >> $GITHUB_STEP_SUMMARY
|
docker run --rm articulate-parser:latest --help
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
echo '```'
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo ""
|
||||||
|
|
||||||
# Test image size
|
# Test image size
|
||||||
IMAGE_SIZE=$(docker image inspect articulate-parser: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 "**Image size:** $IMAGE_SIZE"
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo ""
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
dependency-review:
|
dependency-review:
|
||||||
name: Dependency Review
|
name: Dependency Review
|
||||||
@ -354,7 +365,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
needs: [test, docker-test, dependency-review]
|
needs: [test, docker-test]
|
||||||
if: |
|
if: |
|
||||||
github.event_name == 'push' && (github.ref == 'refs/heads/master' ||
|
github.event_name == 'push' && (github.ref == 'refs/heads/master' ||
|
||||||
github.ref == 'refs/heads/develop' ||
|
github.ref == 'refs/heads/develop' ||
|
||||||
@ -433,7 +444,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate Docker summary
|
- name: Generate Docker summary
|
||||||
run: |
|
run: |
|
||||||
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
|
cat >> "$GITHUB_STEP_SUMMARY" << 'EOF'
|
||||||
## 🐳 Docker Build Summary
|
## 🐳 Docker Build Summary
|
||||||
|
|
||||||
**Image:** `ghcr.io/${{ github.repository }}`
|
**Image:** `ghcr.io/${{ github.repository }}`
|
||||||
|
|||||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -17,7 +17,7 @@ name: "CodeQL"
|
|||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '44 16 * * 6'
|
- cron: "44 16 * * 6"
|
||||||
# push:
|
# push:
|
||||||
# branches: [ "master" ]
|
# branches: [ "master" ]
|
||||||
# pull_request:
|
# pull_request:
|
||||||
|
|||||||
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@ -16,10 +16,10 @@ jobs:
|
|||||||
dependency-review:
|
dependency-review:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: "Checkout Repository"
|
||||||
uses: actions/checkout@v6
|
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
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -82,7 +82,7 @@ jobs:
|
|||||||
docker:
|
docker:
|
||||||
name: Docker Build & Push
|
name: Docker Build & Push
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: ['release']
|
needs: ["release"]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|||||||
@ -349,7 +349,15 @@ linters:
|
|||||||
|
|
||||||
# stylecheck settings
|
# stylecheck settings
|
||||||
staticcheck:
|
staticcheck:
|
||||||
checks: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"]
|
checks: [
|
||||||
|
"all",
|
||||||
|
"-ST1000",
|
||||||
|
"-ST1003",
|
||||||
|
"-ST1016",
|
||||||
|
"-ST1020",
|
||||||
|
"-ST1021",
|
||||||
|
"-ST1022",
|
||||||
|
]
|
||||||
|
|
||||||
# maintidx settings
|
# maintidx settings
|
||||||
maintidx:
|
maintidx:
|
||||||
|
|||||||
75
.pre-commit-config.yaml
Normal file
75
.pre-commit-config.yaml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v6.0.0
|
||||||
|
hooks:
|
||||||
|
# File quality
|
||||||
|
- id: trailing-whitespace
|
||||||
|
exclude: '^\.github/ISSUE_TEMPLATE/.*\.yml$'
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: mixed-line-ending
|
||||||
|
args: ["--fix=lf"]
|
||||||
|
|
||||||
|
# File validation
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-json
|
||||||
|
- id: check-toml
|
||||||
|
|
||||||
|
# Security
|
||||||
|
- id: detect-private-key
|
||||||
|
|
||||||
|
# Git safety
|
||||||
|
- id: check-merge-conflict
|
||||||
|
- id: check-case-conflict
|
||||||
|
- id: no-commit-to-branch
|
||||||
|
args: ["--branch=master", "--branch=main"]
|
||||||
|
|
||||||
|
# File structure
|
||||||
|
- id: check-added-large-files
|
||||||
|
- id: check-symlinks
|
||||||
|
- id: check-executables-have-shebangs
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: actionlint
|
||||||
|
name: Lint GitHub Actions workflow files
|
||||||
|
description: Runs actionlint to lint GitHub Actions workflow files
|
||||||
|
language: golang
|
||||||
|
types: ["yaml"]
|
||||||
|
files: ^\.github/workflows/
|
||||||
|
entry: actionlint
|
||||||
|
minimum_pre_commit_version: 3.0.0
|
||||||
|
- repo: https://github.com/golangci/golangci-lint
|
||||||
|
rev: v2.7.2
|
||||||
|
hooks:
|
||||||
|
- id: golangci-lint
|
||||||
|
name: golangci-lint
|
||||||
|
description: Fast linters runner for Go. Note that only modified files are linted, so linters like 'unused' that need to scan all files won't work as expected.
|
||||||
|
entry: golangci-lint run --new-from-rev HEAD --fix
|
||||||
|
types: [go]
|
||||||
|
language: golang
|
||||||
|
require_serial: true
|
||||||
|
pass_filenames: false
|
||||||
|
# - id: golangci-lint-full
|
||||||
|
# name: golangci-lint-full
|
||||||
|
# description: Fast linters runner for Go. Runs on all files in the module. Use this hook if you use pre-commit in CI.
|
||||||
|
# entry: golangci-lint run --fix
|
||||||
|
# types: [go]
|
||||||
|
# language: golang
|
||||||
|
# require_serial: true
|
||||||
|
# pass_filenames: false
|
||||||
|
- id: golangci-lint-fmt
|
||||||
|
name: golangci-lint-fmt
|
||||||
|
description: Fast linters runner for Go. Formats all files in the repo.
|
||||||
|
entry: golangci-lint fmt
|
||||||
|
types: [go]
|
||||||
|
language: golang
|
||||||
|
require_serial: true
|
||||||
|
pass_filenames: false
|
||||||
|
- id: golangci-lint-config-verify
|
||||||
|
name: golangci-lint-config-verify
|
||||||
|
description: Verifies the configuration file
|
||||||
|
entry: golangci-lint config verify
|
||||||
|
files: '\.golangci\.(?:yml|yaml|toml|json)'
|
||||||
|
language: golang
|
||||||
|
pass_filenames: false
|
||||||
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
A Go CLI tool that parses Articulate Rise courses from URLs or local JSON files and exports them to Markdown, HTML, or DOCX formats.
|
A Go CLI tool that parses Articulate Rise courses from URLs or local JSON files and exports them to Markdown, HTML, or DOCX formats.
|
||||||
|
|
||||||
|
## Repository Info
|
||||||
|
|
||||||
|
- **GitHub**: https://github.com/kjanat/articulate-parser
|
||||||
|
- **Default branch**: `master` (not `main`)
|
||||||
|
|
||||||
## Build/Test Commands
|
## Build/Test Commands
|
||||||
|
|
||||||
### Primary Commands (using Taskfile)
|
### Primary Commands (using Taskfile)
|
||||||
|
|||||||
@ -226,7 +226,7 @@ docker run --rm ghcr.io/kjanat/articulate-parser:latest --help
|
|||||||
### Available Tags
|
### Available Tags
|
||||||
|
|
||||||
| Tag | Description | Use Case |
|
| Tag | Description | Use Case |
|
||||||
|-----|-------------|----------|
|
| --------------------- | ------------------------------------------- | ---------------------- |
|
||||||
| `latest` | Latest stable release from master branch | Production use |
|
| `latest` | Latest stable release from master branch | Production use |
|
||||||
| `edge` | Latest development build from master branch | Testing new features |
|
| `edge` | Latest development build from master branch | Testing new features |
|
||||||
| `v1.x.x` | Specific version releases | Production pinning |
|
| `v1.x.x` | Specific version releases | Production pinning |
|
||||||
@ -314,7 +314,7 @@ docker build --build-arg VERSION=local --build-arg BUILD_TIME=$(date -u +%Y-%m-%
|
|||||||
The Docker image supports the following build-time arguments:
|
The Docker image supports the following build-time arguments:
|
||||||
|
|
||||||
| Argument | Description | Default |
|
| Argument | Description | Default |
|
||||||
|----------|-------------|---------|
|
| ------------ | ------------------------------------- | -------------- |
|
||||||
| `VERSION` | Version string embedded in the binary | `dev` |
|
| `VERSION` | Version string embedded in the binary | `dev` |
|
||||||
| `BUILD_TIME` | Build timestamp | Current time |
|
| `BUILD_TIME` | Build timestamp | Current time |
|
||||||
| `GIT_COMMIT` | Git commit hash | Current commit |
|
| `GIT_COMMIT` | Git commit hash | Current commit |
|
||||||
@ -460,7 +460,9 @@ This is a utility tool for educational content conversion. Please ensure you hav
|
|||||||
[Go report]: https://goreportcard.com/report/github.com/kjanat/articulate-parser
|
[Go report]: https://goreportcard.com/report/github.com/kjanat/articulate-parser
|
||||||
[gomod]: go.mod
|
[gomod]: go.mod
|
||||||
[Issues]: https://github.com/kjanat/articulate-parser/issues
|
[Issues]: https://github.com/kjanat/articulate-parser/issues
|
||||||
|
|
||||||
<!-- [Latest release]: https://github.com/kjanat/articulate-parser/releases/latest -->
|
<!-- [Latest release]: https://github.com/kjanat/articulate-parser/releases/latest -->
|
||||||
|
|
||||||
[MIT License]: LICENSE
|
[MIT License]: LICENSE
|
||||||
[Package documentation]: https://godoc.org/github.com/kjanat/articulate-parser
|
[Package documentation]: https://godoc.org/github.com/kjanat/articulate-parser
|
||||||
[Tags]: https://github.com/kjanat/articulate-parser/tags
|
[Tags]: https://github.com/kjanat/articulate-parser/tags
|
||||||
|
|||||||
@ -16,6 +16,13 @@ import (
|
|||||||
"github.com/kjanat/articulate-parser/internal/services"
|
"github.com/kjanat/articulate-parser/internal/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Font sizes for DOCX document headings (in half-points, so "32" = 16pt).
|
||||||
|
const (
|
||||||
|
docxTitleSize = "32" // Course title (16pt)
|
||||||
|
docxLessonSize = "28" // Lesson heading (14pt)
|
||||||
|
docxItemSize = "24" // Item heading (12pt)
|
||||||
|
)
|
||||||
|
|
||||||
// DocxExporter implements the Exporter interface for DOCX format.
|
// DocxExporter implements the Exporter interface for DOCX format.
|
||||||
// It converts Articulate Rise course data into a Microsoft Word document
|
// It converts Articulate Rise course data into a Microsoft Word document
|
||||||
// using the go-docx package.
|
// using the go-docx package.
|
||||||
@ -53,7 +60,7 @@ func (e *DocxExporter) Export(course *models.Course, outputPath string) error {
|
|||||||
|
|
||||||
// Add title
|
// Add title
|
||||||
titlePara := doc.AddParagraph()
|
titlePara := doc.AddParagraph()
|
||||||
titlePara.AddText(course.Course.Title).Size("32").Bold()
|
titlePara.AddText(course.Course.Title).Size(docxTitleSize).Bold()
|
||||||
|
|
||||||
// Add description if available
|
// Add description if available
|
||||||
if course.Course.Description != "" {
|
if course.Course.Description != "" {
|
||||||
@ -106,7 +113,7 @@ func (e *DocxExporter) Export(course *models.Course, outputPath string) error {
|
|||||||
func (e *DocxExporter) exportLesson(doc *docx.Docx, lesson *models.Lesson) {
|
func (e *DocxExporter) exportLesson(doc *docx.Docx, lesson *models.Lesson) {
|
||||||
// Add lesson title
|
// Add lesson title
|
||||||
lessonPara := doc.AddParagraph()
|
lessonPara := doc.AddParagraph()
|
||||||
lessonPara.AddText(fmt.Sprintf("Lesson: %s", lesson.Title)).Size("28").Bold()
|
lessonPara.AddText(fmt.Sprintf("Lesson: %s", lesson.Title)).Size(docxLessonSize).Bold()
|
||||||
|
|
||||||
// Add lesson description if available
|
// Add lesson description if available
|
||||||
if lesson.Description != "" {
|
if lesson.Description != "" {
|
||||||
@ -132,7 +139,7 @@ func (e *DocxExporter) exportItem(doc *docx.Docx, item *models.Item) {
|
|||||||
if item.Type != "" {
|
if item.Type != "" {
|
||||||
itemPara := doc.AddParagraph()
|
itemPara := doc.AddParagraph()
|
||||||
caser := cases.Title(language.English)
|
caser := cases.Title(language.English)
|
||||||
itemPara.AddText(caser.String(item.Type)).Size("24").Bold()
|
itemPara.AddText(caser.String(item.Type)).Size(docxItemSize).Bold()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sub-items
|
// Add sub-items
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import (
|
|||||||
//go:embed html_styles.css
|
//go:embed html_styles.css
|
||||||
var defaultCSS string
|
var defaultCSS string
|
||||||
|
|
||||||
//go:embed html_template.html
|
//go:embed html_template.gohtml
|
||||||
var htmlTemplate string
|
var htmlTemplate string
|
||||||
|
|
||||||
// HTMLExporter implements the Exporter interface for HTML format.
|
// HTMLExporter implements the Exporter interface for HTML format.
|
||||||
@ -69,7 +69,16 @@ func (e *HTMLExporter) Export(course *models.Course, outputPath string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create file: %w", err)
|
return fmt.Errorf("failed to create file: %w", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer func() {
|
||||||
|
// Close errors are logged but not fatal since the content has already been written.
|
||||||
|
// The file must be closed to flush buffers, but a close error doesn't invalidate
|
||||||
|
// the data already written to disk.
|
||||||
|
if closeErr := f.Close(); closeErr != nil {
|
||||||
|
// Note: In production, this should log via a logger passed to the exporter.
|
||||||
|
// For now, we silently ignore close errors as they're non-fatal.
|
||||||
|
_ = closeErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return e.WriteHTML(f, course)
|
return e.WriteHTML(f, course)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
|
||||||
|
Cantarell, sans-serif;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: #333;
|
color: #333;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
|
|||||||
@ -96,7 +96,10 @@ func (e *MarkdownExporter) SupportedFormat() string {
|
|||||||
func (e *MarkdownExporter) processItemToMarkdown(buf *bytes.Buffer, item models.Item, level int) {
|
func (e *MarkdownExporter) processItemToMarkdown(buf *bytes.Buffer, item models.Item, level int) {
|
||||||
headingPrefix := strings.Repeat("#", level)
|
headingPrefix := strings.Repeat("#", level)
|
||||||
|
|
||||||
switch item.Type {
|
// Normalize item type to lowercase for consistent matching
|
||||||
|
itemType := strings.ToLower(item.Type)
|
||||||
|
|
||||||
|
switch itemType {
|
||||||
case "text":
|
case "text":
|
||||||
e.processTextItem(buf, item, headingPrefix)
|
e.processTextItem(buf, item, headingPrefix)
|
||||||
case "list":
|
case "list":
|
||||||
@ -105,7 +108,7 @@ func (e *MarkdownExporter) processItemToMarkdown(buf *bytes.Buffer, item models.
|
|||||||
e.processMultimediaItem(buf, item, headingPrefix)
|
e.processMultimediaItem(buf, item, headingPrefix)
|
||||||
case "image":
|
case "image":
|
||||||
e.processImageItem(buf, item, headingPrefix)
|
e.processImageItem(buf, item, headingPrefix)
|
||||||
case "knowledgeCheck":
|
case "knowledgecheck":
|
||||||
e.processKnowledgeCheckItem(buf, item, headingPrefix)
|
e.processKnowledgeCheckItem(buf, item, headingPrefix)
|
||||||
case "interactive":
|
case "interactive":
|
||||||
e.processInteractiveItem(buf, item, headingPrefix)
|
e.processInteractiveItem(buf, item, headingPrefix)
|
||||||
|
|||||||
Binary file not shown.
@ -15,6 +15,9 @@ import (
|
|||||||
"github.com/kjanat/articulate-parser/internal/models"
|
"github.com/kjanat/articulate-parser/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// shareIDRegex is compiled once at package init for extracting share IDs from URIs.
|
||||||
|
var shareIDRegex = regexp.MustCompile(`/share/([a-zA-Z0-9_-]+)`)
|
||||||
|
|
||||||
// ArticulateParser implements the CourseParser interface specifically for Articulate Rise courses.
|
// ArticulateParser implements the CourseParser interface specifically for Articulate Rise courses.
|
||||||
// It can fetch courses from the Articulate Rise API or load them from local JSON files.
|
// It can fetch courses from the Articulate Rise API or load them from local JSON files.
|
||||||
type ArticulateParser struct {
|
type ArticulateParser struct {
|
||||||
@ -78,15 +81,15 @@ func (p *ArticulateParser) FetchCourse(ctx context.Context, uri string) (*models
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
var course models.Course
|
var course models.Course
|
||||||
if err := json.Unmarshal(body, &course); err != nil {
|
if err := json.Unmarshal(body, &course); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
|
||||||
@ -133,8 +136,7 @@ func (p *ArticulateParser) extractShareID(uri string) (string, error) {
|
|||||||
return "", fmt.Errorf("invalid domain for Articulate Rise URI: %s", parsedURL.Host)
|
return "", fmt.Errorf("invalid domain for Articulate Rise URI: %s", parsedURL.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile(`/share/([a-zA-Z0-9_-]+)`)
|
matches := shareIDRegex.FindStringSubmatch(uri)
|
||||||
matches := re.FindStringSubmatch(uri)
|
|
||||||
if len(matches) < 2 {
|
if len(matches) < 2 {
|
||||||
return "", fmt.Errorf("could not extract share ID from URI: %s", uri)
|
return "", fmt.Errorf("could not extract share ID from URI: %s", uri)
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@ -92,7 +92,7 @@ func run(args []string) int {
|
|||||||
// Returns:
|
// Returns:
|
||||||
// - true if the string appears to be a URI, false otherwise
|
// - true if the string appears to be a URI, false otherwise
|
||||||
func isURI(str string) bool {
|
func isURI(str string) bool {
|
||||||
return len(str) > 7 && (str[:7] == "http://" || str[:8] == "https://")
|
return strings.HasPrefix(str, "http://") || strings.HasPrefix(str, "https://")
|
||||||
}
|
}
|
||||||
|
|
||||||
// printUsage prints the command-line usage information.
|
// printUsage prints the command-line usage information.
|
||||||
|
|||||||
Reference in New Issue
Block a user