Skip to content

Commit c8127a6

Browse files
author
desiena
committed
Integration tests + new CI/CD pipeline + Fields + fixes
1 parent aa78983 commit c8127a6

21 files changed

Lines changed: 3300 additions & 677 deletions

.github/workflows/ci-cd.yml

Lines changed: 170 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,155 @@
1-
name: Build and publish
1+
name: CI/CD
22

33
on:
44
workflow_dispatch:
55
push:
66
branches:
7-
- '*'
7+
- '**' # run on all branches (including master)
8+
tags:
9+
- 'v*.*.*' # release tags like v1.2.3
810

911
env:
1012
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
11-
PRE_RELEASE_VERSION: true
12-
DRAFT_VERSION: true
1313

1414
jobs:
15-
build-and-publish:
15+
integration-fms17:
16+
name: Integration tests (FMS17 on fms_17)
17+
runs-on: [fms_17]
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: '3.9'
26+
27+
- name: Cache pip
28+
uses: actions/cache@v4
29+
with:
30+
path: ~\AppData\Local\pip\Cache
31+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
32+
restore-keys: |
33+
${{ runner.os }}-pip-
34+
35+
- name: Install dependencies
36+
run: |
37+
python -m pip install --upgrade pip
38+
pip install -r requirements.txt
39+
40+
- name: Create tests/.env for FMS17
41+
shell: powershell
42+
run: |
43+
$envContent = @"
44+
FMS_ADDRESS="https://localhost"
45+
FMS_DB_NAME="fmdata_testing"
46+
FMS_DB_USER="${{ secrets.FMDATA_TESTING_USER }}"
47+
FMS_DB_PASSWORD="${{ secrets.FMDATA_TESTING_PASSWORD }}"
48+
FMS_VERSION="17"
49+
"@
50+
New-Item -ItemType Directory -Force -Path tests | Out-Null
51+
Set-Content -Path tests/.env -Value $envContent -NoNewline
52+
53+
- name: Run integration tests with coverage (FMS17)
54+
shell: powershell
55+
run: |
56+
$env:ENV_FILE = ".env"
57+
coverage run -m unittest discover -s tests -t tests
58+
coverage xml -o coverage_fms17.xml
59+
60+
- name: Upload coverage artifact (FMS17)
61+
uses: actions/upload-artifact@v4
62+
with:
63+
name: coverage-fms17
64+
path: |
65+
coverage_fms17.xml
66+
.coverage.fms17
67+
68+
integration-fms22:
69+
name: Integration tests (FMS22 on fms_22)
70+
runs-on: [ fms_22]
71+
if: false
72+
steps:
73+
- name: Checkout repository
74+
uses: actions/checkout@v5
75+
76+
- name: Set up Python
77+
uses: actions/setup-python@v6
78+
with:
79+
python-version: '3.8'
80+
81+
- name: Cache pip
82+
uses: actions/cache@v4
83+
with:
84+
path: ~\AppData\Local\pip\Cache
85+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
86+
restore-keys: |
87+
${{ runner.os }}-pip-
88+
89+
- name: Install dependencies
90+
run: |
91+
python -m pip install --upgrade pip
92+
pip install -r requirements.txt
93+
94+
- name: Create tests/.env for FMS22
95+
shell: powershell
96+
run: |
97+
$envContent = @"
98+
FMS_ADDRESS="http://localhost"
99+
FMS_DB_NAME="fmdata_testing"
100+
FMS_DB_USER="${{ secrets.FMDATA_TESTING_USER }}"
101+
FMS_DB_PASSWORD="${{ secrets.FMDATA_TESTING_PASSWORD }}"
102+
FMS_VERSION="22"
103+
"@
104+
New-Item -ItemType Directory -Force -Path tests | Out-Null
105+
Set-Content -Path tests/.env -Value $envContent -NoNewline
106+
107+
- name: Run integration tests with coverage (FMS22)
108+
shell: pwsh
109+
run: |
110+
$env:ENV_FILE = ".env"
111+
coverage run --data-file=.coverage.fms22 -m unittest discover -s tests -t tests
112+
coverage xml -o coverage_fms22.xml
113+
114+
- name: Upload coverage artifact (FMS22)
115+
uses: actions/upload-artifact@v4
116+
with:
117+
name: coverage-fms22
118+
path: |
119+
coverage_fms22.xml
120+
.coverage.fms22
121+
122+
sonarcloud:
123+
name: SonarCloud analysis
124+
runs-on: ubuntu-latest
125+
needs:
126+
- integration-fms17
127+
steps:
128+
- name: Checkout repository
129+
uses: actions/checkout@v4
130+
131+
- name: Download coverage artifact (FMS17)
132+
uses: actions/download-artifact@v4
133+
with:
134+
name: coverage-fms17
135+
path: coverage_artifacts
136+
137+
# - name: Download coverage artifact (FMS22)
138+
# uses: actions/download-artifact@v4
139+
# with:
140+
# name: coverage-fms22
141+
# path: coverage_artifacts
142+
143+
- name: SonarCloud Scan
144+
uses: SonarSource/sonarqube-scan-action@v6.0.0
145+
env:
146+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
147+
148+
release:
149+
name: Release on tag
16150
runs-on: ubuntu-latest
151+
needs: sonarcloud
152+
if: startsWith(github.ref, 'refs/tags/v')
17153
environment:
18154
name: pypi
19155
url: https://pypi.org/p/fmdata
@@ -23,61 +159,57 @@ jobs:
23159
steps:
24160
- name: Checkout repository
25161
uses: actions/checkout@v4
26-
27-
- name: Sets env vars for main
28-
if: ${{ env.BRANCH_NAME == 'main' }}
29-
run: |
30-
echo "PRE_RELEASE_VERSION=false" >> $GITHUB_ENV
31-
echo "DRAFT_VERSION=false" >> $GITHUB_ENV
32-
33-
- name: Get next version
34-
uses: reecetech/version-increment@2024.10.1
35-
id: version
36162
with:
37-
scheme: semver
38-
release_branch: main
163+
fetch-depth: 0
39164

