Skip to content

Dockerize the test environment for better reproducibility #1189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions .github/workflows/build_base_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ on:
paths:
- 'Dockerfile.base'
- '.github/workflows/build_base_image.yml'
pull_request:
branches: [main, master, develop]
paths:
- 'Dockerfile.base'
- '.github/workflows/build_base_image.yml'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-push-base:
runs-on: ubuntu-latest
Expand All @@ -25,6 +34,7 @@ jobs:
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
Expand All @@ -41,7 +51,8 @@ jobs:
run: |
echo "PYVER_SHORT=$(echo ${{ matrix.pyver }} | cut -d'.' -f1,2)" >> $GITHUB_OUTPUT

- name: Build and push base image
- name: Build and push base image (on push)
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v5
with:
context: .
Expand All @@ -50,4 +61,16 @@ jobs:
build-args: |
PYTHON_VERSION=${{ matrix.pyver }}
tags: |
ghcr.io/${{ steps.repo.outputs.REPO }}-base:${{ steps.pyver_short.outputs.PYVER_SHORT }}-latest
ghcr.io/${{ steps.repo.outputs.REPO }}-base:${{ steps.pyver_short.outputs.PYVER_SHORT }}-latest

- name: Build base image (on PR)
if: github.event_name == 'pull_request'
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.base
push: false
build-args: |
PYTHON_VERSION=${{ matrix.pyver }}
tags: |
ghcr.io/${{ steps.repo.outputs.REPO }}-base:${{ steps.pyver_short.outputs.PYVER_SHORT }}-pr-test
116 changes: 51 additions & 65 deletions .github/workflows/test_pymode.yml
Original file line number Diff line number Diff line change
@@ -1,71 +1,57 @@
name: Testing python-mode

on: [push]
on:
push:
branches: [main, master, develop]
pull_request:
branches: [main, master, develop]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test-python-3_8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install dependencies
run: |
sudo apt update
export PYTHON_CONFIGURE_OPTS="--enable-shared"
sudo apt install -yqq libncurses5-dev libgtk2.0-dev libatk1.0-dev libcairo2-dev libx11-dev libxpm-dev libxt-dev python3-dev lua5.2 liblua5.2-dev libperl-dev git
sudo apt remove --purge -yqq vim vim-runtime gvim
- name: build and install vim from source
working-directory: /tmp
run: |
export PYTHON_CONFIGURE_OPTS="--enable-shared"
git clone https://github.com/vim/vim.git
cd vim
./configure --with-features=huge --enable-multibyte --enable-python3interp=yes --with-python3-config-dir=/usr/lib/python3.8/config-3.8m-x86_64-linux-gnu --enable-perlinterp=yes --enable-luainterp=yes --enable-cscope --prefix=/usr/local
sudo make && sudo make install
- name: Install python-mode
run: |
export PYMODE_DIR="${HOME}/work/python-mode/python-mode"
mkdir -p ${HOME}/.vim/pack/foo/start/
ln -s ${PYMODE_DIR} ${HOME}/.vim/pack/foo/start/python-mode
cp ${PYMODE_DIR}/tests/utils/pymoderc ${HOME}/.pymoderc
cp ${PYMODE_DIR}/tests/utils/vimrc ${HOME}/.vimrc
touch ${HOME}/.vimrc.before ${HOME}/.vimrc.after
- name: Run python-mode test script
run: |
alias python=python3
cd ${HOME}/work/python-mode/python-mode
git submodule update --init --recursive
git submodule sync
bash tests/test.sh
test-python-3_9:
test-python-versions:
runs-on: ubuntu-latest
strategy:
matrix:
python_version:
- short: "3.10"
full: "3.10.13"
- short: "3.11"
full: "3.11.9"
- short: "3.12"
full: "3.12.4"
- short: "3.13"
full: "3.13.0"
fail-fast: false
name: Test Python ${{ matrix.python_version.short }} (${{ matrix.python_version.full }})
steps:
- uses: actions/checkout@v1
- name: Install dependencies
run: |
sudo apt update
export PYTHON_CONFIGURE_OPTS="--enable-shared"
sudo apt install -yqq libncurses5-dev libgtk2.0-dev libatk1.0-dev libcairo2-dev libx11-dev libxpm-dev libxt-dev python3-dev lua5.2 liblua5.2-dev libperl-dev git
sudo apt remove --purge -yqq vim vim-runtime gvim
- name: build and install vim from source
working-directory: /tmp
run: |
export PYTHON_CONFIGURE_OPTS="--enable-shared"
git clone https://github.com/vim/vim.git
cd vim
./configure --with-features=huge --enable-multibyte --enable-python3interp=yes --with-python3-config-dir=/usr/lib/python3.9/config-3.9m-x86_64-linux-gnu --enable-perlinterp=yes --enable-luainterp=yes --enable-cscope --prefix=/usr/local
sudo make && sudo make install
- name: Install python-mode
run: |
export PYMODE_DIR="${HOME}/work/python-mode/python-mode"
mkdir -p ${HOME}/.vim/pack/foo/start/
ln -s ${PYMODE_DIR} ${HOME}/.vim/pack/foo/start/python-mode
cp ${PYMODE_DIR}/tests/utils/pymoderc ${HOME}/.pymoderc
cp ${PYMODE_DIR}/tests/utils/vimrc ${HOME}/.vimrc
touch ${HOME}/.vimrc.before ${HOME}/.vimrc.after
- name: Run python-mode test script
run: |
alias python=python3
cd ${HOME}/work/python-mode/python-mode
git submodule update --init --recursive
git submodule sync
bash tests/test.sh
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build Docker image
run: |
docker compose build -q \
--build-arg PYTHON_VERSION="${{ matrix.python_version.full }}" \
--build-arg PYTHON_VERSION_SHORT="${{ matrix.python_version.short }}" \
python-mode-tests

