Skip to content

Fix #12222: Unecessary nullsafe operator reported on nullable array index #15861

Fix #12222: Unecessary nullsafe operator reported on nullable array index

Fix #12222: Unecessary nullsafe operator reported on nullable array index #15861

Workflow file for this run

# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
name: "Issue bot"
on:
workflow_dispatch:
pull_request:
paths-ignore:
- 'compiler/**'
- 'apigen/**'
- 'changelog-generator/**'
push:
branches:
- "2.1.x"
paths-ignore:
- 'compiler/**'
- 'apigen/**'
- 'changelog-generator/**'
concurrency:
group: run-issue-bot-${{ github.head_ref || github.run_id }} # will be canceled on subsequent pushes in pull requests but not branches
cancel-in-progress: true
jobs:
download:
name: "Download data"
runs-on: "ubuntu-latest"
outputs:
matrix: ${{ steps.shards.outputs.shards }}
steps:
- name: "Checkout"
uses: actions/checkout@v4
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.5"
- name: "Install issue-bot dependencies"
uses: "ramsey/composer-install@v3"
with:
working-directory: "issue-bot"
- name: "Cache downloads"
uses: actions/cache@v4
with:
path: ./issue-bot/tmp
key: "issue-bot-download-v7-${{ github.run_id }}"
restore-keys: |
issue-bot-download-v7-
- name: "Download data"
working-directory: "issue-bot"
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
run: ./console.php download > matrix.json
- name: "Output shards"
id: shards
working-directory: "issue-bot"
run: |
echo "shards=$(jq -c '{include: [range(length) | {shard: .}]}' matrix.json)" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: playground-cache
path: issue-bot/tmp/playgroundCache.tmp
- uses: actions/upload-artifact@v4
with:
name: issue-cache
path: issue-bot/tmp/issueCache.tmp
- uses: actions/upload-artifact@v4
with:
name: matrix
path: issue-bot/matrix.json
analyse:
name: "Analyse"
needs: download
runs-on: "ubuntu-latest"
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.download.outputs.matrix) }}
steps:
- name: "Checkout"
uses: actions/checkout@v4
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.5"
- uses: "ramsey/composer-install@v3"
with:
composer-options: "--no-dev"
- name: "Install issue-bot dependencies"
uses: "ramsey/composer-install@v3"
with:
working-directory: "issue-bot"
- uses: Wandalen/wretry.action@v3.8.0
with:
action: actions/download-artifact@v4
with: |
name: playground-cache
path: issue-bot/tmp
attempt_limit: 5
attempt_delay: 1000
- uses: Wandalen/wretry.action@v3.8.0
with:
action: actions/download-artifact@v4
with: |
name: matrix
path: issue-bot
attempt_limit: 5
attempt_delay: 1000
- name: "Extract shard"
working-directory: "issue-bot"
id: chunk
run: |
echo "phpVersion=$(jq -r '.[${{ matrix.shard }}].phpVersion' matrix.json)" >> "$GITHUB_OUTPUT"
echo "playgroundExamples=$(jq -r '.[${{ matrix.shard }}].playgroundExamples' matrix.json)" >> "$GITHUB_OUTPUT"
echo "chunkNumber=$(jq -r '.[${{ matrix.shard }}].chunkNumber' matrix.json)" >> "$GITHUB_OUTPUT"
- name: "Run PHPStan"
working-directory: "issue-bot"
timeout-minutes: 5
run: ./console.php run ${{ steps.chunk.outputs.phpVersion }} ${{ steps.chunk.outputs.playgroundExamples }}
- uses: actions/upload-artifact@v4
with:
name: results-${{ steps.chunk.outputs.phpVersion }}-${{ steps.chunk.outputs.chunkNumber }}
path: issue-bot/tmp/results-${{ steps.chunk.outputs.phpVersion }}-*.tmp
evaluate:
name: "Evaluate results"
needs: analyse
runs-on: "ubuntu-latest"
steps:
- name: "Checkout"
uses: actions/checkout@v4
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.5"
- name: "Install issue-bot dependencies"
uses: "ramsey/composer-install@v3"
with:
working-directory: "issue-bot"
- uses: actions/download-artifact@v4
with:
name: playground-cache
path: issue-bot/tmp
- uses: actions/download-artifact@v4
with:
name: issue-cache
path: issue-bot/tmp
- uses: actions/download-artifact@v4
with:
pattern: results-*
merge-multiple: true
path: issue-bot/tmp
- name: "List tmp"
run: "ls -lA issue-bot/tmp"
- name: "Evaluate results - pull request"
working-directory: "issue-bot"
if: github.event_name == 'pull_request'
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
run: |
set +e
./console.php evaluate > tmp/step-summary.md
exit_code="$?"
cat tmp/step-summary.md >> $GITHUB_STEP_SUMMARY
if [[ "$exit_code" == "2" ]]; then
echo "::notice file=.github/workflows/issue-bot.yml,line=3 ::Issue bot detected open issues which are affected by this pull request - see https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
exit 0
fi
exit $exit_code
- name: "Upload step summary"
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: step-summary
path: issue-bot/tmp/step-summary.md
- name: "Evaluate results - push"
working-directory: "issue-bot"
if: "github.repository_owner == 'phpstan' && github.ref == 'refs/heads/2.1.x'"
env:
GITHUB_PAT: ${{ secrets.PHPSTAN_BOT_TOKEN }}
PHPSTAN_SRC_COMMIT_BEFORE: ${{ github.event.before }}
PHPSTAN_SRC_COMMIT_AFTER: ${{ github.event.after }}
run: |
set +e
./console.php evaluate --post-comments >> $GITHUB_STEP_SUMMARY
exit_code="$?"
# its fine when issue-bot found affected issues
if [[ "$exit_code" == "2" ]]; then
exit 0
fi
exit $exit_code
regression-tests:
name: "Generate regression tests"
needs: evaluate
if: github.event_name == 'pull_request' && github.event.pull_request.user.login == 'phpstan-bot'
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 60
steps:
- name: "Check for feedback loop"
id: check
env:
GH_TOKEN: ${{ secrets.PHPSTAN_BOT_TOKEN }}
run: |
COMMIT_MSG=$(gh api "repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}" --jq '.commit.message' 2>/dev/null || true)
if [[ "$COMMIT_MSG" == "Add regression test for #"* ]]; then
echo "Last commit was regression test addition, skipping"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: "Checkout"
if: steps.check.outputs.skip != 'true'
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
- name: "Download step summary"
if: steps.check.outputs.skip != 'true'
uses: actions/download-artifact@v4
with:
name: step-summary
path: ./tmp
- name: "Install PHP"
if: steps.check.outputs.skip != 'true'
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.4"
ini-file: development
extensions: mbstring
- name: "Install dependencies"
if: steps.check.outputs.skip != 'true'
uses: "ramsey/composer-install@v3"
- name: "Install Claude Code"
if: steps.check.outputs.skip != 'true'
run: npm install -g @anthropic-ai/claude-code
- name: "Save HEAD before generation"
if: steps.check.outputs.skip != 'true'
id: before
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: "Generate regression tests"
if: steps.check.outputs.skip != 'true'
env:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
GH_TOKEN: ${{ secrets.PHPSTAN_BOT_TOKEN }}
run: |
git config user.name "phpstan-bot"
git config user.email "ondrej+phpstanbot@mirtes.cz"
claude -p \
--model claude-opus-4-6 \
--dangerously-skip-permissions \
"Read the file ./tmp/step-summary.md which contains the Issue Bot step summary from CI in Markdown format. Interpret this Markdown to figure out which GitHub issues need regression tests added. For each affected issue (where behavior changed), run /regression-test with the issue number.
Also read the diff of this branch to see what has already been done. The primary fixed issue will already have a test committed. The Issue Bot step summary might mention other fixed issues, so please add regression tests for those.
Do not create a branch or push - this will be handled automatically."
- name: "Push"
if: steps.check.outputs.skip != 'true'
run: |
if [ "$(git rev-parse HEAD)" = "$(git rev-parse @{u})" ]; then
echo "No new commits to push"
exit 0
fi
git push
- name: "Update PR description"
if: steps.check.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.PHPSTAN_BOT_TOKEN }}
run: |
BEFORE_SHA="${{ steps.before.outputs.sha }}"
CURRENT_SHA="$(git rev-parse HEAD)"
if [ "$BEFORE_SHA" = "$CURRENT_SHA" ]; then
echo "No new commits, skipping PR description update"
exit 0
fi
# Extract issue numbers from new commit messages
ISSUE_NUMBERS=$(git log --format='%s' "$BEFORE_SHA".."$CURRENT_SHA" | grep -oP '#\K[0-9]+' | sort -u)
if [ -z "$ISSUE_NUMBERS" ]; then
echo "No issue numbers found in new commits"
exit 0
fi
# Get current PR body via REST API (avoids GraphQL scope requirements)
PR_API="repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}"
gh api "$PR_API" --jq '.body' > /tmp/pr-body.txt
# Append closes lines for issues not already in the body
ADDED=false
for NUM in $ISSUE_NUMBERS; do
ISSUE_URL="https://github.com/phpstan/phpstan/issues/$NUM"
if ! grep -qF "$ISSUE_URL" /tmp/pr-body.txt; then
if [ "$ADDED" = false ]; then
echo "" >> /tmp/pr-body.txt
fi
echo "Closes $ISSUE_URL" >> /tmp/pr-body.txt
ADDED=true
fi
done
if [ "$ADDED" = false ]; then
echo "All issues already referenced in PR description"
exit 0
fi
gh api "$PR_API" -X PATCH -f body="$(cat /tmp/pr-body.txt)"