Go linters check and fix using AI #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Go linters check and fix using AI | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| FILE: | |
| description: 'File name for check' | |
| required: true | |
| default: 'main.go' | |
| LINES: | |
| description: 'Range of lines for context' | |
| required: false | |
| default: '20' | |
| PR: | |
| description: 'Creat Pull Request' | |
| default: false | |
| type: boolean | |
| jobs: | |
| lint: | |
| name: Linters check and fix using AI | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| models: read | |
| env: | |
| APP_VERSION: 'latest' | |
| RESULTS: '' | |
| ISSUES_COUNT: '' | |
| ISSUE_LINT: '' | |
| ISSUE_TEXT: '' | |
| ISSUE_CODE: '' | |
| ISSUE_LINE: '' | |
| START_LINE: '' | |
| END_LINE: '' | |
| CONTEXT: '' | |
| FIXED: 'false' | |
| steps: | |
| - name: Checkout repository (main branch and 1 last commits) | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| ref: main | |
| - name: Install Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: 1.25 | |
| - name: Install dependencies | |
| run: | | |
| go fmt ./... | |
| go vet ./... | |
| go get ./... | |
| go mod tidy | |
| go mod verify | |
| go build -v ./... | |
| - name: Get app version in env | |
| run: | | |
| APP_VERSION=$(go run main.go -v) | |
| echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV | |
| - name: Install golangci | |
| run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0 | |
| - name: Getting linter check results in json format before fixing | |
| run: | | |
| results=$(golangci-lint run --output.json.path stdout --show-stats=false --issues-exit-code 0 ${{ github.event.inputs.file }} 2>/dev/null | jq -c .) | |
| echo "RESULTS=$results" >> $GITHUB_ENV | |
| count=$(echo "$results" | jq ".Issues | length") | |
| echo "ISSUES_COUNT=$count" >> $GITHUB_ENV | |
| - name: Extract context for fix | |
| run: | | |
| lint=$(echo $RESULTS | jq -r .Issues[0].FromLinter) | |
| text=$(echo $RESULTS | jq -r .Issues[0].Text) | |
| code=$(echo $RESULTS | jq -r .Issues[0].SourceLines[0]) | |
| line=$(echo $RESULTS | jq -r .Issues[0].Pos.Line) | |
| line=$(echo "$line" | tr -d '\r') | |
| lines_offset=$(echo "${{ github.event.inputs.LINES }}" | tr -d '\r') | |
| start=$((line - lines_offset)) | |
| [ $start -le 0 ] && start=1 # Защита от отрицательных строк | |
| end=$((line + lines_offset)) | |
| echo "ISSUE_LINT=$lint" >> $GITHUB_ENV | |
| echo "ISSUE_TEXT=$text" >> $GITHUB_ENV | |
| echo "ISSUE_CODE=$code" >> $GITHUB_ENV | |
| echo "ISSUE_LINE=$line" >> $GITHUB_ENV | |
| echo "START_LINE=$start" >> $GITHUB_ENV | |
| echo "END_LINE=$end" >> $GITHUB_ENV | |
| echo "CONTEXT<<EOF" >> $GITHUB_ENV | |
| sed -n "${start},${end}p" "${{ github.event.inputs.FILE }}" >> $GITHUB_ENV | |
| echo "EOF" >> $GITHUB_ENV | |
| - name: Fix issue using AI | |
| id: ai_query | |
| uses: actions/ai-inference@v2 | |
| with: | |
| model: gpt-4.1 | |
| max-tokens: 2048 | |
| system-prompt: | | |
| You are a Go code refactoring expert. | |
| Task: Fix golangci-lint issues in the provided code snippet. | |
| Rules: | |
| 1. Output ONLY the fixed code. | |
| 2. NO explanations, NO markdown blocks (no ```go). | |
| 3. Do not change any logic except what is required by the linter. | |
| 4. You must return the FULL provided context, including the fixes. | |
| 5. Ensure the code is syntactically complete and doesn't cut off. | |
| prompt: | | |
| Linter: ${{ env.ISSUE_LINT }} | |
| Issue text: ${{ env.ISSUE_TEXT }} | |
| Line of code with an error: ${{ env.ISSUE_CODE }} | |
| Context: | |
| ${{ env.CONTEXT }} | |
| - name: Update file | |
| run: | | |
| GO_FILE=${{ github.event.inputs.FILE }} | |
| TMP_FILE=$(echo $(echo "$GO_FILE" | sed "s/.go//")-fix.go) | |
| head -n $((START_LINE - 1)) "$GO_FILE" > "$TMP_FILE" | |
| cat <<'EOF' >> "$TMP_FILE" | |
| ${{ steps.ai_query.outputs.response }} | |
| EOF | |
| tail -n +$((END_LINE + 1)) "$GO_FILE" >> "$TMP_FILE" | |
| go fmt "$TMP_FILE" | |
| cat <<EOF >> $GITHUB_STEP_SUMMARY | |
| ## Issue ${{ env.ISSUE_LINT }} | |
| ${{ env.ISSUE_TEXT }} | |
| \`${{ env.ISSUE_CODE }}\` | |
| ## Fix diff | |
| \`\`\`diff | |
| $(diff -u "$GO_FILE" "$TMP_FILE" || true) | |
| \`\`\` | |
| EOF | |
| mv "$TMP_FILE" "$GO_FILE" | |
| - name: Getting linter check results in json format after fixing | |
| run: | | |
| results=$(golangci-lint run --output.json.path stdout --show-stats=false --issues-exit-code 0 ${{ github.event.inputs.file }}) | |
| count=$(echo "$results" | jq ".Issues | length") | |
| echo "Issue count before fixing: $ISSUES_COUNT" >> $GITHUB_STEP_SUMMARY | |
| echo "Issue count after fixing: $count" >> $GITHUB_STEP_SUMMARY | |
| if [ "$count" -lt "$ISSUES_COUNT" ]; then | |
| echo "FIXED=true" >> $GITHUB_ENV | |
| fi | |
| - name: Create Pull Request for fix lint | |
| if: ${{ github.event.inputs.PR == 'true' && env.FIXED == 'true' }} | |
| uses: peter-evans/create-pull-request@v8 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| commit-message: "fix linters using ai" | |
| branch: "fix/${{ env.APP_VERSION }}-lint" | |
| title: "Fixing linters" | |
| body: | | |
| ## ${{ env.ISSUE_LINT }} | |
| ${{ env.ISSUE_TEXT }} | |
| `${{ env.ISSUE_CODE }}` | |
| add-paths: | | |
| ${{ github.event.inputs.file }} |