Compare commits

...

6 Commits

Author SHA1 Message Date
Gauvain
7c1900a27d fix(issue-form): bound the gh release fetch with a 30s timeout 2026-06-10 20:24:35 +02:00
Gauvain
888b8bb342 fix(issue-form): pin checkout to develop, serialize runs, simplify release fetch
- `release` events check out the tagged commit, so the script regenerated
  the form from the tag's stale copy and the bot PR could revert form
  edits made on develop since that release - checkout develop explicitly.
- Fixed concurrency group: a release event and the weekly cron no longer
  race on the same ci/update-issue-form branch (queue, no cancel).
- Replace `gh api --paginate` (fetches every release page) with
  `gh release list --exclude-drafts --exclude-pre-releases --limit N`.
- Document the GITHUB_TOKEN limitation on the auto-merge step: bot PRs
  don't trigger required checks; close/reopen kicks them, then auto-merge
  completes after reviews.
2026-06-10 20:20:56 +02:00
Gauvain
1c8a0ac35e Merge remote-tracking branch 'origin/develop' into ci/auto-update-issue-form
# Conflicts:
#	.github/ISSUE_TEMPLATE/issue_report.yml
2026-06-10 20:11:27 +02:00
Gauvino
e4def1f2a1 docs(issue-form): guide TestFlight/dev users to report the exact build
The version dropdown lists published releases only, so a TestFlight or dev
build will not appear in it. Point those reporters to the
"TestFlight/Development build" option and the exact version shown in the
app's Settings.
2026-06-05 13:38:52 +02:00
Gauvino
55376cd824 fix(issue-form): list published releases only, drop TestFlight draft entries
Per maintainer feedback (fredrikburmester, lancechant): the version dropdown
no longer surfaces draft releases as "X (TestFlight)" — drafts and prereleases
are unreliable version identifiers. update-issue-form.mjs now fetches only
published, non-prerelease releases and drops the per-version TestFlight label;
the workflow triggers on `released` events only; and the generic
"TestFlight/Development build" sentinel is restored at the end of the list.
2026-06-05 13:30:47 +02:00
Gauvino
3c8369ea4d ci(issue-form): auto-populate version dropdown from GitHub releases
Replaces the broken update workflow (it targeted a non-existent bug_report.yml
via the npm-based populate action; Streamyfin isn't on npm) with
scripts/update-issue-form.mjs (Bun, dep-free): reads release tags via gh and
rewrites the 'version' dropdown in issue_report.yml, preserving sentinels
(older, TestFlight/Development build), newest-first, capped at
ISSUE_FORM_LIMIT (5) — so each new release rotates the oldest entry out.

Drafts/prereleases are included on purpose: release.yml drafts
v<app.json version> for every TestFlight (iOS) / beta (Android) build, and the
app shows that nativeApplicationVersion to users (UserInfo.tsx), so those
in-flight versions must be selectable. Runs on release events + a weekly cron
safety net + workflow_dispatch, opens a PR and enables auto-merge. Seeds the
current versions.
2026-06-01 16:53:53 +02:00
3 changed files with 204 additions and 44 deletions

View File

@@ -75,10 +75,13 @@ body:
id: version
attributes:
label: Streamyfin Version
description: What version of Streamyfin are you using?
description: What version of Streamyfin are you running? On a TestFlight or development build, choose "TestFlight/Development build" and include the exact version string shown in the app's Settings.
options:
- 0.54.1
- 0.51.0
- 0.47.1
- 0.30.2
- 0.28.0
- Older
- TestFlight/Development build
validations:

View File

@@ -1,67 +1,102 @@
name: 🐛 Update Bug Report Template
name: 🐛 Update Issue Form Versions
on:
release:
types: [published] # Run on every published release on any branch
# Only full releases populate the dropdown (no drafts/prereleases).
types: [released]
schedule:
- cron: "0 3 * * 1" # Weekly safety net (Mondays 03:00 UTC) in case a release event was missed
workflow_dispatch:
# Fixed group so a release event and the weekly cron can't race on the same
# ci/update-issue-form branch — runs queue instead of force-pushing over each other.
concurrency:
group: update-issue-form-${{ github.event.release.tag_name || github.run_id }}
cancel-in-progress: true
group: update-issue-form
cancel-in-progress: false
permissions:
contents: read
jobs:
update-bug-report:
update-issue-form:
name: 🔢 Populate version dropdown
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
issues: write
runs-on: ubuntu-24.04
steps:
- name: 📥 Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: "🟢 Setup Node.js"
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24.x'
cache: 'npm'
# On `release` events GITHUB_SHA is the tagged commit — without this the
# script would regenerate the form from the tag's (stale) copy and the bot
# PR would revert any form edits made on develop since that release.
ref: develop
- name: 🔍 Extract minor version from app.json
id: minor
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # main
- name: 🍞 Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
result-encoding: string
script: |
const fs = require('fs-extra');
const semver = require('semver');
const content = fs.readJsonSync('./app.json');
const version = content.expo.version;
const minorVersion = semver.minor(version);
return minorVersion.toString();
bun-version: latest
- name: 📝 Update bug report version
uses: ShaMan123/gha-populate-form-version@be012141ca560dbb92156e3fe098c46035f6260d #v2.0.5
with:
semver: '^0.${{ steps.minor.outputs.result }}.0'
dry_run: no-push
- name: 🔢 Populate version dropdown from GitHub releases
id: populate
run: bun scripts/update-issue-form.mjs
env:
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
- name: ⚙️ Update bug report node version dropdown
uses: ShaMan123/gha-populate-form-version@be012141ca560dbb92156e3fe098c46035f6260d #v2.0.5
with:
dropdown: _node_version
package: node
semver: '>=24.0.0'
dry_run: no-push
- name: 📬 Commit and create pull request
- name: 📬 Create pull request
id: cpr
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
add-paths: .github/ISSUE_TEMPLATE/bug_report.yml
branch: ci-update-bug-report
add-paths: .github/ISSUE_TEMPLATE/issue_report.yml
branch: ci/update-issue-form
base: develop
delete-branch: true
labels: ⚙️ ci, 🤖 github-actions
title: 'chore(): Update bug report template to match release version'
commit-message: "chore: update issue form version dropdown"
title: "chore: update issue form version dropdown"
# Follows .github/pull_request_template.md so the bot PR isn't flagged by PR validation.
body: |
Automated update to `.github/ISSUE_TEMPLATE/bug_report.yml`
Triggered by workflow run [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
# 📦 Pull Request
## 📝 Description
Automated update of the **Streamyfin Version** dropdown in `.github/ISSUE_TEMPLATE/issue_report.yml`, populated from the latest published GitHub releases by `scripts/update-issue-form.mjs`.
**Version dropdown now lists:** ${{ steps.populate.outputs.versions }}
Triggered by `${{ github.event_name }}`${{ github.event.release.tag_name && format(' — release {0}', github.event.release.tag_name) || '' }} · [run ${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).
## 🏷️ Ticket / Issue
N/A — automated maintenance.
### 🖼️ Screenshots / GIFs (if UI)
N/A — issue-template metadata only, no app UI.
## ✅ Checklist
- [x] Ive read the [contribution guidelines](CONTRIBUTING.md)
- [x] Verified that changes behave as expected for all platforms
- [x] Code passes lint/formatting and type checks (`tsc`/`biome`)
- [x] No secrets, hardcoded credentials, or private config files are included
- [x] I've declared if AI was used to assist with this PR (by uncommenting the line at the bottom, or not)
## 🔍 Testing Instructions
N/A — generated by CI from published releases; review the dropdown diff in `issue_report.yml`.
- name: 🔀 Enable auto-merge
if: steps.cpr.outputs.pull-request-operation == 'created'
env:
GH_TOKEN: ${{ github.token }}
# Known limitation: PRs created with GITHUB_TOKEN don't trigger CI workflows
# (GitHub anti-recursion), so the required checks stay "Expected" until a
# maintainer kicks them (close/reopen the PR, or push an empty commit).
# Auto-merge is still worth enabling: once checks run and reviews land,
# the PR merges itself.
run: |
gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" \
|| echo "::warning::Could not enable auto-merge — enable 'Allow auto-merge' in repo settings (and branch protection); merge the PR manually for now."

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env bun
/**
* Populates the "Streamyfin Version" dropdown in the issue report form with the
* latest GitHub releases. Run by the "Update Issue Form Versions" workflow on
* release events + a weekly cron (and manually via workflow_dispatch).
*
* Source: published, non-draft, non-prerelease GitHub releases, newest first.
* Non-version sentinels (e.g. "older", "TestFlight/Development build") are
* preserved at the end of the list.
*
* Usage:
* bun scripts/update-issue-form.mjs # rewrite the form in place
* ISSUE_FORM_LIMIT=8 bun scripts/update-issue-form.mjs
* bun scripts/update-issue-form.mjs --dry-run # print the new options, don't write
*
* Env: GITHUB_REPOSITORY (owner/repo), GH_TOKEN/GITHUB_TOKEN (for gh, provided in CI).
*/
import { execFileSync } from "node:child_process";
import {
appendFileSync,
readFileSync as read,
writeFileSync as write,
} from "node:fs";
const FORM = ".github/ISSUE_TEMPLATE/issue_report.yml";
const DROPDOWN_ID = "version"; // the `id:` of the dropdown to populate
const parsedLimit = Number.parseInt(process.env.ISSUE_FORM_LIMIT ?? "", 10);
const LIMIT =
Number.isInteger(parsedLimit) && parsedLimit > 0 ? parsedLimit : 5;
const REPO = process.env.GITHUB_REPOSITORY || "streamyfin/streamyfin";
const DRY = process.argv.includes("--dry-run");
// Matches "0.54.1" and prerelease/beta tags like "0.54.0-beta.1".
const isVersion = (s) => /^\d+\.\d+/.test(s.trim());
// 1. Fetch the latest published releases (newest first) — drafts and prereleases
// aren't a full release users run, so they don't belong in the dropdown.
const raw = execFileSync(
"gh",
[
"release",
"list",
"--repo",
REPO,
"--exclude-drafts",
"--exclude-pre-releases",
"--limit",
String(LIMIT),
"--json",
"tagName",
"--jq",
".[].tagName",
],
// Bounded timeout so a stuck gh process fails the job fast instead of
// holding the workflow open until the job-level timeout.
{ encoding: "utf8", timeout: 30_000 },
);
const seen = new Set();
const versions = [];
for (const tag of raw.split("\n")) {
if (!tag) continue;
const ver = tag.trim().replace(/^v/, "");
if (!isVersion(ver) || seen.has(ver)) continue;
seen.add(ver);
versions.push(ver);
}
if (!versions.length) {
console.error("No release versions found — leaving the form untouched.");
process.exit(1);
}
// 2. rewrite the dropdown options, preserving non-version sentinels
// (e.g. "older", "TestFlight/Development build") at the end of the list.
const lines = read(FORM, "utf8").split("\n");
const idIdx = lines.findIndex((l) =>
l.match(new RegExp(`^\\s*id:\\s*${DROPDOWN_ID}\\s*$`)),
);
if (idIdx === -1)
throw new Error(`dropdown id: ${DROPDOWN_ID} not found in ${FORM}`);
const optIdx = lines.findIndex(
(l, i) => i > idIdx && /^\s*options:\s*$/.test(l),
);
if (optIdx === -1)
throw new Error(`options: not found after id: ${DROPDOWN_ID}`);
const itemIndent = lines[optIdx].match(/^\s*/)[0] + " "; // options items are nested one level deeper
let end = optIdx + 1;
const sentinels = [];
while (end < lines.length && /^\s*-\s+/.test(lines[end])) {
const val = lines[end].replace(/^\s*-\s+/, "");
if (!isVersion(val)) sentinels.push(val);
end++;
}
const newOptions = [...versions, ...sentinels].map(
(v) => `${itemIndent}- ${v}`,
);
const updated = [
...lines.slice(0, optIdx + 1),
...newOptions,
...lines.slice(end),
].join("\n");
console.log(
`Versions: ${versions.join(", ")}${sentinels.length ? ` | kept: ${sentinels.join(", ")}` : ""}`,
);
if (DRY) {
console.log("--dry-run: not writing.");
} else {
write(FORM, updated);
console.log(`Updated ${FORM}.`);
}
// Expose the resulting list for the workflow (PR description).
if (process.env.GITHUB_OUTPUT) {
appendFileSync(
process.env.GITHUB_OUTPUT,
`versions=${versions.join(", ")}\n`,
);
}