diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50d6b86d..9d6669c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main, master] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest @@ -14,25 +17,23 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v4 + - &checkout-step + uses: actions/checkout@v6 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + - &setup-uv-matrix-no-cache + name: Set up uv (Python ${{ matrix.python-version }}) + uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install build - pip install -e . + - name: Sync runtime dependencies + run: uv sync --locked --no-dev - name: Check package builds - run: python -m build + run: uv build - name: Verify CLI entry point - run: | - python -c "from sqlit.cli import main; print('CLI import OK')" + run: uv run python -c "from sqlit.cli import main; print('CLI import OK')" nix-flake: runs-on: ubuntu-latest @@ -47,23 +48,20 @@ jobs: test-unit: runs-on: ubuntu-latest + env: + UV_EXTRAS: "" strategy: matrix: python-version: ["3.10", "3.12"] steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} + - *setup-uv-matrix-no-cache - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev + - &install-test-deps + name: Install dependencies + run: uv sync --locked --group test --no-dev ${{ env.UV_EXTRAS }} - name: Run unit tests run: | @@ -83,23 +81,23 @@ jobs: test-sqlite: runs-on: ubuntu-latest + env: + UV_EXTRAS: "" strategy: matrix: python-version: ["3.10", "3.12"] steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + - &setup-uv-matrix-with-cache + name: Set up uv (Python ${{ matrix.python-version }}) + uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.python-version }} + enable-cache: true - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev + - *install-test-deps - name: Run SQLite integration tests run: uv run pytest tests/test_sqlite.py -v --timeout=60 @@ -107,6 +105,8 @@ jobs: test-mssql: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra mssql services: mssql: @@ -125,18 +125,16 @@ jobs: --health-start-period 30s steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 + - &setup-uv-py312-with-cache + name: Set up uv + uses: astral-sh/setup-uv@v7 with: python-version: "3.12" + enable-cache: true - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev --extra mssql + - *install-test-deps - name: Wait for SQL Server to be ready run: | @@ -160,6 +158,8 @@ jobs: test-postgresql: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra postgres services: postgres: @@ -178,18 +178,11 @@ jobs: --health-start-period 10s steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *setup-uv-py312-with-cache - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev --extra postgres + - *install-test-deps - name: Run PostgreSQL integration tests env: @@ -203,6 +196,8 @@ jobs: test-mysql: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra mysql services: mysql: @@ -222,18 +217,11 @@ jobs: --health-start-period 30s steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *checkout-step - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra mysql + - *install-test-deps - name: Run MySQL integration tests env: @@ -247,6 +235,8 @@ jobs: test-oracle: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra oracle services: oracle: @@ -265,18 +255,11 @@ jobs: --health-start-period 60s steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *checkout-step - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra oracle + - *install-test-deps - name: Run Oracle integration tests env: @@ -290,6 +273,8 @@ jobs: test-mariadb: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra mariadb services: mariadb: @@ -309,23 +294,16 @@ jobs: --health-start-period 30s steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *setup-uv-py312-with-cache - name: Install MariaDB Connector/C run: | sudo apt-get update sudo apt-get install -y libmariadb-dev - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev --extra mariadb + - *install-test-deps - name: Run MariaDB integration tests env: @@ -338,23 +316,18 @@ jobs: test-duckdb: runs-on: ubuntu-latest + env: + UV_EXTRAS: --extra duckdb strategy: matrix: python-version: ["3.10", "3.12"] steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-matrix-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra duckdb + - *install-test-deps - name: Run DuckDB integration tests run: uv run pytest tests/test_duckdb.py -v --timeout=60 @@ -362,20 +335,15 @@ jobs: test-cockroachdb: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra cockroachdb steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra cockroachdb + - *install-test-deps - name: Start CockroachDB run: | @@ -403,6 +371,8 @@ jobs: test-firebird: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra firebird services: firebird: @@ -415,18 +385,11 @@ jobs: - 3050:3050 steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *checkout-step - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra firebird + - *install-test-deps - name: Run Firebird integration tests env: @@ -440,20 +403,15 @@ jobs: test-clickhouse: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra clickhouse steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *setup-uv-py312-with-cache - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install dependencies - run: uv sync --group test --no-dev --extra clickhouse + - *install-test-deps - name: Start ClickHouse run: | @@ -483,20 +441,15 @@ jobs: test-ssh: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra ssh --extra postgres steps: - - uses: actions/checkout@v4 + - *checkout-step - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra ssh --extra postgres + - *install-test-deps - name: Create Docker network run: docker network create ssh-test-net @@ -565,20 +518,15 @@ jobs: test-turso: runs-on: ubuntu-latest needs: build + env: + UV_EXTRAS: --extra turso steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: "3.12" + - *checkout-step - - name: Install uv - uses: astral-sh/setup-uv@v5 + - *setup-uv-py312-with-cache - - name: Install dependencies - run: uv sync --group test --no-dev --extra turso + - *install-test-deps - name: Start Turso (libsql-server) run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0aa872dc..c38b95f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,76 +3,75 @@ name: Release and Publish on: push: tags: - - 'v*' + - "v*" workflow_dispatch: inputs: version: - description: 'Version to release (e.g., 0.4.2)' + description: "Version to release (e.g., 0.4.2)" required: true +permissions: + contents: read + jobs: - release: + publish: + if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + environment: pypi permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - - name: Extract version from tag - id: version - run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 - with: - name: ${{ steps.version.outputs.VERSION }} - generate_release_notes: true - draft: false - prerelease: false - - build: - runs-on: ubuntu-latest + id-token: write + contents: read steps: - - uses: actions/checkout@v4 + - &checkout_step + uses: actions/checkout@v6 - - name: Set up Python - uses: actions/setup-python@v5 + - name: Set up uv + uses: astral-sh/setup-uv@v7 with: python-version: "3.12" - - name: Install build tools - run: python -m pip install --upgrade build - - name: Build package - run: python -m build + run: uv build --no-sources - name: Upload dist artifacts - uses: actions/upload-artifact@v4 - with: + uses: actions/upload-artifact@v7 + with: &dist_artifact name: dist path: dist/ - publish: - needs: build + - name: Publish to PyPI + run: uv publish --trusted-publishing always dist/* + + release: + needs: publish + if: needs.publish.result == 'success' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest - environment: pypi permissions: - id-token: write + contents: write steps: - name: Download dist artifacts - uses: actions/download-artifact@v4 - with: - name: dist - path: dist/ + uses: actions/download-artifact@v8 + with: *dist_artifact - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: ${{ steps.version.outputs.VERSION }} + generate_release_notes: true + draft: false + prerelease: false + files: dist/* aur: - needs: [build, publish] + needs: publish + if: always() && (github.event_name == 'workflow_dispatch' || needs.publish.result == 'success') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - *checkout_step - name: Download dist artifacts uses: actions/download-artifact@v4 @@ -84,22 +83,34 @@ jobs: id: info run: | if [ -n "${{ github.event.inputs.version }}" ]; then - VERSION="${{ github.event.inputs.version }}" + echo "VERSION=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT" + elif [[ "${GITHUB_REF}" == refs/tags/v* ]]; then + echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT" else - VERSION="${GITHUB_REF#refs/tags/v}" - fi - echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - - # Get checksum from the built artifact (no need to wait for PyPI) - TARBALL="dist/sqlit_tui-${VERSION}.tar.gz" - if [ ! -f "$TARBALL" ]; then - echo "::error::Tarball not found: $TARBALL" - ls -la dist/ + echo "Could not determine version" >&2 exit 1 fi - CHECKSUM=$(sha256sum "$TARBALL" | cut -d' ' -f1) - echo "CHECKSUM=${CHECKSUM}" >> $GITHUB_OUTPUT - echo "Version: ${VERSION}" + + - name: Wait for PyPI and get checksum + id: pypi + run: | + VERSION=${{ steps.version.outputs.VERSION }} + URL="https://files.pythonhosted.org/packages/source/s/sqlit-tui/sqlit_tui-${VERSION}.tar.gz" + + echo "Waiting for package to be available on PyPI..." + for i in {1..20}; do + HTTP_CODE=$(curl -sI -o /dev/null -w "%{http_code}" "$URL") + if [ "$HTTP_CODE" = "200" ]; then + echo "Package available on PyPI (attempt $i)" + break + fi + echo "Waiting for PyPI... attempt $i (got HTTP $HTTP_CODE)" + sleep 30 + done + + curl -sL "$URL" -o /tmp/pkg.tar.gz + CHECKSUM=$(sha256sum /tmp/pkg.tar.gz | cut -d' ' -f1) + echo "CHECKSUM=${CHECKSUM}" >> "$GITHUB_OUTPUT" echo "Checksum: ${CHECKSUM}" - name: Update PKGBUILD @@ -112,11 +123,8 @@ jobs: sed -i "s/^pkgrel=.*/pkgrel=1/" PKGBUILD sed -i "s/^sha256sums=.*/sha256sums=('${CHECKSUM}')/" PKGBUILD - echo "Updated PKGBUILD:" - cat PKGBUILD - - name: Publish to AUR - uses: KSXGitHub/github-actions-deploy-aur@v3.0.1 + uses: KSXGitHub/github-actions-deploy-aur@v4 with: pkgname: sqlit pkgbuild: ./aur/PKGBUILD