Kaynağa Gözat

feat(release): dynamic notes per manager/features + always summary

- render_release_body.py now reads ROOT_FLAVOR/FEATURE_SET/MANAGER_LIST
  and USE_SUSFS/BBG/DS/NET/NTSync/PTRACE/UNICODE/BPF to filter sections
  (SUSFS, Baseband Guard, DroidSpaces, Networking, NTSync)
- **Manager:** line replaced with **Managers:** list when MANAGER_LIST
  is set (All -> 3 entries with run links, single flavor -> single entry)
- injects > Root: X | Features: Y header after Features anchor
- main.yml create-release Set release body now passes all flags/managers
  and uploads release-notes artifact
- new notes-preview job runs always() for any workflow_dispatch, posts
  rendered notes to GITHUB_STEP_SUMMARY + uploads release-notes-preview
  artifact so Action runs also show dynamic notes
TheWildJames 2 hafta önce
ebeveyn
işleme
80638aa3d3

+ 91 - 0
.github/scripts/render_release_body.py

@@ -16,12 +16,103 @@ PLACEHOLDERS = {
 }
 
 
+def build_managers_markdown(text: str) -> str:
+    raw = os.environ.get("MANAGER_LIST", "").strip()
+    if not raw:
+        return text
+    try:
+        managers = json.loads(raw)
+    except Exception:
+        return text
+    if not isinstance(managers, list) or not managers:
+        return text
+    # Build markdown list for all selected managers
+    flavor_labels = {"next": "KernelSU-Next", "kernelsu": "KernelSU", "resukisu": "ReSukiSU"}
+    lines = []
+    for m in managers:
+        flavor = m.get("flavor", "")
+        label = flavor_labels.get(flavor, flavor or "unknown")
+        run_id = m.get("run_id")
+        owner = m.get("owner", "")
+        repo = m.get("repo", "")
+        stock = m.get("stock", "")
+        if run_id and owner and repo:
+            url = f"https://github.com/{owner}/{repo}/actions/runs/{run_id}"
+            note = f" — stock `{stock[:12]}`" if stock else ""
+            lines.append(f"- **{label}:** [build-manager run]({url}){note}")
+        else:
+            lines.append(f"- **{label}** manager (no run ID)")
+    replacement = "**Managers:**\n" + "\n".join(lines)
+    # Replace the single-manager line in template
+    # Template has: **Manager:** [build-manager run]({{KSU_MANAGER}}) — {{KSU_MANAGER_NOTE}}
+    # Replace that whole line if present
+    import re
+    text = re.sub(r"\*\*Manager:\*\*.*\n", replacement + "\n", text, count=1)
+    return text
+
+
+def filter_sections(text: str) -> str:
+    # Map heading substring -> required env flag
+    # If flag is "false", that section is dropped.
+    flag_map = {
+        "SUSFS": os.environ.get("USE_SUSFS", "true") == "true",
+        "Baseband Guard": os.environ.get("USE_BBG", "true") == "true",
+        "BBG": os.environ.get("USE_BBG", "true") == "true",
+        "DroidSpaces": os.environ.get("USE_DS", "true") == "true",
+        "Networking": os.environ.get("USE_NET", "true") == "true",
+        "NTSync": os.environ.get("USE_NTSYNC", "true") == "true",
+        "Ptrace": os.environ.get("USE_PTRACE", "true") == "true",
+        "Unicode": os.environ.get("USE_UNICODE", "true") == "true",
+        "BPF": os.environ.get("USE_BPF", "true") == "true",
+    }
+    # Split keeping delimiters: first chunk is preamble before first ## 
+    parts = text.split("\n## ")
+    if len(parts) <= 1:
+        return text
+    kept = [parts[0]]
+    for part in parts[1:]:
+        heading_line = part.split("\n", 1)[0]
+        keep = True
+        for key, enabled in flag_map.items():
+            if key.lower() in heading_line.lower() and not enabled:
+                keep = False
+                break
+        # Also drop specific subsections inside Misc/Other Features if relevant
+        # For now only top-level headings filtered; keep is per heading.
+        if keep:
+            kept.append("## " + part)
+    return "\n".join(kept) if len(kept) > 1 else parts[0] + "\n## ".join(kept[1:])
+
+
+def inject_feature_summary(text: str) -> str:
+    feature_set = os.environ.get("FEATURE_SET", "").strip()
+    root_flavor = os.environ.get("ROOT_FLAVOR", "").strip()
+    if not feature_set and not root_flavor:
+        return text
+    summary_lines = []
+    if root_flavor:
+        summary_lines.append(f"**Root:** {root_flavor}")
+    if feature_set:
+        summary_lines.append(f"**Features:** {feature_set}")
+    # Insert after the Features anchor list or after disclaimer
+    summary = "> " + " | ".join(summary_lines) + "\n" if summary_lines else ""
+    # Find the Features anchor list end (line with <!-- NOTE:)
+    marker = "<!-- NOTE:"
+    if marker in text and summary:
+        text = text.replace(marker, summary + "\n" + marker, 1)
+    return text
+
+
 def render_markdown(template_path: Path):
     text = template_path.read_text()
 
     for placeholder, getter in PLACEHOLDERS.items():
         text = text.replace(placeholder, getter())
 
