Conversation
There was a problem hiding this comment.
Pull request overview
Adds a Windows Scheduled Task setup script and a daily runner script intended to automate GitHub “activity” actions (commit, issue, PR, review, merge) across a rotating set of repositories.
Changes:
- Introduces
setup-automation.ps1to register/update a daily Scheduled Task at a configurable time. - Introduces
daily-activity.ps1to perform git + GitHub CLI actions against a rotating repo list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 14 comments.
| File | Description |
|---|---|
| setup-automation.ps1 | Creates/updates a Scheduled Task to run the daily activity script on a schedule. |
| daily-activity.ps1 | Implements the daily workflow (clone/pull, commit, create issue/PR, approve, merge). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $principal = New-ScheduledTaskPrincipal ` | ||
| -UserId $env:USERNAME ` | ||
| -LogonType S4U ` | ||
| -RunLevel Highest |
There was a problem hiding this comment.
The task principal requests -RunLevel Highest. That can require admin privileges to register/run and may cause failures in non-elevated contexts; consider defaulting to LeastPrivilege (or making RunLevel configurable) unless elevation is truly required.
| # Pick 5 repos for today, rotating evenly by day of year | ||
| $r0 = $repos[($seed + 0) % $count] | ||
| $r1 = $repos[($seed + 1) % $count] | ||
| $r2 = $repos[($seed + 2) % $count] | ||
| $r3 = $repos[($seed + 3) % $count] | ||
| $r4 = $repos[($seed + 4) % $count] |
There was a problem hiding this comment.
$r3 and $r4 are computed as part of the “Pick 5 repos” rotation, but they’re never used (only r0/r1/r2 are acted on). This makes the output misleading and doesn’t match the PR description of 5 actions across rotating repos; either run Review/Merge against r3/r4 (if intended) or remove the extra repo selection/printing.
| try { git switch main 2>$null | Out-Null } catch {} | ||
| try { git pull --ff-only 2>&1 | Out-Null } catch {} | ||
| Pop-Location |
There was a problem hiding this comment.
Ensure-Cloned suppresses errors from git switch main / git pull and then returns $dir regardless. If switching/pulling fails (e.g., local changes, missing main, auth), later steps may create a PR from the wrong base or run in a stale repo state. Consider enforcing a known-good base (fetch + checkout/reset to origin/main) and failing fast when repo sync can’t be ensured.
| try { git switch main 2>$null | Out-Null } catch {} | |
| try { git pull --ff-only 2>&1 | Out-Null } catch {} | |
| Pop-Location | |
| try { | |
| if (-not $DryRun) { | |
| # Ensure local main matches origin/main; fail if this cannot be guaranteed | |
| git fetch origin 2>&1 | Out-Null | |
| git rev-parse --verify origin/main 2>&1 | Out-Null | |
| git checkout -B main origin/main 2>&1 | Out-Null | |
| } else { | |
| Write-Host " DryRun: skipping git fetch/reset for $Repo" | |
| } | |
| } finally { | |
| Pop-Location | |
| } |
| if (-not (Test-Path $dir)) { | ||
| Write-Host " Cloning $Repo..." | ||
| if (-not $DryRun) { | ||
| git clone "https://github.com/$Owner/$Repo.git" $dir 2>&1 | Out-Null |
There was a problem hiding this comment.
When cloning, the script discards git output and doesn’t check whether git clone succeeded before returning the directory. If clone fails, subsequent Push-Location/commands will error in less actionable ways; capture the result/exit code and throw a clear error when cloning fails.
| git clone "https://github.com/$Owner/$Repo.git" $dir 2>&1 | Out-Null | |
| $cloneOutput = git clone "https://github.com/$Owner/$Repo.git" $dir 2>&1 | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "Failed to clone repository '$Repo' into '$dir'. git exited with code $LASTEXITCODE.`nOutput:`n$cloneOutput" | |
| } |
| $url = gh pr create --repo "$Owner/$Repo" --base main --head $branch --title $msg --body $prBody 2>&1 | ||
| $PrUrl.Value = "$url" | ||
| # Extract PR number from URL | ||
| $PrNumber.Value = ($url -replace ".*/pull/", "").Trim() | ||
| Write-Host " PR: $url" | ||
| } finally { Pop-Location } | ||
| } |
There was a problem hiding this comment.
PR number parsing is brittle here: gh pr create output can include extra text/newlines, and the regex replacement may produce a non-numeric value. Prefer retrieving the PR number via structured output (gh JSON/query options) or by calling gh pr view on the created URL/branch to reliably obtain .number.
| $url = gh pr create --repo "$Owner/$Repo" --base main --head $branch --title $msg --body $prBody 2>&1 | |
| $PrUrl.Value = "$url" | |
| # Extract PR number from URL | |
| $PrNumber.Value = ($url -replace ".*/pull/", "").Trim() | |
| Write-Host " PR: $url" | |
| } finally { Pop-Location } | |
| } | |
| $prInfo = gh pr create --repo "$Owner/$Repo" --base main --head $branch --title $msg --body $prBody --json number,url | ConvertFrom-Json | |
| $PrUrl.Value = $prInfo.url | |
| $PrNumber.Value = [string]$prInfo.number | |
| Write-Host " PR: $($PrUrl.Value)" | |
| } finally { Pop-Location } | |
| } | |
| } |
| $title = Get-Rotating $issueTitles $Seed | ||
| $body = Get-Rotating $issueBodies $Seed | ||
| $url = gh issue create --repo "$Owner/$Repo" --title $title --body $body 2>&1 | ||
| Write-Host " Issue: $url" |
There was a problem hiding this comment.
gh issue create failures won’t be caught by try/catch in Windows PowerShell unless you check the exit code. As written, errors captured into $url may be printed as if it were a valid issue URL. Validate $LASTEXITCODE and fail with a clear message when gh returns non-zero.
| $body = $reviewBodies[(Get-Date).DayOfYear % $reviewBodies.Count] | ||
| gh pr review $PrNumber --repo "$Owner/$Repo" --approve --body $body 2>&1 | Out-Null | ||
| Write-Host " Approved PR #$PrNumber" |
There was a problem hiding this comment.
gh pr review can fail (auth, missing permissions, branch protections), but the script suppresses all output and doesn’t check $LASTEXITCODE. That can result in “Approved PR” being printed when no approval happened; check exit code and surface stderr/stdout when the command fails.
| git commit -m $msg 2>&1 | Out-Null | ||
| git push -u origin $branch 2>&1 | Out-Null | ||
| $prBody = "Automated maintenance PR - $(Get-Date -Format 'yyyy-MM-dd')`n`n- Routine log update`n- Part of daily maintenance cycle" | ||
| $url = gh pr create --repo "$Owner/$Repo" --base main --head $branch --title $msg --body $prBody 2>&1 | ||
| $PrUrl.Value = "$url" |
There was a problem hiding this comment.
In this PR flow, failures from git switch/commit/push and gh pr create won’t be caught reliably in Windows PowerShell, and output is mostly suppressed. This can leave a branch pushed without a PR (or vice versa) while the script continues. Check $LASTEXITCODE after each external command and abort/cleanup when a step fails.
| Write-Host "" | ||
| Write-Host "=== daily-activity.ps1 | $(Get-Date -Format 'yyyy-MM-dd HH:mm') ===" | ||
| Write-Host "" | ||
|
|
There was a problem hiding this comment.
This script assumes git and gh are installed and authenticated, but it doesn’t validate prerequisites before starting. Add explicit checks early (e.g., Get-Command git/gh and gh auth status) so the scheduled task fails fast with actionable output.
| # ─── Prerequisite checks: git, gh, and gh auth ─────────────────────────────── | |
| try { | |
| Get-Command git -ErrorAction Stop | Out-Null | |
| } catch { | |
| Write-Error "Required tool 'git' was not found in PATH. Please install Git and try again." | |
| exit 1 | |
| } | |
| try { | |
| Get-Command gh -ErrorAction Stop | Out-Null | |
| } catch { | |
| Write-Error "Required tool 'gh' (GitHub CLI) was not found in PATH. Install it from https://cli.github.com/ and try again." | |
| exit 1 | |
| } | |
| try { | |
| gh auth status 2>&1 | Out-Null | |
| } catch { | |
| Write-Error "GitHub CLI is not authenticated. Run 'gh auth login' to authenticate, then re-run this script." | |
| exit 1 | |
| } |
| param( | ||
| [string]$ScriptPath = "C:\Users\cashh\zakiscoding\daily-activity.ps1", | ||
| [string]$TaskName = "GitHubDailyActivity", | ||
| [int]$Hour = 10, | ||
| [int]$Minute = 0 | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| # Resolve absolute path | ||
| $ScriptPath = (Resolve-Path $ScriptPath).Path | ||
|
|
There was a problem hiding this comment.
The default $ScriptPath is hard-coded to a specific local user path (C:\Users\cashh...). This will fail for other machines and makes the script non-portable; prefer defaulting to the daily-activity.ps1 located alongside this script (e.g., based on $PSScriptRoot) and only Resolve-Path after validating it exists.
Adds two scripts:
Run \setup-automation.ps1\ once then it fires every day at 10am automatically.