|
33 | 33 | required: false |
34 | 34 | default: 'python-package' |
35 | 35 | type: string |
| 36 | + auth-method: |
| 37 | + description: 'Authentication method: oidc or token' |
| 38 | + required: false |
| 39 | + default: 'oidc' |
| 40 | + type: string |
| 41 | + secrets: |
| 42 | + PYPI_API_TOKEN: |
| 43 | + description: 'PyPI API token (only required if auth-method is token)' |
| 44 | + required: false |
| 45 | + TEST_PYPI_API_TOKEN: |
| 46 | + description: 'Test PyPI API token (only required if auth-method is token for TestPyPI)' |
| 47 | + required: false |
36 | 48 |
|
37 | 49 | outputs: |
38 | 50 | build-success: |
@@ -119,24 +131,43 @@ jobs: |
119 | 131 | path: dist/ |
120 | 132 | retention-days: 30 |
121 | 133 |
|
122 | | - - name: Publish to PyPI |
123 | | - if: inputs.operation == 'publish-pypi' |
124 | | - run: | |
125 | | - echo "🚀 Publishing to PyPI..." |
126 | | - uv publish |
127 | | - echo "✅ Published to PyPI successfully" |
| 134 | + - name: Setup PyPI OIDC Authentication |
| 135 | + if: contains(fromJSON('["publish-pypi", "publish-testpypi"]'), inputs.operation) && inputs.auth-method == 'oidc' |
| 136 | + uses: pypa/gh-action-pypi-publish@release/v1 |
| 137 | + with: |
| 138 | + print-hash: true |
| 139 | + verify-metadata: true |
| 140 | + packages-dir: dist/ |
| 141 | + repository-url: ${{ inputs.operation == 'publish-testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }} |
128 | 142 |
|
129 | | - - name: Publish to TestPyPI |
130 | | - if: inputs.operation == 'publish-testpypi' |
| 143 | + - name: Setup PyPI Token Authentication |
| 144 | + if: contains(fromJSON('["publish-pypi", "publish-testpypi"]'), inputs.operation) && inputs.auth-method == 'token' |
| 145 | + env: |
| 146 | + TWINE_USERNAME: __token__ |
| 147 | + TWINE_PASSWORD: ${{ inputs.operation == 'publish-pypi' && secrets.PYPI_API_TOKEN || secrets.TEST_PYPI_API_TOKEN }} |
| 148 | + TWINE_REPOSITORY_URL: ${{ inputs.operation == 'publish-testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }} |
131 | 149 | run: | |
132 | | - echo "🚀 Publishing to TestPyPI..." |
133 | | - uv publish --publish-url https://test.pypi.org/legacy/ |
134 | | - echo "✅ Published to TestPyPI successfully" |
| 150 | + echo "🔑 Using PyPI token authentication..." |
| 151 | + |
| 152 | + # Verify token is available |
| 153 | + if [ -z "$TWINE_PASSWORD" ]; then |
| 154 | + echo "❌ Error: PyPI API token not found in secrets" |
| 155 | + echo "Please ensure ${{ inputs.operation == 'publish-pypi' && 'PYPI_API_TOKEN' || 'TEST_PYPI_API_TOKEN' }} is set in repository secrets" |
| 156 | + exit 1 |
| 157 | + fi |
| 158 | + |
| 159 | + echo "🚀 Publishing to ${{ inputs.operation == 'publish-pypi' && 'PyPI' || 'TestPyPI' }} using token authentication..." |
| 160 | + uv publish ${{ inputs.operation == 'publish-testpypi' && '--publish-url https://test.pypi.org/legacy/' || '' }} |
| 161 | + echo "✅ Published to ${{ inputs.operation == 'publish-pypi' && 'PyPI' || 'TestPyPI' }} successfully" |
135 | 162 |
|
136 | 163 | - name: Operation summary |
137 | 164 | run: | |
138 | 165 | echo "## Python Package Operation Summary" >> $GITHUB_STEP_SUMMARY |
139 | 166 | echo "- **Operation**: ${{ inputs.operation }}" >> $GITHUB_STEP_SUMMARY |
140 | 167 | echo "- **Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY |
141 | 168 | echo "- **Python**: ${{ inputs.python-version }}" >> $GITHUB_STEP_SUMMARY |
| 169 | + if [[ "${{ inputs.operation }}" == "publish-pypi" || "${{ inputs.operation }}" == "publish-testpypi" ]]; then |
| 170 | + echo "- **Auth Method**: ${{ inputs.auth-method == 'oidc' && '🔒 OIDC (Trusted Publisher)' || '🔑 API Token' }}" >> $GITHUB_STEP_SUMMARY |
| 171 | + echo "- **Repository**: ${{ inputs.operation == 'publish-pypi' && 'PyPI (production)' || 'TestPyPI (staging)' }}" >> $GITHUB_STEP_SUMMARY |
| 172 | + fi |
142 | 173 | echo "- **Status**: ✅ Completed successfully" >> $GITHUB_STEP_SUMMARY |
0 commit comments