Skip to content

Commit ef774e4

Browse files
refactor: migrate GitHub Actions from conda to pixi (#75)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 62536b2 commit ef774e4

File tree

6 files changed

+90
-141
lines changed

6 files changed

+90
-141
lines changed

.github/workflows/ci.yml

Lines changed: 18 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI
22

33
on:
44
push:
5-
branches: [main, master, develop, claude/**]
5+
branches: [main, master, develop, claude/**, refactor/**]
66
pull_request:
77
branches: [main, master, develop]
88
workflow_dispatch:
@@ -15,36 +15,17 @@ jobs:
1515
- name: Checkout repository
1616
uses: actions/checkout@v4
1717

18-
- name: Setup Miniforge
19-
uses: conda-incubator/setup-miniconda@v3
20-
with:
21-
miniforge-variant: Miniforge3
22-
miniforge-version: latest
23-
activate-environment: aatrnaseqpipe
24-
use-mamba: true
25-
26-
- name: Cache conda environment
27-
uses: actions/cache@v3
28-
with:
29-
path: /usr/share/miniconda3/envs/aatrnaseqpipe
30-
key: conda-${{ runner.os }}-${{ hashFiles('workflow/envs/aatrnaseqpipe-env.yml') }}
31-
32-
- name: Install dependencies
33-
shell: bash -l {0}
34-
run: |
35-
mamba env update -n aatrnaseqpipe -f workflow/envs/aatrnaseqpipe-env.yml
18+
- name: Setup Pixi
19+
uses: prefix-dev/setup-pixi@v0.9.3
3620

3721
- name: Verify Snakemake installation
38-
shell: bash -l {0}
39-
run: |
40-
conda activate aatrnaseqpipe
41-
snakemake --version
22+
run: pixi run snakemake --version
23+
24+
- name: Download test data
25+
run: pixi run dl-test-data
4226

4327
- name: Snakemake dry-run (syntax check)
44-
shell: bash -l {0}
45-
run: |
46-
conda activate aatrnaseqpipe
47-
snakemake -n --configfile=config/config-test.yml
28+
run: pixi run dry-run
4829

4930
pipeline-test:
5031
name: Pipeline Integration Test
@@ -54,57 +35,18 @@ jobs:
5435
- name: Checkout repository
5536
uses: actions/checkout@v4
5637

57-
- name: Setup Miniforge
58-
uses: conda-incubator/setup-miniconda@v3
59-
with:
60-
miniforge-variant: Miniforge3
61-
miniforge-version: latest
62-
activate-environment: aatrnaseqpipe
63-
use-mamba: true
64-
65-
- name: Cache conda environment
66-
uses: actions/cache@v3
67-
with:
68-
path: /usr/share/miniconda3/envs/aatrnaseqpipe
69-
key: conda-${{ runner.os }}-${{ hashFiles('workflow/envs/aatrnaseqpipe-env.yml') }}
70-
71-
- name: Install dependencies
72-
shell: bash -l {0}
73-
run: |
74-
mamba env update -n aatrnaseqpipe -f workflow/envs/aatrnaseqpipe-env.yml
38+
- name: Setup Pixi
39+
uses: prefix-dev/setup-pixi@v0.9.3
7540

7641
- name: Download test data
77-
shell: bash -l {0}
78-
run: |
79-
bash .tests/dl_test_data.sh
80-
81-
- name: Setup dorado
82-
shell: bash -l {0}
83-
run: |
84-
conda activate aatrnaseqpipe
85-
snakemake setup_dorado --cores 1 --configfile=config/config-test.yml
86-
87-
- name: Download dorado model
88-
shell: bash -l {0}
89-
run: |
90-
conda activate aatrnaseqpipe
91-
snakemake dorado_model --cores 1 --configfile=config/config-test.yml
92-
93-
- name: Setup modkit
94-
shell: bash -l {0}
95-
run: |
96-
conda activate aatrnaseqpipe
97-
snakemake setup_modkit --cores 1 --configfile=config/config-test.yml
42+
run: pixi run dl-test-data
9843

9944
- name: Run pipeline test (non-GPU rules only)
100-
shell: bash -l {0}
10145
run: |
102-
conda activate aatrnaseqpipe
10346
# Run merge_pods rule as a basic test (doesn't require GPU)
104-
snakemake merge_pods --cores 2 --configfile=config/config-test.yml
47+
pixi run snakemake .tests/outputs/pod5/sample1/sample1.pod5 --cores 2 --configfile=config/config-test.yml
10548
10649
- name: Validate outputs
107-
shell: bash -l {0}
10850
run: |
10951
# Check that expected output files were created
11052
if [ ! -d ".tests/outputs" ]; then
@@ -120,12 +62,15 @@ jobs:
12062
- name: Checkout repository
12163
uses: actions/checkout@v4
12264

65+
- name: Setup Pixi
66+
uses: prefix-dev/setup-pixi@v0.9.3
67+
12368
- name: Check config files syntax
12469
run: |
12570
# Validate YAML syntax
126-
python3 -c "import yaml; yaml.safe_load(open('config/config-base.yml'))"
127-
python3 -c "import yaml; yaml.safe_load(open('config/config-test.yml'))"
128-
python3 -c "import yaml; yaml.safe_load(open('config/config-preprint.yml'))"
71+
pixi run python -c "import yaml; yaml.safe_load(open('config/config-base.yml'))"
72+
pixi run python -c "import yaml; yaml.safe_load(open('config/config-test.yml'))"
73+
pixi run python -c "import yaml; yaml.safe_load(open('config/config-preprint.yml'))"
12974
echo "All config files are valid YAML"
13075
13176
- name: Check samples files

.github/workflows/lint.yml

Lines changed: 11 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Lint
22

33
on:
44
push:
5-
branches: [main, master, develop, claude/**]
5+
branches: [main, master, develop, claude/**, refactor/**]
66
pull_request:
77
branches: [main, master, develop]
88
workflow_dispatch:
@@ -15,18 +15,11 @@ jobs:
1515
- name: Checkout repository
1616
uses: actions/checkout@v4
1717

18-
- name: Setup Python
19-
uses: actions/setup-python@v4
20-
with:
21-
python-version: '3.11'
22-
23-
- name: Install Snakemake
24-
run: |
25-
pip install snakemake snakefmt
18+
- name: Setup Pixi
19+
uses: prefix-dev/setup-pixi@v0.9.3
2620

2721
- name: Run snakefmt check
28-
run: |
29-
snakefmt --check workflow/
22+
run: pixi run lint-snakefmt
3023

3124
python-lint:
3225
name: Python Linting
@@ -35,45 +28,12 @@ jobs:
3528
- name: Checkout repository
3629
uses: actions/checkout@v4
3730

38-
- name: Setup Python
39-
uses: actions/setup-python@v4
40-
with:
41-
python-version: '3.11'
42-
43-
- name: Install linting tools
44-
run: |
45-
pip install black flake8 pylint
46-
47-
- name: Run black check
48-
continue-on-error: true
49-
run: |
50-
black --check workflow/scripts/ || echo "Black formatting issues found (non-blocking)"
51-
52-
- name: Run flake8
53-
continue-on-error: true
54-
run: |
55-
flake8 workflow/scripts/ --max-line-length=100 --ignore=E203,W503 || echo "Flake8 issues found (non-blocking)"
56-
57-
markdown-lint:
58-
name: Markdown Linting
59-
runs-on: ubuntu-latest
60-
steps:
61-
- name: Checkout repository
62-
uses: actions/checkout@v4
63-
64-
- name: Setup Node.js
65-
uses: actions/setup-node@v4
66-
with:
67-
node-version: '18'
68-
69-
- name: Install markdownlint
70-
run: |
71-
npm install -g markdownlint-cli
31+
- name: Setup Pixi
32+
uses: prefix-dev/setup-pixi@v0.9.3
7233

73-
- name: Run markdownlint
34+
- name: Run ruff check and format
7435
continue-on-error: true
75-
run: |
76-
markdownlint '**/*.md' --ignore node_modules || echo "Markdown linting issues found (non-blocking)"
36+
run: pixi run lint-python || echo "Python linting issues found (non-blocking)"
7737

7838
yaml-lint:
7939
name: YAML Linting
@@ -82,16 +42,9 @@ jobs:
8242
- name: Checkout repository
8343
uses: actions/checkout@v4
8444

85-
- name: Setup Python
86-
uses: actions/setup-python@v4
87-
with:
88-
python-version: '3.11'
89-
90-
- name: Install yamllint
91-
run: |
92-
pip install yamllint
45+
- name: Setup Pixi
46+
uses: prefix-dev/setup-pixi@v0.9.3
9347

9448
- name: Run yamllint
9549
continue-on-error: true
96-
run: |
97-
yamllint -d "{extends: default, rules: {line-length: {max: 120}, document-start: disable}}" config/ .github/ || echo "YAML linting issues found (non-blocking)"
50+
run: pixi run lint-yaml || echo "YAML linting issues found (non-blocking)"

pixi.lock

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pixi.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ snakemake-executor-plugin-cluster-generic = "*"
2727
# ONT tools
2828
pod5 = "*"
2929
ont-modkit = "*"
30+
# Linting tools
31+
ruff = "*"
32+
yamllint = "*"
3033

3134
[activation]
3235
scripts = ["scripts/setup-env.sh"]
@@ -41,6 +44,10 @@ run-preprint = { cmd = "snakemake --configfile=config/config-preprint.yml --prof
4144
# Development
4245
fmt = { cmd = "snakefmt workflow/Snakefile workflow/rules/*.smk", description = "Format Snakemake files" }
4346
dag = { cmd = "snakemake --configfile=config/config-test.yml --dag | dot -Tpng > workflow/workflow_dag.png", description = "Generate workflow DAG image" }
47+
# Linting
48+
lint-snakefmt = { cmd = "snakefmt --check workflow/", description = "Check Snakemake formatting" }
49+
lint-python = { cmd = "ruff check workflow/scripts/ && ruff format --check workflow/scripts/", description = "Lint and check Python formatting" }
50+
lint-yaml = { cmd = "yamllint -d \"{extends: default, rules: {line-length: {max: 120}, document-start: disable}}\" config/ .github/", description = "Lint YAML files" }
4451

4552
# WarpDemuX demultiplexing feature
4653
[feature.demux]
@@ -66,7 +73,7 @@ ruptures = "*"
6673
catboost = "*"
6774

6875
[feature.demux.tasks]
69-
install-warpdemux = { cmd = "[ -d resources/WarpDemuX ] || git clone --recursive https://github.com/KleistLab/WarpDemuX.git resources/WarpDemuX && uv pip install -e resources/WarpDemuX", description = "Clone and install WarpDemuX" }
76+
install-warpdemux = { cmd = "[ -d resources/tools/WarpDemuX ] || git clone --recursive https://github.com/KleistLab/WarpDemuX.git resources/tools/WarpDemuX && uv pip install -e resources/tools/WarpDemuX", description = "Clone and install WarpDemuX" }
7077
warpdemux = { cmd = "warpdemux $@", env = { LD_LIBRARY_PATH = "$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" } }
7178
dry-run-demux = { cmd = "snakemake -n --configfile=config/config-demux-test.yml", description = "Dry run demux test" }
7279

workflow/rules/common.smk

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ def parse_samples_yaml(fl):
6868
run_path = run["path"]
6969
# Create a unique run_id from the path (last directory component)
7070
run_id = os.path.basename(run_path.rstrip("/"))
71-
barcode_kit = run.get("barcode_kit", config.get("warpdemux", {}).get("barcode_kit"))
71+
barcode_kit = run.get(
72+
"barcode_kit", config.get("warpdemux", {}).get("barcode_kit")
73+
)
7274

7375
for sample_name, barcode in run["samples"].items():
7476
if sample_name in samples:
@@ -284,4 +286,6 @@ def get_sample_pod5(wildcards):
284286
if sample_needs_demux(wildcards.sample):
285287
return os.path.join(outdir, "demux", "pod5", f"{wildcards.sample}.pod5")
286288
else:
287-
return os.path.join(outdir, "pod5", wildcards.sample, f"{wildcards.sample}.pod5")
289+
return os.path.join(
290+
outdir, "pod5", wildcards.sample, f"{wildcards.sample}.pod5"
291+
)

0 commit comments

Comments
 (0)