# Release Pipeline - Build, test, version, package, release when: - event: push branch: main labels: platform: linux/amd64 clone: - name: clone image: woodpeckerci/plugin-git settings: lfs: false partial: false tags: true steps: # Determine next version based on conventional commits - name: calculate-version image: alpine commands: - apk add --no-cache git - | set -e # Ensure we have all tags and history echo "=== Fetching tags and history ===" git fetch --tags --unshallow 2>/dev/null || git fetch --tags || true git fetch origin main --unshallow 2>/dev/null || git fetch origin main || true echo "=== Git log (last 10 commits) ===" git log --oneline -10 echo "=== All tags ===" git tag -l # Get latest tag LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") echo "=== Latest tag: $LATEST_TAG ===" # Parse current version VERSION=$(echo "$LATEST_TAG" | sed 's/^v//') MAJOR=$(echo "$VERSION" | cut -d. -f1) MINOR=$(echo "$VERSION" | cut -d. -f2) PATCH=$(echo "$VERSION" | cut -d. -f3) echo "Current version: $MAJOR.$MINOR.$PATCH" # Get commits since last tag if [ "$LATEST_TAG" = "v0.0.0" ]; then COMMITS=$(git log --pretty=format:"%s" HEAD) else COMMITS=$(git log --pretty=format:"%s" "$LATEST_TAG..HEAD") fi echo "=== Commits since last tag ===" echo "$COMMITS" echo "=== End commits ===" # Check if COMMITS is empty if [ -z "$COMMITS" ]; then echo "No commits found since last tag" echo "none" > .bump-type exit 0 fi # Determine bump type from conventional commits BUMP="none" # Check for breaking changes (major bump) if echo "$COMMITS" | grep -qE '^[a-z]+(\(.+\))?!:|BREAKING CHANGE:'; then BUMP="major" echo "Found breaking change commit" # Check for features (minor bump) elif echo "$COMMITS" | grep -qE '^feat(\(.+\))?:'; then BUMP="minor" echo "Found feat commit" # Check for fixes or other conventional commits (patch bump) elif echo "$COMMITS" | grep -qE '^(fix|perf|refactor|build|ci|docs|style|test)(\(.+\))?:'; then BUMP="patch" echo "Found fix/patch commit" fi echo "=== Bump type: $BUMP ===" # Exit if no version bump needed if [ "$BUMP" = "none" ]; then echo "No conventional commits found, skipping version bump" echo "none" > .bump-type exit 0 fi # Calculate new version case $BUMP in major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; minor) MINOR=$((MINOR + 1)); PATCH=0 ;; patch) PATCH=$((PATCH + 1)) ;; esac NEW_VERSION="$MAJOR.$MINOR.$PATCH" echo "New version: $NEW_VERSION" # Write version files for subsequent steps echo "$NEW_VERSION" > .version echo "v$NEW_VERSION" > .tag echo "$BUMP" > .bump-type # Update version.json echo "{\"version\": \"$NEW_VERSION\"}" > version.json cat .version cat .tag # Build and test with the new version - name: build-and-test image: mcr.microsoft.com/dotnet/sdk:10.0 commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, building with current version" dotnet restore dotnet build -c Release dotnet test -c Release --logger "console;verbosity=detailed" else VERSION=$(cat .version) echo "Building version $VERSION" dotnet restore dotnet build -c Release /p:Version=$VERSION dotnet test -c Release /p:Version=$VERSION --logger "console;verbosity=detailed" fi depends_on: [calculate-version] # Package NuGet - name: package image: mcr.microsoft.com/dotnet/sdk:10.0 commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, skipping package" exit 0 fi VERSION=$(cat .version) echo "Packaging version $VERSION" dotnet pack PaperlessMCP/PaperlessMCP.csproj -c Release -o ./artifacts /p:Version=$VERSION ls -la ./artifacts/ depends_on: [build-and-test] # Build and push Docker with Kaniko - name: docker image: gcr.io/kaniko-project/executor:debug environment: GHCR_USERNAME: from_secret: github_username GHCR_TOKEN: from_secret: github_token commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, skipping docker build" exit 0 fi VERSION=$(cat .version) echo "Building Docker image version: $VERSION" mkdir -p /kaniko/.docker echo "{\"auths\":{\"ghcr.io\":{\"username\":\"$GHCR_USERNAME\",\"password\":\"$GHCR_TOKEN\"}}}" > /kaniko/.docker/config.json /kaniko/executor \ --context="$CI_WORKSPACE/PaperlessMCP" \ --dockerfile="$CI_WORKSPACE/PaperlessMCP/Dockerfile" \ --destination="ghcr.io/barryw/paperlessmcp:v$VERSION" \ --destination="ghcr.io/barryw/paperlessmcp:latest" \ --build-arg="VERSION=$VERSION" depends_on: [build-and-test] # Commit version.json, create git tag and push - name: git-tag image: alpine/git environment: GITHUB_TOKEN: from_secret: github_token commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, skipping git tag" exit 0 fi TAG=$(cat .tag) VERSION=$(cat .version) echo "Creating tag $TAG for version $VERSION" git config user.email "ci@woodpecker.local" git config user.name "Woodpecker CI" git remote set-url origin "https://x-access-token:$GITHUB_TOKEN@github.com/barryw/PaperlessMCP.git" # Commit version.json update git add version.json git diff --staged --quiet || git commit -m "chore(release): bump version to $VERSION [skip ci]" git push origin HEAD:main # Create and push tag git tag -a "$TAG" -m "Release $VERSION" git push origin "$TAG" depends_on: [package, docker] # Create GitHub release - name: release image: alpine environment: GITHUB_TOKEN: from_secret: github_token commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, skipping release" exit 0 fi apk add --no-cache curl git TAG=$(cat .tag) VERSION=$(cat .version) LATEST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "v0.0.0") echo "Creating GitHub release for $TAG" # Generate changelog from commits if [ "$LATEST_TAG" = "v0.0.0" ]; then CHANGELOG=$(git log --pretty=format:"- %s" HEAD | head -20) else CHANGELOG=$(git log --pretty=format:"- %s" "$LATEST_TAG..HEAD^" | head -20) fi # Escape JSON special characters CHANGELOG_JSON=$(echo "$CHANGELOG" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g') BODY="## What's Changed\n\n$CHANGELOG_JSON\n\n**Full Changelog**: https://github.com/barryw/PaperlessMCP/compare/$LATEST_TAG...$TAG" curl -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/barryw/PaperlessMCP/releases \ -d "{\"tag_name\":\"$TAG\",\"name\":\"Release $VERSION\",\"body\":\"$BODY\",\"draft\":false,\"prerelease\":false}" depends_on: [git-tag] # Deploy to Kubernetes - name: deploy image: bitnami/kubectl:latest commands: - | BUMP_TYPE=$(cat .bump-type) if [ "$BUMP_TYPE" = "none" ]; then echo "No version bump, skipping deploy" exit 0 fi VERSION=$(cat .version) echo "Deploying version $VERSION to Kubernetes" # Update deployment image to specific version tag kubectl set image deployment/paperless-mcp \ paperless-mcp=ghcr.io/barryw/paperlessmcp:v$VERSION \ -n default # Wait for rollout to complete kubectl rollout status deployment/paperless-mcp -n default --timeout=120s echo "Deployment complete!" depends_on: [docker, release]