Coverage for little_loops / cli / sprint / create.py: 17%

35 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-03-18 16:18 -0500

1"""ll-sprint create subcommand.""" 

2 

3from __future__ import annotations 

4 

5import argparse 

6 

7from little_loops.cli_args import parse_issue_ids, parse_issue_types 

8from little_loops.logger import Logger 

9from little_loops.sprint import SprintManager, SprintOptions 

10 

11 

12def _cmd_sprint_create(args: argparse.Namespace, manager: SprintManager) -> int: 

13 """Create a new sprint.""" 

14 logger = Logger() 

15 issues = [i.strip().upper() for i in args.issues.split(",")] 

16 

17 # Apply skip filter if provided 

18 skip_ids = parse_issue_ids(args.skip) 

19 if skip_ids: 

20 original_count = len(issues) 

21 issues = [i for i in issues if i not in skip_ids] 

22 skipped = original_count - len(issues) 

23 if skipped > 0: 

24 logger.info( 

25 f"Skipping {skipped} issue(s): " 

26 f"{', '.join(sorted(skip_ids & set(issues) | skip_ids))}" 

27 ) 

28 

29 # Apply type filter if provided 

30 type_prefixes = parse_issue_types(getattr(args, "type", None)) 

31 if type_prefixes: 

32 original_count = len(issues) 

33 issues = [i for i in issues if i.split("-", 1)[0] in type_prefixes] 

34 filtered = original_count - len(issues) 

35 if filtered > 0: 

36 logger.info(f"Filtered {filtered} issue(s) by type: {', '.join(sorted(type_prefixes))}") 

37 

38 # Validate issues exist 

39 valid = manager.validate_issues(issues) 

40 invalid = set(issues) - set(valid.keys()) 

41 

42 if invalid: 

43 logger.warning(f"Issue IDs not found: {', '.join(sorted(invalid))}") 

44 

45 options = SprintOptions( 

46 max_workers=args.max_workers, 

47 timeout=args.timeout, 

48 ) 

49 

50 sprint = manager.create( 

51 name=args.name, 

52 issues=issues, 

53 description=args.description, 

54 options=options, 

55 ) 

56 

57 logger.success(f"Created sprint: {sprint.name}") 

58 logger.info(f" Description: {sprint.description or '(none)'}") 

59 logger.info(f" Issues: {', '.join(sprint.issues)}") 

60 logger.info(f" File: .sprints/{sprint.name}.yaml") 

61 

62 if invalid: 

63 logger.warning(f" Invalid issues: {', '.join(sorted(invalid))}") 

64 

65 return 0