rsdo 0.1.20260301

A Rust client library for the DigitalOcean API v2
Documentation
name: Date-based Release

on:
  schedule:
    # Run on the 1st day of every month at 10:00 AM UTC
    - cron: '0 10 1 * *'
  workflow_dispatch:
    inputs:
      force:
        description: 'Force create release even if one exists for today'
        required: false
        default: false
        type: boolean
      skip_publish:
        description: 'Skip publishing to crates.io'
        required: false
        default: false
        type: boolean
  push:
    branches: [ main ]
    paths-ignore:
      - 'README.md'
      - 'docs/**'
      - '.github/**'
      - '*.md'

env:
  CARGO_TERM_COLOR: always

jobs:
  check-and-release:
    name: Create Date-based Release
    runs-on: ubuntu-latest
    outputs:
      should_release: ${{ steps.check.outputs.should_release }}
      tag_name: ${{ steps.version.outputs.TAG_NAME }}
      version: ${{ steps.version.outputs.VERSION }}
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Configure Git
        run: .github/scripts/configure_git.sh

      - name: Generate version and tag
        id: version
        run: .github/scripts/generate_version.sh

      - name: Check if should create release
        id: check
        run: .github/scripts/check_release.sh "${{ steps.version.outputs.TAG_NAME }}" "${{ github.event.inputs.force }}" "${{ github.event_name }}"

      - name: Install Rust stable
        if: steps.check.outputs.should_release == 'true'
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        if: steps.check.outputs.should_release == 'true'
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-release-cargo-${{ hashFiles('Cargo.lock') }}

      - name: Update Cargo.toml version
        if: steps.check.outputs.should_release == 'true'
        run: .github/scripts/update_cargo_version.sh "${{ steps.version.outputs.VERSION }}"

      - name: Update Cargo.lock
        if: steps.check.outputs.should_release == 'true'
        run: .github/scripts/update_cargo_lock.sh

      - name: Build and test
        if: steps.check.outputs.should_release == 'true'
        run: .github/scripts/build_and_test.sh

      - name: Commit version changes and create tag
        if: steps.check.outputs.should_release == 'true'
        run: .github/scripts/commit_and_tag.sh "${{ steps.version.outputs.TAG_NAME }}" "${{ steps.version.outputs.VERSION }}" "${{ github.event_name }}"

      - name: Generate changelog
        if: steps.check.outputs.should_release == 'true'
        id: changelog
        run: .github/scripts/generate_changelog.sh "${{ steps.version.outputs.VERSION }}" "${{ steps.version.outputs.TAG_NAME }}" "${{ github.event_name }}" "${{ github.repository }}"

      - name: Create GitHub Release
        if: steps.check.outputs.should_release == 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: .github/scripts/create_github_release.sh "${{ steps.version.outputs.TAG_NAME }}" "${{ steps.version.outputs.VERSION }}" "${{ github.event_name }}" "${{ steps.changelog.outputs.CHANGELOG }}" "${{ vars.USE_AUTO_GENERATED_NOTES || 'false' }}"

  quality-checks:
    name: Pre-publish Quality Checks
    runs-on: ubuntu-latest
    needs: check-and-release
    if: needs.check-and-release.outputs.should_release == 'true' && github.event.inputs.skip_publish != 'true'

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.check-and-release.outputs.tag_name }}

      - name: Get MSRV from Cargo.toml
        id: msrv
        run: |
          MSRV=$(grep '^rust-version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
          echo "MSRV is $MSRV"
          echo "version=$MSRV" >> $GITHUB_OUTPUT

      - name: Install Rust MSRV
        uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ steps.msrv.outputs.version }}
          components: rustfmt

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-quality-checks-cargo-${{ hashFiles('Cargo.lock') }}

      - name: Verify Rust version
        run: |
          echo "Expected MSRV: ${{ steps.msrv.outputs.version }}"
          rustc --version
          rustc --version | grep -q "${{ steps.msrv.outputs.version }}" || (echo "Rust version mismatch"; exit 1)

      - name: Build and test (including doctests)
        run: .github/scripts/build_and_test.sh

      # Note: Skipping semver check for now since crate is not yet published
      # After first publish, uncomment this to enable semver checking:
      # - name: Check semver compatibility
      #   uses: obi1kenobi/cargo-semver-checks-action@v2

      - name: Check formatting
        run: .github/scripts/pre_publish_checks.sh

  publish-crate:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    needs: [check-and-release, quality-checks]
    if: needs.check-and-release.outputs.should_release == 'true' && github.event.inputs.skip_publish != 'true'

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.check-and-release.outputs.tag_name }}

      - name: Install Rust stable
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-publish-cargo-${{ hashFiles('Cargo.lock') }}

      - name: Publish to crates.io
        run: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  # Note: rsdo is a library crate, not a binary, so we don't build platform-specific binaries.
  # Users will include rsdo as a dependency in their Cargo.toml instead.

  generate-sbom:
    name: Generate and Attach SBOM
    runs-on: ubuntu-latest
    needs: check-and-release
    if: needs.check-and-release.outputs.should_release == 'true'
    continue-on-error: true  # Don't fail entire workflow if SBOM generation fails

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.check-and-release.outputs.tag_name }}

      - name: Install Rust stable
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry and target
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-sbom-cargo-${{ hashFiles('Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-sbom-cargo-

      - name: Cache cargo-cyclonedx installation
        id: cache-cyclonedx
        uses: actions/cache@v4
        with:
          path: ~/.cargo/bin/cargo-cyclonedx
          key: ${{ runner.os }}-cargo-cyclonedx-0.5.7

      - name: Install cargo-cyclonedx
        if: steps.cache-cyclonedx.outputs.cache-hit != 'true'
        run: cargo install cargo-cyclonedx --version 0.5.7 --locked

      - name: Verify project builds
        run: cargo check --locked

      - name: Generate SBOM files
        run: .github/scripts/generate_sbom.sh

      - name: Upload SBOM files to release
        if: success()
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.check-and-release.outputs.tag_name }}
          files: |
            rsdo-sbom.json
            rsdo-sbom.xml
          fail_on_unmatched_files: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}