Fixed issue with whitespaces #157
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
| name: Python Package CI | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| # Trigger on any tag (matches 0.0.1, v0.0.1 etc.) | |
| - 'v[0-9]+.[0-9]+.[0-9]+' # Matches vX.Y.Z | |
| - '[0-9]+.[0-9]+.[0-9]+' # Matches X.Y.Z | |
| pull_request: | |
| branches: | |
| - main | |
| release: | |
| types: [published] # Trigger if you create releases via GitHub UI based on tags | |
| # Define permissions required for the workflow jobs | |
| permissions: | |
| contents: read # Needed for actions/checkout | |
| packages: write # Needed for pushing Docker images to GHCR | |
| jobs: | |
| lint: | |
| name: Lint (Python ${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false # Don't cancel other jobs if one lint version fails | |
| matrix: | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # No fetch-depth needed for linting typically | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: 'pip' # Cache pip dependencies | |
| - name: Install lint dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| # Install linters AND setuptools (might be needed by some implicitly) | |
| pip install ruff flake8 pylint isort setuptools | |
| # Install project dependencies if linters need to import them | |
| if [ -f requirements.txt ]; then pip install -r requirements.txt; fi | |
| # Optional: Install package if pylint needs deep import checks | |
| # pip install . | |
| - name: Analysing the code with pylint | |
| run: | | |
| # Adjust path if needed | |
| pylint python_gpt_po/ || echo "Pylint found issues but continuing..." # Or remove || to fail on issues | |
| - name: Check code style with flake8 | |
| run: | | |
| # Adjust path if needed | |
| flake8 python_gpt_po/ | |
| - name: Check import order with isort | |
| run: | | |
| isort --check-only --diff . | |
| - name: Linting with Ruff | |
| run: | | |
| # Uses git ls-files to find only tracked python files | |
| ruff check $(git ls-files '*.py') | |
| test: | |
| name: Test (Python ${{ matrix.python-version }}) | |
| needs: lint # Run tests only if linting passes | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false # Don't cancel other jobs if one test version fails | |
| matrix: | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # Fetch depth and tags might be needed if tests rely on git history/version | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: 'pip' | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gettext | |
| - name: Install test dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| # Install runtime dependencies | |
| if [ -f requirements.txt ]; then pip install -r requirements.txt; fi | |
| # Install test runner (e.g., pytest) and any test-specific packages | |
| pip install pytest pytest-cov | |
| # Install the package itself in editable mode for testing | |
| pip install -e . | |
| - name: Run tests with pytest | |
| run: | | |
| pytest --cov=python_gpt_po --cov-report=xml --cov-report=term-missing | |
| docker-test-build: | |
| name: Docker Test Build (Python ${{ matrix.python-version }}) | |
| # Renamed job to be clearer it's for testing the build, not deploying | |
| needs: test | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Needed for git describe | |
| fetch-tags: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Cache Docker layers for Test Build | |
| uses: actions/cache@v4 | |
| with: | |
| path: /tmp/.buildx-cache-test # Separate cache path for test builds | |
| # Key includes python version and commit SHA for distinct caching per commit | |
| key: ${{ runner.os }}-buildx-test-${{ matrix.python-version }}-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-buildx-test-${{ matrix.python-version }}- | |
| - name: Get Version using git describe | |
| # Use git describe for non-tag builds (main, PRs) and tags | |
| id: get_version | |
| run: | | |
| git fetch --tags --force --prune --unshallow || echo "Fetching tags failed, proceeding..." | |
| # Use git describe. Outputs exact tag (e.g., 0.1.0) or dev version (0.1.0-3-gddfce44) | |
| GIT_DESCRIBE=$(git describe --tags --always --dirty 2>/dev/null || echo "0.0.0") | |
| # Remove 'v' prefix if tags have it (adjust if your tags don't use 'v') | |
| VERSION=${GIT_DESCRIBE#v} | |
| echo "Using version for Docker build arg: $VERSION" | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Build Docker Image (Test) - Python ${{ matrix.python-version }} | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| # Load image into Docker daemon for local testing, don't push | |
| load: true | |
| tags: local/gpt-po-translator:py${{ matrix.python-version }}-test | |
| build-args: | | |
| PYTHON_VERSION=${{ matrix.python-version }} | |
| VERSION=${{ steps.get_version.outputs.VERSION }} | |
| cache-from: type=gha,scope=test-${{ matrix.python-version }} | |
| cache-to: type=gha,mode=max,scope=test-${{ matrix.python-version }} | |
| - name: Test Docker Image - Basic Commands | |
| run: | | |
| docker run --rm local/gpt-po-translator:py${{ matrix.python-version }}-test --version | |
| docker run --rm local/gpt-po-translator:py${{ matrix.python-version }}-test --help | |
| echo "✅ Basic command tests passed for Docker image (Python ${{ matrix.python-version }})" | |
| - name: Test Docker Image - CLI Options Help | |
| run: | | |
| docker run --rm local/gpt-po-translator:py${{ matrix.python-version }}-test --provider openai --help | |
| docker run --rm local/gpt-po-translator:py${{ matrix.python-version }}-test --provider anthropic --help | |
| echo "✅ CLI provider help test passed for Docker image (Python ${{ matrix.python-version }})" | |
| - name: Test Docker Image - Volume Mount Help | |
| # This verifies the entrypoint script and basic arg parsing work with volumes | |
| run: | | |
| mkdir -p ./test-po-dir # Create a temporary directory on the runner | |
| echo 'msgid "Test"\nmsgstr ""' > ./test-po-dir/sample.po | |
| docker run --rm \ | |
| -v $(pwd)/test-po-dir:/app/po_files \ | |
| local/gpt-po-translator:py${{ matrix.python-version }}-test \ | |
| --folder /app/po_files --help | |
| rm -rf ./test-po-dir # Clean up | |
| echo "✅ Volume mount help test passed for Docker image (Python ${{ matrix.python-version }})" | |
| deploy: | |
| name: Deploy to PyPI and GHCR | |
| needs: [test, docker-test-build] # Depends on successful tests and Docker builds | |
| runs-on: ubuntu-latest | |
| # Condition: Run only on pushing a tag matching the pattern | |
| if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') | |
| # Optional: Define environment for secrets or protection rules | |
| environment: release | |
| # Permissions: Add id-token write if using PyPI Trusted Publishing | |
| permissions: | |
| contents: read # For checkout | |
| packages: write # For GHCR push | |
| # id-token: write # Uncomment if using PyPI Trusted Publishing` | |
| strategy: | |
| fail-fast: true # If one deployment fails, stop others | |
| matrix: | |
| # Define ALL python versions for Docker images | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | |
| # Designate ONE primary version for PyPI publish and Docker 'latest' tag | |
| primary-py: ['3.11'] # Choose your primary Python version | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Needed for setuptools_scm | |
| fetch-tags: true | |
| # === PyPI Deployment (runs only once for the primary Python version) === | |
| - name: Set up Python for PyPI deploy | |
| # Run ONLY for the designated primary version | |
| if: matrix.python-version == matrix.primary-py | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.primary-py }} | |
| - name: Install PyPI build dependencies | |
| if: matrix.python-version == matrix.primary-py | |
| run: python -m pip install --upgrade pip build twine | |
| - name: Verify Git state before PyPI build | |
| if: matrix.python-version == matrix.primary-py | |
| run: | | |
| echo "Current Git Ref: ${{ github.ref }}" | |
| git status | |
| git describe --tags --exact-match # Should match the tag exactly | |
| - name: Build package for PyPI | |
| # Uses setuptools_scm automatically via pyproject.toml build-system config | |
| if: matrix.python-version == matrix.primary-py | |
| run: python -m build | |
| - name: Verify built package metadata for PyPI | |
| if: matrix.python-version == matrix.primary-py | |
| run: twine check dist/* | |
| - name: Publish package to PyPI | |
| if: matrix.python-version == matrix.primary-py | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| # --- API Token Authentication --- | |
| # Ensure PYPI_API_TOKEN is set in GitHub Secrets | |
| user: __token__ | |
| password: ${{ secrets.PYPI_API_TOKEN }} | |
| # --- Or use Trusted Publishing (recommended) --- | |
| # Requires 'id-token: write' permission at job level | |
| # Requires configuration on PyPI website first | |
| # trust-token: true | |
| # === Docker Deployment (runs for EACH Python version in the matrix) === | |
| # No 'if' condition on these Docker steps, they run for all matrix versions | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Cache Docker layers for Deploy | |
| uses: actions/cache@v4 | |
| with: | |
| path: /tmp/.buildx-cache-deploy # Separate cache path for deploy builds | |
| # Cache key includes python version and the specific tag ref being built | |
| key: ${{ runner.os }}-deploy-buildx-${{ matrix.python-version }}-${{ github.ref }} | |
| restore-keys: | | |
| ${{ runner.os }}-deploy-buildx-${{ matrix.python-version }}- | |
| - name: Log in to GitHub Container Registry (GHCR) | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| # GITHUB_TOKEN is automatically available, no secret needed | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata (tags, labels) for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository }} | |
| # Use the Git tag from the event ref as the base version | |
| # Assumes tags are like '0.1.0' or 'v0.1.0' - metadata-action handles 'v' prefix | |
| tags: | | |
| # Generate tags like: 0.1.0-py3.9, 0.1-py3.9, 0-py3.9 | |
| type=semver,pattern={{version}}-py${{ matrix.python-version }} | |
| type=semver,pattern={{major}}.{{minor}}-py${{ matrix.python-version }} | |
| type=semver,pattern={{major}}-py${{ matrix.python-version }} | |
| # Add 'latest' tag ONLY for the primary python version build | |
| type=raw,value=latest,enable=${{ matrix.python-version == matrix.primary-py }} | |
| - name: Get Version from Tag for Build Arg | |
| # Extract the clean tag name (e.g., 0.1.0) to pass as build arg | |
| id: get_version_tag | |
| run: | | |
| # Get the tag name from the ref (e.g., refs/tags/0.1.0 -> 0.1.0) | |
| GIT_TAG=${GITHUB_REF#refs/tags/} | |
| # Remove 'v' prefix if present (adjust if your tags don't use 'v') | |
| VERSION=${GIT_TAG#v} | |
| echo "Using version for Docker build arg: $VERSION" | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Build and Push Docker Image to GHCR | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: true # Push the image to GHCR | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| PYTHON_VERSION=${{ matrix.python-version }} | |
| VERSION=${{ steps.get_version_tag.outputs.VERSION }} | |
| cache-from: type=gha,scope=deploy-${{ matrix.python-version }} | |
| cache-to: type=gha,mode=max,scope=deploy-${{ matrix.python-version }} |