- name: Run tests with Python ${{ matrix.python_version.short }}
run: |
docker compose run --rm \
-e PYTHON_VERSION="${{ matrix.python_version.full }}" \
-e PYTHON_VERSION_SHORT="${{ matrix.python_version.short }}" \
python-mode-tests
42 changes: 42 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
ARG PYTHON_VERSION_SHORT
ARG PYTHON_VERSION
ARG REPO_OWNER=python-mode
FROM ghcr.io/${REPO_OWNER}/python-mode-base:${PYTHON_VERSION_SHORT}-latest

ENV PYTHON_VERSION=${PYTHON_VERSION}
ENV PYTHONUNBUFFERED=1
ENV PYMODE_DIR="/workspace/python-mode"

# Set up working directory
WORKDIR /workspace

# Copy the python-mode plugin
COPY . /workspace/python-mode

# Set up python-mode in the test environment
RUN mkdir -p /root/.vim/pack/foo/start/ && \
ln -s ${PYMODE_DIR} /root/.vim/pack/foo/start/python-mode && \
cp ${PYMODE_DIR}/tests/utils/pymoderc /root/.pymoderc && \
cp ${PYMODE_DIR}/tests/utils/vimrc /root/.vimrc && \
touch /root/.vimrc.before /root/.vimrc.after

# Initialize git submodules
WORKDIR /workspace/python-mode

# Create a script to run tests
RUN echo '#!/bin/bash\n\
# export PYENV_ROOT="/opt/pyenv"\n\
# export PATH="${PYENV_ROOT}/bin:${PYENV_ROOT}/shims:${PATH}"\n\
eval "$(pyenv init -)"\n\
eval "$(pyenv init --path)"\n\
# Use specified Python version\n\
pyenv shell ${PYTHON_VERSION}\n\
cd /workspace/python-mode\n\
echo "Using Python: $(python --version)"\n\
bash ./tests/test.sh\n\
rm -f tests/.swo tests/.swp 2>&1 >/dev/null \n\
' > /usr/local/bin/run-tests && \
chmod +x /usr/local/bin/run-tests

# Default command
CMD ["/usr/local/bin/run-tests"]
132 changes: 132 additions & 0 deletions README-Docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Docker Test Environment for python-mode

This directory contains Docker configuration to run python-mode tests in a containerized environment that matches the GitHub Actions CI environment.

## Prerequisites

- Docker
- Docker Compose

## Quick Start

### Run Tests

To run all tests in Docker (default version 3.13.0):

```bash
# Using the convenience script
./scripts/run-tests-docker.sh

# Or manually with docker-compose
docker compose run --rm python-mode-tests
```

### Interactive Development

To start an interactive shell for development:

```bash
docker compose run --rm python-mode-dev
```

## What's Included

The Docker environment includes:

- **Ubuntu 24.04** base image
- **pyenv** for Python version management
- **Multiple Python versions**: 3.10.13, 3.11.9, 3.12.4, 3.13.0
- **Python 3.13.0** as default
- **Vim built from source** with Python support for each Python version
- All required system dependencies:
- GUI libraries (GTK, X11, etc.)
- Lua 5.2
- Perl
- Build tools
- Python build dependencies
- **python-mode plugin** properly installed and configured
- **Git submodules** initialized
- **Test environment** matching the CI setup

