diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml new file mode 100644 index 0000000..f4d9eb1 --- /dev/null +++ b/.github/workflows/release-manual.yml @@ -0,0 +1,249 @@ +name: Manual Release (Simple) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to release (e.g., 0.3.2) - make sure tag v0.3.2 exists!' + required: true + type: string + pypi_environment: + description: 'PyPI environment' + required: true + type: choice + options: + - 'pypi' + - 'testpypi' + default: 'pypi' + +env: + UV_VERSION: "0.5.13" + PYTHON_VERSION: "3.12" + +jobs: + validate: + runs-on: ubuntu-latest + outputs: + tag_name: ${{ steps.validate_tag.outputs.tag }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate version format + run: | + if ! echo "${{ github.event.inputs.version }}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$'; then + echo "Error: Version must be in format X.Y.Z or X.Y.Z-suffix" + exit 1 + fi + + - name: Check if tag exists + id: validate_tag + run: | + TAG="v${{ github.event.inputs.version }}" + if ! git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Error: Tag $TAG does not exist!" + echo "Please create it first with:" + echo " git tag $TAG" + echo " git push origin $TAG" + exit 1 + fi + echo "tag=$TAG" >> $GITHUB_OUTPUT + + lint: + needs: validate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.validate.outputs.tag_name }} + + - name: Install UV + run: | + curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install dependencies + run: | + uv pip install --system -e ".[dev]" + + - name: Run ruff check + run: | + uv run ruff check src tests + + - name: Run ruff format check + run: | + uv run ruff format --check src tests + + typecheck: + needs: validate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.validate.outputs.tag_name }} + + - name: Install UV + run: | + curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install dependencies + run: | + uv pip install --system -e ".[dev]" + + - name: Run mypy + run: | + uv run mypy src + + test: + needs: validate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.validate.outputs.tag_name }} + + - name: Install UV + run: | + curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install xdelta3 + run: | + sudo apt-get update + sudo apt-get install -y xdelta3 + + - name: Install dependencies + run: | + uv pip install --system -e ".[dev]" + + - name: Run unit tests + run: | + uv run pytest tests/unit -v --tb=short + + - name: Run integration tests + run: | + uv run pytest tests/integration -v --tb=short + + e2e-test: + needs: validate + runs-on: ubuntu-latest + services: + localstack: + image: localstack/localstack:latest + ports: + - 4566:4566 + env: + SERVICES: s3 + DEBUG: 0 + DATA_DIR: /tmp/localstack/data + options: >- + --health-cmd "curl -f http://localhost:4566/_localstack/health" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.validate.outputs.tag_name }} + + - name: Install UV + run: | + curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install xdelta3 + run: | + sudo apt-get update + sudo apt-get install -y xdelta3 + + - name: Install dependencies + run: | + uv pip install --system -e ".[dev]" + + - name: Run E2E tests + env: + AWS_ACCESS_KEY_ID: test + AWS_SECRET_ACCESS_KEY: test + AWS_DEFAULT_REGION: us-east-1 + AWS_ENDPOINT_URL: http://localhost:4566 + run: | + uv run pytest tests/e2e -v --tb=short + + publish: + needs: [validate, lint, typecheck, test, e2e-test] + runs-on: ubuntu-latest + environment: ${{ github.event.inputs.pypi_environment }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.validate.outputs.tag_name }} + fetch-depth: 0 # Important for setuptools-scm + + - name: Install UV + run: | + curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Build package + run: | + uv build + + - name: Publish to TestPyPI + if: github.event.inputs.pypi_environment == 'testpypi' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + + - name: Publish to PyPI + if: github.event.inputs.pypi_environment == 'pypi' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ needs.validate.outputs.tag_name }} + name: Release v${{ github.event.inputs.version }} + body: | + ## DeltaGlider v${{ github.event.inputs.version }} + + Published to ${{ github.event.inputs.pypi_environment == 'pypi' && 'PyPI' || 'TestPyPI' }} + + ### Installation + ```bash + pip install deltaglider==${{ github.event.inputs.version }} + ``` + draft: false + prerelease: ${{ contains(github.event.inputs.version, '-') }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a178c51..0e8efcb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.PAT_TOKEN }} - name: Validate version format run: |