Skip to content

Commit e8e9d87

Browse files
authored
Merge pull request #358 from xylar/add-mache-deploy-workflow-tests
Add mache deploy workflow tests
2 parents da85621 + e002dc9 commit e8e9d87

File tree

18 files changed

+426
-6
lines changed

18 files changed

+426
-6
lines changed

.github/workflows/build_workflow.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,43 @@ jobs:
109109
name: Build Sphinx Docs
110110
run: |
111111
pixi run -e ${{ matrix.pixi-env }} bash -e -c "cd docs && DOCS_VERSION=test make versioned-html"
112+
113+
workflow-tests:
114+
name: workflow tests - python ${{ matrix.python-version }}
115+
runs-on: ubuntu-latest
116+
timeout-minutes: 30
117+
strategy:
118+
matrix:
119+
include:
120+
- python-version: "3.10"
121+
pixi-env: py310
122+
- python-version: "3.14"
123+
pixi-env: py314
124+
fail-fast: false
125+
steps:
126+
- id: skip_check
127+
uses: fkirc/skip-duplicate-actions@master
128+
with:
129+
cancel_others: ${{ env.CANCEL_OTHERS }}
130+
paths_ignore: ${{ env.PATHS_IGNORE }}
131+
132+
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
133+
uses: actions/checkout@v6
134+
135+
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
136+
name: Set up Pixi
137+
uses: prefix-dev/setup-pixi@v0.9.4
138+
with:
139+
pixi-version: v0.62.2
140+
cache: ${{ hashFiles('pixi.lock') != '' }}
141+
environments: ${{ matrix.pixi-env }}
142+
143+
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
144+
name: Install mache
145+
run: |
146+
pixi run -e ${{ matrix.pixi-env }} python -m pip install --no-deps --no-build-isolation -vv -e .
147+
148+
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
149+
name: Run workflow tests
150+
run: |
151+
pixi run -e ${{ matrix.pixi-env }} pytest workflow_tests

conda/recipe/recipe.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ schema_version: 1
22

33
context:
44
name: mache
5-
version: 3.0.0
5+
version: 3.0.1
66

77
package:
88
name: ${{ name|lower }}
@@ -42,6 +42,10 @@ tests:
4242
run:
4343
- python ${{ python_min }}.*
4444
script:
45+
- mache deploy init --help
46+
- mache deploy update --help
47+
- mache deploy run --help
48+
- mache jigsaw install --help
4549
- mache sync diags --help
4650

4751
about:

mache/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ def _build_parser() -> argparse.ArgumentParser:
4040
add_deploy_subparser(subparsers)
4141
add_jigsaw_subparser(subparsers)
4242
return parser
43+
44+
45+
if __name__ == '__main__':
46+
main()

mache/deploy/bootstrap.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,29 @@
22

33
import argparse
44
import os
5+
import platform
56
import shlex
67
import shutil
78
import subprocess
89
import sys
910
from pathlib import Path
1011

12+
CONDA_PLATFORM_MAP = {
13+
('linux', 'x86_64'): 'linux-64',
14+
('linux', 'aarch64'): 'linux-aarch64',
15+
('linux', 'ppc64le'): 'linux-ppc64le',
16+
('osx', 'x86_64'): 'osx-64',
17+
('osx', 'arm64'): 'osx-arm64',
18+
}
19+
20+
LOCAL_MACHE_SOURCE_ENV = 'MACHE_LOCAL_SOURCE_PATH'
21+
PIXI_ENV_VARS_TO_UNSET = (
22+
'PIXI_PROJECT_MANIFEST',
23+
'PIXI_PROJECT_ROOT',
24+
'PIXI_ENVIRONMENT_NAME',
25+
'PIXI_IN_SHELL',
26+
)
27+
1128

