Initial template: release pipeline + PORTING.md + init helper
What lands in any repo created from this template: - .gitea/workflows/release.yml — canonical Gitea-Actions release pipeline (tag-triggered, curl-based publish, per-asset failure tolerance) - tools/build_zip.sh — git-archive per addon folder, multi-addon bundle - tools/init_from_upstream.sh — one-shot squash-import of upstream tree into <AddonFolder>/ at the repo root - PORTING.md — full CoA-compat bug-pattern checklist (Retail-only globals, FileDataIDs, hardcoded class lists, StaticPopup race, .tga textures, Minimap mask, CLEU arg positions, Ace3 sweep, etc.) - README.md — quick-start backport guide - standard .gitignore (incl dist/) + .gitattributes (* -text)
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
* -text
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*-coa.*' # Asc-1.1.6-coa.2, 9.1.40-coa.3, etc.
|
||||||
|
- 'v*' # v0.3.0 for repos without an upstream version
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: linux-amd64
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # build_zip uses git archive HEAD; full history is fine
|
||||||
|
|
||||||
|
- name: Build per-addon zip(s)
|
||||||
|
run: bash tools/build_zip.sh
|
||||||
|
|
||||||
|
- name: Publish release (Gitea API direct; no action dependency)
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
TAG: ${{ github.ref_name }}
|
||||||
|
API: ${{ github.server_url }}/api/v1
|
||||||
|
# Gitea attachment ceiling is 200 MiB (see roles/gitea config).
|
||||||
|
# Skip anything larger so one oversized asset doesn't fail the job.
|
||||||
|
MAX_BYTES: 209715200
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Create the release (or reuse if it already exists for this tag).
|
||||||
|
RID=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$API/repos/$REPO/releases/tags/$TAG" 2>/dev/null \
|
||||||
|
| jq -r '.id // empty')
|
||||||
|
if [ -z "$RID" ]; then
|
||||||
|
RID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"$API/repos/$REPO/releases" \
|
||||||
|
-d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false}')" \
|
||||||
|
| jq -r '.id')
|
||||||
|
fi
|
||||||
|
echo "release id: $RID"
|
||||||
|
# Upload every dist/*.zip. Per-asset failures don't fail the job —
|
||||||
|
# we want partial releases to still publish rather than block the
|
||||||
|
# whole pipeline on one big file.
|
||||||
|
failed=0
|
||||||
|
uploaded=0
|
||||||
|
for f in dist/*.zip; do
|
||||||
|
name=$(basename "$f")
|
||||||
|
size=$(stat -c '%s' "$f")
|
||||||
|
if [ "$size" -gt "$MAX_BYTES" ]; then
|
||||||
|
echo "::warning::skip $name (${size} B > ${MAX_BYTES} B Gitea limit; host on CDN instead)"
|
||||||
|
failed=$((failed+1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "uploading $name ($(numfmt --to=iec "$size"))"
|
||||||
|
if curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-F "attachment=@$f" \
|
||||||
|
"$API/repos/$REPO/releases/$RID/assets?name=$name" \
|
||||||
|
| jq -r '" -> " + .browser_download_url'; then
|
||||||
|
uploaded=$((uploaded+1))
|
||||||
|
else
|
||||||
|
echo "::warning::upload failed for $name"
|
||||||
|
failed=$((failed+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "release published: $uploaded uploaded, $failed skipped/failed"
|
||||||
|
# Only fail the job if NO assets uploaded — a release with zero
|
||||||
|
# attachments isn't useful to anyone.
|
||||||
|
[ "$uploaded" -gt 0 ]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.env
|
||||||
|
.DS_Store
|
||||||
|
.release
|
||||||
|
.install
|
||||||
|
.lua/*
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
dist/
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
# Porting addons to CoA / Project Ascension 3.3.5
|
||||||
|
|
||||||
|
The CoA Beta client is WoW 3.3.5 with a heavily reworked FrameXML /
|
||||||
|
SharedXML / StaticPopup / Settings system, 21 custom playable classes,
|
||||||
|
and selectively-modern globals (`C_Timer.After`, `C_ClassInfo`). Most
|
||||||
|
upstream retail / Classic / Wrath addons need a small bundle of fixes.
|
||||||
|
This document lists every recurring failure mode we've seen across the
|
||||||
|
existing 25 Exiles forks plus the matching one-paragraph fix.
|
||||||
|
|
||||||
|
Keep this file in your fork until you're done porting; once everything
|
||||||
|
loads cleanly you can leave it as documentation or delete it.
|
||||||
|
|
||||||
|
The canonical / live version of this checklist is at
|
||||||
|
[coa.exil.es/coa/dev/addons](https://coa.exil.es/coa/dev/addons) — if
|
||||||
|
you discover a new failure mode while porting, please add it there.
|
||||||
|
|
||||||
|
## Bug-pattern checklist
|
||||||
|
|
||||||
|
### Retail-only globals are nil
|
||||||
|
`InterfaceOptionsFrame*`, `InterfaceOptions_AddCategory`,
|
||||||
|
`InterfaceOptionsFramePanelContainer`, `Settings.*`, `Enum.ClassMask`
|
||||||
|
(only knows vanilla classes), retail `C_TooltipInfo`. Guard with
|
||||||
|
`if X then … end` or fall back to a sensible default (`UIParent` for
|
||||||
|
parent-frame fallbacks).
|
||||||
|
|
||||||
|
### FileDataIDs silently no-op
|
||||||
|
`Set*Texture(<integer>)` does nothing on 3.3.5 — textures render as red
|
||||||
|
placeholders. Use string paths. The comment next to an FDID call in
|
||||||
|
upstream code usually already names the path.
|
||||||
|
|
||||||
|
### Hardcoded class lists miss CoA's 21 custom classes
|
||||||
|
`SHAMAN/HERO` masks, `CLASS_SORT_ORDER` iteration, `RAID_CLASS_COLORS`
|
||||||
|
direct keys, `CLASS_ICON_TCOORDS`. Witchdoctor / Templar / Sun Cleric /
|
||||||
|
Primalist / Tinker / etc. won't appear. Extend via `GetNumClasses()`,
|
||||||
|
`LOCALIZED_CLASS_NAMES_MALE` fallback, or a class-keyed `or { … }`
|
||||||
|
guard.
|
||||||
|
|
||||||
|
### `C_ClassInfo.GetSpecInfo(class, spec)` arg mismatch
|
||||||
|
`GetAllSpecs(class)` returns non-string items on this client. Always
|
||||||
|
`pcall` the `GetSpecInfo` / `GetSpecInfoByID` call and skip iterations
|
||||||
|
that fail.
|
||||||
|
|
||||||
|
### `StaticPopup_Show` during `PLAYER_LOGIN` silently fails
|
||||||
|
Fires too early on this client. Defer with `C_Timer.After(0, …)`.
|
||||||
|
Failure mode is silent — the popup never appears and any code that
|
||||||
|
depends on user confirmation (e.g. WeakAuras' downgrade-repair flow)
|
||||||
|
never runs.
|
||||||
|
|
||||||
|
### `.tga` textures don't load
|
||||||
|
The engine only loads `.blp`. Ship BLP2 / DXT3 (`alphaEncoding = 1`) —
|
||||||
|
DXT5 (`ae=7`) does NOT decode on 3.3.5. Conversion:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
blp-conv --blp-version blp2 --blp-format dxt3 --alpha-bits 8 in.png out.blp
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Minimap:SetMaskTexture("Interface\\BUTTONS\\WHITE8X8")` silently rounds
|
||||||
|
The shared white mask used by retail SexyMap-style addons falls back to
|
||||||
|
the round minimap on CoA. Bundle an opaque BLP and point the mask at it
|
||||||
|
instead.
|
||||||
|
|
||||||
|
### `UnitClass("player")` at file-load time returns nil
|
||||||
|
Resolve class inside `OnEnable` / event handler, not as a file-level
|
||||||
|
`local`.
|
||||||
|
|
||||||
|
### CLEU argument positions changed
|
||||||
|
Verify against the 3.3.5 signature:
|
||||||
|
|
||||||
|
```
|
||||||
|
(event, timestamp, subevent, hideCaster,
|
||||||
|
srcGUID, srcName, srcFlags, srcRaidFlags,
|
||||||
|
destGUID, destName, destFlags, destRaidFlags,
|
||||||
|
spellId, spellName, spellSchool, …)
|
||||||
|
```
|
||||||
|
|
||||||
|
`destFlags` is arg 11, not arg 9. Many retail-era addons get this
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
## Ace3 specifics
|
||||||
|
|
||||||
|
If the addon embeds Ace3 libs (`Libs/AceXxx-3.0/`), use the canonical
|
||||||
|
`Exiles/coa-ace3` bundle to overwrite them. The sweep script in that
|
||||||
|
repo handles every fork in one pass — see its README. Don't ship a
|
||||||
|
bespoke Ace3 vendor; mismatched MINOR versions across loaded addons
|
||||||
|
cause silent breakage at LibStub resolution time.
|
||||||
|
|
||||||
|
`coa-elvui` is the one exception — ElvUI ships its own customized
|
||||||
|
Ace3 stack and is excluded from the sweep.
|
||||||
|
|
||||||
|
## Standard layout
|
||||||
|
|
||||||
|
The Exiles fork-layout convention is `<repo>/<AddonFolder>/<AddonFolder>.toc`
|
||||||
|
at depth-1, with dev tooling (`tools/`, `.gitea/`, `README.md`, `LICENSE`,
|
||||||
|
`PORTING.md`) at the repo root. Multi-addon repos place each addon in its
|
||||||
|
own sibling folder.
|
||||||
|
|
||||||
|
`tools/build_zip.sh` discovers these `<Folder>/<Folder>.toc` pairs
|
||||||
|
automatically.
|
||||||
|
|
||||||
|
## Tagging convention
|
||||||
|
|
||||||
|
`<upstream>-coa.N` per repo. Examples:
|
||||||
|
|
||||||
|
| Repo | Tag |
|
||||||
|
|---|---|
|
||||||
|
| `coa-decursive` | `Asc-1.1.6-coa.1` |
|
||||||
|
| `coa-leatrix-plus` | `3.3.5-coa.1` |
|
||||||
|
| `coa-ace3` | `52e5f2c-coa.1` (upstream commit pin) |
|
||||||
|
| `coa-dbm` | `2026.05.25-coa.1` (no `## Version:` line; date-based) |
|
||||||
|
|
||||||
|
The trailing `-coa.N` counter bumps for each CoA-fork iteration. Pushing
|
||||||
|
the tag fires the release workflow and publishes the per-addon zips to
|
||||||
|
`https://git.sub-net.at/Exiles/<repo>/releases/tag/<tag>`.
|
||||||
|
|
||||||
|
See [coa.exil.es/coa/dev/releases](https://coa.exil.es/coa/dev/releases)
|
||||||
|
for the full release pipeline doc.
|
||||||
@@ -1,3 +1,100 @@
|
|||||||
# coa-template
|
# coa-template
|
||||||
|
|
||||||
Template repo for new Exiles addon forks. Click Use This Template to start a coa-* repo with the canonical release pipeline pre-wired.
|
Template repo for new `Exiles/coa-*` addon forks. Click **Use This
|
||||||
|
Template** on the Gitea page to start a fresh repo with the canonical
|
||||||
|
release pipeline, layout convention, and CoA porting checklist
|
||||||
|
pre-wired.
|
||||||
|
|
||||||
|
## What you get
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── .gitea/workflows/release.yml # tag-triggered release pipeline
|
||||||
|
├── tools/
|
||||||
|
│ ├── build_zip.sh # git-archive per addon folder
|
||||||
|
│ └── init_from_upstream.sh # one-shot upstream import helper
|
||||||
|
├── .gitattributes # * -text (preserve upstream EOLs)
|
||||||
|
├── .gitignore # standard 7-line + dist/
|
||||||
|
├── LICENSE # 0BSD
|
||||||
|
├── PORTING.md # CoA-compat bug-pattern checklist
|
||||||
|
└── README.md # this file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick start (backporting an existing addon)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Use this template to create Exiles/coa-myaddon, then:
|
||||||
|
git clone gitea@git.sub-net.at:Exiles/coa-myaddon.git
|
||||||
|
cd coa-myaddon
|
||||||
|
|
||||||
|
# 2. Pull the upstream source into MyAddon/ at the repo root.
|
||||||
|
tools/init_from_upstream.sh \
|
||||||
|
https://github.com/Ascension-Addons/MyAddon \
|
||||||
|
MyAddon
|
||||||
|
|
||||||
|
# 3. Make it run on CoA. Read PORTING.md — every recurring failure mode
|
||||||
|
# we've seen across the existing 25 Exiles forks is documented there
|
||||||
|
# with the matching fix.
|
||||||
|
|
||||||
|
# 4. Verify the build works.
|
||||||
|
bash tools/build_zip.sh
|
||||||
|
unzip -l dist/MyAddon.zip | head -5 # first entry: MyAddon/
|
||||||
|
|
||||||
|
# 5. Push your fork.
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
# 6. Tag the first release. Read MyAddon/MyAddon.toc for the upstream
|
||||||
|
# version, then:
|
||||||
|
git tag -a 1.2.3-coa.1 -m "first Exiles release"
|
||||||
|
git push origin 1.2.3-coa.1
|
||||||
|
|
||||||
|
# The runner picks it up within seconds and publishes
|
||||||
|
# https://git.sub-net.at/Exiles/coa-myaddon/releases/tag/1.2.3-coa.1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layout convention
|
||||||
|
|
||||||
|
Every addon source folder sits at the repo root with the same name as
|
||||||
|
its `.toc`:
|
||||||
|
|
||||||
|
```
|
||||||
|
coa-myaddon/
|
||||||
|
├── MyAddon/
|
||||||
|
│ ├── MyAddon.toc
|
||||||
|
│ └── ...
|
||||||
|
└── (dev tooling at root)
|
||||||
|
```
|
||||||
|
|
||||||
|
Multi-addon repos (DBM, Altoholic, Atlasloot, …) place each addon as a
|
||||||
|
sibling folder at the repo root. `tools/build_zip.sh` discovers them all
|
||||||
|
and emits one zip per addon plus a combined `coa-myaddon-all.zip`.
|
||||||
|
|
||||||
|
## Release pipeline
|
||||||
|
|
||||||
|
The workflow in `.gitea/workflows/release.yml` triggers on tags matching
|
||||||
|
`*-coa.*` or `v*`. It checks out, runs `tools/build_zip.sh`, and uploads
|
||||||
|
each `dist/*.zip` as a Gitea release attachment via plain `curl` — no
|
||||||
|
external action dependency, no org-level secret. Per-asset upload
|
||||||
|
failures are tolerated (the job still publishes whatever uploaded);
|
||||||
|
oversized assets (>200 MiB) get a `::warning` and skip.
|
||||||
|
|
||||||
|
Runner: `gitea-runner01.corp.sub-net.at` (host executor, label
|
||||||
|
`linux-amd64`). Configured by the `gitea_runner` Ansible role.
|
||||||
|
|
||||||
|
Full docs: [coa.exil.es/coa/dev/releases](https://coa.exil.es/coa/dev/releases).
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
This template is updated by hand when the canonical files in
|
||||||
|
`Exiles/coa-decursive` (the pilot) change. To re-sync the canonical
|
||||||
|
release pipeline from the pilot:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp /path/to/coa-decursive/tools/build_zip.sh tools/build_zip.sh
|
||||||
|
cp /path/to/coa-decursive/.gitea/workflows/release.yml .gitea/workflows/release.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
The PORTING.md checklist is the lean snapshot of
|
||||||
|
[coa.exil.es/coa/dev/addons](https://coa.exil.es/coa/dev/addons) — when
|
||||||
|
you discover a new CoA failure mode, add it to the Tome page first, then
|
||||||
|
re-snapshot here.
|
||||||
|
|||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build per-addon zip artefacts from HEAD via git-archive.
|
||||||
|
#
|
||||||
|
# - Discovers top-level addon folders (Foo/Foo.toc).
|
||||||
|
# - Re-creates dist/ each run.
|
||||||
|
# - Always archives HEAD, so the working tree state is irrelevant.
|
||||||
|
# - If more than one addon folder is present, also emits <repo>-all.zip
|
||||||
|
# with every addon folder side-by-side at the zip root.
|
||||||
|
# - When run inside Gitea Actions the working tree lives under a
|
||||||
|
# per-job dir like /var/lib/act_runner/work/.../hostexecutor, so the
|
||||||
|
# repo name comes from $GITHUB_REPOSITORY (set by the runner) and
|
||||||
|
# only falls back to the toplevel basename for local invocations.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
root=$(git rev-parse --show-toplevel)
|
||||||
|
cd "$root"
|
||||||
|
|
||||||
|
# Gitea Actions sets GITHUB_REPOSITORY=owner/repo. The basename of
|
||||||
|
# `git rev-parse --show-toplevel` inside the runner is the worker dir
|
||||||
|
# (e.g. `hostexecutor`), which would name the bundle wrong.
|
||||||
|
if [ -n "${GITHUB_REPOSITORY:-}" ]; then
|
||||||
|
repo_name="${GITHUB_REPOSITORY##*/}"
|
||||||
|
else
|
||||||
|
repo_name=$(basename "$root")
|
||||||
|
fi
|
||||||
|
dist="$root/dist"
|
||||||
|
|
||||||
|
# Find Foo/Foo.toc pairs at depth 1; ignore libs nested deeper.
|
||||||
|
addons=()
|
||||||
|
while IFS= read -r toc; do
|
||||||
|
dir=$(dirname "$toc")
|
||||||
|
folder=$(basename "$dir")
|
||||||
|
base=$(basename "$toc" .toc)
|
||||||
|
# Accept Foo.toc and Foo_Wrath.toc style flavour variants; folder must match
|
||||||
|
# at least one toc basename prefix (Foo).
|
||||||
|
case "$base" in
|
||||||
|
"$folder"|"$folder"_*) addons+=("$folder") ;;
|
||||||
|
esac
|
||||||
|
done < <(command find . -mindepth 2 -maxdepth 2 -type f -name '*.toc' | sed 's|^\./||' | sort)
|
||||||
|
|
||||||
|
# Dedupe (a folder with Foo.toc + Foo_Wrath.toc shows up twice).
|
||||||
|
if [ ${#addons[@]} -gt 0 ]; then
|
||||||
|
mapfile -t addons < <(printf '%s\n' "${addons[@]}" | awk '!seen[$0]++')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#addons[@]} -eq 0 ]; then
|
||||||
|
echo "no addon folders found (looking for */Foo.toc with matching folder name)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$dist"
|
||||||
|
mkdir -p "$dist"
|
||||||
|
|
||||||
|
for folder in "${addons[@]}"; do
|
||||||
|
out="$dist/$folder.zip"
|
||||||
|
# No --prefix: the folder already sits at the repo root, so git-archive
|
||||||
|
# emits entries as <folder>/... which is exactly what
|
||||||
|
# Interface/AddOns/ expects after extraction.
|
||||||
|
git archive HEAD --format=zip -o "$out" -- "$folder"
|
||||||
|
echo "built dist/$folder.zip"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Combined bundle only makes sense when there are multiple addons.
|
||||||
|
if [ ${#addons[@]} -gt 1 ]; then
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
git archive HEAD --format=tar -- "${addons[@]}" | tar -x -C "$tmp"
|
||||||
|
out="$dist/$repo_name-all.zip"
|
||||||
|
( cd "$tmp" && zip -qr "$out" "${addons[@]}" )
|
||||||
|
echo "built dist/$repo_name-all.zip"
|
||||||
|
fi
|
||||||
Executable
+99
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# init_from_upstream.sh — bootstrap a new Exiles addon fork from upstream.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# tools/init_from_upstream.sh <upstream-url> <AddonFolderName> [upstream-branch]
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# tools/init_from_upstream.sh https://github.com/Ascension-Addons/CallToArms CallToArms
|
||||||
|
#
|
||||||
|
# What it does:
|
||||||
|
# 1. Adds `upstream` remote and fetches it.
|
||||||
|
# 2. Squash-imports the upstream tree at the named branch (default master/main)
|
||||||
|
# into <AddonFolderName>/ at the repo root.
|
||||||
|
# 3. Leaves you with a single staged commit you review and finalise.
|
||||||
|
#
|
||||||
|
# What it does NOT do:
|
||||||
|
# - Push anything.
|
||||||
|
# - Tag anything.
|
||||||
|
# - Modify the upstream history (it's a squash import, not a merge).
|
||||||
|
#
|
||||||
|
# After running, verify with:
|
||||||
|
# bash tools/build_zip.sh
|
||||||
|
# unzip -l dist/<AddonFolderName>.zip | head -5
|
||||||
|
# then `git commit --amend` if you want to edit the message, push,
|
||||||
|
# and tag <upstream-version>-coa.1 to trigger the first release.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
||||||
|
echo "usage: $0 <upstream-url> <AddonFolderName> [upstream-branch]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
upstream_url=$1
|
||||||
|
folder=$2
|
||||||
|
branch=${3:-}
|
||||||
|
|
||||||
|
if [ -d "$folder" ]; then
|
||||||
|
echo "refusing to overwrite existing folder $folder/" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git remote get-url upstream >/dev/null 2>&1; then
|
||||||
|
git remote add upstream "$upstream_url"
|
||||||
|
else
|
||||||
|
git remote set-url upstream "$upstream_url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> fetching upstream"
|
||||||
|
git fetch --tags upstream
|
||||||
|
|
||||||
|
if [ -z "$branch" ]; then
|
||||||
|
# Try master, then main.
|
||||||
|
if git rev-parse --verify "upstream/master" >/dev/null 2>&1; then
|
||||||
|
branch=master
|
||||||
|
elif git rev-parse --verify "upstream/main" >/dev/null 2>&1; then
|
||||||
|
branch=main
|
||||||
|
else
|
||||||
|
echo "couldn't find upstream/master or upstream/main; pass branch explicitly" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "==> importing tree from upstream/$branch into $folder/"
|
||||||
|
|
||||||
|
# Extract upstream tree into a temporary worktree-like dir, then move into folder.
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
git archive "upstream/$branch" | tar -x -C "$tmp"
|
||||||
|
mkdir -p "$folder"
|
||||||
|
# rsync preserves dotfiles; --exclude keeps obvious noise out.
|
||||||
|
rsync -a --exclude '.git/' --exclude '.github/' --exclude '.gitea/' \
|
||||||
|
--exclude '.idea/' --exclude '.vscode/' --exclude '.DS_Store' \
|
||||||
|
"$tmp"/ "$folder"/
|
||||||
|
|
||||||
|
git add "$folder"
|
||||||
|
upstream_sha=$(git rev-parse "upstream/$branch")
|
||||||
|
upstream_short=$(git rev-parse --short "upstream/$branch")
|
||||||
|
git commit -m "Import $folder from upstream@$upstream_short
|
||||||
|
|
||||||
|
upstream: $upstream_url
|
||||||
|
branch: $branch
|
||||||
|
commit: $upstream_sha"
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
==> done. next steps:
|
||||||
|
1. bash tools/build_zip.sh
|
||||||
|
2. unzip -l dist/$folder.zip | head -5
|
||||||
|
(expect first entry: $folder/)
|
||||||
|
3. git push origin master
|
||||||
|
4. Read $folder/$folder.toc — look for the version string.
|
||||||
|
Tag with <upstream-version>-coa.1, e.g.:
|
||||||
|
git tag -a 1.2.3-coa.1 -m "first Exiles release"
|
||||||
|
git push origin 1.2.3-coa.1
|
||||||
|
The release workflow picks it up and publishes
|
||||||
|
https://git.sub-net.at/Exiles/<this-repo>/releases/tag/<tag>.
|
||||||
|
|
||||||
|
The upstream remote stays configured so future rebases / re-imports
|
||||||
|
are one-line: \`git fetch upstream && ...\`.
|
||||||
|
EOF
|
||||||
Reference in New Issue
Block a user