Spaces:
Running
Running
Download scripts/sync-upstream.ps1 from Hoctar77/DocEditorPlayground: direct link, hf CLI and curl.
- Browser
- Download file 7.14 kB
-
https://huggingface.co/spaces/Hoctar77/DocEditorPlayground/resolve/main/scripts/sync-upstream.ps1
- Command line
-
hf download hf://spaces/Hoctar77/DocEditorPlayground/scripts/sync-upstream.ps1
-
curl -L -o sync-upstream.ps1 https://huggingface.co/spaces/Hoctar77/DocEditorPlayground/resolve/main/scripts/sync-upstream.ps1
7.14 kB
| <# | |
| .SYNOPSIS | |
| Mirror the upstream DocEditorPlayground checkout into ./app. | |
| .DESCRIPTION | |
| ./app is a vendored copy of the upstream Next.js app, trimmed to just what | |
| the Docker build needs. This script wipes and re-mirrors it, then records | |
| the upstream commit in UPSTREAM.json so the Space can always be traced back | |
| to a specific revision. | |
| Anything you edit under ./app is destroyed by the next run. Fix upstream | |
| instead, then re-sync. | |
| .PARAMETER UpstreamPath | |
| The local DocEditorPlayground checkout. Defaults to C:\dev\DocEditorPlayground. | |
| .PARAMETER AllowDirty | |
| Sync even when the upstream checkout has uncommitted changes. Without this, | |
| a dirty upstream is an error, because the recorded commit would not describe | |
| what actually got deployed. | |
| .EXAMPLE | |
| .\scripts\sync-upstream.ps1 | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [string] $UpstreamPath = 'C:\dev\DocEditorPlayground', | |
| [switch] $AllowDirty | |
| ) | |
| $ErrorActionPreference = 'Stop' | |
| $repoRoot = Split-Path -Parent $PSScriptRoot | |
| $appDir = Join-Path $repoRoot 'app' | |
| # --- Validate upstream ----------------------------------------------------- | |
| if (-not (Test-Path -LiteralPath $UpstreamPath -PathType Container)) { | |
| throw "Upstream path not found: $UpstreamPath" | |
| } | |
| $upstreamPkgPath = Join-Path $UpstreamPath 'package.json' | |
| if (-not (Test-Path -LiteralPath $upstreamPkgPath -PathType Leaf)) { | |
| throw "No package.json at $UpstreamPath - is that really the DocEditorPlayground checkout?" | |
| } | |
| $upstreamPkg = Get-Content -LiteralPath $upstreamPkgPath -Raw | ConvertFrom-Json | |
| if ($upstreamPkg.name -ne 'doceditorplayground') { | |
| throw "Expected package name 'doceditorplayground' at $UpstreamPath but found '$($upstreamPkg.name)'." | |
| } | |
| # --- Read upstream git provenance ----------------------------------------- | |
| $commit = 'unknown' | |
| $branch = 'unknown' | |
| $isDirty = $false | |
| $originUrl = 'unknown' | |
| if (Test-Path -LiteralPath (Join-Path $UpstreamPath '.git')) { | |
| Push-Location $UpstreamPath | |
| try { | |
| $commit = (& git rev-parse HEAD).Trim() | |
| $branch = (& git rev-parse --abbrev-ref HEAD).Trim() | |
| $status = & git status --porcelain | |
| $isDirty = -not [string]::IsNullOrWhiteSpace(($status -join '')) | |
| try { $originUrl = (& git remote get-url origin).Trim() } catch { $originUrl = 'none' } | |
| } | |
| finally { Pop-Location } | |
| } | |
| else { | |
| Write-Warning "$UpstreamPath is not a git repo - provenance will be recorded as 'unknown'." | |
| } | |
| if ($isDirty -and -not $AllowDirty) { | |
| throw @" | |
| Upstream checkout has uncommitted changes. | |
| Commit them in $UpstreamPath first so the deployed Space maps to a real revision, | |
| or re-run with -AllowDirty to deploy the working tree as-is. | |
| "@ | |
| } | |
| # --- Mirror upstream -> ./app --------------------------------------------- | |
| # Directories excluded as full paths are top-level only, so a same-named nested | |
| # directory that the build needs is not silently dropped. Bare names (build | |
| # output) are excluded at any depth on purpose. | |
| $excludeDirs = @( | |
| (Join-Path $UpstreamPath '.git'), | |
| (Join-Path $UpstreamPath '.github'), | |
| (Join-Path $UpstreamPath '.claude'), | |
| (Join-Path $UpstreamPath '.dev'), | |
| (Join-Path $UpstreamPath '.vscode'), | |
| (Join-Path $UpstreamPath '.idea'), | |
| (Join-Path $UpstreamPath 'tests'), | |
| (Join-Path $UpstreamPath 'docs'), | |
| (Join-Path $UpstreamPath 'scripts'), | |
| 'node_modules', '.next', 'out', 'dist', | |
| 'coverage', 'reports', 'test-results', 'playwright-report' | |
| ) | |
| # Dev tooling and repo-hygiene files the container never reads. LICENSE, | |
| # package-lock.json, and every config the build touches are deliberately kept. | |
| $excludeFiles = @( | |
| 'CLAUDE.md', 'CHANGELOG.md', 'README.md', | |
| '.claudeignore', '.backupignore', | |
| 'playwright.config.ts', 'vitest.config.ts', | |
| 'eslint.config.js', '.eslintrc.json', '.prettierrc', | |
| 'tsconfig.test.json', | |
| '*.log', '*.tsbuildinfo', '.env', '.env.local' | |
| ) | |
| Write-Host "Syncing $UpstreamPath -> $appDir" -ForegroundColor Cyan | |
| New-Item -ItemType Directory -Force -Path $appDir | Out-Null | |
| $robocopyArgs = @( | |
| $UpstreamPath, $appDir, | |
| '/MIR', # mirror: also deletes files removed upstream | |
| '/NFL', '/NDL', # quiet: no per-file or per-directory listing | |
| '/NJH', '/NP', | |
| '/R:2', '/W:1' | |
| ) + @('/XD') + $excludeDirs + @('/XF') + $excludeFiles | |
| & robocopy @robocopyArgs | Out-Null | |
| # Robocopy exit codes 0-7 are success (8+ means copy failures). | |
| if ($LASTEXITCODE -ge 8) { | |
| throw "robocopy failed with exit code $LASTEXITCODE" | |
| } | |
| # --- Sanity-check what landed -------------------------------------------- | |
| $required = @( | |
| 'package.json', 'package-lock.json', '.npmrc', '.nvmrc', | |
| 'next.config.js', 'tsconfig.json', | |
| 'postcss.config.cjs', 'tailwind.config.js', | |
| 'pages', 'components', 'extensions', 'utils', 'types', | |
| 'styles', 'stubs', 'public' | |
| ) | |
| $missing = $required | Where-Object { -not (Test-Path -LiteralPath (Join-Path $appDir $_)) } | |
| if ($missing.Count -gt 0) { | |
| throw "Sync incomplete - missing from app/: $($missing -join ', ')" | |
| } | |
| # --- Warn if the Dockerfile's Node pin drifted from .nvmrc --------------- | |
| $nvmrc = (Get-Content -LiteralPath (Join-Path $appDir '.nvmrc') -Raw).Trim() | |
| $dockerfilePath = Join-Path $repoRoot 'Dockerfile' | |
| $dockerFrom = (Select-String -LiteralPath $dockerfilePath -Pattern '^FROM node:([^\s-]+)' ).Matches[0].Groups[1].Value | |
| if ($dockerFrom -ne $nvmrc) { | |
| Write-Warning "Node version drift: app/.nvmrc is $nvmrc but Dockerfile builds on node:$dockerFrom. Update the FROM line in Dockerfile." | |
| } | |
| # --- Record provenance --------------------------------------------------- | |
| $upstream = [ordered]@{ | |
| upstreamRepo = $originUrl | |
| upstreamPath = $UpstreamPath | |
| commit = $commit | |
| branch = $branch | |
| dirtyWorkingTree = $isDirty | |
| appVersion = $upstreamPkg.version | |
| nodeVersion = $nvmrc | |
| syncedAtUtc = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') | |
| } | |
| # Written without a BOM: Windows PowerShell 5.1's -Encoding utf8 emits one, and | |
| # a BOM breaks strict JSON parsers that may read this file later. | |
| $upstreamJson = ($upstream | ConvertTo-Json) + [Environment]::NewLine | |
| [System.IO.File]::WriteAllText( | |
| (Join-Path $repoRoot 'UPSTREAM.json'), | |
| $upstreamJson, | |
| (New-Object System.Text.UTF8Encoding $false) | |
| ) | |
| # --- Summary ------------------------------------------------------------- | |
| $shortCommit = if ($commit.Length -ge 7) { $commit.Substring(0, 7) } else { $commit } | |
| Write-Host '' | |
| Write-Host "Synced doceditorplayground v$($upstreamPkg.version) @ $shortCommit ($branch)" -ForegroundColor Green | |
| if ($isDirty) { Write-Warning 'Deployed from a dirty upstream working tree.' } | |
| Write-Host '' | |
| Push-Location $repoRoot | |
| try { | |
| $changes = & git status --porcelain | |
| if ([string]::IsNullOrWhiteSpace(($changes -join ''))) { | |
| Write-Host 'No changes - the Space already matches upstream.' -ForegroundColor Yellow | |
| } | |
| else { | |
| Write-Host 'Pending changes:' | |
| & git status --short | |
| Write-Host '' | |
| Write-Host 'Deploy with: .\scripts\deploy.ps1' -ForegroundColor Cyan | |
| } | |
| } | |
| finally { Pop-Location } | |