Skip to content

Commit 6fc5d5e

Browse files
committed
include uninstaller script, refactor iwc isntaller workflow
1 parent b0d4062 commit 6fc5d5e

File tree

2 files changed

+184
-12
lines changed

2 files changed

+184
-12
lines changed
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
name: Install and update IWC tools
22

33
on:
4-
schedule:
5-
# At 10:00 every day
6-
- cron: "0 10 * * *"
7-
8-
# Allows you to run this workflow manually from the Actions tab
94
workflow_dispatch:
10-
5+
inputs:
6+
instance:
7+
description: 'Galaxy Instance URL'
8+
required: true
9+
type: choice
10+
options:
11+
- galaxy-qa1.galaxy.cloud.e-infra.cz
12+
- usegalaxy.cz
13+
- galaxy-umsa.grid.cesnet.cz
1114
jobs:
1215
update-repos:
1316
permissions:
1417
contents: write
1518
pull-requests: write
1619
runs-on: ubuntu-latest
17-
strategy:
18-
matrix:
19-
toolset: [galaxy-qa1.galaxy.cloud.e-infra.cz]
2020
steps:
2121
- uses: actions/setup-python@v5
2222
with:
@@ -29,16 +29,16 @@ jobs:
2929
- name: Clone IWC repo
3030
run: git clone https://github.com/galaxyproject/iwc /tmp/iwc
3131
- name: Run update script
32-
run: python scripts/get_iwc_tools.py -w /tmp/iwc -s ${{ matrix.toolset }} -u uncategorized.yml
32+
run: python scripts/get_iwc_tools.py -w /tmp/iwc -s ${{ inputs.instance }} -u uncategorized.yml
3333
- name: Get current date
3434
id: date
3535
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
3636
- name: Create Pull Request
3737
uses: peter-evans/create-pull-request@v7
3838
with:
39-
branch: iwc-update-${{ matrix.toolset }}
39+
branch: iwc-update-${{ inputs.instance }}
4040
committer: CESNETbot <[email protected]>
41-
title: Install IWC tools for ${{ matrix.toolset }}
41+
title: Install IWC tools for ${{ inputs.instance }}
4242
commit-message: "output of get_iwc_tools.py"
4343
labels: automated
4444
assignees: martenson

