Mirror release sources without inherited history
This commit is contained in:
+2
-2
@@ -34,7 +34,7 @@ emulation is slower than a native ARM machine; the job timeout is four hours.
|
||||
|
||||
The public mirror's `.github/workflows/platforms.yml` uses standard `windows-2022`,
|
||||
`macos-15-intel`, and `macos-15` runners. Windows Server 2022 includes WiX Toolset 3; the
|
||||
workflow adds it to `PATH` for `jpackage`. Each job checks that the mirrored commit matches the
|
||||
workflow adds it to `PATH` for `jpackage`. Each job checks that the snapshot's Git tree matches the
|
||||
Gitea manual run, builds its native package, and uploads a one-day GitHub Actions artifact.
|
||||
The Gitea workflow downloads these artifacts into a draft Gitea release. The macOS DMGs are
|
||||
development packages without Apple notarization.
|
||||
@@ -49,7 +49,7 @@ In Gitea **Repository Settings → Actions → General**, enable Actions and per
|
||||
**Code: read** and **Releases: write**. The workflow uses its built-in `GITEA_TOKEN` for draft
|
||||
creation and attachment uploads. Store a GitHub token in the Gitea repository Actions secret
|
||||
`GH_TOKEN`. It needs access only to the public `NilsBriggen/Logisim-Revolution` mirror with
|
||||
**Contents: read and write** and **Actions: read and write**. It pushes the exact Gitea commit
|
||||
**Contents: read and write** and **Actions: read and write**. It pushes a history-free snapshot of the Gitea source tree
|
||||
to GitHub `main`, dispatches the hosted workflow, checks its result, and downloads its artifacts.
|
||||
The GitHub workflow receives no Gitea credential.
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_sha:
|
||||
description: Commit mirrored from Gitea main
|
||||
description: Gitea main commit represented by this source snapshot
|
||||
required: true
|
||||
source_tree:
|
||||
description: Git tree SHA from the Gitea commit
|
||||
required: true
|
||||
release_tag:
|
||||
description: Unique Gitea draft release tag
|
||||
@@ -25,12 +28,12 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
architecture: x64
|
||||
- name: Verify the mirrored commit and build MSI and portable ZIP
|
||||
- name: Verify the mirrored source tree and build MSI and portable ZIP
|
||||
shell: pwsh
|
||||
env:
|
||||
SOURCE_SHA: ${{ inputs.source_sha }}
|
||||
SOURCE_TREE: ${{ inputs.source_tree }}
|
||||
run: |
|
||||
if ($env:GITHUB_SHA -ne $env:SOURCE_SHA) { throw 'GitHub mirror is not at the requested Gitea commit.' }
|
||||
if ((git rev-parse 'HEAD^{tree}') -ne $env:SOURCE_TREE) { throw 'GitHub source tree differs from Gitea.' }
|
||||
if ($env:PROCESSOR_ARCHITECTURE -ne 'AMD64') { throw 'An x86_64 Windows runner is required.' }
|
||||
$wix = 'C:\Program Files (x86)\WiX Toolset v3.14\bin'
|
||||
if (!(Test-Path "$wix\candle.exe") -or !(Test-Path "$wix\light.exe")) {
|
||||
@@ -59,11 +62,11 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
architecture: x64
|
||||
- name: Verify the mirrored commit and build Intel DMG
|
||||
- name: Verify the mirrored source tree and build Intel DMG
|
||||
env:
|
||||
SOURCE_SHA: ${{ inputs.source_sha }}
|
||||
SOURCE_TREE: ${{ inputs.source_tree }}
|
||||
run: |
|
||||
test "$GITHUB_SHA" = "$SOURCE_SHA"
|
||||
test "$(git rev-parse HEAD^{tree})" = "$SOURCE_TREE"
|
||||
test "$(uname -m)" = x86_64
|
||||
./gradlew clean createDmg --no-daemon --console=plain
|
||||
- uses: actions/upload-artifact@v4
|
||||
@@ -84,11 +87,11 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: '21'
|
||||
architecture: aarch64
|
||||
- name: Verify the mirrored commit and build Apple Silicon DMG
|
||||
- name: Verify the mirrored source tree and build Apple Silicon DMG
|
||||
env:
|
||||
SOURCE_SHA: ${{ inputs.source_sha }}
|
||||
SOURCE_TREE: ${{ inputs.source_tree }}
|
||||
run: |
|
||||
test "$GITHUB_SHA" = "$SOURCE_SHA"
|
||||
test "$(git rev-parse HEAD^{tree})" = "$SOURCE_TREE"
|
||||
test "$(uname -m)" = arm64
|
||||
./gradlew clean createDmg --no-daemon --console=plain
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -46,12 +46,39 @@ def git(*args, env=None):
|
||||
subprocess.run(["git", *args], check=True, env=env)
|
||||
|
||||
|
||||
def git_output(*args):
|
||||
return subprocess.check_output(["git", *args], text=True).strip()
|
||||
|
||||
|
||||
def mirror_and_dispatch():
|
||||
sha = os.environ["GITEA_SHA"]
|
||||
if subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip() != sha:
|
||||
if git_output("rev-parse", "HEAD") != sha:
|
||||
raise ValueError("Gitea checkout does not match the dispatched commit.")
|
||||
source_tree = git_output("rev-parse", "HEAD^{tree}")
|
||||
tag = os.environ["RELEASE_TAG"]
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
# GitHub contains source snapshots, never the inherited Gitea history.
|
||||
mirror = Path(temporary) / "mirror"
|
||||
git("clone", "--depth=1", f"https://github.com/{GITHUB_REPOSITORY}.git", str(mirror))
|
||||
for path in mirror.iterdir():
|
||||
if path.name != ".git":
|
||||
if path.is_dir() and not path.is_symlink():
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
path.unlink()
|
||||
archive = Path(temporary) / "source.tar"
|
||||
with archive.open("wb") as output:
|
||||
subprocess.run(["git", "archive", "--format=tar", sha], stdout=output, check=True)
|
||||
subprocess.run(["tar", "-xf", str(archive), "-C", str(mirror)], check=True)
|
||||
git("-C", str(mirror), "switch", "-C", "main")
|
||||
git("-C", str(mirror), "add", "-A")
|
||||
if git_output("-C", str(mirror), "write-tree") != source_tree:
|
||||
raise ValueError("GitHub snapshot does not match the Gitea source tree.")
|
||||
if subprocess.run(["git", "-C", str(mirror), "diff", "--cached", "--quiet"]).returncode:
|
||||
git("-C", str(mirror), "-c", "user.name=Logisim Revolution CI",
|
||||
"-c", "user.email=ci@users.noreply.github.com", "commit",
|
||||
"-m", f"Build snapshot of Gitea {sha}")
|
||||
mirror_sha = git_output("-C", str(mirror), "rev-parse", "HEAD")
|
||||
askpass = Path(temporary) / "askpass.sh"
|
||||
askpass.write_text(
|
||||
'#!/bin/sh\ncase "$1" in *Username*) printf "x-access-token";; '
|
||||
@@ -62,18 +89,21 @@ def mirror_and_dispatch():
|
||||
env = os.environ.copy()
|
||||
env.update({"GIT_ASKPASS": str(askpass), "GIT_TERMINAL_PROMPT": "0"})
|
||||
git(
|
||||
"-c", "credential.helper=", "push",
|
||||
"-C", str(mirror), "-c", "credential.helper=", "push",
|
||||
f"https://github.com/{GITHUB_REPOSITORY}.git",
|
||||
f"{sha}:refs/heads/main", env=env,
|
||||
"HEAD:refs/heads/main", env=env,
|
||||
)
|
||||
mirror_sha = github_api("git/ref/heads/main")["object"]["sha"]
|
||||
if mirror_sha != sha:
|
||||
raise ValueError(f"GitHub mirror is at {mirror_sha}, expected {sha}.")
|
||||
if github_api("git/ref/heads/main")["object"]["sha"] != mirror_sha:
|
||||
raise ValueError("GitHub mirror did not advance to the source snapshot.")
|
||||
if github_api(f"git/commits/{mirror_sha}")["tree"]["sha"] != source_tree:
|
||||
raise ValueError("GitHub mirror tree differs from the Gitea source tree.")
|
||||
github_api(
|
||||
f"actions/workflows/{GITHUB_WORKFLOW}/dispatches", "POST",
|
||||
{"ref": "main", "inputs": {"source_sha": sha, "release_tag": tag}},
|
||||
{"ref": "main", "inputs": {
|
||||
"source_sha": sha, "source_tree": source_tree, "release_tag": tag,
|
||||
}},
|
||||
)
|
||||
print(f"Dispatched GitHub Windows and macOS builds for {tag} ({sha}).")
|
||||
print(f"Dispatched GitHub Windows and macOS builds for {tag} (source {sha}).")
|
||||
|
||||
|
||||
def matching_run(tag):
|
||||
@@ -83,9 +113,15 @@ def matching_run(tag):
|
||||
matches = [
|
||||
run for run in result["workflow_runs"]
|
||||
if run["display_title"] == f"Gitea build {tag}"
|
||||
and run["head_sha"] == os.environ["GITEA_SHA"]
|
||||
]
|
||||
return max(matches, key=lambda run: run["id"]) if matches else None
|
||||
if not matches:
|
||||
return None
|
||||
run = max(matches, key=lambda candidate: candidate["id"])
|
||||
source_tree = git_output("rev-parse", "HEAD^{tree}")
|
||||
mirror_tree = github_api(f"git/commits/{run['head_sha']}")["tree"]["sha"]
|
||||
if mirror_tree != source_tree:
|
||||
raise ValueError("GitHub workflow source tree differs from the Gitea release commit.")
|
||||
return run
|
||||
|
||||
|
||||
class NoRedirect(urllib.request.HTTPRedirectHandler):
|
||||
|
||||
Reference in New Issue
Block a user