Publish to TestPyPI #4
Workflow file for this run
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
| # ============================================================================= | |
| # Publish to TestPyPI | |
| # Trigger: Manual workflow dispatch (workflow_dispatch) | |
| # Features: | |
| # 1. Build distribution package | |
| # 2. Publish to TestPyPI (using API Token) | |
| # 3. Verify installation | |
| # | |
| # Usage Instructions: | |
| # 1. Prerequisites: | |
| # - Generate API Token on TestPyPI account: https://test.pypi.org/manage/account/tokens/ | |
| # - In GitHub repository Settings > Secrets and variables > Actions, add: | |
| # - Name: TEST_PYPI_API_TOKEN | |
| # - Secret: <your-test-pypi-api-token> | |
| # - Ensure TEST_PYPI_API_TOKEN secret is configured in the environment | |
| # | |
| # 2. Trigger Publishing: | |
| # - Go to GitHub Actions page and select this workflow | |
| # - Click "Run workflow" | |
| # - Enter version tag (e.g., v1.0.0-test, v0.1.0rc1, v2.0.0.dev1) | |
| # - Click "Run workflow" | |
| # | |
| # 3. The workflow will automatically: | |
| # - Build sdist and wheel distributions | |
| # - Publish to TestPyPI | |
| # - Verify installation | |
| # ============================================================================= | |
| name: Publish to TestPyPI | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version_tag: | |
| description: 'Version tag to test publish (e.g., v1.0.0-test, v0.1.0rc1, v2.0.0.dev1)' | |
| required: true | |
| type: string | |
| jobs: | |
| publish-test: | |
| name: Publish to TestPyPI | |
| runs-on: ubuntu-latest | |
| environment: testpypi | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 # setuptools-scm requires complete git history | |
| - name: Check git tag exists (fail if not) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| TAG="${{ github.event.inputs.version_tag }}" | |
| git fetch --tags --force | |
| if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then | |
| echo "Tag already exists: ${TAG}" | |
| else | |
| echo "::error::Tag does not exist: ${TAG}" | |
| exit 1 | |
| fi | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.8" | |
| - name: Install build tools | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build twine | |
| - name: Build package | |
| run: python -m build | |
| - name: Check package | |
| run: twine check dist/* | |
| - name: Publish to TestPyPI (using API Token) | |
| env: | |
| TWINE_USERNAME: __token__ | |
| TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }} | |
| TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ | |
| TWINE_NON_INTERACTIVE: 1 | |
| run: twine upload dist/* --skip-existing | |
| - name: Wait for package to be available | |
| run: sleep 30 | |
| - name: Extract and validate version from tag | |
| id: version | |
| run: | | |
| TAG="${{ github.event.inputs.version_tag }}" | |
| # Remove 'v' prefix if present to get version string | |
| VERSION="${TAG#v}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Extracted version from tag: $VERSION" | |
| - name: Test installation from TestPyPI | |
| env: | |
| EXPECTED_VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| # Create new virtual environment for testing | |
| python -m venv test-env | |
| source test-env/bin/activate | |
| # Install from TestPyPI (use PyPI as extra index for dependencies) | |
| pip install --index-url https://test.pypi.org/simple/ \ | |
| --extra-index-url https://pypi.org/simple/ \ | |
| deep-solutions | |
| # Create validation script | |
| cat > validate_package.py << 'EOF' | |
| import sys | |
| import deep_solutions | |
| # Expected version from input | |
| expected_version = "$EXPECTED_VERSION" | |
| actual_version = deep_solutions.__version__ | |
| print(f"Expected version: {expected_version}") | |
| print(f"Actual version: {actual_version}") | |
| # Validate version matches | |
| if actual_version != expected_version: | |
| print(f"❌ Version mismatch! Expected '{expected_version}', got '{actual_version}'") | |
| sys.exit(1) | |
| else: | |
| print(f"✅ Version validated successfully!") | |
| # Test hello_world function | |
| from deep_solutions import hello_world | |
| result = hello_world() | |
| expected_output = "Hello from deep-solutions!" | |
| print(f"Function output: {result}") | |
| # Validate hello_world output | |
| if result != expected_output: | |
| print(f"❌ Output mismatch! Expected '{expected_output}', got '{result}'") | |
| sys.exit(1) | |
| else: | |
| print(f"✅ hello_world() validated successfully!") | |
| print("\n✅ All validations passed! Package is ready for production PyPI.") | |
| EOF | |
| # Run validation | |
| python validate_package.py | |
| deactivate | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: dist-testpypi | |
| path: dist/ |