Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"openclaw:prompts:check": "bun scripts/sync-openclaw-prompts.ts --check",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"test:deploy": "bun test src/lib/deployment-config.test.ts scripts/lib/build-info.test.ts scripts/lib/build-timestamp.test.ts scripts/lib/deploy-artifact.test.ts scripts/lib/aws-deploy.test.ts scripts/lib/deploy-setup.test.ts scripts/lib/deployment-command-plan.test.ts scripts/lib/deployment-tracked-files.test.ts scripts/lib/provider-deploy.test.ts scripts/lib/readme-deploy-urls.test.ts scripts/lib/live-deploy-verify.test.ts scripts/lib/github-pages.test.ts scripts/lib/tracked-deployment-config.test.ts scripts/lib/upstream-sync.test.ts scripts/github-actions/deploy-production-workflow.test.ts scripts/github-actions/nightly-follower-history-workflow.test.ts scripts/github-actions/upstream-sync-summary.test.ts scripts/enrichment/generated-metadata.test.ts scripts/enrichment/public-augmentation.test.ts scripts/enrichment/public-browser.test.ts scripts/clean-public-build-artifacts.test.ts scripts/reset-fork-template.test.ts",
"test:deploy": "bun test src/lib/deployment-config.test.ts scripts/lib/build-info.test.ts scripts/lib/build-timestamp.test.ts scripts/lib/deploy-artifact.test.ts scripts/lib/aws-deploy.test.ts scripts/lib/deploy-setup.test.ts scripts/lib/deployment-command-plan.test.ts scripts/lib/deployment-tracked-files.test.ts scripts/lib/provider-deploy.test.ts scripts/lib/readme-deploy-urls.test.ts scripts/lib/live-deploy-verify.test.ts scripts/lib/github-pages.test.ts scripts/lib/tracked-deployment-config.test.ts scripts/lib/upstream-sync.test.ts scripts/github-actions/deploy-production-workflow.test.ts scripts/github-actions/nightly-follower-history-workflow.test.ts scripts/github-actions/upstream-sync-sh.test.ts scripts/github-actions/upstream-sync-summary.test.ts scripts/enrichment/generated-metadata.test.ts scripts/enrichment/public-augmentation.test.ts scripts/enrichment/public-browser.test.ts scripts/clean-public-build-artifacts.test.ts scripts/reset-fork-template.test.ts",
"test:playwright:navigation-menu": "playwright test tests/playwright/navigation-menu.spec.ts",
"test:playwright:payment-qr": "playwright test tests/playwright/payment-qr.spec.ts",
"test:playwright:payment-qr:update": "playwright test tests/playwright/payment-qr.spec.ts --update-snapshots",
Expand Down
104 changes: 104 additions & 0 deletions scripts/github-actions/upstream-sync-sh.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import process from "node:process";
import test from "node:test";

const ROOT = process.cwd();
const SCRIPT_PATH = path.join(ROOT, "scripts/github-actions/upstream-sync.sh");

const writeExecutable = (filePath: string, contents: string) => {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, contents, "utf8");
fs.chmodSync(filePath, 0o755);
};

const createFakeGit = (binDir: string) => {
writeExecutable(
path.join(binDir, "git"),
`#!/usr/bin/env bash
set -euo pipefail

if [[ "$1" == "rev-parse" && "\${2:-}" == "HEAD" ]]; then
printf 'fake-head-sha\\n'
exit 0
fi

printf 'unexpected git args: %s\\n' "$*" >&2
exit 1
`,
);
};

const createFakeBun = (binDir: string, exitCode: 0 | 1) => {
writeExecutable(
path.join(binDir, "bun"),
`#!/usr/bin/env bash
set -euo pipefail

if [[ "$1" == "run" && "\${2:-}" == "sync:upstream" && "\${3:-}" == "--json" ]]; then
cat <<'JSON'
{
"status": "${exitCode === 0 ? "up_to_date" : "conflict"}",
"message": "${exitCode === 0 ? "Already up to date with upstream/main." : "Fork has shared-file conflicts with upstream; manual resolution required (README.md)."}",
"branchChanged": false,
"targetBranch": "main",
"upstreamRef": "upstream/main",
"sharedConflicts": ${exitCode === 0 ? "[]" : '["README.md"]'},
"forkOwnedConflicts": []
}
JSON
exit ${exitCode}
fi

printf 'unexpected bun args: %s\\n' "$*" >&2
exit 1
`,
);
};

const runWrapper = (t: test.TestContext, exitCode: 0 | 1) => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "open-links-upstream-sync-sh-"));
const binDir = path.join(tempDir, "bin");
t.after(() => {
fs.rmSync(tempDir, { force: true, recursive: true });
});

createFakeGit(binDir);
createFakeBun(binDir, exitCode);

return spawnSync("bash", [SCRIPT_PATH, "run-sync"], {
cwd: ROOT,
encoding: "utf8",
env: {
...process.env,
GITHUB_OUTPUT: "",
PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}`,
RUNNER_TEMP: tempDir,
},
});
};

test("upstream sync wrapper prints structured result when sync fails", (t) => {
const result = runWrapper(t, 1);

assert.equal(result.status, 0);
assert.match(result.stdout, /before_sha=fake-head-sha/u);
assert.match(result.stdout, /after_sha=fake-head-sha/u);
assert.match(result.stdout, /command_status=1/u);
assert.match(result.stdout, /result_path=/u);
assert.match(result.stderr, /Upstream sync failed; structured result follows:/u);
assert.match(result.stderr, /"status": "conflict"/u);
assert.match(result.stderr, /"sharedConflicts": \["README\.md"\]/u);
});

test("upstream sync wrapper keeps successful runs quiet", (t) => {
const result = runWrapper(t, 0);

assert.equal(result.status, 0);
assert.match(result.stdout, /command_status=0/u);
assert.doesNotMatch(result.stderr, /structured result follows/u);
assert.doesNotMatch(result.stderr, /"status": "up_to_date"/u);
});
17 changes: 17 additions & 0 deletions scripts/github-actions/upstream-sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ write_output() {
fi
}

print_failed_sync_result() {
local result_path="$1"

if [[ ! -s "$result_path" ]]; then
printf 'Upstream sync failed before writing a structured result: %s\n' "$result_path" >&2
return 0
fi

printf 'Upstream sync failed; structured result follows:\n' >&2
cat "$result_path" >&2
printf '\n' >&2
}

configure_upstream_remote() {
local upstream_url="${UPSTREAM_REPOSITORY_URL:-https://github.com/pRizz/open-links.git}"

Expand Down Expand Up @@ -57,6 +70,10 @@ run_sync() {
local command_status=$?
set -e

if [[ "$command_status" -ne 0 ]]; then
print_failed_sync_result "$result_path"
fi

local after_sha
after_sha="$(git rev-parse HEAD)"
write_output "after_sha" "$after_sha"
Expand Down
Loading