1229
def check_call(
1330
commands,
@@ -197,7 +214,7 @@ def build_pixi_shell_hook_prefix(*, pixi_exe: str, pixi_toml: str) -> str:
197214
running a nested shell process.
198215
"""
199216
hook_cmd = (
200-
'env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT '
217+
f'{build_pixi_env_unset_prefix()} '
201218
f'{shlex.quote(pixi_exe)} shell-hook -s bash -m '
202219
f'{shlex.quote(pixi_toml)}'
203220
)
@@ -353,7 +370,7 @@ def _run(log_filename):
353370

354371
cmd_install = (
355372
f'cd "{bootstrap_dir}" && '
356-
'env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT '
373+
f'{build_pixi_env_unset_prefix()} '
357374
f'"{pixi_exe}" install'
358375
)
359376
check_call(cmd_install, log_filename, quiet)
@@ -380,7 +397,7 @@ def _run(log_filename):
380397

381398
cmd_install = (
382399
f'cd "{bootstrap_dir}" && '
383-
'env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT '
400+
f'{build_pixi_env_unset_prefix()} '
384401
f'"{pixi_exe}" install'
385402
)
386403
check_call(cmd_install, log_filename, quiet)
@@ -569,6 +586,23 @@ def _default_pixi_path():
569586
return os.path.join(home, '.pixi', 'bin', 'pixi')
570587

571588

589+
def build_pixi_env_unset_prefix():
590+
return 'env ' + ' '.join(f'-u {name}' for name in PIXI_ENV_VARS_TO_UNSET)
591+
592+
593+
def _get_pixi_platform():
594+
system = platform.system().lower()
595+
if system == 'darwin':
596+
system = 'osx'
597+
machine = platform.machine().lower()
598+
try:
599+
return CONDA_PLATFORM_MAP[(system, machine)]
600+
except KeyError as exc:
601+
raise ValueError(
602+
f'Unsupported platform for pixi bootstrap: {system} {machine}'
603+
) from exc
604+
605+
572606
def _install_pixi(*, log_filename, quiet, pixi_bin_dir=None):
573607
env_prefix_parts = [
574608
# Avoid modifying shell rc files during bootstrap.
@@ -672,6 +706,7 @@ def _write_bootstrap_pixi_toml_with_mache(
672706
'[workspace]',
673707
f'name = "{name}"',
674708
'channels = ["conda-forge"]',
709+
f'platforms = ["{_get_pixi_platform()}"]',
675710
'channel-priority = "strict"',
676711
'',
677712
'[dependencies]',
@@ -712,6 +747,32 @@ def _clone_mache_repo(
712747

713748
build_root.mkdir(parents=True, exist_ok=True)
714749

750+
local_source = os.environ.get(LOCAL_MACHE_SOURCE_ENV)
751+
if local_source:
752+
source_repo = Path(
753+
os.path.abspath(os.path.expanduser(local_source))
754+
).resolve()
755+
if not source_repo.is_dir():
756+
raise RuntimeError(
757+
f'Local mache source override does not exist: {source_repo}'
758+
)
759+
760+
try:
761+
os.symlink(source_repo, repo_dir, target_is_directory=True)
762+
except OSError:
763+
shutil.copytree(
764+
source_repo,
765+
repo_dir,
766+
ignore=shutil.ignore_patterns(
767+
'.git',
768+
'.pixi',
769+
'deploy_tmp',
770+
'__pycache__',
771+
'*.pyc',
772+
),
773+
)
774+
return
775+
715776
commands = (
716777
f'cd "{build_root!s}" && '
717778
+ "GIT_SSH_COMMAND='ssh -oBatchMode=yes' git clone "

mache/deploy/run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from mache.jigsaw import deploy_jigsawpy
1616

1717
from .bootstrap import (
18+
build_pixi_env_unset_prefix,
1819
build_pixi_shell_hook_prefix,
1920
check_call,
2021
check_location,
@@ -986,7 +987,7 @@ def _pixi_install(
986987
# - Otherwise pixi uses its own defaults (typically under $HOME).
987988
cmd = (
988989
f'cd {shlex.quote(project_dir)} && '
989-
'env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT '
990+
f'{build_pixi_env_unset_prefix()} '
990991
f'{shlex.quote(pixi_exe)} install'
991992
)
992993
check_call(cmd, log_filename=log_filename, quiet=quiet)

mache/deploy/templates/deploy.py.j2

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ def _bootstrap_url(
300300
mache_fork=None,
301301
mache_branch=None,
302302
):
303+
override_url = str(os.environ.get('MACHE_BOOTSTRAP_URL', '')).strip()
304+
if override_url:
305+
return override_url
306+
303307
if mache_fork is not None and mache_branch is not None:
304308
# Raw file from a fork/branch
305309
return f'https://raw.githubusercontent.com/{mache_fork}/{mache_branch}/{BOOTSTRAP_RELPATH}' # noqa: E501
@@ -456,6 +460,7 @@ def _run_mache_deploy_run(pixi_exe, repo_root, mache_run_argv):
456460

457461
cmd = (
458462
f'env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT '
463+
f'-u PIXI_ENVIRONMENT_NAME -u PIXI_IN_SHELL '
459464
f'{shlex.quote(pixi_exe)} run -m {shlex.quote(pixi_toml)} bash -lc '
460465
f'{shlex.quote("cd " + repo_root + " && " + mache_cmd)}'
461466
)

mache/deploy/templates/load.sh.j2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ if [[ -n "${MACHE_DEPLOY_RUNTIME_VERSION_CMD:-}" ]]; then
5353
# Use a non-login shell so pixi-provided PATH/env are not reset by site profiles.
5454
probe_output="$(
5555
env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT \
56+
-u PIXI_ENVIRONMENT_NAME -u PIXI_IN_SHELL \
5657
"${PIXI}" run -m "${PIXI_TOML}" -- \
5758
bash -c "${MACHE_DEPLOY_RUNTIME_VERSION_CMD}" 2>&1
5859
)"
@@ -90,6 +91,7 @@ fi
9091
echo "loading pixi env..."
9192
# Use `shell-hook` (not `pixi run`) so activation applies to this shell.
9293
eval "$(env -u PIXI_PROJECT_MANIFEST -u PIXI_PROJECT_ROOT \
94+
-u PIXI_ENVIRONMENT_NAME -u PIXI_IN_SHELL \
9395
"${PIXI}" shell-hook -s bash -m "${PIXI_TOML}")"
9496
echo " pixi env loaded."
9597

mache/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = (3, 0, 0)
1+
__version_info__ = (3, 0, 1)
22
__version__ = '.'.join(str(vi) for vi in __version_info__)

tests/test_deploy_bootstrap.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,48 @@ def fake_popen(commands, **kwargs):
6161
assert recorded['commands'] == 'printf hello'
6262
assert 'text' not in recorded['kwargs']
6363
assert recorded['kwargs']['universal_newlines'] is False
64+
65+
66+
def test_write_bootstrap_pixi_toml_with_mache_includes_platform(
67+
monkeypatch, tmp_path: Path
68+
):
69+
monkeypatch.setattr(bootstrap, '_get_pixi_platform', lambda: 'linux-64')
70+
71+
pixi_toml = tmp_path / 'pixi.toml'
72+
bootstrap._write_bootstrap_pixi_toml_with_mache(
73+
pixi_toml_path=pixi_toml,
74+
software='polaris',
75+
mache_version='3.0.0',
76+
python_version='3.12',
77+
)
78+
79+
text = pixi_toml.read_text(encoding='utf-8')
80+
assert 'platforms = ["linux-64"]' in text
81+
assert 'mache = "==3.0.0"' in text
82+
83+
84+
def test_clone_mache_repo_uses_local_source_override(
85+
monkeypatch, tmp_path: Path
86+
):
87+
monkeypatch.chdir(tmp_path)
88+
89+
source_repo = tmp_path / 'local-mache'
90+
source_repo.mkdir()
91+
(source_repo / 'pixi.toml').write_text(
92+
'[workspace]\nname = "mache-dev"\n',
93+
encoding='utf-8',
94+
)
95+
96+
monkeypatch.setenv(bootstrap.LOCAL_MACHE_SOURCE_ENV, str(source_repo))
97+
98+
bootstrap._clone_mache_repo(
99+
mache_fork='ignored',
100+
mache_branch='ignored',
101+
log_filename=str(tmp_path / 'bootstrap.log'),
102+
quiet=True,
103+
recreate=False,
104+
)
105+
106+
cloned_repo = tmp_path / 'deploy_tmp' / 'build_mache' / 'mache'
107+
assert cloned_repo.exists()
108+
assert (cloned_repo / 'pixi.toml').is_file()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
project:
2+
software: "toyflow"
3+
version: "0.1.0"
4+
machine: null
5+
runtime_version_cmd: >-
6+
python -c 'from toyflow.version import __version__; print(__version__)'
7+
8+
pixi:
9+
deploy: true
10+
prefix: "pixi-env"
11+
channels:
12+
- conda-forge
13+
mpi: "nompi"
14+
install_dev_software: true
15+
16+
spack:
17+
deploy: false
18+
supported: false
19+
20+
jigsaw:
21+
enabled: false

0 commit comments

Comments
 (0)