diff --git a/.gitignore b/.gitignore index 0d3538e..e5e34d9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ venv/ # Real device check logs logs/real_device/ +# Temporary PR body +pr_body.md + diff --git a/README.md b/README.md index 5e89409..56b212e 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,16 @@ PR本文テンプレートを表示、またはファイルへ保存します。 これらのスクリプトは実機通信、`real_device_check.py`、`git push`、PR作成、mergeを自動実行しません。 +PR作業の開始、公開準備、merge後の同期を補助します。 + +```powershell +.\scripts\new_task.ps1 -Branch codex/example-task +.\scripts\publish_pr.ps1 -Message "Add PR helper scripts" -Title "Add PR helper scripts" +.\scripts\sync_after_merge.ps1 -Branch codex/example-task +``` + +`publish_pr.ps1` は確認後に `git commit` と `git push` を実行します。PR作成とmergeは自動実行しません。 + ## mock TCPサーバーの使い方 UTRリーダライタ実機の代わりに、localhost 上で mock TCPサーバーを起動できます。 diff --git a/scripts/new_task.ps1 b/scripts/new_task.ps1 new file mode 100644 index 0000000..2f61be4 --- /dev/null +++ b/scripts/new_task.ps1 @@ -0,0 +1,61 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Branch +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") + +function Invoke-Step { + param( + [Parameter(Mandatory = $true)] + [string]$Title, + + [Parameter(Mandatory = $true)] + [scriptblock]$Command + ) + + Write-Host "" + Write-Host "== $Title ==" + $global:LASTEXITCODE = 0 + & $Command + if ($LASTEXITCODE -ne 0) { + throw "$Title failed with exit code $LASTEXITCODE" + } +} + +Push-Location $repoRoot +try { + $changes = git status --porcelain + if ($changes) { + Write-Host "ERROR: Uncommitted changes exist. Commit or stash them before creating a new task branch." -ForegroundColor Red + git status --short + exit 1 + } + + git show-ref --verify --quiet "refs/heads/$Branch" + if ($LASTEXITCODE -eq 0) { + Write-Host "ERROR: Branch already exists: $Branch" -ForegroundColor Red + exit 1 + } + + Invoke-Step "checkout main" { + git checkout main + } + + Invoke-Step "git pull" { + git pull + } + + Invoke-Step "create branch $Branch" { + git checkout -b $Branch + } + + Write-Host "" + Write-Host "Created and switched to branch: $Branch" +} +finally { + Pop-Location +} diff --git a/scripts/publish_pr.ps1 b/scripts/publish_pr.ps1 new file mode 100644 index 0000000..9313a47 --- /dev/null +++ b/scripts/publish_pr.ps1 @@ -0,0 +1,162 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Message, + + [string]$Title, + + [string[]]$Paths +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +if (-not $Title) { + $Title = $Message +} + +function Invoke-Step { + param( + [Parameter(Mandatory = $true)] + [string]$TitleText, + + [Parameter(Mandatory = $true)] + [scriptblock]$Command + ) + + Write-Host "" + Write-Host "== $TitleText ==" + $global:LASTEXITCODE = 0 + & $Command + if ($LASTEXITCODE -ne 0) { + throw "$TitleText failed with exit code $LASTEXITCODE" + } +} + +function Get-PullRequestUrl { + param( + [Parameter(Mandatory = $true)] + [string]$Branch, + + [Parameter(Mandatory = $true)] + [string]$PrTitle + ) + + $remote = git remote get-url origin + if ($LASTEXITCODE -ne 0 -or -not $remote) { + return $null + } + + $ownerRepo = $null + if ($remote -match "github\.com[:/](?[^/]+/[^/.]+)(\.git)?$") { + $ownerRepo = $Matches["repo"] + } + + if (-not $ownerRepo) { + return $null + } + + $encodedBranch = [System.Uri]::EscapeDataString($Branch) + $encodedTitle = [System.Uri]::EscapeDataString($PrTitle) + return "https://github.com/$ownerRepo/compare/main...$encodedBranch" + "?expand=1&title=$encodedTitle" +} + +Push-Location $repoRoot +try { + $branch = git branch --show-current + if ($LASTEXITCODE -ne 0 -or -not $branch) { + Write-Host "ERROR: Could not determine current branch." -ForegroundColor Red + exit 1 + } + + if ($branch -eq "main") { + Write-Host "ERROR: Refusing to commit directly on main." -ForegroundColor Red + exit 1 + } + + $preflightScript = Join-Path $PSScriptRoot "git_preflight.ps1" + Invoke-Step "git_preflight.ps1" { + & $preflightScript + } + + $status = git status --short + Write-Host "" + Write-Host "== Pending changes ==" + if ($status) { + $status | ForEach-Object { Write-Host $_ } + } + else { + Write-Host "No pending changes." + } + + Write-Host "" + Write-Host "== Publish summary ==" + Write-Host "Branch: $branch" + Write-Host "Commit message: $Message" + Write-Host "PR title: $Title" + if ($Paths) { + Write-Host "git add target: specified paths" + $Paths | ForEach-Object { Write-Host " $_" } + } + else { + Write-Host "git add target: all changes (-A)" + } + + Write-Host "" + $answer = Read-Host "Type YES to run git add, git commit, and git push" + if ($answer -ne "YES") { + Write-Host "Canceled." + exit 1 + } + + if ($Paths) { + Invoke-Step "git add specified paths" { + git add -- $Paths + } + } + else { + Invoke-Step "git add -A" { + git add -A + } + } + + Invoke-Step "git commit" { + git commit -m $Message + } + + Invoke-Step "git push" { + git push -u origin $branch + } + + $bodyPath = Join-Path $repoRoot "pr_body.md" + $prBodyScript = Join-Path $PSScriptRoot "pr_body.ps1" + Invoke-Step "create pr_body.md" { + & $prBodyScript -OutputPath $bodyPath + } + + try { + if (Get-Command Set-Clipboard -ErrorAction SilentlyContinue) { + Get-Content -LiteralPath $bodyPath -Raw | Set-Clipboard + Write-Host "Copied pr_body.md to clipboard." + } + } + catch { + Write-Host "Could not copy pr_body.md to clipboard: $_" -ForegroundColor Yellow + } + + $url = Get-PullRequestUrl -Branch $branch -PrTitle $Title + Write-Host "" + if ($url) { + Write-Host "PR creation URL:" + Write-Host $url + } + else { + Write-Host "PR URLを推定できませんでした。GitHub上で手動作成してください" -ForegroundColor Yellow + } + + Write-Host "" + Write-Host "PR creation and merge were not automated." +} +finally { + Pop-Location +} diff --git a/scripts/sync_after_merge.ps1 b/scripts/sync_after_merge.ps1 new file mode 100644 index 0000000..c982495 --- /dev/null +++ b/scripts/sync_after_merge.ps1 @@ -0,0 +1,63 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Branch +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") + +function Invoke-Step { + param( + [Parameter(Mandatory = $true)] + [string]$Title, + + [Parameter(Mandatory = $true)] + [scriptblock]$Command + ) + + Write-Host "" + Write-Host "== $Title ==" + $global:LASTEXITCODE = 0 + & $Command + if ($LASTEXITCODE -ne 0) { + throw "$Title failed with exit code $LASTEXITCODE" + } +} + +if ($Branch -eq "main") { + Write-Host "ERROR: Refusing to delete main." -ForegroundColor Red + exit 1 +} + +Push-Location $repoRoot +try { + Write-Host "Branch to delete locally: $Branch" + Write-Host "This uses git branch -d only. It will not delete the branch on GitHub." + $answer = Read-Host "Type YES to checkout main, pull, delete the local branch, and run dev_check" + if ($answer -ne "YES") { + Write-Host "Canceled." + exit 1 + } + + Invoke-Step "checkout main" { + git checkout main + } + + Invoke-Step "git pull" { + git pull + } + + Invoke-Step "delete local branch $Branch" { + git branch -d $Branch + } + + $devCheckScript = Join-Path $PSScriptRoot "dev_check.ps1" + Invoke-Step "dev_check.ps1" { + & $devCheckScript + } +} +finally { + Pop-Location +}