Development Setup
Development Setup
Complete guide for new contributors — from a fresh Windows machine to a working dev environment with CI/CD.
Prerequisites
| Requirement | Notes |
|---|---|
| Windows 10/11 | Admin access required for GitLab Runner service |
| Icarus | Installed via Steam — needed to use the editor (tests use bundled fixtures) |
| Python 3.10+ | ✅ Check "Add to PATH" during install |
| Git for Windows | Includes Git Bash — most commands below use it |
Verify your installs:
python --version # Python 3.10+ required
git --version # Any recent version
No pip dependencies needed for the editor itself. The entire project uses only the Python 3 standard library (tkinter, json, struct, zlib).
1. Clone the Repository
git clone https://git.eurekaendeavors.com/root/icarus-pets.git
cd icarus-pets
You should see the full project structure described in the Architecture wiki page.
2. Get Your Mounts.json
The editor needs a Mounts.json save file to load your creatures. (Tests use bundled fixtures — no local save file needed.) Icarus stores these at:
%LOCALAPPDATA%\Icarus\Saved\PlayerData\{SteamID}\Mounts.json
Find yours:
ls "$LOCALAPPDATA/Icarus/Saved/PlayerData/"*/Mounts.json
You should see one or more paths like:
C:\Users\you\AppData\Local\Icarus\Saved\PlayerData\76561198012345678\Mounts.json
Important: You must have at least one tamed mount, pet, or farm animal stored at a station in-game for data to appear in this file. Creatures currently following you or active in the world may not be saved yet.
For local development, copy it into the project directory:
cp "$LOCALAPPDATA/Icarus/Saved/PlayerData/<YourSteamID>/Mounts.json" .
3. Run the Editor
python mount_editor.py
This launches the Tkinter GUI. You should see your mounts listed in the sidebar with the 4-tab interface (Overview, Genetics, Talents, Advanced). See the GUI Guide for usage details.
4. Run Tests Locally
Both test suites should pass before committing any changes.
Species Swap Tests (no test data needed)
python tests/test_species_swap.py
Expected: 13 tests, all ✓, zero failures.
Roundtrip Tests (no setup needed)
python tests/test_roundtrip.py
Expected: Every mount across all locale fixtures in tests/sample_mounts/ parses and re-serializes to identical bytes. Tests 14 mounts across 2 locales (EN-US UTF-8, FR-FR UTF-16 LE) including accented names. No local Mounts.json needed.
5. Request a GitLab Account
Contact the project maintainer to get:
- A GitLab account on
git.eurekaendeavors.com - Developer (or higher) access to the
icarus-petsproject - A Personal Access Token — go to Settings → Access Tokens → create one with
api+read_repository+write_repositoryscopes
Save your token in .gitlab_token at the project root (this file is gitignored):
echo "glpat-your-token-here" > .gitlab_token
6. Install the GitLab Runner
The CI/CD pipeline runs on a local GitLab Runner installed on your dev machine. This is a Windows service that picks up jobs from the GitLab server.
6a. Download the Runner
mkdir -p /c/GitLab-Runner
curl -L -o /c/GitLab-Runner/gitlab-runner.exe \
https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe
6b. Get Your Runner Registration Token
From the GitLab web UI:
- Go to Project → Settings → CI/CD → Runners
- Expand the Runners section
- Copy the registration token (starts with
GR1348941...)
Or via the API (requires admin token):
TOKEN=$(cat .gitlab_token)
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
"https://git.eurekaendeavors.com/api/v4/projects/1" \
| python -c "import sys,json; print(json.load(sys.stdin)['runners_token'])"
6c. Register the Runner
/c/GitLab-Runner/gitlab-runner.exe register \
--non-interactive \
--url "https://git.eurekaendeavors.com/" \
--registration-token "GR1348941_YOUR_TOKEN_HERE" \
--executor "shell" \
--shell "powershell" \
--description "your-machine-name" \
--tag-list "windows,python"
Important: Use
--shell "powershell", not"cmd". Thecmdshell is not properly supported and will fail withshell cmd not found.
The runner config is saved to config.toml in the current directory. Move it to the runner directory:
mv config.toml /c/GitLab-Runner/config.toml
6d. Verify the config
Check that the shell is set to powershell:
cat /c/GitLab-Runner/config.toml
You should see:
[[runners]]
name = "your-machine-name"
url = "https://git.eurekaendeavors.com/"
executor = "shell"
shell = "powershell"
6e. Install as a Windows Service
Open an Administrator PowerShell (right-click → Run as Administrator):
cd C:\GitLab-Runner
.\gitlab-runner.exe install --working-directory "C:\GitLab-Runner" --config "C:\GitLab-Runner\config.toml"
.\gitlab-runner.exe start
This requires admin access — the
installcommand registers a Windows service that runs automatically on boot.
6f. Enable "Run Untagged Jobs"
By default, the runner only picks up jobs with matching tags. Enable untagged job execution so all pipeline jobs run:
Option A — GitLab UI: Go to Project → Settings → CI/CD → Runners → click the pencil icon on your runner → check "Run untagged jobs" → Save.
Option B — API:
TOKEN=$(cat .gitlab_token)
# First, find your runner ID
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
"https://git.eurekaendeavors.com/api/v4/projects/1/runners" \
| python -c "import sys,json; [print(f'#{r[\"id\"]}: {r[\"description\"]}') for r in json.load(sys.stdin)]"
# Then enable run_untagged (replace RUNNER_ID)
curl -s --request PUT \
--header "PRIVATE-TOKEN: $TOKEN" \
--data "run_untagged=true" \
"https://git.eurekaendeavors.com/api/v4/runners/RUNNER_ID"
6g. Verify the Runner is Online
TOKEN=$(cat .gitlab_token)
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
"https://git.eurekaendeavors.com/api/v4/projects/1/runners" \
| python -c "import sys,json; [print(f'#{r[\"id\"]}: {r[\"description\"]} — {r[\"status\"]}') for r in json.load(sys.stdin)]"
Expected: status: online.
7. Configure the CI Pipeline
The .gitlab-ci.yml in the repo defines three stages with 14 jobs:
| Job | Stage | Trigger | Purpose |
|---|---|---|---|
test:all |
test | Every push | Unified runner — all test_*.py files |
test:roundtrip |
test | Every push | Binary roundtrip (bundled EN-US + FR-FR fixtures) |
test:species_swap |
test | Every push | 13 species swap test cases |
test:ue4_parser |
test | Every push | 28 UE4 binary parser tests |
test:ue4_serializer |
test | Every push | 28 UE4 serializer tests |
test:mount_model |
test | Every push | 28 MountModel API tests |
test:species_swap_edge |
test | Every push | 22 edge case tests |
test:save_backup |
test | Every push | Save/backup/restore tests |
test:packaging |
test | Every push | Frozen-app path tests |
test:refresh |
test | Every push | Refresh tool tests |
test:talent_data |
test | Every push | Talent data integrity (35 tests) |
test:changed_files_check |
test | Every push | Soft gate — warns on missing test changes |
build:exe |
build | Tags / [build] / Manual |
PyInstaller → IcarusPetEditor.exe |
release:package |
release | Tags only | ZIP → Package Registry → Release link |
No local configuration needed. All tests use bundled fixtures in
tests/sample_mounts/. NoMOUNTS_JSONpath or local save file required.
Trigger the Pipeline
Push a commit to see the pipeline run:
git add -A && git commit -m "Test CI pipeline" && git push origin main
Monitor the pipeline via the GitLab UI (CI/CD → Pipelines) or via API:
TOKEN=$(cat .gitlab_token)
curl -s --header "PRIVATE-TOKEN: $TOKEN" \
"https://git.eurekaendeavors.com/api/v4/projects/1/pipelines?per_page=1" \
| python -c "import sys,json; p=json.load(sys.stdin)[0]; print(f'Pipeline #{p[\"id\"]}: {p[\"status\"]}')"
8. Install PyInstaller (for Build Stage)
The build:exe job installs PyInstaller automatically via pip, but you'll want it locally too for testing builds:
pip install pyinstaller
Test a local build using the build script:
python build.py
This cleans previous artifacts, runs PyInstaller with the project's .spec file, and reports the output:
✅ Build successful!
Version: v2.0.0
Output: dist/IcarusPetEditor.exe
Size: 10.0 MB
Time: 10.8s
Clean build artifacts only: python build.py --clean
Verify the exe works: ./dist/IcarusPetEditor.exe --version
Build Triggers in CI
The build:exe job runs when:
- A version tag is pushed: git tag v2.0.0 && git push --tags
- A commit message contains [build]: git commit -m "feature X [build]"
- Manually via the GitLab CI/CD UI (play button on the pipeline)
Built .exe files are stored as pipeline artifacts (downloadable from GitLab, 30-day expiry).
9. Day-to-Day Development Workflow
Making Changes
# 1. Pull latest
git pull origin main
# 2. Make your changes
# ... edit files ...
# 3. Run tests locally
python tests/test_species_swap.py
python tests/test_roundtrip.py
# 4. Commit and push
git add -A
git commit -m "Brief description of changes"
git push origin main
# 5. CI pipeline runs automatically — check it passes
Files You Should NOT Commit
These are gitignored — don't force-add them:
| File | Reason |
|---|---|
Mounts.json |
Your personal save data |
Mounts_edited.json |
Editor output file |
.gitlab_token |
Your API credentials |
config.toml |
Runner auth token |
pak-files/ |
Extracted game data (large) |
dist/, build/ |
PyInstaller output |
Updating After Game Patches
When Icarus releases a game update that changes talent data, use the one-command refresh tool:
python scripts/refresh_talent_data.py
This auto-detects your Steam/Icarus installation, finds data.pak, and runs the full extraction pipeline:
1. Copies data.pak from your Steam install to pak-files/
2. Extracts talent definition chunks (pak_extract.py)
3. Parses talent entries (pak_talent_extract.py)
4. Regenerates talent_data.py (generate_talent_data.py)
The tool reports any changes (new/removed talents, type counts) so you know what to review before committing.
Dry run — just check detection without running the pipeline:
python scripts/refresh_talent_data.py --detect
Manual path — if auto-detection fails:
python scripts/refresh_talent_data.py "D:\Steam\steamapps\common\Icarus\Icarus\Content\Data\data.pak"
After refresh, also update bestiary data:
python scripts/extract_bestiary.py
python scripts/add_bestiary_to_talent_data.py
See Architecture → Pak Extraction Pipeline for details.
Troubleshooting
shell cmd not found in CI jobs
Your runner's config.toml has shell = "cmd". Change it to shell = "powershell" and restart the runner service.
UnicodeEncodeError: 'charmap' codec can't encode character
The runner's PowerShell uses Windows cp1252 encoding. The .gitlab-ci.yml sets PYTHONIOENCODING: "utf-8" to fix this. Make sure this variable is present.
test:roundtrip fails with encoding errors
The roundtrip test handles both UTF-8 and UTF-16 LE encoded save files. If you see encoding-related failures, ensure:
1. The PYTHONIOENCODING: "utf-8" variable is set in .gitlab-ci.yml
2. The test fixtures in tests/sample_mounts/ are intact (not corrupted by line-ending conversion)
Runner shows offline in GitLab
# In admin PowerShell:
cd C:\GitLab-Runner
.\gitlab-runner.exe status # Check if running
.\gitlab-runner.exe restart # Restart the service
PyInstaller build fails with missing modules
Add --hidden-import MODULE_NAME to the PyInstaller command in .gitlab-ci.yml. Common ones: tkinter, tkinter.ttk.
See also: Architecture · GUI Guide · Binary Format