Skip to content

tests: improve coverage #1

tests: improve coverage

tests: improve coverage #1

Workflow file for this run

name: Release

Check failure on line 1 in .github/workflows/release.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/release.yml

Invalid workflow file

(Line: 19, Col: 5): 'inputs' is already defined
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., 0.1.0)'
required: true
type: string
prerelease:
description: 'Mark as pre-release'
required: false
default: false
type: boolean
target:
description: 'target_commitish (branch name or commit SHA). Defaults to the triggering commit.'
required: false
type: string
inputs:
version:
description: 'Release version (e.g., 0.1.0)'
required: true
type: string
prerelease:
description: 'Mark as pre-release'
required: false
default: false
type: boolean
permissions:
contents: write
pages: write
id-token: write
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
JAVA_OPTS: -Xmx4G -XX:+UseG1GC
SBT_OPTS: -Xmx4G -XX:+UseG1GC
jobs:
validate-release:
name: Validate Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is-prerelease: ${{ steps.version.outputs.is-prerelease }}
target-commitish: ${{ steps.version.outputs.target_commitish }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
- name: Determine version
id: version
run: |
VERSION="${{ github.event.inputs.version }}"
IS_PRERELEASE="${{ github.event.inputs.prerelease }}"
TARGET_INPUT="${{ github.event.inputs.target }}"
if [ -z "$TARGET_INPUT" ]; then
TARGET_INPUT="${GITHUB_SHA}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "is-prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
echo "target_commitish=$TARGET_INPUT" >> $GITHUB_OUTPUT
echo "Release version: $VERSION (prerelease: $IS_PRERELEASE, target=$TARGET_INPUT)"
- name: Validate version format
run: |
VERSION="${{ steps.version.outputs.version }}"
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "Invalid version format: $VERSION"
echo "Expected format: X.Y.Z or X.Y.Z-qualifier"
exit 1
fi
- name: Check for existing release
run: |
VERSION="${{ steps.version.outputs.version }}"
if gh release view "v$VERSION" &>/dev/null; then
echo "Release v$VERSION already exists!"
exit 1
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pre-release-tests:
name: Pre-release tests
needs: [validate-release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Setup Java 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
with:
distribution: 'temurin'
java-version: '17'
- name: Coursier cache (sbt/ivy)
uses: coursier/cache-action@4e2615869d13561d626ed48655e1a39e5b192b3c
- name: Check formatting
run: sbt scalafmtCheckAll
- name: Compile all modules
run: sbt compile Test/compile
- name: Run full test suite
run: |
echo "🧪 Running full test suite for release"
sbt coverage test
echo "🔥 Running compile-fail tests - proving contract enforcement"
sbt "compile-fail-tests / test"
echo "🚀 Running engine smoke tests"
sbt "engines-spark/testOnly *StreamingCDCSpec"
sbt "engines-flink/testOnly *EngineAbstractionSpec"
sbt coverageReport
echo "✅ All release tests passed!"
- name: Generate coverage report
run: sbt coverageAggregate
- name: Validate g8 template for release
run: |
echo "📋 Validating g8 template for release"
cd /tmp
sbt new file://${{ github.workspace }}/flowforge.g8 --name="release-test-pipeline" --organization="com.flowforge.release"
cd release-test-pipeline
echo "🔨 Testing template compilation"
sbt compile
echo "🧪 Testing template tests"
sbt test
echo "🎯 Testing contract drift demo"
sed -i 's/id: Long/id: String/' src/main/scala/Contract.scala
if sbt compile; then
echo "❌ Contract drift should have failed compilation!"
exit 1
else
echo "✅ Contract drift prevention working correctly!"
fi
build-artifacts:
name: Build release artifacts
needs: [validate-release, pre-release-tests]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Setup Java 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
with:
distribution: 'temurin'
java-version: '17'
- name: Coursier cache (sbt/ivy)
uses: coursier/cache-action@4e2615869d13561d626ed48655e1a39e5b192b3c
- name: Set release version
run: |
VERSION="${{ needs.validate-release.outputs.version }}"
echo "Building with version: $VERSION (from git tag)"
# sbt-dynver uses git tags for versioning automatically
git tag -f "v$VERSION" 2>/dev/null || true
- name: Build JAR artifacts
run: |
sbt clean compile
sbt "validation-cli / assembly"
sbt "contracts-extractor-cli / assembly"
- name: Create release directory
run: mkdir -p release-artifacts
- name: Copy artifacts
run: |
find . -name "*assembly*.jar" -exec cp {} release-artifacts/ \;
ls -la release-artifacts/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts-${{ needs.validate-release.outputs.version }}
path: release-artifacts/
retention-days: 30
publish-docs:
name: Publish Scaladoc to GitHub Pages
needs: [validate-release, pre-release-tests]
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
- name: Setup Java 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
with:
distribution: 'temurin'
java-version: '17'
- name: Coursier cache (sbt/ivy)
uses: coursier/cache-action@4e2615869d13561d626ed48655e1a39e5b192b3c
- name: Generate Scaladoc for all modules
run: |
sbt -batch doc
# Try unified docs for Scala 2.13 modules; don't fail release if unidoc fails
sbt -batch unidoc || echo "unidoc failed (non-fatal)"
- name: Assemble site folder
run: |
mkdir -p public/api
for m in modules/*; do \
mod=$(basename "$m"); \
api_dir="$m/target/scala-2.13/api"; \
if [ -d "$api_dir" ]; then \
mkdir -p "public/api/$mod"; \
cp -R "$api_dir"/* "public/api/$mod"/; \
fi; \
done
# Root module (if any aggregated docs exist)
if [ -d target/scala-2.13/api ]; then \
mkdir -p public/api/root && cp -R target/scala-2.13/api/* public/api/root/; \
fi
# Unified docs (if present)
if [ -d target/scala-2.13/unidoc ] || [ -d target/scala-2.13/api-unidoc ]; then \
UNIDOC_DIR="$(ls -d target/scala-2.13/*unidoc 2>/dev/null | head -n1)"; \
if [ -n "$UNIDOC_DIR" ]; then \
mkdir -p public/api/unified && cp -R "$UNIDOC_DIR"/* public/api/unified/; \
fi; \
fi
# Add index
cat > public/index.html << 'EOF'
<!doctype html>
<html><head><meta charset="utf-8"><title>FlowForge API</title></head>
<body>
<h1>FlowForge API (Scaladoc)</h1>
<ul>
$(for d in api/*; do echo "<li><a href=\"$d/index.html\">$(basename "$d")</a></li>"; done)
</ul>
</body></html>
EOF
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
with:
path: public
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e
create-release:
name: Create GitHub Release
needs: [validate-release, pre-release-tests, build-artifacts, publish-docs]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Download artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: release-artifacts-${{ needs.validate-release.outputs.version }}
path: release-artifacts/
- name: Generate dynamic release notes
id: release-notes
run: |
VERSION="${{ needs.validate-release.outputs.version }}"
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
{
echo "# FlowForge v$VERSION"
echo ""
if [ -n "$PREV_TAG" ]; then
echo "## 📝 Changes since $PREV_TAG"
echo ""
git log ${PREV_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges | head -n 50
echo ""
echo ""
fi
echo "## 🚀 Core Features"
echo "- 100% Compile-time contracts - Data pipelines fail to compile on schema drift"
echo "- Phantom-state builder pattern - Type-safe pipeline construction"
echo "- Macro-based schema validation - Zero-runtime overhead"
echo ""
echo "## 🛠 CLI Tools"
echo "- **validation-cli**: Schema validation and contract checking"
echo "- **contracts-extractor-cli**: Extract contracts from data sources"
echo ""
echo "## 📊 Statistics"
COMMIT_COUNT=$(git rev-list --count ${PREV_TAG}..HEAD 2>/dev/null || echo "N/A")
CONTRIBUTOR_COUNT=$(git shortlog -sn ${PREV_TAG}..HEAD 2>/dev/null | wc -l || echo "N/A")
echo "- Commits: $COMMIT_COUNT"
echo "- Contributors: $CONTRIBUTOR_COUNT"
echo "- Commit: \`${{ github.sha }}\`"
echo ""
echo "## 📚 Documentation"
echo "- API Docs: https://vim89.github.io/flowforge/api/"
echo "- Getting Started: https://github.com/vim89/flowforge#getting-started"
} > release-notes.md
- name: Create gitHub release
uses: softprops/action-gh-release@26f96dfa697d77e81fd5907df203aa23a56210a8
with:
tag_name: v${{ needs.validate-release.outputs.version }}
name: FlowForge v${{ needs.validate-release.outputs.version }}
body_path: release-notes.md
target_commitish: ${{ needs.validate-release.outputs.target-commitish }}
prerelease: ${{ needs.validate-release.outputs.is-prerelease == 'true' }}
files: release-artifacts/*
token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload to Codecov
if: success()
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
- name: Rollback instructions
if: failure()
run: |
echo "❌ Release failed!"
echo ""
echo "To rollback:"
echo " 1. Delete failed release: gh release delete v${{ needs.validate-release.outputs.version }} -y"
echo " 2. Delete tag: git push --delete origin v${{ needs.validate-release.outputs.version }}"
echo " 3. Fix issues and re-tag when ready"