diff --git a/.bumpversion.cfg b/.bumpversion.cfg index b020388..dd9a5f6 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,13 +1,10 @@ [bumpversion] current_version = 4.0.7 commit = True -parse = (?P\d+)(\.(?P\d+))(\.(?P\d+))(\-(?P.*))? -serialize = - {major}.{minor}.{patch}-{release} - {major}.{minor}.{patch} +tag = False [bumpversion:file:VERSION] [bumpversion:file:pyproject.toml] - -[bumpversion:file:src/halpi/const.py] +search = version = "{current_version}" +replace = version = "{new_version}" diff --git a/.github/actions/build-deb/action.yml b/.github/actions/build-deb/action.yml new file mode 100644 index 0000000..aab7e2f --- /dev/null +++ b/.github/actions/build-deb/action.yml @@ -0,0 +1,23 @@ +name: 'Build Debian Package' +description: 'Build HALPI2 daemon .deb package' + +runs: + using: 'composite' + steps: + - name: Create minimal .env file + run: | + if [ ! -f .env ]; then + echo "# Environment file for GitHub Actions" > .env + fi + shell: bash + + - name: Build package + run: ./run docker-build-deb + shell: bash + + - name: Collect built packages + run: | + # Find .deb files created by dpkg-buildpackage (in parent directory) + find . .. -maxdepth 1 -name "*.deb" -exec mv {} ./ \; 2>/dev/null || true + ls -lh *.deb + shell: bash diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml new file mode 100644 index 0000000..7318c76 --- /dev/null +++ b/.github/actions/run-tests/action.yml @@ -0,0 +1,17 @@ +name: 'Run Tests' +description: 'Run Python tests for HALPI2 daemon' + +runs: + using: 'composite' + steps: + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install uv + uses: astral-sh/setup-uv@v4 + + - name: Run tests + run: uv run pytest + shell: bash diff --git a/.github/scripts/check-release-exists.sh b/.github/scripts/check-release-exists.sh new file mode 100755 index 0000000..91a4111 --- /dev/null +++ b/.github/scripts/check-release-exists.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Check if a release exists and set output flags +# Usage: check-release-exists.sh [RELEASE_TYPE] +# RELEASE_TYPE: "prerelease" (default), "draft", or "stable" + +set -e + +VERSION="${1:?Version required}" +RELEASE_TYPE="${2:-prerelease}" + +if [ -z "$VERSION" ]; then + echo "Error: VERSION argument required" + exit 1 +fi + +case "$RELEASE_TYPE" in + prerelease) + # Check if published (non-prerelease) release with same or higher version exists + HIGHEST_STABLE=$(gh release list --limit 100 --json tagName,isPrerelease,isDraft \ + --jq '.[] | select(.isDraft == false and .isPrerelease == false) | .tagName' | \ + sed 's/^v//' | sort -V | tail -n1) + + if [ -n "$HIGHEST_STABLE" ]; then + echo "Found highest stable release: v${HIGHEST_STABLE}" + # Compare versions using dpkg --compare-versions + # Strip Debian revision from VERSION for comparison (0.2.0-1 โ†’ 0.2.0) + # Note: ${VERSION%-*} is safe - if VERSION has no dash, it returns VERSION unchanged + if dpkg --compare-versions "${VERSION%-*}" le "$HIGHEST_STABLE"; then + echo "action=skip" >> "$GITHUB_OUTPUT" + echo "โญ๏ธ Stable release v${HIGHEST_STABLE} >= v${VERSION%-*} - skipping pre-release" + exit 0 + fi + fi + echo "action=create" >> "$GITHUB_OUTPUT" + echo "โœ… No published release with same or higher version - will create pre-release v${VERSION%-*}" + ;; + + draft) + # Check if release exists (any kind) + if gh release view "v$VERSION" &>/dev/null; then + IS_DRAFT=$(gh release view "v$VERSION" --json isDraft --jq '.isDraft') + if [ "$IS_DRAFT" = "true" ]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "delete_existing=true" >> "$GITHUB_OUTPUT" + echo "Existing draft release found - will delete and recreate" + else + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "delete_existing=false" >> "$GITHUB_OUTPUT" + echo "Published release v$VERSION already exists - skipping" + fi + else + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "delete_existing=false" >> "$GITHUB_OUTPUT" + echo "No existing release found" + fi + ;; + + stable) + # For stable releases, check if prerelease exists to delete first + if gh release view "v$VERSION" &>/dev/null; then + IS_PRERELEASE=$(gh release view "v$VERSION" --json isPrerelease --jq '.isPrerelease') + if [ "$IS_PRERELEASE" = "true" ]; then + echo "action=delete" >> "$GITHUB_OUTPUT" + echo "๐Ÿ—‘๏ธ Existing pre-release v$VERSION found - will delete before creating stable" + else + echo "action=skip" >> "$GITHUB_OUTPUT" + echo "โญ๏ธ Published release v$VERSION already exists - skipping" + fi + else + echo "action=create" >> "$GITHUB_OUTPUT" + echo "โœ… No existing release found - will create v$VERSION" + fi + ;; + + *) + echo "Error: Unknown RELEASE_TYPE '$RELEASE_TYPE'. Use 'prerelease', 'draft', or 'stable'" + exit 1 + ;; +esac diff --git a/.github/scripts/generate-release-notes.sh b/.github/scripts/generate-release-notes.sh new file mode 100755 index 0000000..587e112 --- /dev/null +++ b/.github/scripts/generate-release-notes.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# Generate release notes for a release +# Usage: generate-release-notes.sh +# RELEASE_TYPE: "prerelease", "draft", or "stable" + +set -e + +VERSION="${1:?Version required}" +TAG_VERSION="${2:?Tag version required}" +RELEASE_TYPE="${3:?Release type required}" + +if [ -z "$VERSION" ] || [ -z "$TAG_VERSION" ] || [ -z "$RELEASE_TYPE" ]; then + echo "Usage: generate-release-notes.sh " + exit 1 +fi + +SHORT_SHA="${GITHUB_SHA:0:7}" + +# Get the latest published (non-prerelease) release +LAST_TAG=$(gh release list --limit 100 --json tagName,isPrerelease,isDraft \ + --jq '.[] | select(.isDraft == false and .isPrerelease == false) | .tagName' | head -n1) + +if [ -n "$LAST_TAG" ]; then + echo "Generating changelog since $LAST_TAG" + CHANGELOG=$(git log "${LAST_TAG}"..HEAD --pretty=format:"- %s (%h)" --no-merges --) +else + echo "No previous published releases found, using recent commits" + CHANGELOG=$(git log -10 --pretty=format:"- %s (%h)" --no-merges) +fi + +case "$RELEASE_TYPE" in + prerelease) + cat > release_notes.md < release_notes.md < release_notes.md <> "$GITHUB_OUTPUT" +echo "tag_version=$TAG_VERSION" >> "$GITHUB_OUTPUT" +echo "Version from VERSION file: $VERSION (tag version: $TAG_VERSION)" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 86dbc5d..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: build - -on: [push, pull_request] - -jobs: - # Build packages on every push - build-packages: - runs-on: ubuntu-latest-arm64 - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v5 - - - name: Read version from VERSION file - id: version - run: | - VERSION=$(cat VERSION | tr -d '\n\r ') - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Found version: $VERSION" - - - name: Build packages - run: | - # Create minimal .env file to prevent docker-compose warnings - if [ ! -f .env ]; then - echo "# Environment file for GitHub Actions" > .env - fi - - # Use the CI-specific package build function - ./run package:deb:docker:ci - - - name: Collect built packages - run: | - mkdir -p packages - # Find .deb files in current and parent directory (dpkg-buildpackage creates them in parent) - find . .. -maxdepth 1 -name "*.deb" -exec cp {} packages/ \; 2>/dev/null || true - ls -la packages/ - echo "Found packages:" - ls -1 packages/*.deb 2>/dev/null || echo "No packages found" - - - name: Upload packages as artifacts - if: success() - uses: actions/upload-artifact@v4 - with: - name: debian-packages-${{ steps.version.outputs.version }} - path: packages/*.deb - retention-days: 30 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..3fa7553 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,158 @@ +name: Main Branch CI/CD + +on: + push: + branches: [main] + +permissions: + contents: write + +env: + APT_DISTRO: ${{ vars.APT_DISTRO || 'trixie' }} + APT_COMPONENT: ${{ vars.APT_COMPONENT || 'hatlabs' }} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run tests + uses: ./.github/actions/run-tests + + build-and-release: + needs: test + runs-on: ubuntu-latest-arm64 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Read version from VERSION + id: version + run: .github/scripts/read-version.sh + + - name: Check if published release exists + id: check + run: .github/scripts/check-release-exists.sh "${{ steps.version.outputs.version }}" prerelease + env: + GH_TOKEN: ${{ github.token }} + + - name: Build .deb package + if: steps.check.outputs.action == 'create' + uses: ./.github/actions/build-deb + + - name: Rename package with distro+component suffix + if: steps.check.outputs.action == 'create' + run: | + VERSION="${{ steps.version.outputs.version }}" + OLD_NAME="halpi2-daemon_${VERSION}_arm64.deb" + NEW_NAME="halpi2-daemon_${VERSION}_arm64+${APT_DISTRO}+${APT_COMPONENT}.deb" + + if [ -f "$OLD_NAME" ]; then + echo "๐Ÿ“ฆ Renaming package: $(basename $OLD_NAME) โ†’ $(basename $NEW_NAME)" + mv "$OLD_NAME" "$NEW_NAME" + echo "โœ… Package renamed successfully" + echo "Package location: $NEW_NAME" + else + echo "โŒ Error: Expected package not found: $OLD_NAME" + exit 1 + fi + + - name: Generate release notes + if: steps.check.outputs.action == 'create' + id: notes + run: .github/scripts/generate-release-notes.sh "${{ steps.version.outputs.version }}" "${{ steps.version.outputs.tag_version }}" prerelease + env: + GH_TOKEN: ${{ github.token }} + + - name: Delete existing pre-release + if: steps.check.outputs.action == 'create' + run: | + TAG_VERSION="${{ steps.version.outputs.tag_version }}" + if gh release view "v${TAG_VERSION}" &>/dev/null; then + IS_PRERELEASE=$(gh release view "v${TAG_VERSION}" --json isPrerelease --jq '.isPrerelease') + if [ "$IS_PRERELEASE" = "true" ]; then + echo "๐Ÿ—‘๏ธ Deleting existing pre-release v${TAG_VERSION}" + gh release delete "v${TAG_VERSION}" --yes --cleanup-tag + fi + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Create pre-release + if: steps.check.outputs.action == 'create' + run: | + TAG_VERSION="${{ steps.version.outputs.tag_version }}" + if ! ls *.deb 1> /dev/null 2>&1; then + echo "โŒ Error: No .deb files found" + exit 1 + fi + echo "๐Ÿ“ฆ Creating pre-release v${TAG_VERSION}" + gh release create "v${TAG_VERSION}" \ + --prerelease \ + --title "v${TAG_VERSION} (Pre-release)" \ + --notes-file release_notes.md \ + *.deb + echo "โœ… Pre-release created successfully" + env: + GH_TOKEN: ${{ github.token }} + + - name: Create draft release + if: steps.check.outputs.action == 'create' + run: | + VERSION="${{ steps.version.outputs.version }}" + TAG_VERSION="${{ steps.version.outputs.tag_version }}" + + # Check if draft release already exists + if gh release view "v${VERSION}" &>/dev/null; then + IS_DRAFT=$(gh release view "v${VERSION}" --json isDraft --jq '.isDraft') + IS_PRERELEASE=$(gh release view "v${VERSION}" --json isPrerelease --jq '.isPrerelease') + + if [ "$IS_DRAFT" = "true" ] && [ "$IS_PRERELEASE" = "false" ]; then + echo "Draft release v${VERSION} already exists, skipping creation" + fi + else + # Generate release notes for draft + .github/scripts/generate-release-notes.sh "${VERSION}" "${VERSION}" draft + + echo "๐Ÿ“‹ Creating draft release v${VERSION}" + gh release create "v${VERSION}" \ + --draft \ + --title "v${VERSION}" \ + --notes-file release_notes.md + echo "โœ… Draft release created successfully" + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Dispatch to APT repository + if: steps.check.outputs.action == 'create' + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.REPO_DISPATCH_PAT }} + repository: hatlabs/apt.hatlabs.fi + event-type: package-updated + client-payload: | + { + "repository": "${{ github.repository }}", + "distro": "${{ env.APT_DISTRO }}", + "channel": "unstable", + "component": "${{ env.APT_COMPONENT }}" + } + + - name: Report success + if: steps.check.outputs.action == 'create' + run: | + VERSION="${{ steps.version.outputs.version }}" + TAG_VERSION="${{ steps.version.outputs.tag_version }}" + echo "=== Main Branch CI/CD Complete ===" + echo "Package version: ${VERSION}" + echo "Release tag: v${TAG_VERSION}" + echo "Release URL: https://github.com/${{ github.repository }}/releases/tag/v${TAG_VERSION}" + echo "" + echo "โœ… Pre-release created" + echo "โœ… Draft release created" + echo "โœ… Dispatched to apt.hatlabs.fi unstable channel" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..4262322 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,19 @@ +name: Pull Request Checks + +on: + pull_request: + branches: [ main ] + +permissions: + contents: read + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run tests + uses: ./.github/actions/run-tests diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml deleted file mode 100644 index 3d0334f..0000000 --- a/.github/workflows/release-drafter.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Release Drafter - -on: - workflow_run: - workflows: ["build"] - types: - - completed - branches: - - main - -jobs: - update_release_draft: - runs-on: ubuntu-latest - # Only run if the build workflow succeeded - if: github.event.workflow_run.conclusion == 'success' - steps: - - uses: actions/checkout@v5 - - - name: Read version from VERSION file - id: version - run: | - VERSION=$(cat VERSION | tr -d '\n\r ') - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Found version: $VERSION" - - # Download packages built by the build workflow - - name: Download packages from build workflow - uses: actions/download-artifact@v4 - with: - name: debian-packages-${{ steps.version.outputs.version }} - path: packages/ - github-token: ${{ secrets.GITHUB_TOKEN }} - repository: ${{ github.repository }} - run-id: ${{ github.event.workflow_run.id }} - - - name: List downloaded packages - run: | - echo "Downloaded packages:" - ls -la packages/ || echo "packages/ directory not found" - find packages/ -name "*.deb" -ls 2>/dev/null || echo "No .deb files found" - echo "Package count: $(find packages/ -name "*.deb" 2>/dev/null | wc -l)" - - # Drafts your next Release notes as Pull Requests are merged into "main" - - uses: release-drafter/release-drafter@v6 - id: release_drafter - with: - version: ${{ steps.version.outputs.version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Debug release drafter outputs - - name: Debug release drafter outputs - run: | - echo "Release ID: ${{ steps.release_drafter.outputs.id }}" - echo "Upload URL: ${{ steps.release_drafter.outputs.upload_url }}" - echo "HTML URL: ${{ steps.release_drafter.outputs.html_url }}" - - # Upload packages to the draft release - - name: Upload packages to release - if: steps.release_drafter.outputs.upload_url - run: | - echo "Starting package upload process..." - upload_url_template="${{ steps.release_drafter.outputs.upload_url }}" - echo "Upload URL template: $upload_url_template" - - package_count=0 - for deb_file in packages/*.deb; do - if [ -f "$deb_file" ]; then - filename=$(basename "$deb_file") - filesize=$(stat -c%s "$deb_file") - echo "Uploading $filename (${filesize} bytes)..." - - # Replace the URL template properly - upload_url="${upload_url_template%\{*\}}?name=${filename}" - echo "Final upload URL: $upload_url" - - response=$(curl -w "%{http_code}" -s -o /tmp/upload_response.json \ - -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ - -H "Content-Type: application/octet-stream" \ - --data-binary @"$deb_file" \ - "$upload_url") - - echo "HTTP response code: $response" - if [ "$response" -ge 200 ] && [ "$response" -lt 300 ]; then - echo "โœ… Successfully uploaded $filename" - package_count=$((package_count + 1)) - else - echo "โŒ Failed to upload $filename" - echo "Response body:" - cat /tmp/upload_response.json || echo "No response body" - fi - fi - done - - echo "Upload summary: $package_count packages uploaded" - if [ $package_count -eq 0 ]; then - echo "โŒ No packages were uploaded successfully" - exit 1 - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d485ab2..3a4c521 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,28 +4,29 @@ on: release: types: [published] +permissions: + contents: read + +env: + APT_DISTRO: ${{ vars.APT_DISTRO || 'trixie' }} + APT_COMPONENT: ${{ vars.APT_COMPONENT || 'hatlabs' }} + jobs: - notify-apt-repo: + trigger-packaging: runs-on: ubuntu-latest + # Only handle stable releases - pre-releases are handled by auto-prerelease.yml + if: ${{ github.event.release.prerelease == false }} steps: - - name: Extract version from tag - id: version - run: | - # Extract version from tag (remove 'v' prefix if present) - VERSION="${{ github.event.release.tag_name }}" - VERSION="${VERSION#v}" - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Extracted version: $VERSION" - - - name: Trigger APT repository update + - name: Trigger APT repository uses: peter-evans/repository-dispatch@v3 with: - token: ${{ secrets.APT_REPO_PAT }} + token: ${{ secrets.REPO_DISPATCH_PAT }} repository: hatlabs/apt.hatlabs.fi event-type: package-updated client-payload: | { - "package": "${{ github.event.repository.name }}", - "version": "${{ steps.version.outputs.version }}", - "repository": "${{ github.repository }}" + "repository": "${{ github.repository }}", + "distro": "${{ env.APT_DISTRO }}", + "channel": "stable", + "component": "${{ env.APT_COMPONENT }}" } diff --git a/run b/run index 79a9c52..d54e38d 100755 --- a/run +++ b/run @@ -68,33 +68,33 @@ function clean { build-remove } -function release:version { +function version { #@ Show current project version #@ Category: Core Development cat VERSION } +function bumpversion { + #@ Bump version using bumpversion tool + #@ Usage: bumpversion [patch|minor|major] or bumpversion --new-version X.Y.Z patch + #@ Category: Core Development + command bumpversion "$@" +} + ################################################################################ # Package Management Commands -function package:deb { +function build-deb { #@ Build Debian package (native) #@ Category: Package Management echo "๐Ÿ—๏ธ Building Debian package..." - package:deb:only -} - -function package:deb:only { - #@ Build Debian package from existing artifacts (internal) - #@ Category: Package Management - echo "๐Ÿ“ฆ Creating Debian package..." # Set up environment - dev:env + dev-env export DEBEMAIL="info@hatlabs.fi" export DEBFULLNAME="Hat Labs CI" - export PACKAGE_VERSION=$(release:version) + export PACKAGE_VERSION=$(release-version) DEB_VERSION=$(echo "$PACKAGE_VERSION" | sed 's/-\([a-zA-Z]\)/~\1/g') # Create a new changelog entry @@ -108,27 +108,7 @@ function package:deb:only { echo "โœ… Debian package built successfully" } -function package:deb:only:ci { - #@ Build Debian package for CI (bypasses environment setup) - #@ Category: Package Management - echo "๐Ÿ“ฆ Creating Debian package (CI mode)..." - - # Skip environment setup that's causing issues in CI - # Set required environment variables directly - export DEBEMAIL="info@hatlabs.fi" - export DEBFULLNAME="Hat Labs CI" - export PACKAGE_VERSION=$(release:version) - - # CI mode: Use existing changelog entry created by dev:version:bump - # No dch call needed - changelog should already be updated - echo "๐Ÿ“‹ Using existing debian/changelog entry for version $PACKAGE_VERSION" - - dpkg-buildpackage -us -uc -b - - echo "โœ… Debian package built successfully (CI mode)" -} - -function package:deb:docker { +function docker-build-deb { #@ Build Debian package using Docker container #@ Category: Package Management echo "๐Ÿณ Building Debian package using Docker..." @@ -136,27 +116,12 @@ function package:deb:docker { # Use Docker container for Debian packaging echo "๐Ÿณ Running Debian packaging in Docker container..." export DIR_NAME=$(basename "$PWD") - docker compose -f docker/docker-compose.debtools.yml run --rm debtools ./run package:deb:only + debtools ./run build-deb-only echo "โœ… Docker-based Debian package built successfully" } -function package:deb:docker:ci { - #@ Build Debian package using Docker container (CI mode) - #@ Category: Package Management - echo "๐Ÿณ Building Debian package using Docker (CI mode)..." - - # Use Docker container for Debian packaging with CI-specific function - echo "๐Ÿณ Running Debian packaging in Docker container (CI mode)..." - export DIR_NAME=$(basename "$PWD") - - # Run as root in CI to avoid permission issues with mounted volumes - docker compose -f docker/docker-compose.debtools.yml run --rm --user root debtools ./run package:deb:only:ci - - echo "โœ… Docker-based Debian package built successfully (CI mode)" -} - -function package:docker:build { +function build-docker-tools { #@ Build Docker tools image #@ Category: Package Management export DIR_NAME=$(basename "$PWD") @@ -166,7 +131,7 @@ function package:docker:build { ################################################################################ # Testing/CI Commands -function ci:check { +function ci-check { #@ Run CI verification checks (lint + test) #@ Category: Testing/CI echo "๐Ÿ” Running CI verification checks..." @@ -175,117 +140,16 @@ function ci:check { echo "โœ… CI checks passed" } -function ci:build { +function ci-build { #@ Full CI build pipeline (lint + test + package) #@ Category: Testing/CI echo "๐Ÿš€ Running full CI build pipeline..." clean - ci:check - package:deb:docker + ci-check + docker-build-deb echo "โœ… CI build pipeline completed successfully" } -function test:package:workflow { - #@ Test the package build workflow locally using act - #@ Category: Testing/CI - echo "๐Ÿงช Testing package build workflow with act..." - - # Check if act is installed - if ! command -v act &> /dev/null; then - echo "โŒ Error: 'act' is not installed. Install with: brew install act" - return 1 - fi - - # Test the build-packages job from build.yml - echo "๐Ÿณ Running package build test with act (using linux/amd64 architecture)..." - echo "โ„น๏ธ This will test the build-packages job from build.yml" - echo "" - - # Run the build-packages job with act - act push \ - -W .github/workflows/build.yml \ - --job build-packages \ - --container-architecture linux/amd64 \ - --verbose - - local exit_code=$? - if [ $exit_code -eq 0 ]; then - echo "" - echo "โœ… Package build workflow test completed successfully!" - echo "๐ŸŽฏ The workflow should have created .deb packages and uploaded artifacts" - else - echo "" - echo "โŒ Package build workflow test failed with exit code: $exit_code" - echo "๐Ÿ’ก Check the output above for errors" - return $exit_code - fi -} - -function test:package:workflow:dry { - #@ Dry run test of the package build workflow (shows steps without executing) - #@ Category: Testing/CI - echo "๐Ÿงช Dry run test of package build workflow..." - - # Check if act is installed - if ! command -v act &> /dev/null; then - echo "โŒ Error: 'act' is not installed. Install with: brew install act" - return 1 - fi - - echo "๐Ÿ“‹ Showing workflow steps that would run:" - act push \ - -W .github/workflows/build.yml \ - --job build-packages \ - --container-architecture linux/amd64 \ - -n -} - -function test:release:workflow:local { - #@ Test the release workflow steps locally (without GitHub API calls) - #@ Category: Testing/CI - echo "๐Ÿงช Testing release workflow steps locally..." - - echo "๐Ÿ“– Step 1: Reading version from VERSION file" - VERSION=$(cat VERSION | tr -d '\n\r ') - echo "version=$VERSION" - echo "Found version: $VERSION" - echo "" - - echo "๐Ÿ“ฆ Step 2: Building packages" - # Create minimal .env file to prevent docker-compose warnings - if [ ! -f .env ]; then - echo "# Minimal .env for local testing" > .env - echo "Created minimal .env file" - fi - - # Use the run script's package build function - ./run package:deb:docker - echo "" - - echo "๐Ÿ“‹ Step 3: Collecting built packages" - mkdir -p packages - # Find .deb files in current and parent directory (dpkg-buildpackage creates them in parent) - find . .. -maxdepth 1 -name "*.deb" -exec cp {} packages/ \; 2>/dev/null || true - echo "Packages found:" - ls -la packages/ - echo "Package list:" - ls -1 packages/*.deb 2>/dev/null || echo "No packages found" - echo "" - - echo "โ„น๏ธ Step 4: Release drafter (skipped - requires GitHub API)" - echo "๐Ÿšซ Step 5: Upload packages (skipped - requires GitHub API)" - echo "" - - if [ -n "$(ls -A packages/ 2>/dev/null)" ]; then - echo "โœ… Release workflow local test completed successfully!" - echo "๐Ÿ“ฆ Generated packages are in the 'packages/' directory" - echo "๐ŸŽฏ In the real workflow, these would be attached to a draft release" - else - echo "โŒ Release workflow local test failed - no packages were generated" - return 1 - fi -} - ################################################################################ # Development Utilities Commands @@ -319,94 +183,42 @@ function pull { --exclude='.venv' halpi2:src/halpid/ . } -function dev:env { +function dev-env { #@ Show/check development environment #@ Category: Development Utilities _env } -function dev:version:bump { - #@ Bump to specific version (e.g. 3.2.0) - #@ Usage: dev:version:bump +function debtools { + #@ Run a command inside the debtools Docker container + #@ Usage: debtools [args] #@ Category: Development Utilities - local new_version="${1:-}" - - if [ -z "$new_version" ]; then - echo "Error: Version required. Usage: dev:version:bump " - echo "Current version: $(release:version)" - echo "Example: ./run dev:version:bump 3.2.0" - exit 1 - fi - - echo "๐Ÿ”– Bumping version from $(release:version) to $new_version..." - - # Update version files using bump2version - bump2version --new-version "$new_version" patch - - # Set up environment for debian changelog - export DEBEMAIL="info@hatlabs.fi" - export DEBFULLNAME="Hat Labs CI" - - # Convert version format for Debian (replace - with ~) - DEB_VERSION=$(echo "$new_version" | sed 's/-\([a-zA-Z]\)/~\1/g') - - # Create a new debian/changelog entry - echo "๐Ÿ“ Creating debian/changelog entry for version $DEB_VERSION..." - dch --newversion "$DEB_VERSION" \ - --distribution stable \ - --force-distribution \ - "Development release $new_version. See GitHub for details." - - echo "โœ“ Version bumped to $(release:version)" - echo "โœ“ Debian changelog updated with version $DEB_VERSION" + export DIR_NAME=$(basename "$PWD") + docker compose -f docker/docker-compose.debtools.yml run --rm debtools "$@" } -function dev:version:dry-run { +function bumpversion-dry-run { #@ Preview version change without applying - #@ Usage: dev:version:dry-run + #@ Usage: bumpversion-dry-run #@ Category: Development Utilities local new_version="${1:-}" if [ -z "$new_version" ]; then - echo "Error: Version required. Usage: dev:version:dry-run " - echo "Current version: $(release:version)" - echo "Example: ./run dev:version:dry-run 3.2.0" + echo "Error: Version required. Usage: bumpversion-dry-run " + echo "Current version: $(version)" + echo "Example: ./run bumpversion-dry-run 3.2.0" exit 1 fi - echo "Current version: $(release:version)" + echo "Current version: $(version)" echo "Preview of changes for version $new_version:" - echo "" - - # Show bump2version preview bump2version --new-version "$new_version" patch --dry-run --verbose - - echo "" - echo "Debian changelog entry that would be created:" - echo "----------------------------------------" - - # Convert version format for Debian (replace - with ~) - DEB_VERSION=$(echo "$new_version" | sed 's/-\([a-zA-Z]\)/~\1/g') - - # Show what the changelog entry would look like - echo "halpid ($DEB_VERSION) stable; urgency=medium" - echo "" - echo " * Development release $new_version. See GitHub for details." - echo "" - echo " -- Hat Labs CI $(date -R)" - echo "" -} - -function dev:version:show { - #@ Show current version - #@ Category: Development Utilities - release:version } ################################################################################ # Docker Commands -function docker:build { +function build-docker { #@ Build the Docker image #@ Category: Docker echo Building docker ${DOCKER_IMAGE}:${DOCKER_IMAGE_VERSION} ... @@ -414,7 +226,7 @@ function docker:build { -f ./docker/Dockerfile --no-cache } -function docker:remove { +function remove-docker { #@ Remove the Docker image #@ Category: Docker echo Removing docker ${DOCKER_IMAGE}:${DOCKER_IMAGE_VERSION} ... @@ -424,7 +236,7 @@ function docker:remove { ################################################################################ # Setup/Installation Commands -function uv-download { +function install-uv { #@ Download and install the latest version of uv #@ Category: Setup/Installation curl -LsSf https://astral.sh/uv/install.sh | sh @@ -457,19 +269,6 @@ function build-remove { rm -rf build/ 2>/dev/null || true } -# Legacy aliases for backward compatibility -function debtools { - export DIR_NAME=$(basename "$PWD") - docker compose -f docker/docker-compose.debtools.yml run --rm debtools "$@" -} - -function build-debian { - package:deb:only -} - -function debtools-build { - package:deb:docker -} ################################################################################ # Project-specific commands end.