diff --git a/.gitea/workflows/backport-commoncore.yml b/.gitea/workflows/backport-commoncore.yml deleted file mode 100644 index eee0e527..00000000 --- a/.gitea/workflows/backport-commoncore.yml +++ /dev/null @@ -1,259 +0,0 @@ -name: Backport CommonCore - -on: - pull_request: - types: [closed] - branches: - - main - -permissions: - contents: write - issues: write - pull-requests: write - -jobs: - backport: - name: Backport CommonCore changes - runs-on: ubuntu-latest - if: ${{ github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' }} - steps: - - name: Checkout sources - uses: actions/checkout@v6 - with: - ref: main - fetch-depth: 0 - token: ${{ secrets.GITEA_TOKEN }} - - - name: Create version branch backports - shell: bash - env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - run: | - set -euo pipefail - - api() { - local method="$1" - local path="$2" - local body="${3:-}" - local response_file - local status - - response_file="$(mktemp)" - - if [[ -n "$body" ]]; then - status="$(curl --silent --show-error \ - -X "$method" \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -H "Accept: application/json" \ - -H "Content-Type: application/json" \ - --data "$body" \ - --output "$response_file" \ - --write-out "%{http_code}" \ - "${GITHUB_API_URL}${path}")" - else - status="$(curl --silent --show-error \ - -X "$method" \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -H "Accept: application/json" \ - --output "$response_file" \ - --write-out "%{http_code}" \ - "${GITHUB_API_URL}${path}")" - fi - - if [[ "$status" -lt 200 || "$status" -ge 300 ]]; then - echo "Gitea API ${method} ${path} failed with HTTP ${status}" >&2 - cat "$response_file" >&2 - rm -f "$response_file" - return 1 - fi - - cat "$response_file" - rm -f "$response_file" - } - - repo_path="/repos/${GITHUB_REPOSITORY}" - repo_owner="${GITHUB_REPOSITORY%%/*}" - pr_number="$(jq -r '.number' "$GITHUB_EVENT_PATH")" - pr_title="$(jq -r '.pull_request.title // ""' "$GITHUB_EVENT_PATH")" - event_commit="$(jq -r '.pull_request.merge_commit_sha // .pull_request.merged_commit_id // .commit_id // env.GITHUB_SHA' "$GITHUB_EVENT_PATH")" - - if jq -e '.pull_request.labels[]? | select(.name == "no-backport")' "$GITHUB_EVENT_PATH" >/dev/null; then - echo "PR #${pr_number} has label no-backport; skipping automatic backport." - exit 0 - fi - - commoncore_files=() - page=1 - while true; do - response="$(api GET "${repo_path}/pulls/${pr_number}/files?page=${page}&limit=50")" - count="$(jq 'length' <<< "$response")" - while IFS= read -r file; do - [[ -n "$file" ]] && commoncore_files+=("$file") - done < <(jq -r '.[] | (.filename // .path // .name // "") | select(startswith("CommonCore/"))' <<< "$response") - - [[ "$count" -lt 50 ]] && break - page=$((page + 1)) - done - - if [[ "${#commoncore_files[@]}" -eq 0 ]]; then - echo "PR #${pr_number} did not change CommonCore/; nothing to backport." - exit 0 - fi - - echo "PR #${pr_number} changed CommonCore files:" - printf ' - %s\n' "${commoncore_files[@]}" - - pr_commits=() - page=1 - while true; do - response="$(api GET "${repo_path}/pulls/${pr_number}/commits?page=${page}&limit=50")" - count="$(jq 'length' <<< "$response")" - while IFS= read -r commit; do - [[ -n "$commit" ]] && pr_commits+=("$commit") - done < <(jq -r '.[] | .sha // .id // empty' <<< "$response") - - [[ "$count" -lt 50 ]] && break - page=$((page + 1)) - done - - source_commits=("$event_commit") - if [[ "${#pr_commits[@]}" -gt 1 ]]; then - for commit in "${pr_commits[@]}"; do - if [[ "$commit" == "$event_commit" ]]; then - source_commits=("${pr_commits[@]}") - break - fi - done - fi - - echo "Using source commit plan:" - printf ' - %s\n' "${source_commits[@]}" - - git config --global user.name "SteamWar Backport Bot" - git config --global user.email "backport-bot@steamwar.de" - git fetch origin '+refs/heads/*:refs/remotes/origin/*' - - for commit in "${source_commits[@]}"; do - git cat-file -e "${commit}^{commit}" - done - - apply_commoncore_change() { - local commit="$1" - local parent - local patch_file - - if [[ "$(git rev-list --parents -n 1 "$commit" | wc -w)" -gt 2 ]]; then - parent="${commit}^1" - else - parent="${commit}^" - fi - - patch_file="$(mktemp)" - git diff --binary "$parent" "$commit" -- CommonCore/ > "$patch_file" - - if [[ ! -s "$patch_file" ]]; then - echo "Commit ${commit} has no CommonCore/ diff; skipping it." - rm -f "$patch_file" - return 0 - fi - - if git apply --reverse --check "$patch_file" >/dev/null 2>&1; then - echo "CommonCore/ diff from ${commit} is already present; skipping it." - rm -f "$patch_file" - return 0 - fi - - if git apply --3way --index "$patch_file"; then - rm -f "$patch_file" - return 0 - fi - - rm -f "$patch_file" - return 1 - } - - mapfile -t version_branches < <( - git for-each-ref --format='%(refname:short)' refs/remotes/origin/version | - sed 's#^origin/##' | - sort -u - ) - - if [[ "${#version_branches[@]}" -eq 0 ]]; then - echo "No origin/version/* branches found; nothing to backport." - exit 0 - fi - - failures=() - for target_branch in "${version_branches[@]}"; do - safe_target="$(sed -E 's#[^A-Za-z0-9._-]+#-#g; s#^-+##; s#-+$##' <<< "$target_branch")" - head_branch="backport-pr-${pr_number}-to-${safe_target}" - - existing_pr="$(api GET "${repo_path}/pulls?state=open&base_branch=$(jq -rn --arg value "$target_branch" '$value|@uri')&limit=50" | - jq -r --arg head "$head_branch" '.[] | select(.head.ref == $head) | .number' | - head -n 1)" - - if [[ -n "$existing_pr" ]]; then - echo "Backport PR #${existing_pr} already exists for ${target_branch}; leaving it unchanged." - continue - fi - - echo "Creating ${head_branch} from ${target_branch}" - git checkout -B "$head_branch" "origin/${target_branch}" - - for commit in "${source_commits[@]}"; do - if apply_commoncore_change "$commit"; then - continue - fi - - echo "Failed to apply CommonCore/ diff from ${commit} to ${target_branch}" >&2 - exit 1 - done - - if git diff --cached --quiet; then - echo "${target_branch} already contains the CommonCore/ change; no PR needed." - git checkout main - continue - fi - - git commit -m "Backport CommonCore changes from #${pr_number}" \ - -m "Source PR: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pulls/${pr_number}" \ - -m "Only CommonCore/ changes are included in this backport." - - git push origin "HEAD:refs/heads/${head_branch}" --force-with-lease - - if [[ "${#source_commits[@]}" -eq 1 ]]; then - source_text="Source commit: \`${source_commits[0]}\`" - else - source_text="Source commits:" - for commit in "${source_commits[@]}"; do - source_text="${source_text}"$'\n'"- \`${commit}\`" - done - fi - - body="$(cat </dev/null - echo "Created backport PR from ${head_branch} to ${target_branch}." - git checkout main - done - - if [[ "${#failures[@]}" -gt 0 ]]; then - echo "Backport failures:" - printf ' - %s\n' "${failures[@]}" - exit 1 - fi diff --git a/.gitea/workflows/pull-request-build.yml b/.gitea/workflows/pull-request-build.yml index b67c37c9..e2902e04 100644 --- a/.gitea/workflows/pull-request-build.yml +++ b/.gitea/workflows/pull-request-build.yml @@ -39,34 +39,3 @@ jobs: echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties - name: Build with Gradle run: ./gradlew build --no-daemon - - merge-backport: - name: Merge backport - runs-on: ubuntu-latest - needs: build - if: ${{ startsWith(github.event.pull_request.base.ref, 'version/') && startsWith(github.event.pull_request.head.ref, 'backport-pr-') }} - permissions: - contents: write - issues: write - pull-requests: write - steps: - - name: Merge successful backport PR - shell: bash - env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - run: | - set -euo pipefail - - pr_number="$(jq -r '.number' "$GITHUB_EVENT_PATH")" - target_branch="$(jq -r '.pull_request.base.ref' "$GITHUB_EVENT_PATH")" - payload="$(jq -n \ - --arg title "Merge backport #${pr_number} into ${target_branch}" \ - '{Do: "merge", MergeTitleField: $title, MergeMessageField: "Automatic CommonCore backport after successful build.", delete_branch_after_merge: true}')" - - curl --fail --silent --show-error \ - -X POST \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -H "Accept: application/json" \ - -H "Content-Type: application/json" \ - --data "$payload" \ - "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/merge"