scripts/uninstaller.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Galaxy Repository Uninstaller
4+
5+
Uninstalls repositories from a Galaxy instance using BioBlend.
6+
"""
7+
8+
import argparse
9+
import sys
10+
import time
11+
from typing import Dict
12+
import yaml
13+
from bioblend.galaxy import GalaxyInstance
14+
15+
16+
def load_repositories(file_path: str) -> list:
17+
"""Load and parse YAML file containing repositories."""
18+
with open(file_path) as f:
19+
data = yaml.safe_load(f)
20+
21+
repos = data.get('tools', data) if isinstance(data, dict) else data
22+
if not repos:
23+
raise ValueError("No repositories found in file")
24+
return repos
25+
26+
27+
def uninstall_repositories(gi: GalaxyInstance, repos: list,
28+
remove_from_disk: bool, delay: float) -> Dict[str, int]:
29+
"""Uninstall all repositories and their revisions."""
30+
results = {'success': 0, 'failed': 0}
31+
32+
for repo in repos:
33+
name = repo.get('name')
34+
owner = repo.get('owner')
35+
revisions = repo.get('revisions', [])
36+
tool_shed = repo.get('tool_shed_url', '')
37+
38+
if not all([name, owner, revisions, tool_shed]):
39+
print(f"\n✗ Skipping {name or 'unknown'}: missing required fields")
40+
results['failed'] += 1
41+
continue
42+
43+
if not tool_shed.startswith('http'):
44+
tool_shed = f'https://{tool_shed}'
45+
46+
print(f"\n{name} (owner: {owner})")
47+
48+
for revision in revisions:
49+
print(f" Revision: {revision}")
50+
try:
51+
gi.toolshed.uninstall_repository_revision(
52+
name=name,
53+
owner=owner,
54+
changeset_revision=revision,
55+
tool_shed_url=tool_shed,
56+
remove_from_disk=remove_from_disk
57+
)
58+
print(f" ✓ Successfully uninstalled")
59+
results['success'] += 1
60+
except Exception as e:
61+
print(f" ✗ Failed: {e}")
62+
results['failed'] += 1
63+
64+
if delay > 0:
65+
time.sleep(delay)
66+
67+
return results
68+
69+
70+
def dry_run(repos: list):
71+
"""Display what would be uninstalled without doing it."""
72+
print("\n[DRY RUN MODE - No changes will be made]")
73+
print("=" * 60)
74+
for repo in repos:
75+
print(f"\n{repo['name']} (owner: {repo['owner']})")
76+
print(f" Tool shed: {repo['tool_shed_url']}")
77+
for rev in repo.get('revisions', []):
78+
print(f" - {rev}")
79+
80+
81+
def print_statistics(repos: list):
82+
"""Print statistics about repositories to be uninstalled."""
83+
from collections import Counter
84+
85+
owners = Counter(r.get('owner') for r in repos)
86+
tool_sheds = Counter(r.get('tool_shed_url') for r in repos)
87+
total_revisions = sum(len(r.get('revisions', [])) for r in repos)
88+
89+
print("\nStatistics:")
90+
print(f" Total repositories: {len(repos)}")
91+
print(f" Total revisions: {total_revisions}")
92+
93+
print("\n Repositories by owner:")
94+
for owner, count in sorted(owners.items(), key=lambda x: x[1], reverse=True):
95+
print(f" {owner}: {count}")
96+
97+
print("\n Repositories by tool shed:")
98+
for shed, count in sorted(tool_sheds.items(), key=lambda x: x[1], reverse=True):
99+
print(f" {shed}: {count}")
100+
101+
102+
def main():
103+
parser = argparse.ArgumentParser(
104+
description='Uninstall repositories from a Galaxy instance using BioBlend',
105+
formatter_class=argparse.RawDescriptionHelpFormatter,
106+
epilog="""
107+
Examples:
108+
python uninstall_repos.py https://galaxy.example.org API_KEY repos.yaml
109+
python uninstall_repos.py https://galaxy.example.org API_KEY repos.yaml --dry-run
110+
python uninstall_repos.py https://galaxy.example.org API_KEY repos.yaml --keep-on-disk
111+
112+
YAML format:
113+
tools:
114+
- name: sra_tools
115+
owner: iuc
116+
revisions: [f5ea3ce9b9b0, 8848455c0270]
117+
tool_shed_url: toolshed.g2.bx.psu.edu
118+
119+
Requirements: pip install bioblend pyyaml
120+
"""
121+
)
122+
123+
parser.add_argument('galaxy_url', help='Galaxy instance URL')
124+
parser.add_argument('api_key', help='Galaxy API key')
125+
parser.add_argument('repo_file', help='YAML file with repositories to uninstall')
126+
parser.add_argument('--keep-on-disk', action='store_true',
127+
help='Keep repository files on disk')
128+
parser.add_argument('--delay', type=float, default=5.0,
129+
help='Delay between uninstalls in seconds (default: 5.0)')
130+
parser.add_argument('--dry-run', action='store_true',
131+
help='Show what would be uninstalled without doing it')
132+
133+
args = parser.parse_args()
134+
135+
# Load repositories
136+
try:
137+
repos = load_repositories(args.repo_file)
138+
except FileNotFoundError:
139+
print(f"Error: File '{args.repo_file}' not found")
140+
sys.exit(1)
141+
except Exception as e:
142+
print(f"Error: {e}")
143+
sys.exit(1)
144+
145+
print(f"Galaxy URL: {args.galaxy_url}")
146+
print_statistics(repos)
147+
148+
if args.dry_run:
149+
dry_run(repos)
150+
sys.exit(0)
151+
152+
print("=" * 60)
153+
154+
# Connect and uninstall
155+
try:
156+
gi = GalaxyInstance(url=args.galaxy_url, key=args.api_key)
157+
results = uninstall_repositories(gi, repos, not args.keep_on_disk, args.delay)
158+
except Exception as e:
159+
print(f"Error: {e}")
160+
sys.exit(1)
161+
162+
# Summary
163+
print("\n" + "=" * 60)
164+
print("Uninstall Summary:")
165+
print(f" Successfully uninstalled: {results['success']}")
166+
print(f" Failed: {results['failed']}")
167+
168+
sys.exit(0 if results['failed'] == 0 else 1)
169+
170+
171+
if __name__ == '__main__':
172+
main()

0 commit comments

Comments
 (0)