+    text = build_managers_markdown(text)
+    text = inject_feature_summary(text)
+    text = filter_sections(text)
+
     print(text, end="")
 
 

+ 57 - 0
.github/workflows/main.yml

@@ -1121,6 +1121,18 @@ jobs:
         echo "MANAGER_RUN_ID=$MANAGER_RUN_ID" >> $GITHUB_ENV
 
     - name: Set release body
+      env:
+        ROOT_FLAVOR: ${{ inputs.root_flavor }}
+        FEATURE_SET: ${{ needs.resolve-sources.outputs.feature_set }}
+        MANAGER_LIST: ${{ needs.resolve-sources.outputs.manager_list }}
+        USE_SUSFS: ${{ inputs.use_susfs }}
+        USE_BBG: ${{ inputs.use_bbg }}
+        USE_DS: ${{ inputs.use_ds }}
+        USE_NET: ${{ inputs.use_net }}
+        USE_NTSYNC: ${{ inputs.use_ntsync }}
+        USE_PTRACE: ${{ inputs.use_ptrace }}
+        USE_UNICODE: ${{ inputs.use_unicode }}
+        USE_BPF: ${{ inputs.use_bpf }}
       run: |
         set -e
 
@@ -1137,6 +1149,14 @@ jobs:
           cat release_body.md
         } >> "$GITHUB_STEP_SUMMARY"
 
+    - name: Upload release notes artifact
+      uses: actions/upload-artifact@v7
+      with:
+        name: release-notes
+        path: release_body.md
+        retention-days: 7
+        if-no-files-found: error
+
     - name: Download Manager APK zips
       uses: actions/download-artifact@v7
       with:
@@ -1197,3 +1217,40 @@ jobs:
         files: |
           release-assets/**/*.zip
           release-assets/**/*-boot*.img
+
+  notes-preview:
+    if: always() && github.event_name == 'workflow_dispatch'
+    needs: [resolve-sources, build-android12-5-10, build-android13-5-10, build-android13-5-15, build-android14-5-15, build-android14-6-1, build-android15-6-6, build-android16-6-12, release]
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v7
+      - name: Render release notes preview (always)
+        env:
+          ROOT_FLAVOR: ${{ inputs.root_flavor }}
+          FEATURE_SET: ${{ needs.resolve-sources.outputs.feature_set }}
+          MANAGER_LIST: ${{ needs.resolve-sources.outputs.manager_list }}
+          USE_SUSFS: ${{ inputs.use_susfs }}
+          USE_BBG: ${{ inputs.use_bbg }}
+          USE_DS: ${{ inputs.use_ds }}
+          USE_NET: ${{ inputs.use_net }}
+          USE_NTSYNC: ${{ inputs.use_ntsync }}
+          USE_PTRACE: ${{ inputs.use_ptrace }}
+          USE_UNICODE: ${{ inputs.use_unicode }}
+          USE_BPF: ${{ inputs.use_bpf }}
+          # KSU version not computed here; render will show placeholder if release job skipped
+        run: |
+          set -e
+          python3 .github/scripts/render_release_body.py .github/config/RELEASE_NOTES.md > release_body.md
+          {
+            echo "## Release Notes Preview (CI Summary)"
+            echo
+            cat release_body.md
+          } >> "$GITHUB_STEP_SUMMARY"
+      - name: Upload release notes preview artifact
+        uses: actions/upload-artifact@v7
+        with:
+          name: release-notes-preview
+          path: release_body.md
+          retention-days: 7
+          if-no-files-found: warn
+