diff --git a/.github/workflows/forge-lint.yml b/.github/workflows/forge-lint.yml index ea25b4d..382f231 100644 --- a/.github/workflows/forge-lint.yml +++ b/.github/workflows/forge-lint.yml @@ -3,19 +3,72 @@ name: Forge Lint on: pull_request: workflow_dispatch: + schedule: + - cron: "0 0 * * *" permissions: + actions: read + checks: read contents: read jobs: forge-lint: - name: Forge Lint + name: Forge Lint (${{ matrix.foundry-version }}) runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + foundry-version: + - v1.5.1 + - v1.7.0 + - stable steps: # actions/checkout v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: 0xJem/forge-lint-inline-action@2558c3a619002cd5857e73d750954f5e2248ee07 with: - foundry-version: stable + foundry-version: ${{ matrix.foundry-version }} fail-level: none + + require-annotations: + name: Require annotations + runs-on: ubuntu-latest + needs: forge-lint + if: always() + steps: + - name: Require annotations + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + failed=0 + for version in v1.5.1 v1.7.0 stable; do + job_name="Forge Lint (${version})" + check_run_id="$( + gh api "/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs" \ + --jq ".jobs[] | select(.name == \"${job_name}\") | .id" \ + | head -n 1 + )" + + if [ -z "$check_run_id" ]; then + echo "::error::Could not find check run for ${job_name}" + failed=1 + continue + fi + + annotation_count="$( + gh api "/repos/${GITHUB_REPOSITORY}/check-runs/${check_run_id}/annotations" \ + --jq "length" + )" + + if [ "$annotation_count" -eq 0 ]; then + echo "::error::Expected at least one Forge lint annotation for ${job_name}" + failed=1 + else + echo "Found ${annotation_count} Forge lint annotation(s) for ${job_name}" + fi + done + + exit "$failed" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8a1d07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cache/ +out/ diff --git a/foundry.toml b/foundry.toml index 1d3757c..0b19a05 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,3 +3,6 @@ src = "src" out = "out" libs = ["lib"] solc_version = "0.8.30" + +[lint] +severity = ["high", "medium", "low", "info", "gas", "code-size"] diff --git a/src/MixedCaseFunction.sol b/src/MixedCaseFunction.sol new file mode 100644 index 0000000..8178eb2 --- /dev/null +++ b/src/MixedCaseFunction.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract mixed_case_function { + function get_balance() external pure returns (uint256) { + return 1 ether; + } +} diff --git a/src/MixedCaseVariable.sol b/src/MixedCaseVariable.sol new file mode 100644 index 0000000..7b40c32 --- /dev/null +++ b/src/MixedCaseVariable.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract mixed_case_variable { + uint256 public owner_balance = 1 ether; + + function read() external view returns (uint256) { + return owner_balance; + } +} diff --git a/src/ScreamingSnakeConstant.sol b/src/ScreamingSnakeConstant.sol new file mode 100644 index 0000000..e386ebc --- /dev/null +++ b/src/ScreamingSnakeConstant.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract screaming_snake_constant { + uint256 public constant ownerBalance = 1 ether; + + function read() external pure returns (uint256) { + return ownerBalance; + } +}