| Conditions | 16 |
| Total Lines | 61 |
| Code Lines | 45 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like content_gh.generate_release_notes() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #!/usr/bin/env python3 |
||
| 88 | |||
| 89 | |||
| 90 | def generate_release_notes(repo, args): |
||
| 91 | milestone = get_milestone(repo, args.version) |
||
| 92 | |||
| 93 | entry = "" |
||
| 94 | release_notes = collections.defaultdict(list) |
||
| 95 | product_profiles = collections.defaultdict(set) |
||
| 96 | for pr in get_closed_prs(repo, milestone): |
||
| 97 | pr_title = pr.title |
||
| 98 | pr_number = str(pr.number) |
||
| 99 | section = "nosection" |
||
| 100 | |||
| 101 | changed_files = pr.get_files() |
||
| 102 | for changed_file in changed_files: |
||
| 103 | changed_filename = changed_file.filename |
||
| 104 | |||
| 105 | # do not include files from tests folder |
||
| 106 | # they are part of testing mechanisms |
||
| 107 | if changed_filename.endswith(".profile") and "tests" not in changed_filename: |
||
| 108 | # Track changes to product:profile |
||
| 109 | profile_match = re.match(r"(\w+)/profiles/([\w-]+).profile", changed_filename) |
||
| 110 | product, profile = profile_match.groups() |
||
| 111 | product_profiles[product].add(profile) |
||
| 112 | |||
| 113 | # A PR that changed .profile but not rule, check, remediation or tests, |
||
| 114 | # go to Profiles section |
||
| 115 | if CHANGELOG["profiles"] > CHANGELOG[section]: |
||
| 116 | section = "profiles" |
||
| 117 | |||
| 118 | if "rule.yml" in changed_filename: |
||
| 119 | # A PR that changed any rule.yml file will be in Rules section |
||
| 120 | # Often, changes to infrastructure are done together with changes content |
||
| 121 | section = "rules" |
||
| 122 | elif "tests/" in changed_filename: |
||
| 123 | if CHANGELOG["tests"] > CHANGELOG[section]: |
||
| 124 | section = "tests" |
||
| 125 | |||
| 126 | if section != "nosection": |
||
| 127 | entry = f"- {pr_title} (#{pr_number})\n" |
||
| 128 | release_notes[section].append(entry) |
||
| 129 | |||
| 130 | with open(rn_file, "w") as rn: |
||
| 131 | rn.write("### Highlights:\n") |
||
| 132 | hl_label = repo.get_label("Highlight") |
||
| 133 | hl_prs = repo.get_issues(milestone=milestone, state="closed", labels=[hl_label]) |
||
| 134 | for pr in hl_prs: |
||
| 135 | pr_title = pr.title |
||
| 136 | pr_number = str(pr.number) |
||
| 137 | rn.write(f"- {pr_title} (#{pr_number})\n") |
||
| 138 | |||
| 139 | rn.write("### Profiles changed in this release:\n") |
||
| 140 | for product in product_profiles: |
||
| 141 | rn.write(f"- {product}: {', '.join(product_profiles[product])}\n") |
||
| 142 | |||
| 143 | for section in CHANGELOG: |
||
| 144 | if section == 'nosection': |
||
| 145 | continue |
||
| 146 | rn.write(f"### {section.capitalize()}:\n") |
||
| 147 | for entry in release_notes[section]: |
||
| 148 | rn.write(entry) |
||
| 149 | print(f"Review release notes in '{rn_file}'") |
||
| 240 |