diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 62914b7..66488d7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -5,16 +5,17 @@ This repo is a small .NET global tool (PackageId: `solrevdev.ytx`) that extracts - Entry points: - `src/Ytx/Program.cs` — single-file console app; contains the main flow: input parsing (args or JSON stdin), YoutubeExplode calls, caption selection, transcript normalization, and JSON output. - - `src/Ytx/Ytx.csproj` — packaging details (PackAsTool, ToolCommandName=`ytx`), TargetFrameworks (`net8.0;net9.0`), and Version (auto-bumped by CI). + - `src/Ytx/Ytx.csproj` — packaging details (PackAsTool, ToolCommandName=`ytx`), TargetFrameworks (`net10.0`, plus `net11.0` when the SDK is 11 or later), and Version (auto-bumped by CI). - What to change and where: - Feature or bugfix touching runtime behavior: edit `Program.cs` and add small, well-scoped tests under `tests/` when applicable. - Packaging/version bumps: update `` in `src/Ytx/Ytx.csproj` if needed locally — CI auto-increments on `master` pushes. - Build / run / package (explicit commands example): + - SDK: `global.json` asks for 10.0.100 and rolls forward to the latest major. SDK 11 builds both targets; SDK 10 alone builds net10.0 only. CI installs both SDKs, so releases ship both. - Restore: `dotnet restore src/Ytx` - Build: `dotnet build src/Ytx -c Release` - - Run (manual test): `dotnet run --project src/Ytx --framework net8.0 ""` + - Run (manual test): `dotnet run --project src/Ytx --framework net10.0 ""` - Pack: `dotnet pack src/Ytx -c Release` (packages to `./nupkg` per csproj) - Local tool install for verification: `dotnet tool install -g solrevdev.ytx --add-source ./nupkg` @@ -35,7 +36,7 @@ This repo is a small .NET global tool (PackageId: `solrevdev.ytx`) that extracts - External dependencies & compatibility: - Uses `YoutubeExplode` (pinned to 6.5.4). Avoid upgrading without testing caption extraction end-to-end. - - Targets .NET 8 and 9; keep `Nullable` and `ImplicitUsings` enabled to match project style. + - Targets .NET 10 (LTS baseline) and 11; keep `Nullable` and `ImplicitUsings` enabled to match project style. - Small fixes that are preferred: - Add unit tests for any non-trivial parsing/formatting changes. diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 671d1e0..6e58c83 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -50,9 +50,8 @@ jobs: uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: | - 8.0.x - 9.0.x 10.0.x + 11.0.x - name: Restore run: | @@ -68,6 +67,24 @@ jobs: - name: Pack run: dotnet pack "$PROJECT_DIR" --configuration Release --no-build + - name: Check package targets + shell: bash + run: | + set -euo pipefail + # The targets depend on the SDK that built them; fail rather than + # ship a package missing one. + PACKAGES=("$NUPKG_DIR"/solrevdev.ytx.*.nupkg) + # unzip -l reads a second path as a member name, so insist on one package. + if [[ ${#PACKAGES[@]} -ne 1 || ! -f "${PACKAGES[0]}" ]]; then + echo "Expected one package in $NUPKG_DIR, found: ${PACKAGES[*]}" >&2 + exit 1 + fi + LISTING=$(unzip -l "${PACKAGES[0]}") + for tfm in net10.0 net11.0; do + grep -q "tools/$tfm/any/Ytx.dll" <<<"$LISTING" \ + || { echo "Package is missing tools/$tfm" >&2; exit 1; } + done + publish: if: github.event_name != 'pull_request' permissions: @@ -84,9 +101,8 @@ jobs: uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: | - 8.0.x - 9.0.x 10.0.x + 11.0.x - name: Determine and bump version id: bump @@ -166,6 +182,24 @@ jobs: - name: Pack run: dotnet pack "$PROJECT_DIR" --configuration Release --no-build + - name: Check package targets + shell: bash + run: | + set -euo pipefail + # The targets depend on the SDK that built them; fail rather than + # ship a package missing one. + PACKAGES=("$NUPKG_DIR"/solrevdev.ytx.*.nupkg) + # unzip -l reads a second path as a member name, so insist on one package. + if [[ ${#PACKAGES[@]} -ne 1 || ! -f "${PACKAGES[0]}" ]]; then + echo "Expected one package in $NUPKG_DIR, found: ${PACKAGES[*]}" >&2 + exit 1 + fi + LISTING=$(unzip -l "${PACKAGES[0]}") + for tfm in net10.0 net11.0; do + grep -q "tools/$tfm/any/Ytx.dll" <<<"$LISTING" \ + || { echo "Package is missing tools/$tfm" >&2; exit 1; } + done + - name: Verify package id: package shell: bash diff --git a/AGENTS.md b/AGENTS.md index 9c1d9e3..13bb357 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ This file provides guidance to coding agents such as Codex and Claude Code when ## Project Overview -This is `ytx`, a .NET Global Tool that extracts YouTube video metadata and transcripts as structured JSON. It's packaged as `solrevdev.ytx` on NuGet and targets .NET 8.0, 9.0, and 10.0. +This is `ytx`, a .NET Global Tool that extracts YouTube video metadata and transcripts as structured JSON. It's packaged as `solrevdev.ytx` on NuGet and targets .NET 10.0 and 11.0. ## Core Architecture @@ -24,10 +24,11 @@ This is `ytx`, a .NET Global Tool that extracts YouTube video metadata and trans ## Development Commands ```bash -# Build and test locally +# Build and test locally. global.json rolls forward to the latest SDK major. +# SDK 11 builds net10.0 and net11.0; SDK 10 alone builds net10.0 only. dotnet restore src/Ytx dotnet build src/Ytx -c Release -dotnet run --project src/Ytx --framework net8.0 "YOUTUBE_URL" +dotnet run --project src/Ytx --framework net10.0 "YOUTUBE_URL" # Package for local testing dotnet pack src/Ytx -c Release @@ -40,7 +41,7 @@ dotnet tool install -g solrevdev.ytx --add-source ./nupkg ## CI/CD Integration **GitHub Actions Workflow** (`.github/workflows/publish.yml`): -- Pull requests that change the project, tests or workflow run read-only restore, build, test (net8.0, net9.0, net10.0) and pack validation +- Pull requests that change the project, tests or workflow run read-only restore, build, test (net10.0, net11.0) and pack validation - Pushes to `master` automatically use a patch bump; manual dispatch can select patch, minor, or major - Builds and packs before publishing the exact package to NuGet with `--skip-duplicate` - Only after NuGet publication succeeds, atomically pushes the version commit and tag @@ -66,7 +67,7 @@ dotnet tool install -g solrevdev.ytx --add-source ./nupkg ## Key Dependencies - `YoutubeExplode` 6.6.2 - Core YouTube data extraction -- .NET 8.0/9.0/10.0 target frameworks with nullable reference types enabled +- .NET 10.0/11.0 target frameworks with nullable reference types enabled. net10.0 (LTS) is the baseline; net11.0 is added only when the SDK is 11 or later (a `NETCoreSdkVersion` condition in both csproj files). `global.json` pins SDK 10.0.100 with `rollForward: latestMajor`. CI installs SDKs 10 and 11 so the package ships both targets - System.Text.Json for serialization - System.Text.RegularExpressions for caption text normalization diff --git a/CHANGELOG.md b/CHANGELOG.md index c00acc9..46e5a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ All notable changes to ytx are listed here. The format follows ## [Unreleased] +### Breaking + +- ytx now targets .NET 10 and 11 only. The net8.0 and net9.0 builds are gone because .NET 8 and 9 left support on 10 November 2026. A machine with only .NET 8 or 9 can no longer install new releases. It needs the .NET 10 or 11 runtime. Older ytx versions stay on NuGet for those machines. + +### Changed + +- Tests and CI run on .NET 10 and 11. + ### Fixed - The tool rolls forward to a newer .NET major, so it keeps running when only a later runtime, such as .NET 11, is installed. diff --git a/README.md b/README.md index dc9a8fb..d521aab 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ A .NET global tool that extracts YouTube video metadata and transcripts as JSON. - 🌍 **Captions-aware** — Prefers human-written captions in your language, reports which track it used - 📝 **Markdown transcript** — Human-readable format with timestamped links, split into sections by chapter - 📑 **Chapters** — Read from the video description, using YouTube's own rules -- 🚀 **Cross-platform** — Works on macOS, Windows, Linux (.NET 8/9/10) +- 🚀 **Cross-platform** — Works on macOS, Windows, Linux (.NET 10/11) - ⚡ **Fast & lightweight** — No dependencies beyond .NET and YoutubeExplode ## Quick Start @@ -159,6 +159,14 @@ When `captionStatus` is not `ok`, the caption fields are `null` and both transcr ## Development +### SDK policy + +.NET 10 is the LTS and the baseline. `global.json` asks for SDK 10.0.100 and rolls forward to the latest installed major, so a machine with SDKs 10 and 11 builds with 11. + +- With SDK 11 (alone or with 10), the project builds and tests `net10.0` and `net11.0`. +- With SDK 10 only, it builds and tests `net10.0` only. That is fine for local work, but release packages must come from SDK 11. +- CI installs SDKs 10 and 11, so the published package holds both targets. + ### Local Build & Test ```bash @@ -172,7 +180,8 @@ dotnet restore src/Ytx # Build dotnet build src/Ytx -c Release -# Run the unit tests (on .NET 8, 9 and 10; add -f net8.0 to use one runtime) +# Run the unit tests (net10.0 and net11.0 with SDK 11, net10.0 only with SDK 10; +# add -f net10.0 to use one runtime) dotnet test tests/Ytx.Tests -c Release # Test locally (choose an installed target framework) @@ -248,7 +257,7 @@ The GitHub Actions workflow uses NuGet Trusted Publishing and does not need a st ## Dependencies - [YoutubeExplode](https://github.com/Tyrrrz/YoutubeExplode) — YouTube video data extraction -- .NET 8.0+ SDK (for development) +- .NET 10 SDK or later for development. SDK 11 builds both targets; see [SDK policy](#sdk-policy). ## License diff --git a/global.json b/global.json new file mode 100644 index 0000000..a49afd6 --- /dev/null +++ b/global.json @@ -0,0 +1 @@ +{ "sdk": { "version": "10.0.100", "rollForward": "latestMajor", "allowPrerelease": false } } diff --git a/src/Ytx/Ytx.csproj b/src/Ytx/Ytx.csproj index 2684dd3..56004f5 100644 --- a/src/Ytx/Ytx.csproj +++ b/src/Ytx/Ytx.csproj @@ -1,7 +1,9 @@ Exe - net8.0;net9.0;net10.0 + + net10.0 + net10.0;net11.0 Major enable diff --git a/tests/Ytx.Tests/Ytx.Tests.csproj b/tests/Ytx.Tests/Ytx.Tests.csproj index d6ffa8f..bfd3d55 100644 --- a/tests/Ytx.Tests/Ytx.Tests.csproj +++ b/tests/Ytx.Tests/Ytx.Tests.csproj @@ -1,6 +1,8 @@ - net8.0;net9.0;net10.0 + + net10.0 + net10.0;net11.0 enable enable false