Skip to content

Commit 5466b6a

Browse files
authored
Support local hoster (#401)
* beefing up local hoster implementation to keep merge requests on disk * remove pytest-cov * making e2e tests independent of a local gitlab instance
1 parent 1fc6c18 commit 5466b6a

30 files changed

+920
-916
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ jobs:
6666
run: python -m mypy src tests
6767

6868

69-
unit-tests:
70-
name: unit tests on ${{ matrix.python-version }}
69+
tests:
70+
name: tests on ${{ matrix.python-version }}
7171
runs-on: ubuntu-22.04
7272
strategy:
7373
fail-fast: false
@@ -78,7 +78,7 @@ jobs:
7878
- uses: actions/checkout@v4
7979
- uses: actions/setup-python@v4
8080
with:
81-
python-version: ${{ env.PYTHON_LATEST }}
81+
python-version: ${{ matrix.python-version }}
8282
- uses: snok/install-poetry@v1
8383
with:
8484
version: ${{ env.POETRY_VERSION }}
@@ -87,92 +87,15 @@ jobs:
8787
poetry self add "poetry-dynamic-versioning[plugin]"
8888
poetry install
8989
90-
- run: python -m pytest -m 'not e2e'
90+
- run: coverage run -m pytest
9191
env:
9292
# FoxOps test configuration
93-
FOXOPS_GITLAB_ADDRESS: https://nonsense.com/api/v4
94-
FOXOPS_GITLAB_TOKEN: nonsense
95-
96-
# Test runner configuration
97-
COVERAGE_FILE: .coverage.unit.${{ matrix.python-version }}
98-
99-
- name: Upload coverage data
100-
uses: actions/upload-artifact@v3
101-
with:
102-
name: coverage-data
103-
path: .coverage.*
104-
if-no-files-found: ignore
105-
106-
107-
e2e-tests:
108-
name: e2e tests on ${{ matrix.python-version }}
109-
runs-on: ubuntu-22.04
110-
strategy:
111-
fail-fast: false
112-
matrix:
113-
python-version: ["3.11"]
114-
115-
steps:
116-
- uses: actions/checkout@v4
117-
- uses: actions/setup-python@v4
118-
with:
119-
python-version: ${{ env.PYTHON_LATEST }}
120-
- uses: snok/install-poetry@v1
121-
with:
122-
version: ${{ env.POETRY_VERSION }}
123-
- name: Install dependencies
124-
run: |
125-
poetry self add "poetry-dynamic-versioning[plugin]"
126-
poetry install
127-
128-
- name: Start GitLab test instance
129-
run: |
130-
docker compose up -d
131-
./scripts/await-healthy.sh
132-
133-
- run: python -m pytest -m 'e2e'
134-
env:
135-
# FoxOps test configuration
136-
FOXOPS_GITLAB_ADDRESS: https://nonsense.com/api/v4
137-
FOXOPS_GITLAB_TOKEN: nonsense
138-
139-
# Test runner configuration
140-
COVERAGE_FILE: .coverage.e2e.${{ matrix.python-version }}
141-
142-
- name: Upload coverage data
143-
uses: actions/upload-artifact@v3
144-
with:
145-
name: coverage-data
146-
path: .coverage.*
147-
if-no-files-found: ignore
148-
149-
150-
coverage:
151-
name: Combine & check coverage
152-
runs-on: ubuntu-latest
153-
needs: [unit-tests, e2e-tests]
154-
155-
steps:
156-
- uses: actions/checkout@v4
157-
- uses: actions/setup-python@v4
158-
with:
159-
# Use latest Python, so it understands all syntax.
160-
python-version: ${{env.PYTHON_LATEST}}
161-
- run: python -m pip install --upgrade coverage[toml]
162-
- uses: actions/download-artifact@v3
163-
with:
164-
name: coverage-data
165-
- name: Combine coverage & fail if it's <70%.
166-
run: |
167-
python -m coverage combine
168-
python -m coverage html --skip-covered --skip-empty
169-
python -m coverage report --fail-under=70
170-
- name: Upload HTML report
171-
uses: actions/upload-artifact@v3
172-
with:
173-
name: html-report
174-
path: htmlcov
93+
FOXOPS_TESTS_GITLAB_ADDRESS: https://gitlab.com
94+
FOXOPS_TESTS_GITLAB_ROOT_GROUP_ID: 73622910
95+
FOXOPS_TESTS_GITLAB_TOKEN: ${{ secrets.FOXOPS_TESTS_GITLAB_TOKEN }}
17596

97+
- name: Check test coverage
98+
run: coverage report
17699

177100
package:
178101
name: Build & verify package

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
.python-version
22
__pycache__/
33
dist/
4+
run/
45
.coverage*
56
docs/build/
67
.idea
78
test.db
89
**/.DS_Store
910
.dmypy.json
11+
.env.test

CONTRIBUTING.md

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,80 @@ This project uses [Poetry](https://python-poetry.org/)
44
and [poetry-dynamic-versioning](https://pypi.org/project/poetry-dynamic-versioning/)
55
for dependency management and the package building process.
66

7-
## Running tests
7+
## Run foxops locally
88

9-
The test suite uses `pytest` as a test runner and it's located under `tests/`.
9+
### With docker-compose
1010

11-
The unit tests can be executed by excluding the `e2e` tests:
11+
The easiest way to get started is to run foxops locally via docker-compose. Just execute this command in the root folder of the project:
1212

13-
```
14-
pytest -m 'not e2e'
13+
```shell
14+
docker compose up
1515
```
1616

17-
which doesn't require any external database nor GitLab instance.
17+
It will build the docker image and run foxops with an SQlite database and a local hoster configuration.
1818

19-
To run the `e2e` tests a test GitLab instance needs to be available. It can be started using `docker compose`:
19+
Now foxops can be accessed at `http://localhost:8000` with `dummy` as the token.
2020

21-
```
22-
docker compose up -d
21+
### Directly with Python
22+
23+
First, start by making sure that your virtual Python environment is up to date by running
24+
25+
```shell
26+
poetry install
2327
```
2428

25-
Be aware that an **initial startup of the Gitlab instance can take some time** (5 minutes). Check the logs with `docker-compose logs` to verify it if reached a stable state.
29+
Then, you can run foxops with
2630

27-
Then, the tests can be run using `pytest`:
31+
```shell
32+
export FOXOPS_DATABASE_URL=sqlite+aiosqlite:///./foxops.db
33+
export FOXOPS_HOSTER_TYPE=local
34+
export FOXOPS_HOSTER_LOCAL_DIRECTORY=<path to a local directory where foxops can store the repositories>
35+
export FOXOPS_STATIC_TOKEN=dummy
2836

29-
```
30-
pytest -m 'e2e'
37+
# initialize sqlite database in ./foxops.db
38+
poetry run alembic upgrade head
39+
40+
# run foxops webserver
41+
poetry run uvicorn foxops.__main__:create_app --host localhost --port 5001 --reload --factory
3142
```
3243

33-
## Running foxops locally
44+
## Running Tests
3445

35-
The foxops API can be run locally using `uvicorn`:
46+
The test suite uses `pytest` as a test runner and it's located under `tests/`.
3647

37-
```
38-
uvicorn foxops.__main__:create_app --host localhost --port 5001 --reload --factory
48+
Simply execute the following commands to run the entire foxops test suite:
49+
50+
```shell
51+
pytest
3952
```
4053

41-
For this to work foxops needs a few configuration settings to be available.
42-
These are at least a GitLab address and token. To use the test instance you can run the following
54+
Tests can also run with parallelization enabled to speed up execution. To do so, simply add the `-n` flag with the number of parallel processes to use:
4355

56+
```shell
57+
pytest -n 4
4458
```
45-
FOXOPS_STATIC_TOKEN=dummy FOXOPS_GITLAB_ADDRESS=http://localhost:5002/api/v4 FOXOPS_GITLAB_TOKEN=ACCTEST1234567890123 uvicorn foxops.__main__:create_app --host localhost --port 5001 --reload --factory
59+
60+
Some tests require a Gitlab instance to be available and will be skipped automatically if it's not the case.
61+
62+
### Run Tests that Require Gitlab
63+
64+
To run tests that require a Gitlab instance, you can either [run one locally](https://docs.gitlab.com/ee/install/docker.html) or use the public [gitlab.com](https://gitlab.com) instance. The latter is typically recommended for ease of use.
65+
66+
On that Gitlab instance, a "root group" is required, in which foxops can create temporary projects for test templates and incarnations (these will be automatically cleaned after the test execution). Also an access token is required that has access to that group.
67+
68+
Once you have all this, add the following environment variables and rerun the tests:
69+
70+
```shell
71+
# defaults to "https://gitlab.com" if not specified
72+
export FOXOPS_TESTS_GITLAB_ADDRESS=<address of the Gitlab instance>
73+
# defaults to 73622910, which is the "foxops-e2e" group on gitlab.com
74+
export FOXOPS_TESTS_GITLAB_ROOT_GROUP_ID=<id of the root group>
75+
export FOXOPS_TESTS_GITLAB_TOKEN=<access token with access to the root group>
76+
77+
# these variables can also be set in a file called `.env.test` in the root folder of the project
78+
79+
# execute tests (parallelization is recommended)
80+
pytest -n 4
4681
```
4782

4883
### Documentation

docker-compose.yml

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
1-
# by default gitlab will run on localhost (i.e. same host where tests are run) listening on port 5002
2-
# this can be overriden with environment variables: GITLAB_HOST & GITLAB_PORT & GITLAB_ADDRESS
3-
# Eg:
4-
# env GITLAB_HOST="myserver.example.com" GITLAB_PORT="8002" docker-compose up -d
5-
# env GITLAB_HOST="myserver.example.com" GITLAB_PORT="8002" ./script/await-healthy.sh
6-
# env GITLAB_ADDRESS="http://myserver.example.com:8002/api/v4" poetry run pytest -m 'e2e'
7-
81
version: '3'
92

103
services:
11-
gitlab-ce:
12-
image: gitlab/gitlab-ce:${GITLAB_CE_VERSION:-15.8.3-ce.0}
13-
restart: always
4+
foxops:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile
148
ports:
15-
- ${GITLAB_PORT:-5002}:80
16-
environment:
17-
GITLAB_ROOT_PASSWORD: dvqMom4ruD9oqcErwtij
18-
GITLAB_OMNIBUS_CONFIG: |
19-
external_url "http://${GITLAB_HOST:-127.0.0.1}:${GITLAB_PORT:-5002}"
20-
nginx['listen_port'] = 80
21-
labels:
22-
foxops-gitlab/owned: ''
9+
- 8000:8000
2310
volumes:
24-
- config-ce:/etc/gitlab
25-
- logs-ce:/var/log/gitlab
26-
- data-ce:/var/opt/gitlab
27-
- ${PWD}/scripts/healthcheck-and-setup.sh:/healthcheck-and-setup.sh:Z
28-
healthcheck:
29-
test: /healthcheck-and-setup.sh
30-
interval: 10s
31-
timeout: 2m
11+
- database:/app/database
12+
- hoster:/app/hoster
13+
environment:
14+
FOXOPS_DATABASE_URL: sqlite+aiosqlite:////app/database/foxops.db
15+
FOXOPS_HOSTER_TYPE: local
16+
FOXOPS_HOSTER_LOCAL_DIRECTORY: /app/hoster
17+
FOXOPS_STATIC_TOKEN: dummy
3218

3319
volumes:
34-
config-ce:
35-
logs-ce:
36-
data-ce:
20+
database:
21+
hoster:

docs/source/installation.md

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,49 @@ docker run --rm -v "$(pwd)"/foxops_db:/database \
1515
alembic upgrade head
1616
```
1717

18-
With the database in place, we can now start the foxops API server:
18+
With the database in place, we can now start the foxops API server. Two options exist for running it locally:
19+
20+
### Run FoxOps Connected to an Existing Gitlab Instance
21+
22+
If you already have a running Gitlab instance where you want to host your templates and incarnations, you can run foxops connected to that instance:
23+
24+
```bash
25+
export FOXOPS_HOSTER_GITLAB_ADDRESS=https://gitlab.com
26+
export FOXOPS_HOSTER_GITLAB_TOKEN=glpat-abcdefgh123456
27+
28+
docker run --rm -p 8000:8000 -v "$(pwd)"/foxops_db:/database \
29+
-e FOXOPS_DATABASE_URL=sqlite+aiosqlite:////database/foxops.sqlite \
30+
-e FOXOPS_STATIC_TOKEN=dummy-token \
31+
-e FOXOPS_HOSTER_TYPE=gitlab \
32+
-e FOXOPS_HOSTER_GITLAB_ADDRESS=$FOXOPS_HOSTER_GITLAB_ADDRESS \
33+
-e FOXOPS_HOSTER_GITLAB_TOKEN=$FOXOPS_HOSTER_GITLAB_TOKEN \
34+
ghcr.io/roche/foxops:latest
35+
```
36+
37+
### Run FoxOps Without Gitlab
38+
39+
For the very first steps (development only), foxops can also be run without a Gitlab instance connected. This is not only useful for getting started quickly, but also when running tests in other systems that require a running foxops instance.
40+
41+
Be aware that Gitlab in this is the replaced with a very basic implementation that creates all repositories/merge requests in a local folder. There is no UI for viewing or interacting with these repositories, except for your file browser.
1942

2043
```bash
21-
export GITLAB_TOKEN=my-gitlab-token
44+
# put a folder here where foxops should create the repositories
45+
export FOXOPS_HOSTER_LOCAL_DIRECTORY=/tmp/foxops_hoster
2246

2347
docker run --rm -p 8000:8000 -v "$(pwd)"/foxops_db:/database \
2448
-e FOXOPS_DATABASE_URL=sqlite+aiosqlite:////database/foxops.sqlite \
2549
-e FOXOPS_STATIC_TOKEN=dummy-token \
26-
-e FOXOPS_GITLAB_ADDRESS=https://gitlab.com/api/v4 \
27-
-e FOXOPS_GITLAB_TOKEN=$GITLAB_TOKEN \
50+
-e FOXOPS_HOSTER_TYPE=local \
51+
-e FOXOPS_HOSTER_LOCAL_DIRECTORY=$FOXOPS_HOSTER_LOCAL_DIRECTORY \
2852
ghcr.io/roche/foxops:latest
2953
```
3054

55+
```{note}
56+
In this setup, your template repositories must also be placed in the `/tmp/foxops_hoster` folder. Place the git repositories of your templates in a folder called `/tmp/foxops_hoster/<template_name>/git` to make them usable by foxops.
57+
```
58+
59+
### Accessing FoxOps
60+
3161
Then, you can open your browser and go to the following URLs:
3262
* <http://localhost:8000/> - the foxops web UI (login with `dummy-token` when prompted for the password)
3363
* <http://localhost:8000/docs> - the foxops API documentation
@@ -69,8 +99,9 @@ The following is needed to run foxops:
6999
* Set the following environment variables:
70100
* `FOXOPS_STATIC_TOKEN` - Set to a (long) random and **secret** string. This secret is used to authenticate all users of the foxops UI & API
71101
* `FOXOPS_DATABASE_URL` - Set to the database URL
72-
* `FOXOPS_GITLAB_ADDRESS` - Set to the address of your GitLab instance (e.g. `https://gitlab.com/api/v4`)
73-
* `FOXOPS_GITLAB_TOKEN` - Set to a GitLab access token that has access to all repositories (incarnations & templates) that foxops should manage
102+
* `FOXOPS_HOSTER_TYPE` - Set to `gitlab` for a production deployment
103+
* `FOXOPS_HOSTER_GITLAB_ADDRESS` - Set to the address of your GitLab instance (e.g. `https://gitlab.com`) (if hoster type is set to `gitlab`)
104+
* `FOXOPS_HOSTER_GITLAB_TOKEN` - Set to a GitLab access token that has access to all repositories (incarnations & templates) that foxops should manage (if hoster type is set to `gitlab`)
74105

75106
#### Kubernetes Example
76107

@@ -109,9 +140,11 @@ spec:
109140
- name: foxops
110141
image: ghcr.io/roche/foxops:v2.0.0
111142
env:
112-
- name: FOXOPS_GITLAB_ADDRESS
113-
value: https://gitlab.com/api/v4
114-
- name: FOXOPS_GITLAB_TOKEN
143+
- name: FOXOPS_HOSTER_TYPE
144+
value: gitlab
145+
- name: FOXOPS_HOSTER_GITLAB_ADDRESS
146+
value: https://gitlab.com
147+
- name: FOXOPS_HOSTER_GITLAB_TOKEN
115148
value: <dummy>
116149
- name: FOXOPS_STATIC_TOKEN
117150
value: <dummy>

0 commit comments

Comments
 (0)