v0.3.0: CI dotnet 8.0.424 pinned with isolated install
- Pin .NET SDK to 8.0.424 in all CI jobs to avoid floating channel drift - Install SDK to runner temp via DOTNET_INSTALL_DIR to bypass C:\\Program Files\\dotnet overwrite/extract conflicts on Gitea Windows runners - Simplify release job to dotnet publish + upload-artifact - Exclude memory-bank/ via .gitignore (internal dev memory stays local)
This commit is contained in:
1 parent
c9e643d617
commit
43f64ec68f
23 files changed
+22
-1311
No files matched your search
+22
-16
@@ -12,7 +12,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: windows
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -22,7 +22,9 @@ jobs:
|
|||||||
- name: Setup .NET 8 SDK
|
- name: Setup .NET 8 SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 8.0.424
|
||||||
|
env:
|
||||||
|
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
|
||||||
|
|
||||||
- name: Cache NuGet packages
|
- name: Cache NuGet packages
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -43,7 +45,7 @@ jobs:
|
|||||||
run: dotnet build src/RgbLedStripController/RgbLedStripController.csproj -c Release --no-restore
|
run: dotnet build src/RgbLedStripController/RgbLedStripController.csproj -c Release --no-restore
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: windows
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -53,7 +55,9 @@ jobs:
|
|||||||
- name: Setup .NET 8 SDK
|
- name: Setup .NET 8 SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 8.0.424
|
||||||
|
env:
|
||||||
|
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
|
||||||
|
|
||||||
- name: Cache NuGet packages
|
- name: Cache NuGet packages
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -83,7 +87,7 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
if: startsWith(gitea.ref, 'refs/tags/v')
|
if: startsWith(gitea.ref, 'refs/tags/v')
|
||||||
runs-on: windows
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -93,7 +97,9 @@ jobs:
|
|||||||
- name: Setup .NET 8 SDK
|
- name: Setup .NET 8 SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 8.0.424
|
||||||
|
env:
|
||||||
|
DOTNET_INSTALL_DIR: ${{ runner.temp }}\dotnet
|
||||||
|
|
||||||
- name: Cache NuGet packages
|
- name: Cache NuGet packages
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -107,14 +113,14 @@ jobs:
|
|||||||
- name: Restore tools
|
- name: Restore tools
|
||||||
run: dotnet tool restore
|
run: dotnet tool restore
|
||||||
|
|
||||||
- name: Package (Velopack, unsigned)
|
- name: Publish (Release, self-contained, single file)
|
||||||
shell: pwsh
|
run: dotnet publish src/RgbLedStripController/RgbLedStripController.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true --configfile NuGet.Config
|
||||||
run: |
|
|
||||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/package-velopack.ps1 -SkipSigning
|
|
||||||
|
|
||||||
- name: Upload to Gitea Releases
|
- name: Upload release artifacts
|
||||||
shell: pwsh
|
uses: actions/upload-artifact@v4
|
||||||
env:
|
with:
|
||||||
VPK_TOKEN: ${{ secrets.VPK_TOKEN }}
|
name: rgb-led-strip-controller-${{ gitea.ref_name }}-win-x64
|
||||||
run: |
|
path: |
|
||||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/upload-feed.ps1 -ExpectedTag ${{ gitea.ref_name }}
|
src/RgbLedStripController/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/RgbLedStripController.exe
|
||||||
|
src/RgbLedStripController/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/RgbLedStripController.pdb
|
||||||
|
if-no-files-found: error
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# Optimization Audit System Prompt v2
|
|
||||||
|
|
||||||
## 1) Identity and Objective
|
|
||||||
You are a senior optimization auditor focused on practical, production-safe improvements.
|
|
||||||
|
|
||||||
Primary objective:
|
|
||||||
Find high-ROI opportunities to improve performance, scalability, efficiency, reliability, maintainability, and cost.
|
|
||||||
|
|
||||||
## 2) Non-Negotiable Context Intake Protocol
|
|
||||||
Before any analysis, read context in this exact order:
|
|
||||||
1. User-specified `memorybank.md` path (if provided and the file exists).
|
|
||||||
2. Project-root `memorybank.md` (if it exists and was not already read in step 1).
|
|
||||||
3. Project memory bank files:
|
|
||||||
- Layer 0 first: `00_project_snapshot.md`, `20_now.md`, `21_backlog.md`
|
|
||||||
- Layer 1 on demand: `10_scope.md`, `11_product.md`, `12_architecture.md`, `13_tech.md`
|
|
||||||
- Layer 2 on demand: `decisions/ADR-*.md`, `logs/tasks/...`, `logs/digests/...`
|
|
||||||
|
|
||||||
If a configured memorybank path is missing, report a brief context notice and continue with available files.
|
|
||||||
|
|
||||||
Default analysis scope is `diff + necessary context`.
|
|
||||||
Run full-repo optimization review only when the user explicitly requests it.
|
|
||||||
|
|
||||||
## 3) Optimization Priorities
|
|
||||||
Prioritize by ROI first, then effort and risk.
|
|
||||||
Preserve correctness and readability unless tradeoffs are explicitly requested.
|
|
||||||
|
|
||||||
Use evidence confidence labels for each bottleneck:
|
|
||||||
- `measured`: profiling, benchmark, or metric evidence exists.
|
|
||||||
- `inferred`: strong code/path evidence, but not benchmark-proven.
|
|
||||||
- `hypothesis`: plausible risk needing validation.
|
|
||||||
|
|
||||||
Evaluate, when relevant:
|
|
||||||
- CPU, memory, I/O, network, database, concurrency, caching.
|
|
||||||
- Reliability and cost inefficiencies.
|
|
||||||
- Duplication, dead code, and over-abstraction that increase runtime or delivery cost.
|
|
||||||
|
|
||||||
## 4) Required Output Format (Strict and Concise)
|
|
||||||
Structure output in this order:
|
|
||||||
|
|
||||||
### 1) Optimization Summary
|
|
||||||
- Current optimization health
|
|
||||||
- Top 3 highest-impact improvements
|
|
||||||
- Biggest risk if unchanged
|
|
||||||
|
|
||||||
### 2) Findings (Prioritized)
|
|
||||||
For each finding:
|
|
||||||
|
|
||||||
#### [OPT-###] <Title>
|
|
||||||
- Category: `CPU | Memory | I/O | Network | DB | Algorithm | Concurrency | Caching | Reliability | Cost | Build | Frontend`
|
|
||||||
- Severity: `Critical | High | Medium | Low`
|
|
||||||
- Confidence: `measured | inferred | hypothesis`
|
|
||||||
- Impact: <latency/throughput/memory/cost/reliability>
|
|
||||||
- Evidence: <path/query/loop/metric>
|
|
||||||
- Why inefficient: <root cause>
|
|
||||||
- Recommended fix: <concrete change>
|
|
||||||
- Tradeoffs or risks: <brief>
|
|
||||||
- Expected impact estimate: <percent or qualitative>
|
|
||||||
- Validation signal: <metric or benchmark to watch>
|
|
||||||
- Classification: `Reuse Opportunity | Dead Code | Over-Abstracted Code | N/A`
|
|
||||||
|
|
||||||
### 3) Quick Wins
|
|
||||||
Fast, high-value changes first.
|
|
||||||
|
|
||||||
### 4) Deeper Optimizations
|
|
||||||
Larger refactors worth planning next.
|
|
||||||
|
|
||||||
### 5) Validation Plan
|
|
||||||
- Benchmarks/profiling steps
|
|
||||||
- Before vs after metrics
|
|
||||||
- Correctness regression checks
|
|
||||||
|
|
||||||
### 6) Optional Mini Patch
|
|
||||||
Include only if enough context exists.
|
|
||||||
|
|
||||||
Sections 3, 4, and 6 may be omitted if empty.
|
|
||||||
Sections 1, 2, and 5 are always required.
|
|
||||||
|
|
||||||
## 5) Behavioral Constraints
|
|
||||||
- Do not apply fixes automatically.
|
|
||||||
- Avoid premature micro-optimizations unless clearly justified.
|
|
||||||
- If evidence is incomplete, label as `inferred` or `hypothesis` and state what to measure.
|
|
||||||
- Keep findings realistic for production teams.
|
|
||||||
- Put analysis output in `OPTIMIZATION_REPORT.md` unless user asks for a different target.
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
# Security Audit System Prompt v2
|
|
||||||
|
|
||||||
## 1) Identity and Objective
|
|
||||||
You are a Senior Security Researcher and Application Security Expert.
|
|
||||||
Mindset: adversarial, evidence-driven, zero trust.
|
|
||||||
|
|
||||||
Primary objective:
|
|
||||||
Analyze code changes for exploitable security weaknesses and provide concrete, verifiable remediation guidance.
|
|
||||||
|
|
||||||
## 2) Non-Negotiable Context Intake Protocol
|
|
||||||
Before any analysis, read context in this exact order:
|
|
||||||
1. User-specified `memorybank.md` path (if provided and the file exists).
|
|
||||||
2. Project-root `memorybank.md` (if it exists and was not already read in step 1).
|
|
||||||
3. Project memory bank files:
|
|
||||||
- Layer 0 first: `00_project_snapshot.md`, `20_now.md`, `21_backlog.md`
|
|
||||||
- Layer 1 on demand: `10_scope.md`, `11_product.md`, `12_architecture.md`, `13_tech.md`
|
|
||||||
- Layer 2 on demand: `decisions/ADR-*.md`, `logs/tasks/...`, `logs/digests/...`
|
|
||||||
|
|
||||||
If a configured memorybank path is missing, report a brief context notice and continue with available files.
|
|
||||||
|
|
||||||
Default analysis scope is `diff + necessary context`.
|
|
||||||
Run full-repo security review only when the user explicitly requests it.
|
|
||||||
|
|
||||||
## 3) Analysis Scope and Protocol
|
|
||||||
Treat changed lines as attack-surface entry points, then expand only where needed.
|
|
||||||
|
|
||||||
Inspect these risk classes where relevant:
|
|
||||||
1. Injection: SQL, command, template, LDAP, NoSQL, path traversal, XSS.
|
|
||||||
2. Authentication, authorization, and session flaws: missing checks, IDOR, privilege escalation, weak session handling.
|
|
||||||
3. Secrets and sensitive data exposure: hardcoded credentials, token leakage, insecure logging, PII disclosure.
|
|
||||||
4. Cryptography and integrity: weak algorithms, bad key handling, missing signature/verification steps.
|
|
||||||
5. Security misconfiguration and hardening gaps: debug modes, permissive CORS, missing headers, unsafe defaults.
|
|
||||||
6. Dependency and supply-chain risks: vulnerable packages, unpinned sources, unsafe update patterns.
|
|
||||||
7. Deserialization, parser, and object integrity flaws.
|
|
||||||
8. SSRF and network boundary issues.
|
|
||||||
9. Concurrency and race-condition abuse paths.
|
|
||||||
10. Availability and abuse vectors: unbounded loops, no rate limits, resource exhaustion, DoS amplification.
|
|
||||||
11. Business-logic abuse and workflow bypass risks.
|
|
||||||
|
|
||||||
## 4) Required Output Format (Strict and Concise)
|
|
||||||
Start directly with:
|
|
||||||
`SECURITY AUDIT: <brief summary of changes reviewed>`
|
|
||||||
|
|
||||||
Then provide sections in this order:
|
|
||||||
|
|
||||||
### Risk Assessment
|
|
||||||
`Critical | High | Medium | Low | Secure`
|
|
||||||
|
|
||||||
### Scope
|
|
||||||
- Mode: `diff + necessary context` or `full repo`
|
|
||||||
- Assumptions and limits (short)
|
|
||||||
|
|
||||||
### Memory Intake
|
|
||||||
- Read order executed (short list)
|
|
||||||
- Missing context files (if any)
|
|
||||||
|
|
||||||
### Findings
|
|
||||||
For each finding, use this exact schema:
|
|
||||||
|
|
||||||
#### [SEC-###] <Title>
|
|
||||||
- Severity: `Critical | High | Medium | Low`
|
|
||||||
- Confidence: `Confirmed | Likely | Possible`
|
|
||||||
- Category: <risk class>
|
|
||||||
- Location: <file:line or component>
|
|
||||||
- Exploit Path: <how attacker can abuse it>
|
|
||||||
- Impact: <confidentiality/integrity/availability/business>
|
|
||||||
- Evidence: <code-level proof or strong signal>
|
|
||||||
- Fix: <concrete remediation + mini patch/snippet when possible>
|
|
||||||
- Verification: <how to prove fix works and exploit is closed>
|
|
||||||
|
|
||||||
### No Findings (only when applicable)
|
|
||||||
If no vulnerabilities are found, output:
|
|
||||||
- `No Findings` with final risk level
|
|
||||||
- Checked areas
|
|
||||||
- Residual risk and what was not fully verifiable
|
|
||||||
|
|
||||||
### Observations
|
|
||||||
Optional hardening notes that are not direct vulnerabilities.
|
|
||||||
|
|
||||||
## 5) Behavioral Constraints
|
|
||||||
- Do not apply fixes automatically.
|
|
||||||
- Keep output high signal and actionable.
|
|
||||||
- If evidence is incomplete, do not overstate certainty; downgrade confidence and provide verification steps.
|
|
||||||
- If potential secrets are found, treat as at least High and escalate to Critical when clearly valid.
|
|
||||||
- Put analysis output in `SECURITY_REPORT.md` unless user asks for a different target.
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# v1 to v2 Migration Playbook
|
|
||||||
|
|
||||||
This playbook migrates the old 6-file memory bank to the v2 layered model.
|
|
||||||
|
|
||||||
## Mapping Table
|
|
||||||
|
|
||||||
| v1 file | v2 destination |
|
|
||||||
| --- | --- |
|
|
||||||
| `projectbrief.md` | `10_scope.md` |
|
|
||||||
| `productContext.md` | `11_product.md` |
|
|
||||||
| `systemPatterns.md` | `12_architecture.md` |
|
|
||||||
| `techContext.md` | `13_tech.md` |
|
|
||||||
| `activeContext.md` | `20_now.md` |
|
|
||||||
| `progress.md` | `21_backlog.md` + `logs/tasks/...` + `00_project_snapshot.md` |
|
|
||||||
|
|
||||||
## Migration Steps
|
|
||||||
|
|
||||||
1. Create the v2 tree from `templates/`.
|
|
||||||
2. Copy current-truth statements from v1 files into mapped v2 core files.
|
|
||||||
3. Remove historical narrative from core content while migrating.
|
|
||||||
4. Extract major decisions into ADRs (`decisions/ADR-*.md`).
|
|
||||||
5. Extract execution history into task logs (`logs/tasks/YYYY/MM/*.md`).
|
|
||||||
6. Build `00_project_snapshot.md` from current state, top risks, and top priorities.
|
|
||||||
7. Build `21_backlog.md` from remaining actionable items only.
|
|
||||||
8. If old history is large, summarize older-than-90-day items into monthly digests.
|
|
||||||
9. Run consistency checks from `OPERATIONS.md`.
|
|
||||||
|
|
||||||
## Conversion Rules
|
|
||||||
- Keep one source of truth per concept.
|
|
||||||
- If a paragraph repeats in multiple files, keep the canonical copy in one core file and link it elsewhere.
|
|
||||||
- Core files must answer "what is true now", not "what happened over time".
|
|
||||||
- Place justifications and tradeoffs in ADRs, not in core files.
|
|
||||||
|
|
||||||
## Suggested First ADRs
|
|
||||||
- `ADR-0001-memory-bank-v2-adoption.md`: why v2 was adopted.
|
|
||||||
- `ADR-0002-layered-read-protocol.md`: why layered reading is required.
|
|
||||||
- `ADR-0003-core-no-changelog-rule.md`: why history is separated from core files.
|
|
||||||
|
|
||||||
## Completion Criteria
|
|
||||||
- Layer 0 files are enough for a fast, accurate project summary.
|
|
||||||
- All backlog items are actionable and non-duplicated.
|
|
||||||
- Old historical detail is linked through task logs and digests.
|
|
||||||
- No core file breaches hard line budgets.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# Memory Bank v2 Operations
|
|
||||||
|
|
||||||
## Command: `update memory bank`
|
|
||||||
|
|
||||||
Use this when significant changes happen or context gets stale.
|
|
||||||
|
|
||||||
### Procedure
|
|
||||||
1. Read Layer 0 (`00_project_snapshot.md`, `20_now.md`, `21_backlog.md`).
|
|
||||||
2. Read additional Layer 1 and Layer 2 files that are relevant to touched work.
|
|
||||||
3. Refresh core files to current truth.
|
|
||||||
4. Write or update ADRs for durable decisions.
|
|
||||||
5. Write a task log for significant implementation steps.
|
|
||||||
6. Validate:
|
|
||||||
- All referenced ADR and task IDs exist.
|
|
||||||
- Core files do not contain changelog-style history.
|
|
||||||
- Budgets from `SCHEMA.md` are respected.
|
|
||||||
7. Update `Last Updated` fields in touched files.
|
|
||||||
|
|
||||||
### Expected Result
|
|
||||||
- Layer 0 gives an accurate project state in minutes.
|
|
||||||
- Decision and execution history is traceable via IDs.
|
|
||||||
|
|
||||||
## Command: `compact memory bank`
|
|
||||||
|
|
||||||
Use this manually for maintenance.
|
|
||||||
|
|
||||||
### Triggers
|
|
||||||
- Any file exceeds hard budget.
|
|
||||||
- Backlog has many stale completed items.
|
|
||||||
- Task logs older than 90 days are accumulating.
|
|
||||||
|
|
||||||
### Procedure
|
|
||||||
1. Identify oversized core files.
|
|
||||||
2. Remove historical narrative from core files.
|
|
||||||
3. Ensure old details live in ADR/task logs.
|
|
||||||
4. For each month older than 90 days, create or refresh `logs/digests/YYYY-MM.md`.
|
|
||||||
5. Replace verbose old references in core files with digest links.
|
|
||||||
6. Re-validate ID/link integrity and budgets.
|
|
||||||
|
|
||||||
### Expected Result
|
|
||||||
- Core remains concise.
|
|
||||||
- Older history stays discoverable through digests and linked logs.
|
|
||||||
|
|
||||||
## Consistency Checklist
|
|
||||||
- Every backlog item has an ID, status, and owner.
|
|
||||||
- Every ADR has status (`proposed`, `accepted`, `superseded`) and links.
|
|
||||||
- `20_now.md` and `21_backlog.md` do not conflict.
|
|
||||||
- `00_project_snapshot.md` reflects the same priorities as `20_now.md`.
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
# Memory Bank v2 Schema
|
|
||||||
|
|
||||||
## Required Tree
|
|
||||||
|
|
||||||
```text
|
|
||||||
memory-bank/
|
|
||||||
00_project_snapshot.md
|
|
||||||
10_scope.md
|
|
||||||
11_product.md
|
|
||||||
12_architecture.md
|
|
||||||
13_tech.md
|
|
||||||
20_now.md
|
|
||||||
21_backlog.md
|
|
||||||
decisions/
|
|
||||||
ADR-0001-short-title.md
|
|
||||||
logs/
|
|
||||||
tasks/YYYY/MM/TASK-YYYYMMDD-001-short-title.md
|
|
||||||
digests/YYYY-MM.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## ID and Naming Rules
|
|
||||||
- ADR ID: `ADR-0001` style, incrementing sequence.
|
|
||||||
- Task ID: `TASK-YYYYMMDD-###` style, sequence resets daily.
|
|
||||||
- Backlog ID: `BG-001` style.
|
|
||||||
- Core file names are fixed and must not be renamed.
|
|
||||||
- Keep file names in English; content may be Turkish or English.
|
|
||||||
|
|
||||||
## Hard Size Budgets
|
|
||||||
|
|
||||||
| File | Max lines | Role |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| `00_project_snapshot.md` | 120 | One-page entry point and quick orientation |
|
|
||||||
| `10_scope.md` | 180 | Scope boundaries and success criteria |
|
|
||||||
| `11_product.md` | 220 | User/problem/value model |
|
|
||||||
| `12_architecture.md` | 260 | Architecture map and critical paths |
|
|
||||||
| `13_tech.md` | 220 | Stack, setup, constraints, runbook basics |
|
|
||||||
| `20_now.md` | 160 | Current focus, blockers, assumptions |
|
|
||||||
| `21_backlog.md` | 200 | Prioritized backlog and status |
|
|
||||||
| `decisions/ADR-*.md` | 180 each | Durable rationale and decision records |
|
|
||||||
| `logs/tasks/.../*.md` | 250 each | Task execution narrative |
|
|
||||||
| `logs/digests/YYYY-MM.md` | 220 each | Monthly summary of old history |
|
|
||||||
|
|
||||||
## Section Budgets
|
|
||||||
|
|
||||||
### `00_project_snapshot.md` (<=120)
|
|
||||||
- Project Card: <=8 lines
|
|
||||||
- One Paragraph Summary: <=6 lines
|
|
||||||
- Current State: <=12 bullets
|
|
||||||
- Decision Index: <=12 ADR links
|
|
||||||
- Top Risks: <=8 bullets
|
|
||||||
- Next 7 Days: <=7 bullets
|
|
||||||
- Read Map: <=6 lines
|
|
||||||
|
|
||||||
### `10_scope.md` (<=180)
|
|
||||||
- Mission: <=6 lines
|
|
||||||
- In Scope: <=25 bullets
|
|
||||||
- Out of Scope: <=25 bullets
|
|
||||||
- Constraints: <=15 bullets
|
|
||||||
- Success Criteria: <=15 bullets
|
|
||||||
- Non-goals: <=10 bullets
|
|
||||||
|
|
||||||
### `11_product.md` (<=220)
|
|
||||||
- User Segments: <=12 bullets
|
|
||||||
- Problems: <=15 bullets
|
|
||||||
- Desired Outcomes: <=15 bullets
|
|
||||||
- Core Flows: <=15 bullets
|
|
||||||
- UX Principles: <=10 bullets
|
|
||||||
- Product Risks: <=12 bullets
|
|
||||||
|
|
||||||
### `12_architecture.md` (<=260)
|
|
||||||
- System Map: <=40 lines
|
|
||||||
- Components and Contracts: <=25 bullets
|
|
||||||
- Data Flows: <=25 bullets
|
|
||||||
- Critical Paths: <=20 bullets
|
|
||||||
- Failure Modes: <=20 bullets
|
|
||||||
- Scaling Constraints: <=15 bullets
|
|
||||||
|
|
||||||
### `13_tech.md` (<=220)
|
|
||||||
- Stack Matrix: <=35 lines
|
|
||||||
- Environments: <=20 bullets
|
|
||||||
- Setup and Commands: <=25 lines
|
|
||||||
- Dependencies: <=20 bullets
|
|
||||||
- Constraints and Limits: <=15 bullets
|
|
||||||
|
|
||||||
### `20_now.md` (<=160)
|
|
||||||
- Current Objective: <=5 lines
|
|
||||||
- Active Workstreams: <=12 bullets
|
|
||||||
- Blockers: <=10 bullets
|
|
||||||
- Next Actions: <=10 bullets
|
|
||||||
- Assumptions: <=10 bullets
|
|
||||||
- Watchlist: <=10 bullets
|
|
||||||
|
|
||||||
### `21_backlog.md` (<=200)
|
|
||||||
- Prioritized table rows: <=60 items
|
|
||||||
- Completed items older than 30 days must be removed from active table and referenced from task logs/digests.
|
|
||||||
|
|
||||||
## Core File Guardrails
|
|
||||||
- Core files are current truth only.
|
|
||||||
- Forbidden in core files: long chronology, date-by-date logs, and narrative changelogs.
|
|
||||||
- Keep details in ADRs and task logs; keep summaries in core files.
|
|
||||||
- Prefer references over duplicated prose.
|
|
||||||
|
|
||||||
## Over-Limit Policy
|
|
||||||
When any file exceeds budget:
|
|
||||||
1. Keep only current truth in the core file.
|
|
||||||
2. Move historical detail to ADR/task logs.
|
|
||||||
3. Add references to moved details.
|
|
||||||
4. Re-run a consistency check (IDs resolve, no stale links).
|
|
||||||
|
|
||||||
## 90-Day Retention Policy
|
|
||||||
- Task logs in the last 90 days are hot history.
|
|
||||||
- History older than 90 days must be summarized into monthly digest files.
|
|
||||||
- Compaction is manual and triggered by `compact memory bank`.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Memory Bank v2 Templates
|
|
||||||
|
|
||||||
Use files under `templates/` as copy-ready starters for each new project.
|
|
||||||
|
|
||||||
## Template Index
|
|
||||||
- `templates/00_project_snapshot.md`
|
|
||||||
- `templates/10_scope.md`
|
|
||||||
- `templates/11_product.md`
|
|
||||||
- `templates/12_architecture.md`
|
|
||||||
- `templates/13_tech.md`
|
|
||||||
- `templates/20_now.md`
|
|
||||||
- `templates/21_backlog.md`
|
|
||||||
- `templates/decisions/ADR-0000-template.md`
|
|
||||||
- `templates/logs/tasks/YYYY/MM/TASK-YYYYMMDD-001-template.md`
|
|
||||||
- `templates/logs/digests/YYYY-MM.md`
|
|
||||||
|
|
||||||
## Usage Rules
|
|
||||||
1. Keep section headings stable so tools can parse quickly.
|
|
||||||
2. Replace placeholders (`<...>`) immediately; avoid leaving TODO placeholders in active projects.
|
|
||||||
3. Keep IDs stable once created.
|
|
||||||
4. Keep core files concise and route history to ADR/log templates.
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Memory Bank v2 Test Checklist
|
|
||||||
|
|
||||||
## 1. Startup Test (2-3 minute orientation)
|
|
||||||
- Read only Layer 0 files.
|
|
||||||
- Confirm the summary includes objective, current status, risks, and next actions.
|
|
||||||
- Pass if no Layer 1/2 file is required for a basic project brief.
|
|
||||||
|
|
||||||
## 2. Scale Test (200+ task logs)
|
|
||||||
- Ensure core files remain within hard budgets.
|
|
||||||
- Confirm old details are reachable through task logs and digests.
|
|
||||||
- Pass if context load time remains fast and no core file turns into a log.
|
|
||||||
|
|
||||||
## 3. Audit Trace Test
|
|
||||||
- Pick one decision and trace:
|
|
||||||
1. Core summary mention
|
|
||||||
2. ADR rationale
|
|
||||||
3. Task log implementation record
|
|
||||||
- Pass if links are complete and consistent.
|
|
||||||
|
|
||||||
## 4. Anti-duplication Test
|
|
||||||
- Scan core files for repeated long paragraphs.
|
|
||||||
- Pass if repeated content is replaced with canonical links.
|
|
||||||
|
|
||||||
## 5. Compaction Test
|
|
||||||
- Run `compact memory bank` procedure.
|
|
||||||
- Confirm:
|
|
||||||
- Core files shrink to budget.
|
|
||||||
- 90+ day history appears in monthly digests.
|
|
||||||
- Link integrity is preserved.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# 00 Project Snapshot
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Project: <name>
|
|
||||||
Owner: <person-or-team>
|
|
||||||
Stage: discovery|build|stabilize|maintenance
|
|
||||||
|
|
||||||
## One Paragraph Summary
|
|
||||||
<3-5 sentences that explain what this project does and why it matters.>
|
|
||||||
|
|
||||||
## Current State
|
|
||||||
- <current truth bullet 1>
|
|
||||||
- <current truth bullet 2>
|
|
||||||
|
|
||||||
## Top Facts
|
|
||||||
- [F01] <fact>
|
|
||||||
- [F02] <fact>
|
|
||||||
|
|
||||||
## Decision Index
|
|
||||||
- [ADR-0001] <title>
|
|
||||||
|
|
||||||
## Top Risks
|
|
||||||
- <risk and impact>
|
|
||||||
|
|
||||||
## Next 7 Days
|
|
||||||
- <priority 1>
|
|
||||||
- <priority 2>
|
|
||||||
|
|
||||||
## Read Map
|
|
||||||
- Scope: `10_scope.md`
|
|
||||||
- Product: `11_product.md`
|
|
||||||
- Architecture: `12_architecture.md`
|
|
||||||
- Tech: `13_tech.md`
|
|
||||||
- Current Operations: `20_now.md`
|
|
||||||
- Backlog: `21_backlog.md`
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 10 Scope
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
<single paragraph>
|
|
||||||
|
|
||||||
## In Scope
|
|
||||||
- <item>
|
|
||||||
|
|
||||||
## Out of Scope
|
|
||||||
- <item>
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
- <constraint>
|
|
||||||
|
|
||||||
## Success Criteria
|
|
||||||
- <measurable criterion>
|
|
||||||
|
|
||||||
## Non-goals
|
|
||||||
- <non-goal>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 11 Product
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## User Segments
|
|
||||||
- <segment>
|
|
||||||
|
|
||||||
## Problems
|
|
||||||
- <problem>
|
|
||||||
|
|
||||||
## Desired Outcomes
|
|
||||||
- <outcome>
|
|
||||||
|
|
||||||
## Core Flows
|
|
||||||
- <flow>
|
|
||||||
|
|
||||||
## UX Principles
|
|
||||||
- <principle>
|
|
||||||
|
|
||||||
## Product Risks
|
|
||||||
- <risk>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 12 Architecture
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## System Map
|
|
||||||
<high-level architecture summary>
|
|
||||||
|
|
||||||
## Components and Contracts
|
|
||||||
- <component>: <contract>
|
|
||||||
|
|
||||||
## Data Flows
|
|
||||||
- <flow>
|
|
||||||
|
|
||||||
## Critical Paths
|
|
||||||
- <path>
|
|
||||||
|
|
||||||
## Failure Modes
|
|
||||||
- <failure mode and mitigation>
|
|
||||||
|
|
||||||
## Scaling Constraints
|
|
||||||
- <constraint>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# 13 Tech
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## Stack Matrix
|
|
||||||
| Layer | Technology | Notes |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| <layer> | <tech> | <notes> |
|
|
||||||
|
|
||||||
## Environments
|
|
||||||
- <environment details>
|
|
||||||
|
|
||||||
## Setup and Commands
|
|
||||||
- `<command>`: <purpose>
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
- <dependency and role>
|
|
||||||
|
|
||||||
## Constraints and Limits
|
|
||||||
- <limit>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 20 Now
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## Current Objective
|
|
||||||
<single objective statement>
|
|
||||||
|
|
||||||
## Active Workstreams
|
|
||||||
- <workstream>
|
|
||||||
|
|
||||||
## Blockers
|
|
||||||
- <blocker>
|
|
||||||
|
|
||||||
## Next Actions
|
|
||||||
- [TASK-YYYYMMDD-001] <action>
|
|
||||||
|
|
||||||
## Assumptions
|
|
||||||
- <assumption>
|
|
||||||
|
|
||||||
## Watchlist
|
|
||||||
- <item to monitor>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# 21 Backlog
|
|
||||||
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## Prioritized Items
|
|
||||||
| ID | Status | Priority | Summary | Owner | Link |
|
|
||||||
| --- | --- | --- | --- | --- | --- |
|
|
||||||
| BG-001 | todo | p1 | <item> | <owner> | <task-log-or-doc-link> |
|
|
||||||
|
|
||||||
Status values: `todo`, `in_progress`, `blocked`, `done`.
|
|
||||||
|
|
||||||
## Deferred
|
|
||||||
| ID | Reason | Revisit Date |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| BG-099 | <reason> | YYYY-MM-DD |
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# ADR-0000: <short title>
|
|
||||||
|
|
||||||
Date: YYYY-MM-DD
|
|
||||||
Status: proposed|accepted|superseded
|
|
||||||
Owners: <person-or-team>
|
|
||||||
|
|
||||||
## Context
|
|
||||||
<why this decision is needed>
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
<what was decided>
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Positive: <impact>
|
|
||||||
- Negative: <tradeoff>
|
|
||||||
|
|
||||||
## Alternatives Considered
|
|
||||||
- <option A> - <why not chosen>
|
|
||||||
- <option B> - <why not chosen>
|
|
||||||
|
|
||||||
## Links
|
|
||||||
- Related tasks: `TASK-YYYYMMDD-001`
|
|
||||||
- Related docs: `<path>`
|
|
||||||
|
|
||||||
## Supersedes / Superseded By
|
|
||||||
- <ADR-id-or-none>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# YYYY-MM Digest
|
|
||||||
|
|
||||||
Month: YYYY-MM
|
|
||||||
Last Updated: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
<high-level summary of this month for old-history compaction>
|
|
||||||
|
|
||||||
## Key Outcomes
|
|
||||||
- <outcome>
|
|
||||||
|
|
||||||
## Decisions Referenced
|
|
||||||
- `ADR-0001` - <title>
|
|
||||||
|
|
||||||
## Notable Tasks
|
|
||||||
- `TASK-YYYYMMDD-001` - <result>
|
|
||||||
|
|
||||||
## Carryover Risks
|
|
||||||
- <risk>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# TASK-YYYYMMDD-001: <short title>
|
|
||||||
|
|
||||||
Date: YYYY-MM-DD
|
|
||||||
Owner: <person-or-team>
|
|
||||||
Status: in_progress|done|blocked
|
|
||||||
|
|
||||||
## Intent
|
|
||||||
<what this task was trying to achieve>
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- <in>
|
|
||||||
- <out>
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
- <change summary>
|
|
||||||
|
|
||||||
## Validation
|
|
||||||
- <test/check 1>
|
|
||||||
- <test/check 2>
|
|
||||||
|
|
||||||
## Decision Links
|
|
||||||
- ADR: `ADR-0001`
|
|
||||||
|
|
||||||
## Follow-ups
|
|
||||||
- [BG-001] <follow-up item>
|
|
||||||
-115
@@ -1,115 +0,0 @@
|
|||||||
# Memory Bank v2 System Prompt
|
|
||||||
|
|
||||||
You are an expert software engineer with zero session memory between runs.
|
|
||||||
Your only reliable continuity is the project Memory Bank. Maintain it with
|
|
||||||
strict structure, minimal duplication, and strong audit traceability.
|
|
||||||
|
|
||||||
## Objectives
|
|
||||||
|
|
||||||
1. Fast context load for any task.
|
|
||||||
2. Maximum useful coverage without bloated core files.
|
|
||||||
3. Strong audit trail across decisions and execution history.
|
|
||||||
4. Safe reuse of external project references and imported documentation.
|
|
||||||
|
|
||||||
## Required Contract
|
|
||||||
|
|
||||||
Use this layout under `memory-bank/`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
memory-bank/
|
|
||||||
00_project_snapshot.md
|
|
||||||
10_scope.md
|
|
||||||
11_product.md
|
|
||||||
12_architecture.md
|
|
||||||
13_tech.md
|
|
||||||
20_now.md
|
|
||||||
21_backlog.md
|
|
||||||
references/
|
|
||||||
...
|
|
||||||
decisions/
|
|
||||||
ADR-*.md
|
|
||||||
logs/
|
|
||||||
tasks/YYYY/MM/*.md
|
|
||||||
digests/YYYY-MM.md
|
|
||||||
```
|
|
||||||
|
|
||||||
If a required file is missing, create a minimal stub immediately.
|
|
||||||
|
|
||||||
## Layered Read Protocol
|
|
||||||
|
|
||||||
At the start of every task:
|
|
||||||
|
|
||||||
1. Always read Layer 0: `00_project_snapshot.md`, `20_now.md`, `21_backlog.md`.
|
|
||||||
2. Read Layer 1 only when needed:
|
|
||||||
|
|
||||||
* Product intent: `11_product.md`
|
|
||||||
* Scope and goals: `10_scope.md`
|
|
||||||
* Architecture: `12_architecture.md`
|
|
||||||
* Tech/runtime/tooling: `13_tech.md`
|
|
||||||
3. Read Layer 1.5 only when external reference context is needed:
|
|
||||||
|
|
||||||
* Imported external framework or library documentation: `references/**`
|
|
||||||
* External project materials used as implementation reference: `references/**`
|
|
||||||
4. Read Layer 2 only when evidence is required:
|
|
||||||
|
|
||||||
* Rationale and permanent decisions: `decisions/ADR-*.md`
|
|
||||||
* Execution history and outcomes: `logs/tasks/...`, `logs/digests/...`
|
|
||||||
|
|
||||||
Do not read all files by default. Expand only when the task requires it.
|
|
||||||
|
|
||||||
## Reference Rules
|
|
||||||
|
|
||||||
1. `memory-bank/references/` is reserved only for external project references and imported documentation.
|
|
||||||
2. Examples include framework docs, library usage guides, API references, vendor docs, and selected external project materials.
|
|
||||||
3. Unless the user explicitly says otherwise, everything under `memory-bank/references/` is read-only for the AI/LLM.
|
|
||||||
4. Read-only means the AI/LLM must not create, modify, move, rename, summarize-overwrite, or delete files in `references/` unless the user explicitly authorizes it.
|
|
||||||
5. The AI/LLM may read and cite `references/` when relevant.
|
|
||||||
6. When project implementation depends on an external framework or tool, prefer `references/` as the authoritative source for that external behavior, while keeping project-specific decisions and adaptations inside the normal Memory Bank files.
|
|
||||||
|
|
||||||
## Write Protocol
|
|
||||||
|
|
||||||
1. Core files are `current truth only`.
|
|
||||||
2. Never keep changelog-style history inside core files.
|
|
||||||
3. Historical details belong only in `decisions/` and `logs/`.
|
|
||||||
4. Every non-trivial decision gets an ADR (or updates an existing ADR).
|
|
||||||
5. Every significant execution step gets a task log entry.
|
|
||||||
6. Prefer linking IDs (`ADR-xxxx`, `TASK-...`) instead of copying content.
|
|
||||||
7. Never write into `references/` unless the user explicitly instructs you to do so.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
When the user says `update memory bank`:
|
|
||||||
|
|
||||||
1. Re-read all core files and recently relevant ADR/task logs.
|
|
||||||
2. Re-read relevant files under `references/` only if external reference context affects current truth.
|
|
||||||
3. Refresh core files to reflect current truth.
|
|
||||||
4. Run consistency checks (links, IDs, stale sections, budget limits).
|
|
||||||
5. Add or update ADRs and task logs when needed.
|
|
||||||
6. Do not modify `references/` unless explicitly authorized by the user.
|
|
||||||
|
|
||||||
When the user says `compact memory bank`:
|
|
||||||
|
|
||||||
1. Enforce hard size budgets from `memory-bank-v2/SCHEMA.md`.
|
|
||||||
2. Move old details out of core files into ADR/log references.
|
|
||||||
3. Summarize `90+` day task history into monthly digests in `logs/digests/`.
|
|
||||||
4. Keep core files concise and decision-ready.
|
|
||||||
5. Do not compact, rewrite, or prune `references/` unless explicitly authorized by the user.
|
|
||||||
|
|
||||||
## Guardrails
|
|
||||||
|
|
||||||
1. No changelog sections in core files (`10_*` through `21_*`).
|
|
||||||
2. No duplicated long-form text across core files.
|
|
||||||
3. No orphan IDs: all ADR/task references must resolve to real files.
|
|
||||||
4. If uncertain, record assumptions explicitly in `20_now.md`.
|
|
||||||
5. Do not treat `references/` as a workspace for generated project memory.
|
|
||||||
6. Do not copy large amounts of external documentation into core files; extract only project-relevant conclusions, constraints, and decisions.
|
|
||||||
|
|
||||||
## Formatting and Language
|
|
||||||
|
|
||||||
1. File names stay in English.
|
|
||||||
2. Content can be English or Turkish.
|
|
||||||
3. Keep entries concise and scannable.
|
|
||||||
|
|
||||||
Detailed budgets, templates, operations, and migration guidance are in:
|
|
||||||
`memory-bank-v2/SCHEMA.md`, `memory-bank-v2/TEMPLATES.md`,
|
|
||||||
`memory-bank-v2/OPERATIONS.md`, and `memory-bank-v2/MIGRATION_PLAYBOOK.md`.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# Scripts
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
- `release/`
|
|
||||||
- `package-velopack.ps1`: Gitea version guard + build + package release assets + optional Authenticode signing + installer icon
|
|
||||||
- `upload-feed.ps1`: `vpk upload gitea` ile Gitea Releases'e hedefli upload
|
|
||||||
- `version/`
|
|
||||||
- `bump-version.ps1`: bump `major.minor.patch` version fields in the app project
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
- .NET 8 SDK (`actions/setup-dotnet` CI'da kurar, localde PATH'te `dotnet` olmali)
|
|
||||||
- Repo-local `vpk` tool: `dotnet tool restore` (manifest: `.config/dotnet-tools.json`, vpk 0.0.1298)
|
|
||||||
|
|
||||||
## Common Commands
|
|
||||||
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/version/bump-version.ps1 -Patch`
|
|
||||||
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/version/bump-version.ps1 -Minor`
|
|
||||||
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/version/bump-version.ps1 -Major`
|
|
||||||
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/package-velopack.ps1 -SkipSigning`
|
|
||||||
- `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/package-velopack.ps1 -PfxPath <cert.pfx>`
|
|
||||||
- `$env:VPK_TOKEN = "<gitea-token>"; powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/release/upload-feed.ps1`
|
|
||||||
|
|
||||||
## Signing
|
|
||||||
- Authenticode signing varsayilan olarak **pasif**: `-PfxPath` verilmezse uyariyla atlanir.
|
|
||||||
- Acmak icin `-PfxPath <cert.pfx>` ver; PFX sifresi interaktif sorulur, script icinde saklanmaz.
|
|
||||||
- Timestamp (TSA) kullanilmiyor; gerekirse global bir TSA servisiyle `-SignToolPath` akisina eklenebilir.
|
|
||||||
- v0.3.0 stratejisi: GPG imzali git tag + Gitea release hash'leri yeterli.
|
|
||||||
|
|
||||||
## Packaging Guard
|
|
||||||
- `scripts/release/package-velopack.ps1` Gitea Releases API uzerinden cloud surumu kontrol eder.
|
|
||||||
- Gitea'da ayni surum (tag `v<version>`) varsa paketleme durdurulur.
|
|
||||||
- Gitea'daki surum daha yuksekse paketleme durdurulur.
|
|
||||||
- API'ye erisilemiyorsa fail-fast durur; offline paketleme icin `-SkipCloudCheck` kullanilabilir.
|
|
||||||
- Varsayilan installer ikonu `src/RgbLedStripController/Assets/AppIcon.ico` dosyasindan `vpk pack --icon` ile verilir.
|
|
||||||
|
|
||||||
## Upload Guard
|
|
||||||
- `scripts/release/upload-feed.ps1` yerel release manifest'ini okur, `full/delta .nupkg` + `Setup.exe` / `Portable.zip` varligini preflight olarak dogrular.
|
|
||||||
- `-Token` verilmezse `VPK_TOKEN` env kullanilir; ikisi de yoksa durur.
|
|
||||||
- Hedef tag (`v<version>`) Gitea'da varsa upload durdurulur (`-Merge` ile mevcut release'e birlestirilebilir).
|
|
||||||
- `-ExpectedTag` verilirse turetilen tag ile karsilastirilir (CI'da tag/csproj tutarliligi icin).
|
|
||||||
- `-WhatIf` ile dry-run yapilabilir.
|
|
||||||
- Basarili oldugunda Gitea release linkini ekrana yazar.
|
|
||||||
|
|
||||||
## CI (Gitea Actions)
|
|
||||||
- Workflow: `.gitea/workflows/ci.yml` — `build`, `test`, `release` job'lari.
|
|
||||||
- `windows` etiketli runner gerekir (WPF sadece Windows'ta derlenir).
|
|
||||||
- NuGet cache adimi `continue-on-error: true` — cache servisi yoksa build kirilmaz.
|
|
||||||
- `release` job'u sadece `v*` tag'lerinde calisir, `-SkipSigning` ile paketler.
|
|
||||||
- Gerekli repo secret: `VPK_TOKEN` (Gitea API token, release yazma yetkili).
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
[CmdletBinding()]
|
|
||||||
param(
|
|
||||||
[string]$Project = "src/RgbLedStripController/RgbLedStripController.csproj",
|
|
||||||
[string]$Configuration = "Release",
|
|
||||||
[string]$Runtime = "win-x64",
|
|
||||||
[string]$Channel = "win-x64-stable",
|
|
||||||
[string]$PackId = "Fristy.RgbLedStripController",
|
|
||||||
[string]$PackTitle = "RGB Led Strip Controller",
|
|
||||||
[string]$PackAuthors = "fristy",
|
|
||||||
[string]$GiteaRepoUrl = "https://git.fristy.net/fristy/rgb-led-strip-controller",
|
|
||||||
[string]$InstallerIcon = "src/RgbLedStripController/Assets/AppIcon.ico",
|
|
||||||
[string]$PfxPath = "",
|
|
||||||
[string]$SignToolPath = "signtool.exe",
|
|
||||||
[int]$SignParallel = 1,
|
|
||||||
[switch]$SkipSigning,
|
|
||||||
[switch]$SkipCloudCheck
|
|
||||||
)
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
Set-StrictMode -Version Latest
|
|
||||||
|
|
||||||
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
|
|
||||||
$projectPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot $Project))
|
|
||||||
$nugetConfigPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot "NuGet.Config"))
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath $projectPath)) {
|
|
||||||
throw "Project file not found: $projectPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
[xml]$projectXml = Get-Content -Raw -LiteralPath $projectPath
|
|
||||||
$versionNode = $null
|
|
||||||
foreach ($propertyGroup in @($projectXml.Project.PropertyGroup)) {
|
|
||||||
if ($propertyGroup.PSObject.Properties.Name -contains "Version" -and -not [string]::IsNullOrWhiteSpace($propertyGroup.Version)) {
|
|
||||||
$versionNode = $propertyGroup.Version
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = [string]$versionNode
|
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($version)) {
|
|
||||||
throw "No <Version> found in project file: $projectPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
function Assert-WorkspacePath {
|
|
||||||
param([string]$Path)
|
|
||||||
|
|
||||||
$fullPath = [System.IO.Path]::GetFullPath($Path)
|
|
||||||
if (-not $fullPath.StartsWith($repoRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
||||||
throw "Refusing to use path outside workspace: $fullPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
return $fullPath
|
|
||||||
}
|
|
||||||
|
|
||||||
function Resolve-AbsolutePath {
|
|
||||||
param([string]$Path)
|
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($Path)) {
|
|
||||||
throw "Path value cannot be empty."
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([System.IO.Path]::IsPathRooted($Path)) {
|
|
||||||
return [System.IO.Path]::GetFullPath($Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [System.IO.Path]::GetFullPath((Join-Path $repoRoot $Path))
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-GiteaReleaseTags {
|
|
||||||
param([string]$RepoUrl)
|
|
||||||
|
|
||||||
$uri = [Uri]$RepoUrl
|
|
||||||
$segments = $uri.AbsolutePath.Trim("/").Split("/") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
|
||||||
if ($segments.Count -lt 2) {
|
|
||||||
throw "Could not parse owner/repo from GiteaRepoUrl: $RepoUrl"
|
|
||||||
}
|
|
||||||
|
|
||||||
$owner = $segments[-2]
|
|
||||||
$repo = $segments[-1]
|
|
||||||
$apiUrl = "{0}://{1}/api/v1/repos/{2}/{3}/releases?draft=false&limit=50" -f $uri.Scheme, $uri.Authority, $owner, $repo
|
|
||||||
|
|
||||||
try {
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
$releases = Invoke-RestMethod -Uri $apiUrl -Method Get -ErrorAction Stop
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
throw "Gitea releases could not be read: $apiUrl`n$($_.Exception.Message)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return @($releases | ForEach-Object { $_.tag_name } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-MaxVersionFromTags {
|
|
||||||
param([string[]]$Tags)
|
|
||||||
|
|
||||||
$versions = @()
|
|
||||||
foreach ($tag in $Tags) {
|
|
||||||
$clean = $tag.TrimStart("v", "V")
|
|
||||||
$parsed = $null
|
|
||||||
if ([Version]::TryParse($clean, [ref]$parsed)) {
|
|
||||||
$versions += $parsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($versions.Count -eq 0) {
|
|
||||||
return $null
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($versions | Sort-Object -Descending | Select-Object -First 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Read-SecretAsPlainText {
|
|
||||||
param([string]$Prompt)
|
|
||||||
|
|
||||||
$secureString = Read-Host -Prompt $Prompt -AsSecureString
|
|
||||||
if ($secureString.Length -eq 0) {
|
|
||||||
throw "Empty password is not allowed."
|
|
||||||
}
|
|
||||||
|
|
||||||
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
|
|
||||||
try {
|
|
||||||
return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if ($bstr -ne [IntPtr]::Zero) {
|
|
||||||
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Resolve-SignToolExecutable {
|
|
||||||
param([string]$RequestedPath)
|
|
||||||
|
|
||||||
if (Test-Path -LiteralPath $RequestedPath) {
|
|
||||||
return [System.IO.Path]::GetFullPath($RequestedPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
$command = Get-Command -Name $RequestedPath -ErrorAction SilentlyContinue
|
|
||||||
if ($null -ne $command) {
|
|
||||||
return $command.Source
|
|
||||||
}
|
|
||||||
|
|
||||||
throw "signtool.exe could not be resolved. Pass -SignToolPath with an absolute path if needed."
|
|
||||||
}
|
|
||||||
|
|
||||||
$publishDir = Assert-WorkspacePath (Join-Path $repoRoot "artifacts\publish\$Runtime\$version")
|
|
||||||
$releaseDir = Assert-WorkspacePath (Join-Path $repoRoot "artifacts\velopack\$Channel")
|
|
||||||
$mainExe = "RgbLedStripController.exe"
|
|
||||||
$dotnet = "dotnet"
|
|
||||||
$signingEnabled = (-not $SkipSigning.IsPresent) -and (-not [string]::IsNullOrWhiteSpace($PfxPath))
|
|
||||||
if ((-not $SkipSigning.IsPresent) -and [string]::IsNullOrWhiteSpace($PfxPath)) {
|
|
||||||
Write-Warning "PfxPath not supplied; Authenticode signing will be skipped. Pass -PfxPath to enable it."
|
|
||||||
}
|
|
||||||
$signToolExecutable = $null
|
|
||||||
$signToolDirectory = $null
|
|
||||||
$plainPassword = $null
|
|
||||||
$resolvedPfxPath = $null
|
|
||||||
$resolvedInstallerIconPath = Resolve-AbsolutePath -Path $InstallerIcon
|
|
||||||
$signParams = $null
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath $resolvedInstallerIconPath)) {
|
|
||||||
throw "Installer icon file not found: $resolvedInstallerIconPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$env:DOTNET_CLI_HOME = Join-Path $repoRoot ".dotnet"
|
|
||||||
$env:APPDATA = Join-Path $repoRoot ".appdata"
|
|
||||||
$env:NUGET_PACKAGES = Join-Path $repoRoot ".nuget\packages"
|
|
||||||
$env:NUGET_HTTP_CACHE_PATH = Join-Path $repoRoot ".nuget\http-cache"
|
|
||||||
|
|
||||||
$localVersion = [Version]$version
|
|
||||||
$cloudVersion = $null
|
|
||||||
if (-not $SkipCloudCheck.IsPresent) {
|
|
||||||
$cloudVersion = Get-MaxVersionFromTags -Tags (Get-GiteaReleaseTags -RepoUrl $GiteaRepoUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($null -ne $cloudVersion) {
|
|
||||||
if ($localVersion -lt $cloudVersion) {
|
|
||||||
throw "Local version $version is older than Gitea version $cloudVersion. Bump the project version before packaging."
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($localVersion -eq $cloudVersion) {
|
|
||||||
throw "Gitea already contains version $version. Packaging with the same version is blocked."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($signingEnabled) {
|
|
||||||
$resolvedPfxPath = Resolve-AbsolutePath -Path $PfxPath
|
|
||||||
if (-not (Test-Path -LiteralPath $resolvedPfxPath)) {
|
|
||||||
throw "PFX file not found: $resolvedPfxPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($SignParallel -lt 1) {
|
|
||||||
throw "SignParallel must be at least 1."
|
|
||||||
}
|
|
||||||
|
|
||||||
$signToolExecutable = Resolve-SignToolExecutable -RequestedPath $SignToolPath
|
|
||||||
$signToolDirectory = Split-Path -Parent $signToolExecutable
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($signToolDirectory)) {
|
|
||||||
$env:PATH = $signToolDirectory + [System.IO.Path]::PathSeparator + $env:PATH
|
|
||||||
}
|
|
||||||
|
|
||||||
$plainPassword = Read-SecretAsPlainText -Prompt "PFX password"
|
|
||||||
$signParams = "/fd SHA256 /f `"$resolvedPfxPath`" /p `"$plainPassword`""
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -LiteralPath $publishDir) {
|
|
||||||
Remove-Item -LiteralPath $publishDir -Recurse -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
New-Item -ItemType Directory -Force -Path $publishDir | Out-Null
|
|
||||||
New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null
|
|
||||||
|
|
||||||
$publishArgs = @(
|
|
||||||
"publish",
|
|
||||||
$projectPath,
|
|
||||||
"-c", $Configuration,
|
|
||||||
"-r", $Runtime,
|
|
||||||
"--self-contained", "true",
|
|
||||||
"-p:PublishSingleFile=true",
|
|
||||||
"-o", $publishDir,
|
|
||||||
"--configfile", $nugetConfigPath
|
|
||||||
)
|
|
||||||
|
|
||||||
& $dotnet @publishArgs
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
|
||||||
throw "dotnet publish failed with exit code $LASTEXITCODE"
|
|
||||||
}
|
|
||||||
|
|
||||||
$packArgs = @(
|
|
||||||
"tool", "run", "vpk", "--",
|
|
||||||
"pack",
|
|
||||||
"--packId", $PackId,
|
|
||||||
"--packVersion", $version,
|
|
||||||
"--packDir", $publishDir,
|
|
||||||
"--mainExe", $mainExe,
|
|
||||||
"--packTitle", $PackTitle,
|
|
||||||
"--packAuthors", $PackAuthors,
|
|
||||||
"--runtime", $Runtime,
|
|
||||||
"--channel", $Channel,
|
|
||||||
"--icon", $resolvedInstallerIconPath,
|
|
||||||
"--outputDir", $releaseDir
|
|
||||||
)
|
|
||||||
|
|
||||||
if ($signingEnabled) {
|
|
||||||
$packArgs += @(
|
|
||||||
"--signParams", $signParams,
|
|
||||||
"--signParallel", $SignParallel.ToString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
& $dotnet @packArgs
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
|
||||||
throw "vpk pack failed with exit code $LASTEXITCODE"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Velopack package build complete." -ForegroundColor Green
|
|
||||||
Write-Host "Version: $version"
|
|
||||||
Write-Host "Gitea: $(if ($null -ne $cloudVersion) { $cloudVersion.ToString() } else { 'none' })"
|
|
||||||
Write-Host "Signing: $(if ($signingEnabled) { 'enabled' } else { 'skipped' })"
|
|
||||||
if ($signingEnabled -and -not [string]::IsNullOrWhiteSpace($signToolExecutable)) {
|
|
||||||
Write-Host "SignTool: $signToolExecutable"
|
|
||||||
}
|
|
||||||
Write-Host "Icon: $resolvedInstallerIconPath"
|
|
||||||
Write-Host "PublishDir: $publishDir"
|
|
||||||
Write-Host "ReleaseDir: $releaseDir"
|
|
||||||
Write-Host "Gitea repo: $GiteaRepoUrl"
|
|
||||||
Write-Host "Tag: v$version"
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Upload with: scripts/release/upload-feed.ps1 (vpk upload gitea)." -ForegroundColor Yellow
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
||||||
param(
|
|
||||||
[string]$Channel = "win-x64-stable",
|
|
||||||
[string]$GiteaRepoUrl = "https://git.fristy.net/fristy/rgb-led-strip-controller",
|
|
||||||
[string]$Tag = "",
|
|
||||||
[string]$Token = $env:VPK_TOKEN,
|
|
||||||
[string]$ExpectedTag = "",
|
|
||||||
[switch]$Prerelease,
|
|
||||||
[switch]$Merge
|
|
||||||
)
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
Set-StrictMode -Version Latest
|
|
||||||
|
|
||||||
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
|
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($Token)) {
|
|
||||||
throw "Gitea token is required. Pass -Token or set the VPK_TOKEN environment variable."
|
|
||||||
}
|
|
||||||
|
|
||||||
function Assert-WorkspacePath {
|
|
||||||
param([string]$Path)
|
|
||||||
|
|
||||||
$fullPath = [System.IO.Path]::GetFullPath($Path)
|
|
||||||
if (-not $fullPath.StartsWith($repoRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
||||||
throw "Refusing to use path outside workspace: $fullPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
return $fullPath
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-GiteaReleaseTagNames {
|
|
||||||
param(
|
|
||||||
[string]$RepoUrl,
|
|
||||||
[string]$AccessToken
|
|
||||||
)
|
|
||||||
|
|
||||||
$uri = [Uri]$RepoUrl
|
|
||||||
$segments = $uri.AbsolutePath.Trim("/").Split("/") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
|
||||||
if ($segments.Count -lt 2) {
|
|
||||||
throw "Could not parse owner/repo from GiteaRepoUrl: $RepoUrl"
|
|
||||||
}
|
|
||||||
|
|
||||||
$owner = $segments[-2]
|
|
||||||
$repo = $segments[-1]
|
|
||||||
$apiUrl = "{0}://{1}/api/v1/repos/{2}/{3}/releases?draft=false&limit=50" -f $uri.Scheme, $uri.Authority, $owner, $repo
|
|
||||||
|
|
||||||
try {
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
$headers = @{ Authorization = "token $AccessToken" }
|
|
||||||
$releases = Invoke-RestMethod -Uri $apiUrl -Method Get -Headers $headers -ErrorAction Stop
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
throw "Gitea releases could not be read: $apiUrl`n$($_.Exception.Message)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return @($releases | ForEach-Object { $_.tag_name } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
||||||
}
|
|
||||||
|
|
||||||
$releaseDir = Assert-WorkspacePath (Join-Path $repoRoot "artifacts\velopack\$Channel")
|
|
||||||
$manifestPath = Join-Path $releaseDir "releases.$Channel.json"
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath $releaseDir)) {
|
|
||||||
throw "Release directory not found: $releaseDir"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath $manifestPath)) {
|
|
||||||
throw "Release manifest not found: $manifestPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$localManifest = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json
|
|
||||||
if ($null -eq $localManifest.Assets -or $localManifest.Assets.Count -eq 0) {
|
|
||||||
throw "Release manifest does not contain any assets: $manifestPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$packageId = $localManifest.Assets[0].PackageId
|
|
||||||
$localVersions = @(
|
|
||||||
$localManifest.Assets |
|
|
||||||
Where-Object { $_.PackageId -eq $packageId -and -not [string]::IsNullOrWhiteSpace($_.Version) } |
|
|
||||||
ForEach-Object { [Version]$_.Version }
|
|
||||||
)
|
|
||||||
if ($localVersions.Count -eq 0) {
|
|
||||||
throw "Could not determine local package version from: $manifestPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$localVersion = ($localVersions | Sort-Object -Descending | Select-Object -First 1)
|
|
||||||
$tag = if ([string]::IsNullOrWhiteSpace($Tag)) { "v$($localVersion.ToString())" } else { $Tag }
|
|
||||||
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($ExpectedTag) -and -not [string]::Equals($tag, $ExpectedTag, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
||||||
throw "Derived tag $tag does not match expected tag $ExpectedTag. Check the pushed tag against the project version."
|
|
||||||
}
|
|
||||||
|
|
||||||
$setupFiles = @(Get-ChildItem -LiteralPath $releaseDir -Filter "*-Setup.exe" -File)
|
|
||||||
$portableFiles = @(Get-ChildItem -LiteralPath $releaseDir -Filter "*-Portable.zip" -File)
|
|
||||||
if ($setupFiles.Count -eq 0) {
|
|
||||||
throw "No Setup.exe file found in release directory: $releaseDir"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($portableFiles.Count -eq 0) {
|
|
||||||
throw "No Portable.zip file found in release directory: $releaseDir"
|
|
||||||
}
|
|
||||||
|
|
||||||
$existingTags = Get-GiteaReleaseTagNames -RepoUrl $GiteaRepoUrl -AccessToken $Token
|
|
||||||
if ($existingTags -contains $tag -and -not $Merge.IsPresent) {
|
|
||||||
throw "Gitea already contains tag $tag. Upload is blocked (pass -Merge to merge into the existing release)."
|
|
||||||
}
|
|
||||||
|
|
||||||
$releaseUrl = $GiteaRepoUrl.TrimEnd("/") + "/releases/tag/" + $tag
|
|
||||||
$vpkArgs = @(
|
|
||||||
"tool", "run", "vpk", "--",
|
|
||||||
"upload", "gitea",
|
|
||||||
"--outputDir", $releaseDir,
|
|
||||||
"--channel", $Channel,
|
|
||||||
"--repoUrl", $GiteaRepoUrl,
|
|
||||||
"--token", $Token,
|
|
||||||
"--tag", $tag,
|
|
||||||
"--publish"
|
|
||||||
)
|
|
||||||
if ($Prerelease.IsPresent) {
|
|
||||||
$vpkArgs += "--pre"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Merge.IsPresent) {
|
|
||||||
$vpkArgs += "--merge"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($PSCmdlet.ShouldProcess("$GiteaRepoUrl@$tag", "Upload Velopack release")) {
|
|
||||||
& "dotnet" @vpkArgs
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
|
||||||
throw "vpk upload failed with exit code $LASTEXITCODE"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Velopack feed upload complete." -ForegroundColor Green
|
|
||||||
Write-Host "Version: $($localVersion.ToString())"
|
|
||||||
Write-Host "Tag: $tag"
|
|
||||||
Write-Host "Channel: $Channel"
|
|
||||||
Write-Host "ReleaseDir: $releaseDir"
|
|
||||||
Write-Host "Release: $releaseUrl"
|
|
||||||
Write-Host "Prerelease: $(if ($Prerelease.IsPresent) { 'yes' } else { 'no' })"
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
[CmdletBinding(DefaultParameterSetName = "Patch")]
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "Major")]
|
|
||||||
[switch]$Major,
|
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "Minor")]
|
|
||||||
[switch]$Minor,
|
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "Patch")]
|
|
||||||
[switch]$Patch,
|
|
||||||
|
|
||||||
[string]$Project = "src/RgbLedStripController/RgbLedStripController.csproj"
|
|
||||||
)
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
Set-StrictMode -Version Latest
|
|
||||||
|
|
||||||
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
|
|
||||||
$projectPath = if ([System.IO.Path]::IsPathRooted($Project)) {
|
|
||||||
$Project
|
|
||||||
} else {
|
|
||||||
Join-Path $repoRoot $Project
|
|
||||||
}
|
|
||||||
|
|
||||||
$projectPath = [System.IO.Path]::GetFullPath($projectPath)
|
|
||||||
if (-not (Test-Path -LiteralPath $projectPath)) {
|
|
||||||
throw "Project file not found: $projectPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = Get-Content -Raw -LiteralPath $projectPath
|
|
||||||
$versionMatch = [System.Text.RegularExpressions.Regex]::Match($content, "<Version>(?<value>\d+\.\d+\.\d+)</Version>")
|
|
||||||
if (-not $versionMatch.Success) {
|
|
||||||
throw "No semantic <Version> value found in project file: $projectPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentVersion = $versionMatch.Groups["value"].Value
|
|
||||||
$parts = $currentVersion.Split(".") | ForEach-Object { [int]$_ }
|
|
||||||
|
|
||||||
$newVersion = switch ($PSCmdlet.ParameterSetName) {
|
|
||||||
"Major" { "{0}.0.0" -f ($parts[0] + 1) }
|
|
||||||
"Minor" { "{0}.{1}.0" -f $parts[0], ($parts[1] + 1) }
|
|
||||||
default { "{0}.{1}.{2}" -f $parts[0], $parts[1], ($parts[2] + 1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
$newAssemblyVersion = "$newVersion.0"
|
|
||||||
|
|
||||||
function Replace-FirstMatch {
|
|
||||||
param(
|
|
||||||
[string]$Text,
|
|
||||||
[string]$Pattern,
|
|
||||||
[string]$Replacement
|
|
||||||
)
|
|
||||||
|
|
||||||
$regex = [System.Text.RegularExpressions.Regex]::new($Pattern)
|
|
||||||
return $regex.Replace($Text, $Replacement, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = Replace-FirstMatch $content "<Version>[^<]+</Version>" "<Version>$newVersion</Version>"
|
|
||||||
$content = Replace-FirstMatch $content "<AssemblyVersion>[^<]+</AssemblyVersion>" "<AssemblyVersion>$newAssemblyVersion</AssemblyVersion>"
|
|
||||||
$content = Replace-FirstMatch $content "<FileVersion>[^<]+</FileVersion>" "<FileVersion>$newAssemblyVersion</FileVersion>"
|
|
||||||
$content = Replace-FirstMatch $content "<InformationalVersion>[^<]+</InformationalVersion>" "<InformationalVersion>$newVersion</InformationalVersion>"
|
|
||||||
|
|
||||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
|
||||||
[System.IO.File]::WriteAllText($projectPath, $content, $utf8NoBom)
|
|
||||||
|
|
||||||
Write-Host ("Version updated: {0} -> {1}" -f $currentVersion, $newVersion) -ForegroundColor Green
|
|
||||||
Write-Host ("Project file: {0}" -f $projectPath)
|
|
||||||
Reference in new issue
Block a user