diff --git a/.github/workflows/merge-upstream.yml b/.github/workflows/merge-upstream.yml index 1f958a543..d3162a20c 100644 --- a/.github/workflows/merge-upstream.yml +++ b/.github/workflows/merge-upstream.yml @@ -15,9 +15,13 @@ permissions: jobs: merge-upstream: runs-on: ubuntu-24.04 + env: + UPSTREAM_REF: ${{ github.event.inputs.upstream_ref }} steps: - name: Checkout repository uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + with: + fetch-depth: 0 - name: Configure Git run: | @@ -28,18 +32,24 @@ jobs: - name: Create new branch run: | - git checkout -b feature/merge-upstream-${{ github.event.inputs.upstream_ref }} + git check-ref-format "refs/tags/$UPSTREAM_REF" + git checkout -b "feature/merge-upstream-$UPSTREAM_REF" - - name: Add upstream remote + - name: Fetch upstream tag run: | git remote add upstream https://github.com/typst/typst.git - git fetch upstream + git fetch --no-tags upstream \ + "refs/tags/$UPSTREAM_REF:refs/remotes/upstream-tags/$UPSTREAM_REF" - name: Attempt merge with commit markers run: | # Try to merge but allow conflicts - TARGET_COMMIT=$(git rev-parse ${{ github.event.inputs.upstream_ref }}) - git merge --no-commit --no-ff --allow-unrelated-histories $TARGET_COMMIT || true + TARGET_COMMIT=$(git rev-parse --verify \ + "refs/remotes/upstream-tags/$UPSTREAM_REF^{commit}") + git merge --no-commit --no-ff "$TARGET_COMMIT" || { + # Continue only when the merge started and stopped because of conflicts. + test -f "$(git rev-parse --git-path MERGE_HEAD)" || exit 1 + } # Remove upstream `.github/` directory git checkout HEAD -- .github/ @@ -52,12 +62,38 @@ jobs: esac done + # Generated test references always follow upstream. + while IFS= read -r -d '' file; do + git checkout --theirs -- "$file" + git add -- "$file" + done < <(git diff --name-only --diff-filter=U -z -- tests/ref/) + + # Do not silently resolve non-text conflicts outside generated files. + while IFS= read -r -d '' file; do + if [[ ! -f "$file" ]]; then + echo "::error file=$file::Unresolved conflict is not a regular file" + exit 1 + fi + + if ! grep -Iq . -- "$file"; then + echo "::error file=$file::Unresolved binary conflict outside tests/ref/" + exit 1 + fi + + if ! grep -q '^<<<<<<< ' -- "$file" \ + || ! grep -qx '=======' -- "$file" \ + || ! grep -q '^>>>>>>> ' -- "$file"; then + echo "::error file=$file::Unresolved text conflict without conflict markers" + exit 1 + fi + done < <(git diff --name-only --diff-filter=U -z) + # Commit the merge with conflict markers - git commit -a -m "Merge upstream changes from ${{ github.event.inputs.upstream_ref }}" + git commit -a -m "Merge upstream changes from $UPSTREAM_REF" - name: Push branch run: | - git push --force origin feature/merge-upstream-${{ github.event.inputs.upstream_ref }} + git push --force origin "feature/merge-upstream-$UPSTREAM_REF" - name: Create Pull Request id: create-pr @@ -74,9 +110,9 @@ jobs: const pr = await github.rest.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, - head: "feature/merge-upstream-${{ github.event.inputs.upstream_ref }}", + head: `feature/merge-upstream-${process.env.UPSTREAM_REF}`, base: "main", - title: "Merge upstream ${{ github.event.inputs.upstream_ref }}", + title: `Merge upstream ${process.env.UPSTREAM_REF}`, body: process.env.PR_BODY }); core.setOutput("pr_number", pr.data.number);