40-
- name: Set PACKAGE_VERSION Environment Variable
41-
run: echo "PACKAGE_VERSION=${{ steps.version.outputs.version }}" >> $GITHUB_ENV
165+
- name: Ensure tag commit is on master
166+
run: |
167+
git fetch origin master:origin-master
168+
if git merge-base --is-ancestor origin-master "${GITHUB_SHA}"; then
169+
echo "Tag commit is contained in master."
170+
else
171+
echo "Error: Release tags must point to a commit on master."
172+
exit 1
173+
fi
42174
43-
- name: Release version
44-
uses: softprops/action-gh-release@v2
45-
with:
46-
draft: ${{ env.DRAFT_VERSION }}
47-
prerelease: ${{ env.PRE_RELEASE_VERSION }}
48-
tag_name: "${{ steps.version.outputs.version }}"
175+
- name: Extract version from tag and export PACKAGE_VERSION
176+
run: |
177+
TAG_NAME="${GITHUB_REF_NAME}"
178+
# Expect tags like v1.2.3 -> PACKAGE_VERSION=1.2.3
179+
VERSION="${TAG_NAME#v}"
180+
echo "PACKAGE_VERSION=${VERSION}" >> $GITHUB_ENV
49181
50182
- name: Set up Python
51-
uses: actions/setup-python@v4
183+
uses: actions/setup-python@v5
52184
with:
53185
python-version: '3.8'
54186

55-
# Cache pip dependencies for faster builds
56187
- name: Cache pip
57-
uses: actions/cache@v3
188+
uses: actions/cache@v4
58189
with:
59190
path: ~/.cache/pip
60191
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
61192
restore-keys: |
62193
${{ runner.os }}-pip-
63194
64-
# Install dependencies
65-
- name: Install dependencies
195+
- name: Install build dependencies
66196
run: |
67197
python -m pip install --upgrade pip
68198
pip install -r requirements.txt
199+
pip install build
69200
70-
# (Optional) Run tests
71-
# - name: Run tests
72-
# run: |
73-
# pytest
74-
75-
# Build the package
76201
- name: Build package
77202
run: |
78-
python setup.py sdist bdist_wheel
203+
python -m build
204+
205+
- name: Create GitHub Release
206+
uses: softprops/action-gh-release@v2
207+
with:
208+
draft: false
209+
prerelease: false
210+
tag_name: "${{ github.ref_name }}"
211+
generate_release_notes: true
79212

80213
- name: Publish package distributions to PyPI
81-
if: ${{ env.PRE_RELEASE_VERSION == 'false' }}
82214
uses: pypa/gh-action-pypi-publish@release/v1
83215

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ celerybeat.pid
123123

124124
# Environments
125125
tests/.env
126+
tests/.env_fms17
127+
tests/.env_fms22
126128
.venv
127129
env/
128130
venv/

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ students = Student.objects.order_by("pk").find(full_name__raw="*")
8787

8888
# Find students with exact match (equivalent to __exact)
8989
student_john = Student.objects.find(full_name="John Doe") # Searches for exact match
90-
students_of_2024_but_not_john = Student.objects.find(graduation_year=2024).omit(full_name="John Doe") # Searches for students graduating in 2024 but not named John Doe
90+
students_of_2024_but_not_john = Student.objects.find(graduation_year=2024).omit(
91+
full_name="John Doe") # Searches for students graduating in 2024 but not named John Doe
9192

9293
# Query with chunking and portal prefetching
9394
result_set = (Student.objects
9495
.order_by("pk")
95-
.find(full_name__raw="*") # __raw means filemaker raw query, so it will search for all students with a non-empty full_name
96-
.chunk_size(1000) # Call the API in chunks of 1000 records (in this example, it will return all students)
96+
.find(
97+
full_name__raw="*") # __raw means filemaker raw query, so it will search for all students with a non-empty full_name
98+
.chunking(1000) # Call the API in chunks of 1000 records (in this example, it will return all students)
9799
.prefetch_portal("classes", limit=100)
98100
)[:1000] # Limit to first 1000 records
99101

@@ -196,7 +198,7 @@ first_10 = Student.objects.find()[0:10]
196198
next_10 = Student.objects.find()[10:20]
197199

198200
# Chunked processing for large datasets
199-
for student in Student.objects.find().chunk_size(1000):
201+
for student in Student.objects.find().chunking(1000):
200202
process_student(student)
201203
```
202204

@@ -217,7 +219,7 @@ for student in students:
217219
classes = student.classes.only_prefetched()
218220

219221
# Or force to fetch fresh portal data
220-
classes = student.classes.avoid_prefetch_cache()
222+
classes = student.classes.ignore_prefetched()
221223

222224
# Create new portal records
223225
student.classes.create(name="New Class", description="Description")

fmdata/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
from .const import FMErrorEnum
2-
from .fmclient import FMClient
3-
from .orm import Model, PortalField, PortalModel, PortalManager
2+
from .fmclient import FMClient, FMVersion
3+
from .orm import Model, PortalField, PortalModel, PortalManager
4+
from .fmd_fields import (
5+
FMFieldType,
6+
String,
7+
Integer,
8+
Float,
9+
Decimal,
10+
Bool,
11+
Date,
12+
DateTime,
13+
Time,
14+
)

0 commit comments

Comments
 (0)