## Environment Details

The container replicates the GitHub Actions environment:

- Vim is built with `--enable-python3interp=yes` for each Python version
- pyenv is installed at `/opt/pyenv`
- Python versions are managed by pyenv:
- 3.10.13
- 3.11.9
- 3.12.4
- 3.13.0 (default)
- Each Python version has its own Vim binary: `vim-3.10.13`, `vim-3.11.9`, etc.
- Python config directory is automatically detected using `python-config --configdir`
- python-mode is installed in `/root/.vim/pack/foo/start/python-mode`
- Test configuration files are copied to the appropriate locations
- All required environment variables are set

## Test Execution

Tests are run using the same `tests/test.sh` script as in CI:

1. **test_autopep8.sh** - Tests automatic code formatting
2. **test_autocommands.sh** - Tests Vim autocommands
3. **test_folding.sh** - Tests code folding functionality
4. **test_textobject.sh** - Tests text object operations

## Testing with Different Python Versions

You can test python-mode with different Python versions:

```bash
# Test with Python 3.11.9
./scripts/run-tests-docker.sh 3.11

# Test with Python 3.12.4
./scripts/run-tests-docker.sh 3.12

# Test with Python 3.13.0
./scripts/run-tests-docker.sh 3.13
```

Available Python versions: 3.10.13, 3.11.9, 3.12.4, 3.13.0

Note: Use the major.minor format (e.g., 3.11) when specifying versions.

## Troubleshooting

### Python Config Directory Issues

The Dockerfile uses `python-config --configdir` to automatically detect the correct Python config directory. If you encounter issues:

1. Check that pyenv is properly initialized
2. Verify that the requested Python version is available
3. Ensure all environment variables are set correctly

### Build Failures

If the Docker build fails:

1. Check that all required packages are available in Ubuntu 24.04
2. Verify that pyenv can download and install Python versions
3. Ensure the Vim source code is accessible
4. Check that pyenv is properly initialized in the shell

### Test Failures

If tests fail in Docker but pass locally:

1. Check that the Vim build includes Python support for the correct version
2. Verify that all git submodules are properly initialized
3. Ensure the test environment variables are correctly set
4. Confirm that the correct Python version is active
5. Verify that pyenv is properly initialized

## Adding More Python Versions

To add support for additional Python versions:

1. Add the new version to the `pyenv install` commands in the Dockerfile.base
2. Update the test scripts to include the new version
4. Test that the new version works with the python-mode plugin
5. Update this documentation with the new version information
23 changes: 22 additions & 1 deletion doc/pymode.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Python-mode contains all you need to develop python applications in Vim.

Features: *pymode-features*

- Support Python version 2.6+ and 3.2+
- Support Python version 3.10.13, 3.11.9, 3.12.4, 3.13.0
- Syntax highlighting
- Virtualenv support
- Run python code (``<leader>r``)
Expand Down Expand Up @@ -161,6 +161,11 @@ python-features of **pymode** will be disabled.
Set value to `python3` if you are working with python3 projects. You could use
|exrc|

+ Currently supported Python versions: 3.10.13, 3.11.9, 3.12.4, 3.13.0
+
+ For testing with different Python versions, see the Docker testing environment
+ described in the Development section.

-------------------------------------------------------------------------------
2.2 Python indentation ~
*pymode-indent*
Expand Down Expand Up @@ -862,6 +867,22 @@ newly added file (2). This latter file should invoke vim which in turn sources
file (3). File (3) may then read (4) as a first part of its assertion
structure and then execute the remaning of the instructions/assertions.

6. Testing Environment: The project uses Docker for consistent testing across
different Python versions. See `README-Docker.md` for detailed information about
the Docker testing environment.

7. CI/CD: The project uses GitHub Actions for continuous integration, building
Docker images for each supported Python version and running tests automatically.

8. Supported Python Versions: The project currently supports Python 3.10.13,
3.11.9, 3.12.4, and 3.13.0. All tests are run against these versions in the
CI environment.

9. Docker Testing: To run tests locally with Docker:
- Use `./scripts/run-tests-docker.sh` to run tests with the default Python version
- Use `./scripts/run-tests-docker.sh 3.11` to test with Python 3.11.9
- Use `./scripts/test-all-python-versions.sh` to test with all supported versions

===============================================================================
8. Credits ~
*pymode-credits*
Expand Down
Loading