chore(deps): bump github.com/pb33f/libopenapi from 0.27.0 to 0.28.0 #75
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
on: | |
push: | |
branches: [ main, develop ] | |
pull_request: | |
branches: [ main ] | |
workflow_dispatch: | |
env: | |
GO_VERSION: '1.24' | |
BUF_VERSION: 'latest' | |
PROTOC_VERSION: '25.1' | |
jobs: | |
lint: | |
name: Lint & Code Quality | |
runs-on: ubuntu-latest | |
outputs: | |
lint-status: ${{ steps.lint-summary.outputs.status }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v5 | |
- name: Setup Go | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ env.GO_VERSION }} | |
cache: true | |
cache-dependency-path: | | |
go.sum | |
go.mod | |
- name: Setup Buf | |
uses: bufbuild/buf-setup-action@v1 | |
with: | |
version: ${{ env.BUF_VERSION }} | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Run golangci-lint | |
uses: golangci/golangci-lint-action@v8 | |
with: | |
version: v2.1.6 | |
args: "" | |
only-new-issues: true | |
- name: Run Go fmt check | |
id: fmt-check | |
run: | | |
fmt_output=$(gofmt -l .) | |
if [ -n "$fmt_output" ]; then | |
echo "::error::The following files need formatting:" | |
echo "$fmt_output" | while read -r file; do | |
echo "::error file=$file::File needs gofmt formatting" | |
done | |
echo "FMT_STATUS=❌ Format issues" >> $GITHUB_ENV | |
exit 1 | |
else | |
echo "FMT_STATUS=✅ Well formatted" >> $GITHUB_ENV | |
fi | |
- name: Run Go vet | |
id: vet-check | |
run: | | |
if go vet ./...; then | |
echo "VET_STATUS=✅ No issues" >> $GITHUB_ENV | |
else | |
echo "VET_STATUS=❌ Vet issues" >> $GITHUB_ENV | |
exit 1 | |
fi | |
- name: Run Buf lint | |
id: buf-check | |
run: | | |
if buf lint proto/; then | |
echo "BUF_STATUS=✅ Proto lint passed" >> $GITHUB_ENV | |
else | |
echo "BUF_STATUS=⚠️ Proto lint warnings" >> $GITHUB_ENV | |
echo "::warning::Buf lint found issues - consider fixing package versioning" | |
# Don't fail for now, just warn | |
fi | |
- name: Lint summary | |
id: lint-summary | |
if: always() | |
run: | | |
echo "📝 Lint Summary:" | |
echo "- Go Format: ${FMT_STATUS:-❌ Failed}" | |
echo "- Go Vet: ${VET_STATUS:-❌ Failed}" | |
echo "- Buf Lint: ${BUF_STATUS:-❌ Failed}" | |
if [[ "${FMT_STATUS}" == *"✅"* && "${VET_STATUS}" == *"✅"* ]]; then | |
if [[ "${BUF_STATUS}" == *"✅"* ]]; then | |
echo "status=✅ All checks passed" >> $GITHUB_OUTPUT | |
else | |
echo "status=⚠️ Passed with warnings" >> $GITHUB_OUTPUT | |
fi | |
else | |
echo "status=❌ Some checks failed" >> $GITHUB_OUTPUT | |
fi | |
test: | |
name: Test (Go ${{ matrix.go-version }} - ${{ matrix.os }}) | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
go-version: ['1.24'] | |
os: [ubuntu-latest, macos-latest] | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v5 | |
- name: Setup Go | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ matrix.go-version }} | |
cache: true | |
cache-dependency-path: | | |
go.sum | |
go.mod | |
- name: Setup Protoc | |
uses: arduino/setup-protoc@v3 | |
with: | |
version: ${{ env.PROTOC_VERSION }} | |
repo-token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Setup Buf | |
uses: bufbuild/buf-setup-action@v1 | |
with: | |
version: ${{ env.BUF_VERSION }} | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Install dependencies | |
run: | | |
go mod download | |
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest | |
- name: Build plugins | |
run: make build | |
- name: Run tests | |
run: ./scripts/run_tests.sh --verbose | |
shell: bash | |
- name: Upload test results | |
if: always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-results-${{ matrix.os }}-go${{ matrix.go-version }} | |
path: | | |
coverage/coverage.out | |
coverage/coverage.html | |
coverage/coverage.json | |
coverage/coverage-badge.svg | |
coverage: | |
name: Coverage Analysis | |
runs-on: ubuntu-latest | |
needs: test | |
if: always() | |
continue-on-error: true # Make coverage a warning, not a failure | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v5 | |
- name: Download coverage from test job | |
uses: actions/download-artifact@v5 | |
with: | |
name: test-results-ubuntu-latest-go1.24 | |
path: ./coverage-download | |
- name: Verify and locate coverage file | |
run: | | |
echo "📁 Checking for coverage files in downloaded artifacts..." | |
echo "Available files in coverage-download:" | |
find ./coverage-download -type f | head -20 | |
# Create coverage directory for final location | |
mkdir -p coverage | |
# Check for coverage file in multiple possible locations within the download | |
if [ -f "coverage-download/coverage/coverage.out" ]; then | |
echo "✅ Coverage file found: coverage-download/coverage/coverage.out" | |
cp coverage-download/coverage/coverage.out coverage/coverage.out | |
echo "COVERAGE_FILE=coverage/coverage.out" >> $GITHUB_ENV | |
elif [ -f "coverage-download/coverage.out" ]; then | |
echo "✅ Coverage file found: coverage-download/coverage.out (root level)" | |
cp coverage-download/coverage.out coverage/coverage.out | |
echo "COVERAGE_FILE=coverage/coverage.out" >> $GITHUB_ENV | |
else | |
echo "❌ No coverage file found in expected locations!" | |
echo "Available files structure:" | |
ls -la coverage-download/ || true | |
find coverage-download -name "*.out" 2>/dev/null || true | |
exit 1 | |
fi | |
echo "📋 Coverage file ready at: coverage/coverage.out" | |
ls -la coverage/ | |
- name: Setup Go for coverage tools | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ env.GO_VERSION }} | |
- name: Generate coverage badge and reports | |
run: | | |
coverage_file="${COVERAGE_FILE:-coverage/coverage.out}" | |
if [ -f "$coverage_file" ]; then | |
echo "📊 Generating coverage reports from: $coverage_file" | |
# Get total coverage percentage | |
total_coverage=$(go tool cover -func="$coverage_file" | grep "total:" | awk '{print $3}') | |
echo "Total coverage: $total_coverage" | |
# Create a simple coverage badge | |
coverage_num=$(echo "$total_coverage" | sed 's/%//') | |
color="red" | |
if (( $(echo "$coverage_num >= 80" | bc -l) )); then | |
color="green" | |
elif (( $(echo "$coverage_num >= 60" | bc -l) )); then | |
color="yellow" | |
fi | |
# Generate badge URL | |
badge_url="https://img.shields.io/badge/coverage-${total_coverage}-${color}" | |
echo "Coverage badge URL: $badge_url" | |
# Save badge info for later use | |
echo "COVERAGE_PERCENTAGE=$total_coverage" >> $GITHUB_ENV | |
echo "COVERAGE_BADGE_URL=$badge_url" >> $GITHUB_ENV | |
else | |
echo "❌ No coverage file found for badge generation" | |
exit 1 | |
fi | |
- name: Upload coverage to Codecov | |
uses: codecov/codecov-action@v5 | |
with: | |
file: ./coverage/coverage.out | |
flags: unittests | |
name: codecov-umbrella | |
fail_ci_if_error: false | |
token: ${{ secrets.CODECOV_TOKEN }} | |
- name: Comment PR with coverage | |
if: github.event_name == 'pull_request' | |
uses: fgrosse/go-coverage-report@v1.2.0 | |
continue-on-error: true # Don't fail on coverage reporting issues | |
with: | |
coverage-artifact-name: test-results-ubuntu-latest-go1.24 | |
coverage-file-name: coverage/coverage.out | |
- name: Upload coverage reports | |
uses: actions/upload-artifact@v4 | |
with: | |
name: coverage-reports | |
path: | | |
coverage/ | |
.testcoverage.yml | |
coverage-check: | |
name: Coverage Status Check | |
runs-on: ubuntu-latest | |
needs: coverage | |
if: always() | |
continue-on-error: true # Don't fail the whole pipeline on coverage issues | |
steps: | |
- name: Download coverage reports | |
uses: actions/download-artifact@v5 | |
with: | |
name: coverage-reports | |
path: ./ | |
continue-on-error: true # Handle missing artifacts gracefully | |
- name: Setup Go for coverage analysis | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ env.GO_VERSION }} | |
- name: Check coverage threshold | |
run: | | |
coverage_file="coverage/coverage.out" | |
if [ -f "$coverage_file" ]; then | |
# Extract total coverage percentage using go tool cover | |
total_coverage=$(go tool cover -func="$coverage_file" | grep "total:" | awk '{print $3}') | |
coverage_num=$(echo "$total_coverage" | sed 's/%//') | |
echo "📊 Coverage: ${total_coverage}" | |
# Set threshold (85%) | |
threshold=85 | |
if [ "${coverage_num%.*}" -ge "$threshold" ]; then | |
echo "✅ Coverage meets threshold (${threshold}%)" | |
echo "COVERAGE_STATUS=✅ ${total_coverage}" >> $GITHUB_ENV | |
else | |
echo "⚠️ Coverage below threshold (${threshold}%) - This is currently a warning" | |
echo "COVERAGE_STATUS=⚠️ ${total_coverage}" >> $GITHUB_ENV | |
# Don't fail, just warn | |
fi | |
else | |
echo "⚠️ No coverage file found" | |
echo "COVERAGE_STATUS=⚠️ No coverage" >> $GITHUB_ENV | |
# Don't fail, just warn | |
fi | |
- name: Update commit status | |
if: github.event_name == 'pull_request' | |
continue-on-error: true # Don't fail on status update issues | |
uses: actions/github-script@v8 | |
with: | |
script: | | |
try { | |
await github.rest.repos.createCommitStatus({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
sha: context.payload.pull_request.head.sha, | |
state: 'success', | |
target_url: `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | |
description: process.env.COVERAGE_STATUS, | |
context: 'Coverage Report' | |
}); | |
} catch (error) { | |
console.log('Failed to update commit status:', error.message); | |
// Don't fail the job | |
} | |
build: | |
name: Build Binaries | |
runs-on: ubuntu-latest | |
needs: [lint, test] | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v5 | |
- name: Setup Go | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ env.GO_VERSION }} | |
cache: true | |
cache-dependency-path: | | |
go.sum | |
go.mod | |
- name: Build all plugins | |
run: | | |
make build | |
- name: Test plugin execution | |
run: | | |
./bin/protoc-gen-go-oneof-helper --version || true | |
./bin/protoc-gen-go-http --version || true | |
./bin/protoc-gen-openapiv3 --version || true | |
- name: Upload binaries | |
uses: actions/upload-artifact@v4 | |
with: | |
name: plugin-binaries | |
path: bin/ | |
integration: | |
name: Integration Tests | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v5 | |
- name: Clean Go module cache to prevent conflicts | |
run: | | |
rm -rf ~/.cache/go-build || true | |
rm -rf ~/go/pkg || true | |
- name: Setup Go | |
uses: actions/setup-go@v6 | |
with: | |
go-version: ${{ env.GO_VERSION }} | |
cache: true | |
cache-dependency-path: | | |
go.sum | |
go.mod | |
- name: Setup Protoc | |
uses: arduino/setup-protoc@v3 | |
with: | |
version: ${{ env.PROTOC_VERSION }} | |
repo-token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Setup Buf | |
uses: bufbuild/buf-setup-action@v1 | |
with: | |
version: ${{ env.BUF_VERSION }} | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Install protoc-gen-go dependency | |
run: | | |
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest | |
- name: Download binaries | |
uses: actions/download-artifact@v5 | |
with: | |
name: plugin-binaries | |
path: bin/ | |
- name: Make binaries executable | |
run: chmod +x bin/* | |
- name: Run integration test with sample proto files | |
run: | | |
# Ensure Go bin directory is in PATH for protoc-gen-go | |
export PATH=$(go env GOPATH)/bin:$PATH | |
# Test all plugins with sample proto files | |
export PATH=$PWD/bin:$PATH | |
# Verify protoc-gen-go is available | |
if ! which protoc-gen-go; then | |
echo "protoc-gen-go not found in PATH" | |
exit 1 | |
fi | |
# Create test directory | |
mkdir -p integration-test-output | |
echo "🔍 Testing oneof helper with simple_oneof.proto (no services)..." | |
# Test oneof helper with simple_oneof.proto (no services) | |
protoc \ | |
--plugin=protoc-gen-go-oneof-helper=bin/protoc-gen-go-oneof-helper \ | |
--go_out=integration-test-output \ | |
--go_opt=module=github.com/SebastienMelki/sebuf \ | |
--go-oneof-helper_out=integration-test-output \ | |
--go-oneof-helper_opt=module=github.com/SebastienMelki/sebuf \ | |
--proto_path=internal/oneofhelper/testdata/proto \ | |
internal/oneofhelper/testdata/proto/simple_oneof.proto | |
echo "🔍 Testing all plugins with simple_service.proto (has services)..." | |
# Test all plugins with simple_service.proto (has services) | |
protoc \ | |
--plugin=protoc-gen-go-oneof-helper=bin/protoc-gen-go-oneof-helper \ | |
--plugin=protoc-gen-go-http=bin/protoc-gen-go-http \ | |
--plugin=protoc-gen-openapiv3=bin/protoc-gen-openapiv3 \ | |
--go_out=integration-test-output \ | |
--go_opt=module=github.com/SebastienMelki/sebuf \ | |
--go-oneof-helper_out=integration-test-output \ | |
--go-oneof-helper_opt=module=github.com/SebastienMelki/sebuf \ | |
--go-http_out=integration-test-output \ | |
--go-http_opt=module=github.com/SebastienMelki/sebuf \ | |
--openapiv3_out=integration-test-output \ | |
--proto_path=internal/openapiv3/testdata/proto \ | |
internal/openapiv3/testdata/proto/simple_service.proto | |
# Debug: List all generated files | |
echo "📁 Generated files:" | |
find integration-test-output -type f -name "*.go" -o -name "*.yaml" | sort | |
# Verify oneof helper output | |
echo "✅ Checking oneof helper outputs..." | |
if [ -f "integration-test-output/internal/oneofhelper/testdata/simple_oneof_helpers.pb.go" ]; then | |
echo "✅ simple_oneof_helpers.pb.go found" | |
else | |
echo "❌ simple_oneof_helpers.pb.go missing" | |
exit 1 | |
fi | |
# Verify HTTP handler output for service proto | |
echo "✅ Checking HTTP handler outputs..." | |
if [ -f "integration-test-output/internal/openapiv3/testdata/simple/simple_service_http.pb.go" ]; then | |
echo "✅ simple_service_http.pb.go found" | |
else | |
echo "❌ simple_service_http.pb.go missing" | |
exit 1 | |
fi | |
# Verify OpenAPI output for service proto (this should exist!) | |
echo "✅ Checking OpenAPI outputs..." | |
openapi_files=$(find integration-test-output -name "*.openapi.yaml" | wc -l) | |
if [ "$openapi_files" -gt 0 ]; then | |
echo "✅ Found $openapi_files OpenAPI service file(s)" | |
find integration-test-output -name "*.openapi.yaml" | |
else | |
echo "❌ No OpenAPI files found - this should not happen with simple_service.proto" | |
echo "Available YAML files:" | |
find integration-test-output -name "*.yaml" -o -name "*.yml" || echo "No YAML files found" | |
exit 1 | |
fi | |
- name: Compile generated code | |
run: | | |
cd integration-test-output | |
go mod init test-module | |
go mod tidy | |
go build ./... | |
status-check: | |
name: PR Status Summary | |
runs-on: ubuntu-latest | |
needs: [lint, test, coverage-check, build, integration] | |
if: always() && github.event_name == 'pull_request' | |
permissions: | |
contents: read | |
pull-requests: write | |
checks: write | |
steps: | |
- name: Generate PR status summary | |
uses: actions/github-script@v8 | |
with: | |
script: | | |
const { data: checkRuns } = await github.rest.checks.listForRef({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
ref: context.payload.pull_request.head.sha | |
}); | |
const jobs = { | |
lint: '${{ needs.lint.result }}', | |
test: '${{ needs.test.result }}', | |
coverage: '${{ needs.coverage-check.result }}', | |
build: '${{ needs.build.result }}', | |
integration: '${{ needs.integration.result }}' | |
}; | |
let summary = '## 🔍 CI Pipeline Status\n\n'; | |
for (const [job, status] of Object.entries(jobs)) { | |
const emoji = status === 'success' ? '✅' : status === 'failure' ? '❌' : '⚠️'; | |
const jobName = job.charAt(0).toUpperCase() + job.slice(1); | |
summary += `${emoji} **${jobName}**: ${status}\n`; | |
} | |
summary += '\n---\n'; | |
summary += '📊 **Coverage Report**: Available in checks above\n'; | |
summary += '🔗 **Artifacts**: Test results and coverage reports uploaded\n'; | |
// Post comment on PR | |
const { data: comments } = await github.rest.issues.listComments({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: context.payload.pull_request.number | |
}); | |
const botComment = comments.find(comment => | |
comment.user.login === 'github-actions[bot]' && | |
comment.body.includes('CI Pipeline Status') | |
); | |
if (botComment) { | |
await github.rest.issues.updateComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
comment_id: botComment.id, | |
body: summary | |
}); | |
} else { | |
await github.rest.issues.createComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: context.payload.pull_request.number, | |
body: summary | |
}); | |
} |