GitHub Action技术问题:修改PR目标分支后如何获取最新分支名
解决GitHub Workflow PR目标分支修改后变量不更新的问题
问题描述
我编写了一个GitHub Workflow,用于禁止非Release分支合并到main分支,原本运行正常。但当用户创建普通分支到main的PR后,若修改PR的目标分支为其他分支,重新运行Workflow时,它仍会将原main分支识别为目标分支。排查确认是Workflow的上下文变量在PR创建时生成,重启后不会更新导致的。
原因分析
GitHub Actions中,PR创建时触发的Workflow run会缓存当时的上下文变量(如github.base_ref、github.event.pull_request.base.ref)。即使后续修改了PR的目标分支,重新运行该旧Workflow run时,这些缓存的变量不会同步更新,导致判断逻辑基于旧的分支信息。
解决方案
通过GitHub API实时拉取PR的最新信息,替代缓存的上下文变量。修改can-merge-pr任务中的分支判断逻辑,直接从API获取当前PR的源分支和目标分支:
修改后的完整Workflow代码
name: CI on: push: branches-ignore: - 'skip-ci-*' pull_request: branches-ignore: - 'skip-ci-*' permissions: contents: write pull-requests: read # 添加PR读取权限,确保API调用正常 env: REPOSITORY_MIRROR: "my-repo.git" jobs: build: runs-on: ubuntu-latest steps: - name: Fetch repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Build run: | make if [ $? -ne 0 ]; then echo "Build failed" exit 1 fi tests: needs: build runs-on: ubuntu-latest steps: - name: Fetch repository uses: actions/checkout@v4 with: fetch-depth: 0 - name : run_tests run: | make tests_run # push: # needs: tests # runs-on: ubuntu-latest # if: ${{ github.event_name == 'push' }} # steps: # - name: checkout # uses: actions/checkout@v4 # with: # fetch-depth: 0 # target_repo_url: ${{ env.REPOSITORY_MIRROR }} # ssh_private_key: ${{ secrets.GIT_SSH_PRIVATE_KEY }} # - name: Push changes # uses: pixta-dev/repository-mirroring-action@v1 # with: # fetch-depth: 0 # target_repo_url: ${{ env.REPOSITORY_MIRROR }} # ssh_private_key: ${{ secrets.GIT_SSH_PRIVATE_KEY }} can-merge-pr: if: ${{ github.event_name == 'pull_request' }} needs: build runs-on: ubuntu-latest steps: - name: Install jq (JSON解析工具) run: sudo apt-get update && sudo apt-get install -y jq - name: Check branch names (实时获取PR最新分支信息) run: | # 调用GitHub API获取当前PR的最新数据 PR_INFO=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}") # 解析出源分支和目标分支 source=$(echo "$PR_INFO" | jq -r '.head.ref') target=$(echo "$PR_INFO" | jq -r '.base.ref') if [ "$source" == "$target" ]; then echo "Branches are the same" exit 1 fi if [ "$target" == "main" ] && [[ "$source" != "Release"* ]]; then echo "You can't merge into main from a branch that is not a release branch" exit 1 fi create_release: if: ${{ github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'Release') == true }} needs: can-merge-pr runs-on: ubuntu-latest steps: - name: Delete Existing Release (if any) run: | if [[ ${{ startsWith(github.event.pull_request.head.ref, 'Release') }} == true ]]; then echo "Condition met. Proceeding." else echo "Condition not met. Skipping." fi release_id=$(curl -s \ -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ github.event.pull_request.head.ref }} \ | jq -r '.id') if [ "$release_id" != "null" ]; then curl -X DELETE \ -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/${{ github.repository }}/releases/$release_id fi - name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.event.pull_request.head.ref }} release_name: ${{ github.event.pull_request.head.ref }} body: | ${{ github.event.pull_request.body}} draft: false prerelease: false - name: Upload Binary to Release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: ./ asset_name: test.sh asset_content_type: application/octet-stream
关键修改说明
- 添加权限:在
permissions中增加pull-requests: read,确保GITHUB_TOKEN有权限调用PR相关的API接口。 - 安装jq工具:新增步骤安装jq,用于解析API返回的JSON数据。
- 实时获取分支信息:通过GitHub API拉取当前PR的最新数据,从中提取源分支(
head.ref)和目标分支(base.ref),替代原有的缓存变量。
这样修改后,无论PR的目标分支何时修改,重新运行Workflow时都会获取最新的分支状态,确保判断逻辑准确。
内容的提问来源于stack exchange,提问作者Yume no hochi
相关产品推荐
相关产品推荐

