Nightly Release #51
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: Nightly Release | |
| on: | |
| schedule: | |
| - cron: "0 0 * * *" # Daily at 00:00 UTC | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| env: | |
| cache_nonce: 0 | |
| pinned_branch: master | |
| jobs: | |
| # Run tests | |
| test: | |
| name: Run tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install mise | |
| uses: jdx/mise-action@v3 | |
| with: | |
| enable: true | |
| cache: true | |
| - name: Create virtual environment | |
| run: | | |
| python -m venv venv | |
| - name: Install test dependencies | |
| run: | | |
| source venv/bin/activate | |
| pip install -r requirements-test.txt | |
| - name: Run tests with coverage | |
| run: | | |
| source venv/bin/activate | |
| pytest tests/ -v --cov=src --cov-report=xml --cov-report=term | |
| - name: Upload coverage reports | |
| if: github.event_name != 'workflow_dispatch' | |
| uses: codecov/codecov-action@v5 | |
| continue-on-error: true | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./coverage.xml | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| # Check for new commits | |
| check-updates: | |
| runs-on: ubuntu-latest | |
| needs: test | |
| outputs: | |
| should_build: ${{ steps.check.outputs.should_build }} | |
| commit_hash: ${{ steps.check.outputs.commit_hash }} | |
| commit_short: ${{ steps.check.outputs.commit_short }} | |
| commit_date: ${{ steps.check.outputs.commit_date }} | |
| branch_name: ${{ steps.check.outputs.branch_name }} | |
| previous_commit: ${{ steps.check.outputs.previous_commit }} | |
| steps: | |
| - name: Check for new commits | |
| id: check | |
| run: | | |
| # Use pinned commit/branch if set, otherwise fetch latest from pinned_branch | |
| if [ -n "${{ env.pinned_commit }}" ]; then | |
| # Validate that both pinned_branch and pinned_commit are set | |
| if [ -z "${{ env.pinned_branch }}" ]; then | |
| echo "Error: pinned_commit is set but pinned_branch is not set. Both must be provided together." | |
| exit 1 | |
| fi | |
| LATEST_COMMIT="${{ env.pinned_commit }}" | |
| LATEST_SHORT=$(echo $LATEST_COMMIT | cut -c1-7) | |
| BRANCH_NAME="${{ env.pinned_branch }}" | |
| echo "Using pinned commit: $LATEST_SHORT from branch: $BRANCH_NAME" | |
| else | |
| # Fetch latest commit from logos-storage-nim | |
| BRANCH_NAME="${{ env.pinned_branch }}" | |
| git ls-remote https://github.com/logos-storage/logos-storage-nim.git refs/heads/$BRANCH_NAME > latest.txt | |
| LATEST_COMMIT=$(awk '{print $1}' latest.txt) | |
| LATEST_SHORT=$(echo $LATEST_COMMIT | cut -c1-7) | |
| echo "Using latest commit from $BRANCH_NAME: $LATEST_SHORT" | |
| fi | |
| # Fetch commit date using GitHub API | |
| API_URL="https://api.github.com/repos/logos-storage/logos-storage-nim/commits/$LATEST_COMMIT" | |
| COMMIT_DATE=$(curl -s "$API_URL" | python3 -c "import sys, json; data=json.load(sys.stdin); print(data['commit']['committer']['date'])" 2>/dev/null || echo "Unknown") | |
| # Get latest prerelease release from this repository | |
| LATEST_PRERELEASE=$(curl -s "https://api.github.com/repos/${{ github.repository }}/releases?per_page=10" | python3 -c "import sys, json; data=json.load(sys.stdin); prereleases=[r for r in data if r.get('prerelease')]; print(prereleases[0]['body'] if prereleases else '')" 2>/dev/null || echo "") | |
| # Extract previous commit hash from prerelease release body | |
| PREVIOUS_COMMIT=$(echo "$LATEST_PRERELEASE" | grep -oP 'Commit: \K[a-f0-9]{40}' || echo "") | |
| # If no prerelease exists, we should build | |
| if [ -z "$LATEST_PRERELEASE" ]; then | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| echo "commit_hash=$LATEST_COMMIT" >> $GITHUB_OUTPUT | |
| echo "commit_short=$LATEST_SHORT" >> $GITHUB_OUTPUT | |
| echo "commit_date=$COMMIT_DATE" >> $GITHUB_OUTPUT | |
| echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
| echo "previous_commit=" >> $GITHUB_OUTPUT | |
| echo "No previous prerelease found, building for commit: $LATEST_SHORT" | |
| exit 0 | |
| fi | |
| # Check if the prerelease body contains the full commit hash | |
| if echo "$LATEST_PRERELEASE" | grep -q "$LATEST_COMMIT"; then | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| echo "Latest commit $LATEST_SHORT is already released" | |
| else | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| echo "commit_hash=$LATEST_COMMIT" >> $GITHUB_OUTPUT | |
| echo "commit_short=$LATEST_SHORT" >> $GITHUB_OUTPUT | |
| echo "commit_date=$COMMIT_DATE" >> $GITHUB_OUTPUT | |
| echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
| echo "previous_commit=$PREVIOUS_COMMIT" >> $GITHUB_OUTPUT | |
| echo "New commit detected: $LATEST_SHORT" | |
| fi | |
| # Matrix build | |
| build: | |
| needs: [test, check-updates] | |
| if: needs.check-updates.outputs.should_build == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: linux | |
| cpu: amd64 | |
| builder: ubuntu-latest | |
| - os: linux | |
| cpu: arm64 | |
| builder: ubuntu-22.04-arm | |
| - os: macos | |
| cpu: arm64 | |
| builder: macos-latest | |
| - os: windows | |
| cpu: amd64 | |
| builder: windows-latest | |
| name: ${{ matrix.os }}-${{ matrix.cpu }} | |
| runs-on: ${{ matrix.builder }} | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install mise | |
| uses: jdx/mise-action@v3 | |
| with: | |
| enable: true | |
| cache: true | |
| - name: Setup MSYS2 (Windows) | |
| if: runner.os == 'Windows' | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: MINGW64 | |
| update: true | |
| path-type: inherit | |
| install: >- | |
| base-devel | |
| mingw-w64-x86_64-gcc | |
| mingw-w64-x86_64-cmake | |
| mingw-w64-x86_64-make | |
| git | |
| - name: Install build dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y git make gcc binutils cmake | |
| shell: bash | |
| - name: Build (Windows) | |
| if: runner.os == 'Windows' | |
| shell: msys2 {0} | |
| run: | | |
| make clean | |
| make | |
| env: | |
| BRANCH: ${{ env.pinned_branch }} | |
| COMMIT: ${{ env.pinned_commit }} | |
| - name: Build (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| make clean | |
| make | |
| env: | |
| BRANCH: ${{ env.pinned_branch }} | |
| COMMIT: ${{ env.pinned_commit }} | |
| shell: bash | |
| - name: Upload artifacts | |
| if: env.ACT != 'true' | |
| uses: actions/upload-artifact@v6 | |
| continue-on-error: true | |
| with: | |
| name: libstorage-${{ matrix.os }}-${{ matrix.cpu }} | |
| path: dist/*/ | |
| retention-days: 90 | |
| - name: Verify artifacts (Windows) | |
| if: runner.os == 'Windows' | |
| shell: msys2 {0} | |
| run: | | |
| echo "Verifying artifacts..." | |
| if [ -d "dist" ]; then | |
| # List all library files | |
| find dist -name "*.a" -type f | while read lib; do | |
| echo "Found: $lib" | |
| ls -lh "$lib" | |
| done | |
| # Verify SHA256SUMS.txt | |
| find dist -name "SHA256SUMS.txt" -type f | while read checksum_file; do | |
| echo "Verifying checksums in: $checksum_file" | |
| # Change to the directory containing the checksum file before verification | |
| checksum_dir=$(dirname "$checksum_file") | |
| (cd "$checksum_dir" && sha256sum -c "SHA256SUMS.txt") | |
| done | |
| echo "" | |
| echo "Artifacts are available in: $(pwd)/dist/" | |
| else | |
| echo "No dist directory found" | |
| fi | |
| - name: Verify artifacts (Unix) | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: | | |
| echo "Verifying artifacts..." | |
| if [ -d "dist" ]; then | |
| # List all library files | |
| find dist -name "*.a" -type f | while read lib; do | |
| echo "Found: $lib" | |
| ls -lh "$lib" | |
| done | |
| # Verify SHA256SUMS.txt | |
| find dist -name "SHA256SUMS.txt" -type f | while read checksum_file; do | |
| echo "Verifying checksums in: $checksum_file" | |
| # Change to the directory containing the checksum file before verification | |
| checksum_dir=$(dirname "$checksum_file") | |
| (cd "$checksum_dir" && sha256sum -c "SHA256SUMS.txt") | |
| done | |
| echo "" | |
| echo "Artifacts are available in: $(pwd)/dist/" | |
| else | |
| echo "No dist directory found" | |
| fi | |
| # Fetch commit changes | |
| fetch-commits: | |
| runs-on: ubuntu-latest | |
| needs: [test, check-updates] | |
| if: needs.check-updates.outputs.should_build == 'true' | |
| outputs: | |
| commit_changes: ${{ steps.fetch.outputs.changes }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install mise | |
| uses: jdx/mise-action@v3 | |
| with: | |
| enable: true | |
| cache: true | |
| - name: Create virtual environment | |
| run: | | |
| python -m venv venv | |
| - name: Install dependencies | |
| run: | | |
| source venv/bin/activate | |
| pip install -r requirements-test.txt | |
| - name: Fetch commit changes | |
| id: fetch | |
| run: | | |
| source venv/bin/activate | |
| PREVIOUS_COMMIT="${{ needs.check-updates.outputs.previous_commit }}" | |
| CURRENT_COMMIT="${{ needs.check-updates.outputs.commit_hash }}" | |
| if [ -z "$PREVIOUS_COMMIT" ]; then | |
| echo "No previous commit found, this is the first release" | |
| echo "changes=First release - no previous commit to compare" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Fetching commits between $PREVIOUS_COMMIT and $CURRENT_COMMIT" | |
| # Clone the upstream repository | |
| git clone --depth 100 https://github.com/logos-storage/logos-storage-nim.git /tmp/logos-storage-nim | |
| # Generate release notes using Python script | |
| CHANGES=$(python src/release_notes.py \ | |
| --repo-path /tmp/logos-storage-nim \ | |
| --previous-commit "$PREVIOUS_COMMIT" \ | |
| --current-commit "$CURRENT_COMMIT") | |
| if [ -z "$CHANGES" ] || [ "$CHANGES" = "No commits found between releases" ]; then | |
| echo "No commits found between releases" | |
| echo "changes=No commits found between releases" >> $GITHUB_OUTPUT | |
| else | |
| # Count commits | |
| COMMIT_COUNT=$(echo "$CHANGES" | wc -l) | |
| echo "Found $COMMIT_COUNT commits" | |
| # Escape for YAML - only escape quotes, keep newlines as-is | |
| CHANGES_ESCAPED=$(echo "$CHANGES" | sed 's/"/\\"/g') | |
| # Use a delimiter to preserve newlines in the output | |
| echo "changes<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGES_ESCAPED" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| fi | |
| # Create release | |
| release: | |
| needs: [check-updates, build, fetch-commits] | |
| if: needs.check-updates.outputs.should_build == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download artifacts | |
| if: env.ACT != 'true' | |
| uses: actions/download-artifact@v7 | |
| continue-on-error: true | |
| with: | |
| pattern: libstorage-* | |
| merge-multiple: true | |
| path: /tmp/release | |
| - name: Compress and checksum | |
| if: env.ACT != 'true' | |
| run: | | |
| cd /tmp/release | |
| # Find all directories and create archives | |
| for dir in */; do | |
| dir_name=$(basename "$dir") | |
| # Directory name is already in the correct format: {branch}-{commit_short}-{platform} | |
| # Use it directly to create the archive name | |
| archive="logos-storage-nim-${dir_name}.tar.gz" | |
| cd "$dir" | |
| tar cfz "/tmp/release/${archive}" *.a libstorage.h SHA256SUMS.txt | |
| cd /tmp/release | |
| done | |
| # Create SHA256SUMS.txt for all archives | |
| sha256sum *.tar.gz > SHA256SUMS.txt | |
| - name: Create release | |
| if: env.ACT != 'true' | |
| uses: softprops/action-gh-release@v2 | |
| continue-on-error: true | |
| with: | |
| tag_name: ${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }} | |
| name: ${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }} | |
| body: | | |
| ## Nightly pre-built static librairies of logos-storage-nim | |
| _⚠️ Nightly builds are not suitable for production use._ | |
| Commit: ${{ needs.check-updates.outputs.commit_hash }} | |
| Branch: ${{ needs.check-updates.outputs.branch_name }} | |
| Date: ${{ needs.check-updates.outputs.commit_date }} | |
| Artifacts: | |
| - Linux x86_64: logos-storage-nim-${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }}-linux-amd64.tar.gz | |
| - Linux AArch64: logos-storage-nim-${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }}-linux-arm64.tar.gz | |
| - macOS Apple Silicon: logos-storage-nim-${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }}-darwin-arm64.tar.gz | |
| - Windows x86_64: logos-storage-nim-${{ needs.check-updates.outputs.branch_name }}-${{ needs.check-updates.outputs.commit_short }}-windows-amd64.tar.gz | |
| Each archive contains: | |
| - libstorage.a: Main storage library | |
| - libnatpmp.a: NAT-PMP library | |
| - libminiupnpc.a: MiniUPnP library | |
| - libbacktrace.a: Backtrace library | |
| - libstorage.h: C header file | |
| - SHA256SUMS.txt: Checksums for all files | |
| Archive checksums: SHA256SUMS.txt | |
| --- | |
| ### Changes since last nightly release | |
| ${{ needs.fetch-commits.outputs.commit_changes }} | |
| files: | | |
| /tmp/release/*.tar.gz | |
| /tmp/release/SHA256SUMS.txt | |
| draft: false | |
| prerelease: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GH_PAT }} |