├── .editorconfig ├── .github ├── renovate.json5 └── workflows │ ├── action_tests.yaml │ ├── annotate_pr.yaml │ ├── cache_trunk.yaml │ ├── codeql.yml │ ├── docker_repo_tests.yaml │ ├── nightly.yaml │ ├── pr.yaml │ ├── repo_tests.yaml │ ├── scorecard.yml │ ├── update_main_version.yaml │ └── weekly.yaml ├── .gitignore ├── .trunk ├── .gitignore ├── configs │ └── .markdownlint.yaml └── trunk.yaml ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── action.yaml ├── action_tests ├── all_test_payload.json ├── assert.js ├── pull_request_test_payload.json ├── setup.sh ├── stub.js └── trunk_merge_test_payload.json ├── all.sh ├── annotate.sh ├── caching.md ├── cleanup.sh ├── determine_check_mode.sh ├── install ├── action.yaml └── get_trunk.sh ├── package-lock.json ├── package.json ├── populate_cache_only.sh ├── pull_request.sh ├── push.sh ├── readme.md ├── repo_tests ├── check_for_task_failures.py ├── flask.yaml ├── highlightjs.yaml └── yaml_cpp.yaml ├── security.md ├── setup-env └── action.yaml ├── setup ├── action.yaml └── locate_trunk.sh ├── trunk_merge.sh └── upgrade ├── action.yaml ├── upgrade.sh └── upgrade_pr.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: ["config:base"], 4 | prConcurrentLimit: 3, 5 | packageRules: [ 6 | { 7 | automerge: true, 8 | groupName: "all non-major dependencies", 9 | groupSlug: "all-minor-patch", 10 | matchPackagePatterns: ["*"], 11 | matchUpdateTypes: ["minor", "patch"] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/action_tests.yaml: -------------------------------------------------------------------------------- 1 | name: action_tests 2 | on: [workflow_dispatch, workflow_call] 3 | 4 | permissions: read-all 5 | 6 | env: 7 | TMPDIR: /tmp/trunk-stub-tmp 8 | TRUNK_STUB_LOGS: /tmp/trunk-stub-logs.json 9 | 10 | jobs: 11 | trunk-merge: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | with: 17 | path: local-action 18 | 19 | - name: Set up test 20 | shell: bash 21 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 22 | 23 | - name: Run trunk-action 24 | shell: bash 25 | run: | 26 | cd repo-under-test 27 | git checkout trunk-merge/of-feature-branch 28 | echo "EXPECTED_UPSTREAM=$(git rev-parse trunk-merge/of-feature-branch^1)" >>$GITHUB_ENV 29 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse trunk-merge/of-feature-branch^2)" >>$GITHUB_ENV 30 | ../local-action/trunk_merge.sh 31 | env: 32 | INPUT_ARGUMENTS: "" 33 | INPUT_CHECK_RUN_ID: "" 34 | INPUT_DEBUG: "" 35 | INPUT_LABEL: "" 36 | TRUNK_PATH: ../local-action/action_tests/stub.js 37 | 38 | - name: Assert CLI calls 39 | shell: bash 40 | run: | 41 | cd local-action 42 | npm install 43 | ./action_tests/assert.js trunk-merge 44 | 45 | trunk-merge-annotate: 46 | runs-on: ubuntu-latest 47 | steps: 48 | - name: Checkout 49 | uses: actions/checkout@v4 50 | with: 51 | path: local-action 52 | 53 | - name: Set up test 54 | shell: bash 55 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 56 | 57 | - name: Run trunk-action 58 | shell: bash 59 | run: | 60 | cd repo-under-test 61 | git checkout trunk-merge/of-feature-branch 62 | echo "EXPECTED_UPSTREAM=$(git rev-parse trunk-merge/of-feature-branch^1)" >>$GITHUB_ENV 63 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse trunk-merge/of-feature-branch^2)" >>$GITHUB_ENV 64 | ../local-action/trunk_merge.sh 65 | env: 66 | INPUT_ARGUMENTS: "" 67 | INPUT_CHECK_RUN_ID: "8675309" 68 | INPUT_DEBUG: "" 69 | INPUT_LABEL: "" 70 | TRUNK_PATH: ../local-action/action_tests/stub.js 71 | 72 | - name: Assert CLI calls 73 | shell: bash 74 | run: | 75 | cd local-action 76 | npm install 77 | ./action_tests/assert.js trunk-merge-annotate 78 | 79 | trunk-merge-annotate-old-cli: 80 | runs-on: ubuntu-latest 81 | steps: 82 | - name: Checkout 83 | uses: actions/checkout@v4 84 | with: 85 | path: local-action 86 | 87 | - name: Set up test 88 | shell: bash 89 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 90 | 91 | - name: Run trunk-action 92 | shell: bash 93 | run: | 94 | cd repo-under-test 95 | git checkout trunk-merge/of-feature-branch 96 | echo "EXPECTED_UPSTREAM=$(git rev-parse trunk-merge/of-feature-branch^1)" >>$GITHUB_ENV 97 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse trunk-merge/of-feature-branch^2)" >>$GITHUB_ENV 98 | ../local-action/trunk_merge.sh 99 | env: 100 | INPUT_ARGUMENTS: "" 101 | INPUT_CHECK_RUN_ID: "8675309" 102 | INPUT_DEBUG: "" 103 | INPUT_LABEL: "" 104 | TRUNK_PATH: ../local-action/action_tests/stub.js 105 | TRUNK_CLI_VERSION: 1.6.0 106 | continue-on-error: true 107 | 108 | - name: Assert CLI calls 109 | shell: bash 110 | run: | 111 | cd local-action 112 | npm install 113 | ./action_tests/assert.js trunk-merge-annotate-old-cli 114 | 115 | pull-request-trunk-annotate: 116 | runs-on: ubuntu-latest 117 | steps: 118 | - name: Checkout 119 | uses: actions/checkout@v4 120 | with: 121 | path: local-action 122 | 123 | - name: Set up test 124 | shell: bash 125 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 126 | 127 | - name: Run trunk-action 128 | shell: bash 129 | run: | 130 | cd repo-under-test 131 | git checkout feature-branch 132 | export GITHUB_EVENT_PULL_REQUEST_HEAD_SHA=$(git rev-parse feature-branch) 133 | export GITHUB_EVENT_PULL_REQUEST_BASE_SHA=$(git rev-parse main) 134 | echo "EXPECTED_UPSTREAM=${GITHUB_EVENT_PULL_REQUEST_BASE_SHA}" >>$GITHUB_ENV 135 | echo "EXPECTED_GITHUB_COMMIT=${GITHUB_EVENT_PULL_REQUEST_HEAD_SHA}" >>$GITHUB_ENV 136 | ../local-action/pull_request.sh 137 | env: 138 | INPUT_ARGUMENTS: "" 139 | INPUT_CHECK_RUN_ID: "8675309" 140 | INPUT_DEBUG: "" 141 | INPUT_LABEL: "" 142 | INPUT_SAVE_ANNOTATIONS: "" 143 | INPUT_GITHUB_REF_NAME: feature_branch 144 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "1337" 145 | TRUNK_PATH: ../local-action/action_tests/stub.js 146 | INPUT_AUTOFIX_AND_PUSH: "" 147 | 148 | - name: Assert CLI calls 149 | shell: bash 150 | run: | 151 | cd local-action 152 | npm install 153 | ./action_tests/assert.js pull-request-trunk-annotate 154 | 155 | pull-request-trunk-annotate-old-cli: 156 | runs-on: ubuntu-latest 157 | steps: 158 | - name: Checkout 159 | uses: actions/checkout@v4 160 | with: 161 | path: local-action 162 | 163 | - name: Set up test 164 | shell: bash 165 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 166 | 167 | - name: Run trunk-action 168 | shell: bash 169 | run: | 170 | cd repo-under-test 171 | git checkout feature-branch 172 | export GITHUB_EVENT_PULL_REQUEST_HEAD_SHA=$(git rev-parse feature-branch) 173 | export GITHUB_EVENT_PULL_REQUEST_BASE_SHA=$(git rev-parse main) 174 | echo "EXPECTED_UPSTREAM=${GITHUB_EVENT_PULL_REQUEST_BASE_SHA}" >>$GITHUB_ENV 175 | echo "EXPECTED_GITHUB_COMMIT=${GITHUB_EVENT_PULL_REQUEST_HEAD_SHA}" >>$GITHUB_ENV 176 | ../local-action/pull_request.sh 177 | env: 178 | INPUT_ARGUMENTS: "" 179 | INPUT_CHECK_RUN_ID: "8675309" 180 | INPUT_DEBUG: "" 181 | INPUT_LABEL: "" 182 | INPUT_SAVE_ANNOTATIONS: "" 183 | INPUT_GITHUB_REF_NAME: feature_branch 184 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "1337" 185 | TRUNK_PATH: ../local-action/action_tests/stub.js 186 | INPUT_AUTOFIX_AND_PUSH: "" 187 | TRUNK_CLI_VERSION: 1.6.0 188 | continue-on-error: true 189 | 190 | - name: Assert CLI calls 191 | shell: bash 192 | run: | 193 | cd local-action 194 | npm install 195 | ./action_tests/assert.js pull-request-trunk-annotate-old-cli 196 | 197 | pull-request-github-annotate-file: 198 | runs-on: ubuntu-latest 199 | steps: 200 | - name: Checkout 201 | uses: actions/checkout@v4 202 | with: 203 | path: local-action 204 | 205 | - name: Set up test 206 | shell: bash 207 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 208 | 209 | - name: Run trunk-action 210 | shell: bash 211 | run: | 212 | cd repo-under-test 213 | git checkout trunk-merge/of-feature-branch 214 | export GITHUB_EVENT_PULL_REQUEST_HEAD_SHA=$(git rev-parse trunk-merge/of-feature-branch^2) 215 | export GITHUB_EVENT_PULL_REQUEST_BASE_SHA=$(git rev-parse trunk-merge/of-feature-branch^1) 216 | echo "EXPECTED_UPSTREAM=${GITHUB_EVENT_PULL_REQUEST_BASE_SHA}" >>$GITHUB_ENV 217 | echo "EXPECTED_GITHUB_COMMIT=${GITHUB_EVENT_PULL_REQUEST_HEAD_SHA}" >>$GITHUB_ENV 218 | ../local-action/pull_request.sh 219 | env: 220 | INPUT_ARGUMENTS: "" 221 | INPUT_CHECK_RUN_ID: "" 222 | INPUT_DEBUG: "" 223 | INPUT_LABEL: "" 224 | INPUT_GITHUB_REF_NAME: feature_branch 225 | INPUT_SAVE_ANNOTATIONS: auto 226 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "1337" 227 | GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK: "true" 228 | TRUNK_PATH: ../local-action/action_tests/stub.js 229 | TRUNK_TMPDIR: /tmp/trunk 230 | INPUT_AUTOFIX_AND_PUSH: "" 231 | 232 | - name: Assert CLI calls 233 | shell: bash 234 | run: | 235 | cd local-action 236 | npm install 237 | ./action_tests/assert.js pull-request-github-annotate-file 238 | 239 | pull-request-merge: 240 | runs-on: ubuntu-latest 241 | steps: 242 | - name: Checkout 243 | uses: actions/checkout@v4 244 | with: 245 | path: local-action 246 | 247 | - name: Set up test 248 | shell: bash 249 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 250 | 251 | - name: Run trunk-action 252 | shell: bash 253 | run: | 254 | cd repo-under-test 255 | git checkout trunk-merge/of-feature-branch 256 | export GITHUB_EVENT_PULL_REQUEST_HEAD_SHA=$(git rev-parse feature-branch) 257 | export GITHUB_EVENT_PULL_REQUEST_BASE_SHA=$(git rev-parse main) 258 | echo "EXPECTED_UPSTREAM=${GITHUB_EVENT_PULL_REQUEST_BASE_SHA}" >>$GITHUB_ENV 259 | echo "EXPECTED_GITHUB_COMMIT=${GITHUB_EVENT_PULL_REQUEST_HEAD_SHA}" >>$GITHUB_ENV 260 | ../local-action/pull_request.sh 261 | env: 262 | INPUT_ARGUMENTS: "" 263 | INPUT_CHECK_RUN_ID: "" 264 | INPUT_DEBUG: "" 265 | INPUT_LABEL: "" 266 | INPUT_SAVE_ANNOTATIONS: "" 267 | INPUT_GITHUB_REF_NAME: trunk-merge/of-feature-branch/merge 268 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "1337" 269 | TRUNK_PATH: ../local-action/action_tests/stub.js 270 | INPUT_AUTOFIX_AND_PUSH: "" 271 | 272 | - name: Assert CLI calls 273 | shell: bash 274 | run: | 275 | cd local-action 276 | npm install 277 | ./action_tests/assert.js pull-request-merge 278 | 279 | all-hold-the-line-new-series: 280 | runs-on: ubuntu-latest 281 | steps: 282 | - name: Checkout 283 | uses: actions/checkout@v4 284 | with: 285 | path: local-action 286 | 287 | - name: Set up test 288 | shell: bash 289 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 290 | 291 | - name: Run trunk-action 292 | shell: bash 293 | run: | 294 | cd repo-under-test 295 | ../local-action/all.sh 296 | env: 297 | INPUT_ARGUMENTS: "" 298 | INPUT_CHECK_ALL_MODE: hold-the-line 299 | INPUT_DEBUG: "" 300 | INPUT_TRUNK_TOKEN: trunk-token 301 | INPUT_UPLOAD_SERIES: series-name 302 | INPUT_UPLOAD_ID: test-upload-id 303 | TRUNK_PATH: ../local-action/action_tests/stub.js 304 | STUB_GET_LATEST_RAW_OUTPUT_STDOUT: "Starting new series of check runs...\n" 305 | 306 | - name: Assert CLI calls 307 | shell: bash 308 | run: | 309 | cd local-action 310 | npm install 311 | ./action_tests/assert.js all-hold-the-line-new-series 312 | 313 | all-hold-the-line-existing-series: 314 | runs-on: ubuntu-latest 315 | steps: 316 | - name: Checkout 317 | uses: actions/checkout@v4 318 | with: 319 | path: local-action 320 | 321 | - name: Set up test 322 | shell: bash 323 | run: | 324 | ./local-action/action_tests/setup.sh src-repo repo-under-test 325 | cd repo-under-test 326 | echo "EXPECTED_UPSTREAM=$(git rev-parse main^)" >>$GITHUB_ENV 327 | 328 | - name: Run trunk-action 329 | shell: bash 330 | run: | 331 | cd repo-under-test 332 | ../local-action/all.sh 333 | env: 334 | INPUT_ARGUMENTS: "" 335 | INPUT_CHECK_ALL_MODE: hold-the-line 336 | INPUT_DEBUG: "" 337 | INPUT_TRUNK_TOKEN: trunk-token 338 | INPUT_UPLOAD_SERIES: series-name 339 | INPUT_UPLOAD_ID: test-upload-id 340 | TRUNK_PATH: ../local-action/action_tests/stub.js 341 | STUB_GET_LATEST_RAW_OUTPUT_STDOUT: ${{ env.EXPECTED_UPSTREAM }} 342 | 343 | - name: Assert CLI calls 344 | shell: bash 345 | run: | 346 | cd local-action 347 | npm install 348 | ./action_tests/assert.js all-hold-the-line-existing-series 349 | 350 | all-hold-the-line-old-cli-version: 351 | runs-on: ubuntu-latest 352 | steps: 353 | - name: Checkout 354 | uses: actions/checkout@v4 355 | with: 356 | path: local-action 357 | 358 | - name: Set up test 359 | shell: bash 360 | run: | 361 | ./local-action/action_tests/setup.sh src-repo repo-under-test 362 | cd repo-under-test 363 | echo "EXPECTED_UPSTREAM=$(git rev-parse main^)" >>$GITHUB_ENV 364 | 365 | - name: Run trunk-action 366 | shell: bash 367 | run: | 368 | cd repo-under-test 369 | ../local-action/all.sh 370 | env: 371 | INPUT_ARGUMENTS: "" 372 | INPUT_CHECK_ALL_MODE: hold-the-line 373 | INPUT_DEBUG: "" 374 | INPUT_TRUNK_TOKEN: trunk-token 375 | INPUT_UPLOAD_SERIES: series-name 376 | INPUT_UPLOAD_ID: test-upload-id 377 | TRUNK_PATH: ../local-action/action_tests/stub.js 378 | TRUNK_CLI_VERSION: 1.12.0 379 | STUB_GET_LATEST_RAW_OUTPUT_STDOUT: ${{ env.EXPECTED_UPSTREAM }} 380 | continue-on-error: true 381 | 382 | - name: Assert CLI calls 383 | shell: bash 384 | run: | 385 | cd local-action 386 | npm install 387 | ./action_tests/assert.js all-hold-the-line-old-cli-version 388 | 389 | all-hold-the-line-no-upload-id: 390 | runs-on: ubuntu-latest 391 | steps: 392 | - name: Checkout 393 | uses: actions/checkout@v4 394 | with: 395 | path: local-action 396 | 397 | - name: Set up test 398 | shell: bash 399 | run: ./local-action/action_tests/setup.sh src-repo repo-under-test 400 | 401 | - name: Run trunk-action 402 | shell: bash 403 | run: | 404 | cd repo-under-test 405 | ../local-action/all.sh 406 | env: 407 | INPUT_ARGUMENTS: "" 408 | INPUT_CHECK_ALL_MODE: hold-the-line 409 | INPUT_DEBUG: "" 410 | INPUT_TRUNK_TOKEN: trunk-token 411 | INPUT_UPLOAD_SERIES: series-name 412 | TRUNK_PATH: ../local-action/action_tests/stub.js 413 | STUB_GET_LATEST_RAW_OUTPUT_STDOUT: "Starting new series of check runs...\n" 414 | 415 | - name: Assert CLI calls 416 | shell: bash 417 | run: | 418 | cd local-action 419 | npm install 420 | ./action_tests/assert.js all-hold-the-line-no-upload-id 421 | 422 | pull_request_expect_trunk_check_timeout: 423 | runs-on: ubuntu-latest 424 | steps: 425 | - name: Checkout 426 | uses: actions/checkout@v3 427 | with: 428 | path: local-action 429 | 430 | - name: Set up test 431 | shell: bash 432 | run: | 433 | ./local-action/action_tests/setup.sh src-repo repo-under-test 434 | cd repo-under-test 435 | git checkout feature-branch 436 | echo "EXPECTED_UPSTREAM=$(git rev-parse feature-branch^1)" >>$GITHUB_ENV 437 | 438 | - name: Run trunk-action 439 | shell: bash 440 | id: trunk-action 441 | run: | 442 | cd repo-under-test 443 | git checkout feature-branch 444 | ../local-action/pull_request.sh 445 | env: 446 | INPUT_ARGUMENTS: "" 447 | INPUT_CHECK_RUN_ID: 12345678 448 | INPUT_DEBUG: "" 449 | INPUT_LABEL: "" 450 | TRUNK_PATH: ../local-action/action_tests/stub.js 451 | INPUT_GITHUB_REF_NAME: feature-branch 452 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "" 453 | GITHUB_EVENT_PULL_REQUEST_BASE_SHA: ${{ env.EXPECTED_UPSTREAM }} 454 | GITHUB_EVENT_PULL_REQUEST_HEAD_SHA: "" 455 | GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK: "" 456 | INPUT_SAVE_ANNOTATIONS: "" 457 | INPUT_AUTOFIX_AND_PUSH: true 458 | INPUT_TIMEOUT_SECONDS: 1 459 | 460 | - name: Assert trunk-action check has failed 461 | shell: bash 462 | if: steps.trunk-action.outcome == 'success' 463 | run: exit 1 464 | 465 | pull_request_autofix: 466 | runs-on: ubuntu-latest 467 | steps: 468 | - name: Checkout 469 | uses: actions/checkout@v4 470 | with: 471 | path: local-action 472 | 473 | - name: Set up test 474 | shell: bash 475 | run: | 476 | ./local-action/action_tests/setup.sh src-repo repo-under-test 477 | cd repo-under-test 478 | git checkout feature-branch 479 | echo "EXPECTED_UPSTREAM=$(git rev-parse feature-branch^1)" >>$GITHUB_ENV 480 | 481 | - name: Run trunk-action 482 | shell: bash 483 | run: | 484 | cd repo-under-test 485 | git checkout feature-branch 486 | ../local-action/pull_request.sh 487 | env: 488 | INPUT_ARGUMENTS: "" 489 | INPUT_CHECK_RUN_ID: 12345678 490 | INPUT_DEBUG: "" 491 | INPUT_LABEL: "" 492 | TRUNK_PATH: ../local-action/action_tests/stub.js 493 | INPUT_GITHUB_REF_NAME: feature-branch 494 | GITHUB_EVENT_PULL_REQUEST_NUMBER: "" 495 | GITHUB_EVENT_PULL_REQUEST_BASE_SHA: ${{ env.EXPECTED_UPSTREAM }} 496 | GITHUB_EVENT_PULL_REQUEST_HEAD_SHA: "" 497 | GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK: "" 498 | INPUT_SAVE_ANNOTATIONS: "" 499 | INPUT_AUTOFIX_AND_PUSH: true 500 | 501 | - name: Assert CLI calls 502 | shell: bash 503 | run: | 504 | cd local-action 505 | npm install 506 | ./action_tests/assert.js pull-request-autofix 507 | 508 | - name: Assert state of feature-branch 509 | shell: bash 510 | run: | 511 | cd src-repo 512 | latest_commit_message=$(git log -1 --pretty=format:%s feature-branch) 513 | expected_commit_message="Trunk Check applied autofixes" 514 | if [ "$latest_commit_message" = "$expected_commit_message" ]; then 515 | echo "The latest commit message was "$latest_commit_message" commits as expected." 516 | exit 0 517 | else 518 | echo "The did not have the expected latest commit message "$latest_commit_message"." 519 | exit 1 520 | fi 521 | 522 | payload: 523 | name: ${{ matrix.description }} 524 | runs-on: ubuntu-latest 525 | strategy: 526 | fail-fast: false 527 | matrix: 528 | include: 529 | - description: pull-request-payload 530 | payload_path: action_tests/pull_request_test_payload.json 531 | - description: trunk-merge-payload 532 | payload_path: action_tests/trunk_merge_test_payload.json 533 | - description: all-payload 534 | payload_path: action_tests/all_test_payload.json 535 | 536 | steps: 537 | - name: Checkout 538 | uses: actions/checkout@v4 539 | with: 540 | path: local-action 541 | 542 | - name: Checkout 543 | shell: bash 544 | run: | 545 | mv local-action .. 546 | ../local-action/action_tests/setup.sh /tmp/src-repo . 547 | mv ../local-action . 548 | 549 | - name: Craft TEST_GITHUB_EVENT_PATH 550 | shell: bash 551 | run: | 552 | payload=$(jq --null-input --slurpfile foo local-action/${{ matrix.payload_path }} '{"payload": ($foo[0] | tostring)}') 553 | echo "$(echo '{"inputs":'$(echo $payload | jq -c '.' )'}')">>local-action/payload.json 554 | echo "TEST_GITHUB_EVENT_PATH=local-action/payload.json">>$GITHUB_ENV 555 | mkdir -p .git/info 556 | if [[ "${{ matrix.description }}" == "pull-request-payload" ]]; then 557 | git checkout 1/merge 558 | echo "EXPECTED_UPSTREAM=$(git rev-parse 1/merge^1)" >>$GITHUB_ENV 559 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse 1/merge^2)" >>$GITHUB_ENV 560 | elif [[ "${{ matrix.description }}" == "trunk-merge-payload" ]]; then 561 | git checkout trunk-merge/of-feature-branch 562 | echo "EXPECTED_UPSTREAM=$(git rev-parse trunk-merge/of-feature-branch^1)" >>$GITHUB_ENV 563 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse trunk-merge/of-feature-branch^2)" >>$GITHUB_ENV 564 | else 565 | echo "EXPECTED_GITHUB_COMMIT=$(git rev-parse main^)" >>$GITHUB_ENV 566 | fi 567 | 568 | - name: Run trunk-action payload test for ${{matrix.description}} 569 | id: trunk 570 | uses: ./local-action/ 571 | with: 572 | check-mode: payload 573 | continue-on-error: true 574 | 575 | - name: Assert CLI calls 576 | shell: bash 577 | run: | 578 | cd local-action 579 | npm install 580 | ./action_tests/assert.js ${{matrix.description}} 581 | -------------------------------------------------------------------------------- /.github/workflows/annotate_pr.yaml: -------------------------------------------------------------------------------- 1 | name: Trunk Check PR Annotation 2 | 3 | on: 4 | workflow_run: 5 | workflows: [Pull Request] 6 | types: 7 | - completed 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | trunk_check_annotate_pr: 13 | name: Trunk Check PR Annotation 14 | runs-on: ubuntu-latest 15 | permissions: 16 | checks: write 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 21 | 22 | - name: Trunk Check 23 | uses: ./ # external users, use: trunk-io/trunk-action@v1 24 | with: 25 | post-annotations: true 26 | -------------------------------------------------------------------------------- /.github/workflows/cache_trunk.yaml: -------------------------------------------------------------------------------- 1 | name: Cache Trunk 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: [.trunk/trunk.yaml] 7 | 8 | permissions: read-all 9 | 10 | jobs: 11 | cache_trunk: 12 | name: Cache Trunk 13 | runs-on: ubuntu-latest 14 | permissions: 15 | actions: write 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 20 | 21 | - name: Trunk Check 22 | uses: ./ # external users, use: trunk-io/trunk-action@v1 23 | with: 24 | check-mode: populate_cache_only 25 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: Code Scanning - Action 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | schedule: 9 | # ┌───────────── minute (0 - 59) 10 | # │ ┌───────────── hour (0 - 23) 11 | # │ │ ┌───────────── day of the month (1 - 31) 12 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 13 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 14 | # │ │ │ │ │ 15 | # │ │ │ │ │ 16 | # │ │ │ │ │ 17 | # * * * * * 18 | - cron: 30 1 * * 0 19 | 20 | permissions: read-all 21 | 22 | jobs: 23 | CodeQL-Build: 24 | # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest 25 | runs-on: ubuntu-latest 26 | 27 | permissions: 28 | # required for all workflows 29 | security-events: write 30 | 31 | # only required for workflows in private repositories 32 | actions: read 33 | contents: read 34 | 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 38 | 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 42 | # Override language selection by uncommenting this and choosing your languages 43 | with: 44 | languages: javascript 45 | 46 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 47 | # If this step fails, then you should remove it and run the build manually (see below). 48 | - name: Autobuild 49 | uses: github/codeql-action/autobuild@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 50 | 51 | # ℹ️ Command-line programs to run using the OS shell. 52 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 53 | 54 | # ✏️ If the Autobuild fails above, remove it and uncomment the following 55 | # three lines and modify them (or add more) to build your code if your 56 | # project uses a compiled language 57 | 58 | #- run: | 59 | # make bootstrap 60 | # make release 61 | 62 | - name: Perform CodeQL Analysis 63 | uses: github/codeql-action/analyze@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 64 | -------------------------------------------------------------------------------- /.github/workflows/docker_repo_tests.yaml: -------------------------------------------------------------------------------- 1 | name: docker_repo_tests 2 | on: [workflow_dispatch, workflow_call] 3 | 4 | permissions: read-all 5 | 6 | jobs: 7 | repo_tests: 8 | name: ${{ matrix.repo }} ${{ matrix.description }} 9 | runs-on: ubuntu-latest 10 | # This is a docker image that mimics the github runner image 11 | # https://github.com/catthehacker/docker_images/pkgs/container/ubuntu 12 | container: ghcr.io/catthehacker/ubuntu:runner-20.04 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | include: 17 | # Items in this list satisfy a few criteria: 18 | # 19 | # * test has to be useful/interesting and add value atop the monorepo tests for 20 | # trunk init 21 | # 22 | # * the repo has to exercise some functionality specific to action.yaml (e.g. our 23 | # custom Node functionality for npm/yarn/pnpm) 24 | # 25 | # * the repo and its dependency closure should be fast to set up, since we trigger 26 | # this workflow on PRs 27 | # 28 | - repo: highlightjs/highlight.js 29 | ref: 4f9cd3bffb6bc55c9e2c4252c7b733a219880151 30 | description: (uses npm) 31 | post-init: | 32 | # terrascan scans dockerfile.js (a JS file for parsing dockerfiles) as a dockerfile itself 33 | echo "src/languages/dockerfile.js" >> .gitignore 34 | cp local-action/repo_tests/highlightjs.yaml .trunk/user.yaml 35 | cache: true 36 | 37 | - repo: pallets/flask 38 | ref: 4bcd4be6b7d69521115ef695a379361732bcaea6 39 | post-init: | 40 | # prettier chokes on this malformed html file 41 | echo "examples/celery/src/task_app/templates/index.html" >> .gitignore 42 | cp local-action/repo_tests/flask.yaml .trunk/user.yaml 43 | cache: true 44 | 45 | - repo: postcss/postcss 46 | ref: aa9e03ea4708909631eba70500c8c0cc0708bb4e 47 | description: (uses pnpm) 48 | post-init: | 49 | ${TRUNK_PATH} check enable eslint 50 | cache: true 51 | 52 | - repo: postcss/postcss 53 | ref: aa9e03ea4708909631eba70500c8c0cc0708bb4e 54 | description: (compat test for cli 1.0.0) 55 | post-init: | 56 | ${TRUNK_PATH} check enable eslint 57 | cache: true 58 | 59 | - repo: prawn-test-staging-rw/setup-node-test 60 | ref: main 61 | post-init: | 62 | if [ "${FAILED_NODE_INSTALL}" != "true" ]; then 63 | echo "::error::Initial setup node didn't fail" 64 | exit 1 65 | fi 66 | if [ "${INSTALL_LATEST_NODE}" != "true" ]; then 67 | echo "::error::Initial setup node didn't fail" 68 | exit 1 69 | fi 70 | description: (test for setup-node) 71 | pre-init: | 72 | while which node > /dev/null; do 73 | rm $(which node) 74 | done 75 | cache: false 76 | 77 | - repo: sass/sass 78 | ref: 225e176115211387e014d97ae0076d94de3152a1 79 | description: (uses npm) 80 | cache: true 81 | 82 | steps: 83 | - name: Checkout ${{ matrix.repo }} 84 | uses: actions/checkout@v4 85 | with: 86 | repository: ${{ matrix.repo }} 87 | ref: ${{ matrix.ref }} 88 | 89 | - name: Checkout ${{ github.repository }} 90 | uses: actions/checkout@v4 91 | with: 92 | path: local-action 93 | 94 | - name: Run pre-init 95 | shell: bash 96 | run: ${{ matrix.pre-init }} 97 | 98 | - name: Run trunk-action in ${{ matrix.repo }} 99 | id: trunk 100 | uses: ./local-action/ 101 | with: 102 | cache: ${{ matrix.cache }} 103 | check-mode: all 104 | post-init: ${{ matrix.post-init }} 105 | arguments: --output-file=/tmp/landing-state.json 106 | cache-key: repo_tests/${{ matrix.repo }} 107 | setup-deps: true 108 | env: 109 | TRUNK_CLI_VERSION: 110 | ${{ matrix.description == '(compat test for cli 1.0.0)' && '1.0.0' || '' }} 111 | continue-on-error: true 112 | 113 | - name: Check for task failures 114 | shell: bash 115 | run: | 116 | python3 local-action/repo_tests/check_for_task_failures.py \ 117 | '${{ github.env }}' \ 118 | '${{ matrix.repo }}' \ 119 | '${{ matrix.description }}' 120 | 121 | - name: Upload landing state 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: ${{ env.landing_state_artifact_name }} landing state 125 | path: .trunk/landing-state.json 126 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yaml: -------------------------------------------------------------------------------- 1 | name: Nightly 2 | on: 3 | schedule: 4 | - cron: 0 8 * * 1-5 5 | workflow_dispatch: {} 6 | 7 | permissions: read-all 8 | 9 | jobs: 10 | trunk_check: 11 | name: Trunk Check Upload 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 17 | 18 | - name: Trunk Check 19 | uses: ./ # external users, use: trunk-io/trunk-action@v1 20 | with: 21 | check-mode: all 22 | -------------------------------------------------------------------------------- /.github/workflows/pr.yaml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | on: [pull_request, workflow_dispatch] 3 | concurrency: 4 | group: ${{ github.head_ref || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | permissions: read-all 8 | 9 | jobs: 10 | trunk_check: 11 | name: Trunk Check Runner 12 | runs-on: ubuntu-latest 13 | permissions: 14 | checks: write # For trunk to post annotations 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 19 | 20 | - name: Trunk Check 21 | uses: ./ # external users, use: trunk-io/trunk-action@v1 22 | 23 | action_tests: 24 | name: Action tests 25 | uses: ./.github/workflows/action_tests.yaml 26 | 27 | repo_tests: 28 | name: Repository tests 29 | uses: ./.github/workflows/repo_tests.yaml 30 | 31 | docker_repo_tests: 32 | name: Repository tests (docker) 33 | uses: ./.github/workflows/docker_repo_tests.yaml 34 | -------------------------------------------------------------------------------- /.github/workflows/repo_tests.yaml: -------------------------------------------------------------------------------- 1 | name: repo_tests 2 | on: [workflow_dispatch, workflow_call] 3 | 4 | permissions: read-all 5 | 6 | jobs: 7 | repo_tests: 8 | name: ${{ matrix.repo }} ${{ matrix.description }} 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | include: 14 | # Items in this list satisfy a few criteria: 15 | # 16 | # * test has to be useful/interesting and add value atop the monorepo tests for 17 | # trunk init 18 | # 19 | # * the repo has to exercise some functionality specific to action.yaml (e.g. our 20 | # custom Node functionality for npm/yarn/pnpm) 21 | # 22 | # * the repo and its dependency closure should be fast to set up, since we trigger 23 | # this workflow on PRs 24 | # 25 | - repo: highlightjs/highlight.js 26 | ref: 4f9cd3bffb6bc55c9e2c4252c7b733a219880151 27 | description: (uses npm) 28 | post-init: | 29 | # terrascan scans dockerfile.js (a JS file for parsing dockerfiles) as a dockerfile itself 30 | echo "src/languages/dockerfile.js" >> .gitignore 31 | cp local-action/repo_tests/highlightjs.yaml .trunk/user.yaml 32 | 33 | - repo: jbeder/yaml-cpp 34 | ref: 0e6e28d1a38224fc8172fae0109ea7f673c096db 35 | description: (compile-commands.json) 36 | post-init: | 37 | # black complains about py2 code 38 | # markdownlint fails for some reason, and what we really care about anyways is clang-tidy 39 | ${TRUNK_PATH} check disable black markdownlint 40 | mkdir build 41 | cd build 42 | cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 43 | cd .. 44 | ln -s build/compile_commands.json 45 | sed -i "s|lint:|lint:\n compile_commands: json|" .trunk/trunk.yaml 46 | cp local-action/repo_tests/yaml_cpp.yaml .trunk/user.yaml 47 | ${TRUNK_PATH} check enable clang-tidy 48 | 49 | - repo: pallets/flask 50 | ref: 4bcd4be6b7d69521115ef695a379361732bcaea6 51 | post-init: | 52 | # prettier chokes on this malformed html file 53 | echo "examples/celery/src/task_app/templates/index.html" >> .gitignore 54 | cp local-action/repo_tests/flask.yaml .trunk/user.yaml 55 | 56 | - repo: postcss/postcss 57 | ref: aa9e03ea4708909631eba70500c8c0cc0708bb4e 58 | description: (uses pnpm) 59 | post-init: | 60 | ${TRUNK_PATH} check enable eslint 61 | 62 | - repo: postcss/postcss 63 | ref: aa9e03ea4708909631eba70500c8c0cc0708bb4e 64 | description: (compat test for cli 1.0.0) 65 | post-init: | 66 | ${TRUNK_PATH} check enable eslint 67 | 68 | - repo: prawn-test-staging-rw/setup-node-test 69 | ref: main 70 | post-init: | 71 | if [ "${FAILED_NODE_INSTALL}" != "true" ]; then 72 | echo "::error::Initial setup node didn't fail" 73 | exit 1 74 | fi 75 | description: (test for setup-node) 76 | 77 | - repo: prawn-test-staging-rw/node-packages-failure-test 78 | ref: main 79 | post-init: | 80 | if [ "${FAILED_NODE_PACKAGE_INSTALL}" != "true" ]; then 81 | echo "::error::Node package install didn't fail" 82 | exit 1 83 | fi 84 | if grep -q "✔ eslint" <(${TRUNK_PATH} check list --color=false); then 85 | echo "::error::eslint not disabled" 86 | exit 1 87 | fi 88 | if grep -q "✔ stylelint" <(${TRUNK_PATH} check list --color=false); then 89 | echo "::error::stylelint not disabled" 90 | exit 1 91 | fi 92 | description: (test for continuing on node package install failure) 93 | 94 | - repo: replayio/devtools 95 | ref: 730a9f0ddaafefc2a1a293d6924ce3910cd156ac 96 | description: (has trunk.yaml) 97 | post-init: | 98 | # replay is on a very old version 99 | # trunk upgrade requires 3 calls to guarantee correctness 100 | ${TRUNK_PATH} upgrade 101 | ${TRUNK_PATH} upgrade 102 | ${TRUNK_PATH} upgrade 103 | trunk-path: node_modules/.bin/trunk 104 | 105 | - repo: sass/sass 106 | ref: 225e176115211387e014d97ae0076d94de3152a1 107 | description: (uses npm) 108 | 109 | - repo: sheldonhull/sheldonhull.hugo 110 | ref: 0810b7219c6681931bbf727cd9fe81693b414b60 111 | description: (has trunk.yaml) 112 | post-init: | 113 | # all of these linters have failures 114 | ${TRUNK_PATH} check disable svgo golangci-lint prettier oxipng 115 | 116 | - repo: shopify/draggable 117 | ref: e6cf325a98c11b8aefbfb626b7a91b95d1c340c9 118 | description: (uses yarn) 119 | 120 | - repo: terraform-linters/tflint 121 | ref: 9c34a740319e2410094ca2754e5eca860f2d13f5 122 | post-init: | 123 | # golangci-lint needs us to init with a newer go runtime 124 | ${TRUNK_PATH} check disable golangci-lint 125 | # tfsec and terrascan scan these malformed test files and error 126 | echo "integrationtest/" >> .gitignore 127 | echo "terraform/test-fixtures" >> .gitignore 128 | 129 | - repo: trunk-io/plugins 130 | ref: main 131 | 132 | # fails because pnpm version is too new 133 | 134 | # - repo: vuejs/core 135 | # ref: 60cd23c7520f9098bf31fc2d0c09d58ded75f173 136 | # description: (uses pnpm) 137 | # post-init: | 138 | # # svgo gets confused by JS module loading 139 | # ${TRUNK_PATH} check disable svgo 140 | 141 | - repo: z-shell/wiki 142 | ref: d6d8b5da28c170b3b226705795412497f7059681 143 | description: (has trunk.yaml) 144 | post-init: | 145 | # stylelint is exiting with error code -11 146 | ${TRUNK_PATH} check disable stylelint 147 | 148 | steps: 149 | - name: Checkout ${{ matrix.repo }} 150 | uses: actions/checkout@v4 151 | with: 152 | repository: ${{ matrix.repo }} 153 | ref: ${{ matrix.ref }} 154 | 155 | - name: Checkout ${{ github.repository }} 156 | uses: actions/checkout@v4 157 | with: 158 | path: local-action 159 | 160 | - name: Run trunk-action in ${{ matrix.repo }} 161 | id: trunk 162 | uses: ./local-action/ 163 | with: 164 | cache: true 165 | check-mode: all 166 | trunk-path: ${{ matrix.trunk-path }} 167 | post-init: ${{ matrix.post-init }} 168 | arguments: --output-file=/tmp/landing-state.json 169 | cache-key: repo_tests/${{ matrix.repo }} 170 | setup-deps: true 171 | env: 172 | TRUNK_CLI_VERSION: 173 | ${{ matrix.description == '(compat test for cli 1.0.0)' && '1.0.0' || '' }} 174 | continue-on-error: true 175 | 176 | - name: Check for task failures 177 | shell: bash 178 | run: | 179 | python3 local-action/repo_tests/check_for_task_failures.py \ 180 | '${{ github.env }}' \ 181 | '${{ matrix.repo }}' \ 182 | '${{ matrix.description }}' 183 | 184 | - name: Upload landing state 185 | uses: actions/upload-artifact@v4 186 | with: 187 | name: ${{ env.landing_state_artifact_name }} landing state 188 | path: .trunk/landing-state.json 189 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | # branch_protection_rule: 10 | 11 | # To guarantee Maintained check is occasionally updated. See 12 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 13 | schedule: 14 | - cron: 44 9 * * 2 15 | push: 16 | branches: [main] 17 | 18 | # Declare default permissions as read only. 19 | permissions: read-all 20 | 21 | jobs: 22 | analysis: 23 | name: Scorecard analysis 24 | runs-on: ubuntu-latest 25 | permissions: 26 | # Needed to upload the results to code-scanning dashboard. 27 | security-events: write 28 | # Needed to publish results and get a badge (see publish_results below). 29 | id-token: write 30 | 31 | steps: 32 | - name: Checkout code 33 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 34 | with: 35 | persist-credentials: false 36 | 37 | - name: Run analysis 38 | uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0 39 | with: 40 | results_file: results.sarif 41 | results_format: sarif 42 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 43 | # - you want to enable the Branch-Protection check on a *public* repository, or 44 | # - you are installing Scorecard on a *private* repository 45 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 46 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 47 | 48 | # Public repositories: 49 | # - Publish results to OpenSSF REST API for easy access by consumers 50 | # - Allows the repository to include the Scorecard badge. 51 | # - See https://github.com/ossf/scorecard-action#publishing-results. 52 | # For private repositories: 53 | # - `publish_results` will always be set to `false`, regardless 54 | # of the value entered here. 55 | publish_results: true 56 | 57 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 58 | # format to the repository Actions tab. 59 | - name: Upload artifact 60 | uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 61 | with: 62 | name: SARIF file 63 | path: results.sarif 64 | retention-days: 5 65 | 66 | # Upload the results to GitHub's code scanning dashboard. 67 | - name: Upload to code-scanning 68 | uses: github/codeql-action/upload-sarif@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4 69 | with: 70 | sarif_file: results.sarif 71 | -------------------------------------------------------------------------------- /.github/workflows/update_main_version.yaml: -------------------------------------------------------------------------------- 1 | name: Update release version 2 | run-name: Move ${{ github.event.inputs.major_version }} to ${{ github.event.inputs.target }} 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | target: 8 | description: The tag to use 9 | required: true 10 | major_version: 11 | type: choice 12 | description: Target major version 13 | options: 14 | - v1 15 | 16 | jobs: 17 | tag: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - name: Git config 24 | run: | 25 | git config user.name trunkio 26 | git config user.email github-actions@trunk.io 27 | # ignoring the shell injection is mildly worrying but this will always only be run by us, so it should be fine 28 | # trunk-ignore-begin(semgrep/yaml.github-actions.security.run-shell-injection.run-shell-injection) 29 | - name: Tag new target 30 | run: git tag -f ${{ github.event.inputs.major_version }} ${{ github.event.inputs.target }} 31 | - name: Push new tag 32 | run: git push origin ${{ github.event.inputs.major_version }} --force 33 | # trunk-ignore-end(semgrep/yaml.github-actions.security.run-shell-injection.run-shell-injection) 34 | -------------------------------------------------------------------------------- /.github/workflows/weekly.yaml: -------------------------------------------------------------------------------- 1 | name: Weekly 2 | on: 3 | schedule: 4 | # Weekly at midnight Monday morning 5 | - cron: 0 8 * * 1 6 | workflow_dispatch: {} 7 | 8 | permissions: read-all 9 | 10 | jobs: 11 | trunk_upgrade: 12 | name: Upgrade Trunk 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write # For trunk to create PRs 16 | pull-requests: write # For trunk to create PRs 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Create App Token for TrunkBuild App (Internal) 22 | uses: tibdex/github-app-token@v1 23 | id: generate-token 24 | with: 25 | app_id: ${{ secrets.TRUNK_OPEN_PR_APP_ID }} 26 | private_key: ${{ secrets.TRUNK_OPEN_PR_APP_PRIVATE_KEY }} 27 | 28 | - name: Trunk Upgrade 29 | id: upgrade 30 | uses: ./upgrade # external users: use trunk-io/trunk-action/upgrade@v1 31 | with: 32 | github-token: ${{ steps.generate-token.outputs.token }} 33 | reviewers: TylerJang27 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # from https://github.com/github/gitignore/blob/main/Python.gitignore 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # from https://github.com/github/gitignore/blob/main/Node.gitignore 8 | node_modules/ 9 | -------------------------------------------------------------------------------- /.trunk/.gitignore: -------------------------------------------------------------------------------- 1 | *out 2 | *logs 3 | *actions 4 | *notifications 5 | *tools 6 | plugins 7 | user_trunk.yaml 8 | user.yaml 9 | tmp 10 | -------------------------------------------------------------------------------- /.trunk/configs/.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Autoformatter friendly markdownlint config (all formatting rules disabled) 2 | default: true 3 | blank_lines: false 4 | bullet: false 5 | html: false 6 | indentation: false 7 | line_length: false 8 | MD041: false 9 | spaces: false 10 | url: false 11 | whitespace: false 12 | -------------------------------------------------------------------------------- /.trunk/trunk.yaml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | 3 | cli: 4 | version: 1.24.0 5 | 6 | plugins: 7 | sources: 8 | - id: trunk 9 | ref: v1.7.0 10 | uri: https://github.com/trunk-io/plugins 11 | - id: configs 12 | ref: v1.1.0 13 | uri: https://github.com/trunk-io/configs 14 | 15 | lint: 16 | # enabled list inherited from plugin 'configs' 17 | disabled: 18 | - eslint 19 | ignore: 20 | - linters: [ALL] 21 | paths: 22 | - repo_tests/** 23 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["eamodio.gitlens", "redhat.vscode-yaml", "trunk.io"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "trunk.io", 3 | "files.insertFinalNewline": true, 4 | "files.trimFinalNewlines": true, 5 | "files.trimTrailingWhitespace": true, 6 | "git.enableSmartCommit": true, 7 | "git.ignoreLimitWarning": true, 8 | "gitlens.advanced.fileHistoryFollowsRenames": true, 9 | "gitlens.codeLens.enabled": false, 10 | "terminal.integrated.scrollback": 100000, 11 | "workbench.list.horizontalScrolling": true 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Trunk Technologies, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /action.yaml: -------------------------------------------------------------------------------- 1 | name: Trunk Check 2 | author: trunk.io 3 | description: The official trunk.io GitHub action 4 | 5 | branding: 6 | icon: check 7 | color: green 8 | 9 | inputs: 10 | trunk-path: 11 | description: 12 | Path to Trunk Launcher. If not provided, we'll look for it the repo root, `.trunk/bin` and 13 | `tools/`. If it can't be found anywhere and is not provided explicitly, we'll download it on 14 | demand. 15 | required: false 16 | 17 | label: 18 | description: 19 | Label to append to the check run name (useful if running Trunk Check on multiple platforms) 20 | deprecationMessage: "Use `arguments: --github-label=value` instead." 21 | required: false 22 | 23 | arguments: 24 | description: Extra arguments to pass to trunk 25 | required: false 26 | 27 | check-mode: 28 | description: 29 | Trunk check mode. Leave unset to autodetect. Set to 'all' to check the entire repository. Set 30 | to 'populate_cache_only' in a dedicated workflow to populate the GitHub Actions cache with 31 | Trunk artifacts (see docs for more details). 32 | required: false 33 | 34 | check-all-mode: 35 | description: 36 | If set to "hold-the-line", computes new/existing issues by comparing to previous upload. 37 | required: false 38 | default: "" 39 | 40 | check-run-id: 41 | description: Check run ID. If set, posts annotations using CheckService. 42 | required: false 43 | 44 | cache: 45 | description: 46 | Cache trunk downloads and results between runs. Caching is only needed when using ephemeral CI 47 | runners. 48 | required: false 49 | default: "true" 50 | 51 | cache-key: 52 | description: 53 | A key unique to the repo/branch this action is being run on (e.g. the repo name and branch) 54 | required: false 55 | 56 | post-init: 57 | description: Steps to run after auto-init / before check 58 | required: false 59 | 60 | github-token: 61 | description: For overriding github.token 62 | required: false 63 | 64 | trunk-token: 65 | description: 66 | You can find a per-repo API token in the Trunk web app settings. This will cause results to be 67 | uploaded to the Trunk web app if this job is a scheduled job running on a branch, or if 68 | `check-mode` is set to 'all'. 69 | required: false 70 | 71 | upload-series: 72 | description: 73 | Upload series name, for when `trunk-token` is provided. If not provided, we'll use the branch 74 | name. 75 | required: false 76 | 77 | save-annotations: 78 | description: 79 | Save annotations as an artifact instead of posting them from this action. This is neccesary if 80 | your repository will be used with forks as they will will not have permissions to upload 81 | annotations. By default forks will be auto-detected. 82 | required: false 83 | default: auto 84 | 85 | post-annotations: 86 | description: 87 | Post annotations previously uploaded with the `save-annotations` option (specific to posting 88 | annotations from forks). 89 | required: false 90 | default: "false" 91 | 92 | setup-deps: 93 | description: 94 | Install dependencies for trunk check that the trunk CLI does not manage. This is only 95 | necessary if you have Node dependencies in your package.json that your Node linters need (e.g. 96 | eslint dependencies, or @types packages). 97 | required: false 98 | default: "false" 99 | 100 | debug: 101 | description: Internal use only 102 | required: false 103 | default: "false" 104 | 105 | timeout-seconds: 106 | description: 107 | Timeout seconds before we kill the long running trunk check process via unix timeout command. 108 | Default setting of 0 seconds disables the timeout. 109 | required: false 110 | default: 0 111 | 112 | cat-trunk-debug-logs: 113 | description: Option to cat .trunk/logs/cli.log && .trunk/logs/daemon.log 114 | required: false 115 | default: false 116 | 117 | lfs-checkout: 118 | description: Option to checkout LFS files 119 | required: false 120 | default: true 121 | 122 | runs: 123 | using: composite 124 | steps: 125 | - name: Set up inputs 126 | shell: bash 127 | run: | 128 | cat >>$GITHUB_ENV </dev/null; then 141 | jq -r ".inputs.payload | fromjson | .$1 // ${DEFAULT_VALUE}" ${TEST_GITHUB_EVENT_PATH:-${GITHUB_EVENT_PATH}} 142 | else 143 | echo "::error::jq not installed on system!" 144 | exit 1 145 | fi 146 | } 147 | 148 | # Every inputs.field should be referenced as INPUT_FIELD later in the action. This allows 149 | # the field to be set either as an argument to the github action or via inputs.json. 150 | if [[ "${{ inputs.check-mode }}" == "payload" ]]; then 151 | 152 | INPUT_GITHUB_TOKEN=$(payload githubToken) 153 | INPUT_TRUNK_TOKEN=$(payload trunkToken) 154 | echo "::add-mask::${INPUT_GITHUB_TOKEN}" 155 | echo "::add-mask::${INPUT_TRUNK_TOKEN}" 156 | 157 | cat >>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV 255 | fi 256 | 257 | - name: Detect setup strategy 258 | shell: bash 259 | run: | 260 | if [[ -e .trunk/setup-ci ]]; then 261 | echo "INPUT_SETUP_DEPS=true" >>$GITHUB_ENV 262 | else 263 | mkdir -p .trunk 264 | ln -s ${{ github.action_path }}/setup-env .trunk/setup-ci 265 | echo .trunk/setup-ci >>.git/info/exclude 266 | fi 267 | 268 | - name: Find Comment 269 | uses: peter-evans/find-comment@v3 270 | if: | 271 | inputs.check-mode == 'payload' && env.TRUNK_CHECK_MODE == 'pull_request' && 272 | env.INPUT_GITHUB_TOKEN 273 | id: fc 274 | continue-on-error: true 275 | with: 276 | issue-number: ${{ env.GITHUB_EVENT_PULL_REQUEST_NUMBER }} 277 | repository: ${{ env.INPUT_TARGET_CHECKOUT }} 278 | token: ${{ env.INPUT_GITHUB_TOKEN }} 279 | body-regex: ^.*https://docs.trunk.io/code-quality/setup-and-installation/prevent-new-issues/migration-guide.*$ 280 | 281 | - name: Post comment 282 | uses: peter-evans/create-or-update-comment@v4 283 | if: | 284 | inputs.check-mode == 'payload' && env.TRUNK_CHECK_MODE == 'pull_request' && 285 | env.INPUT_GITHUB_TOKEN 286 | continue-on-error: true 287 | with: 288 | comment-id: ${{ steps.fc.outputs.comment-id }} 289 | issue-number: ${{ env.GITHUB_EVENT_PULL_REQUEST_NUMBER }} 290 | repository: ${{ env.INPUT_TARGET_CHECKOUT }} 291 | token: ${{ env.INPUT_GITHUB_TOKEN }} 292 | edit-mode: replace 293 | body: | 294 | Running Code Quality on PRs by uploading data to Trunk will soon be removed. You can still run checks on your PRs using [trunk-action](https://github.com/trunk-io/trunk-action) - see the [migration guide](https://docs.trunk.io/code-quality/setup-and-installation/prevent-new-issues/migration-guide) for more information. 295 | 296 | - name: Set up env 297 | uses: ./.trunk/setup-ci 298 | if: env.INPUT_SETUP_DEPS == 'true' 299 | with: 300 | cache-key: ${{ env.INPUT_SETUP_CACHE_KEY }} 301 | 302 | - name: Post-init steps 303 | if: inputs.post-init 304 | shell: bash 305 | run: ${{ inputs.post-init }} 306 | 307 | - name: Cache Linters/Formatters 308 | if: env.TRUNK_CHECK_MODE != 'none' && env.INPUT_CACHE == 'true' 309 | uses: actions/cache@v4 310 | with: 311 | path: ${{ env.INPUT_CACHE_PATH }} 312 | key: ${{ env.INPUT_CACHE_KEY }} 313 | 314 | - name: Run trunk check on pull request 315 | if: env.TRUNK_CHECK_MODE == 'pull_request' 316 | shell: bash 317 | run: | 318 | # Run 'trunk check' on pull request 319 | if [[ "${{ inputs.timeout-seconds }}" != "0" ]]; then 320 | timeout ${{ inputs.timeout-seconds }} ${GITHUB_ACTION_PATH}/pull_request.sh 321 | else 322 | ${GITHUB_ACTION_PATH}/pull_request.sh 323 | fi 324 | env: 325 | INPUT_SAVE_ANNOTATIONS: ${{ inputs.save-annotations }} 326 | 327 | - name: Run trunk check on push 328 | if: env.TRUNK_CHECK_MODE == 'push' 329 | shell: bash 330 | run: | 331 | # Run 'trunk check' on push 332 | if [[ "${{ inputs.timeout-seconds }}" != "0" ]]; then 333 | timeout ${{ inputs.timeout-seconds }} ${GITHUB_ACTION_PATH}/push.sh 334 | else 335 | ${GITHUB_ACTION_PATH}/push.sh 336 | fi 337 | env: 338 | GITHUB_EVENT_AFTER: ${{ env.GITHUB_EVENT_AFTER || github.event.after }} 339 | GITHUB_EVENT_BEFORE: ${{ env.GITHUB_EVENT_BEFORE || github.event.before }} 340 | 341 | - name: Run trunk check on all 342 | if: env.TRUNK_CHECK_MODE == 'all' 343 | shell: bash 344 | run: | 345 | # Run 'trunk check' on all 346 | if [[ "${{ inputs.timeout-seconds }}" != "0" ]]; then 347 | timeout ${{ inputs.timeout-seconds }} ${GITHUB_ACTION_PATH}/all.sh 348 | else 349 | ${GITHUB_ACTION_PATH}/all.sh 350 | fi 351 | 352 | - name: Run trunk check on Trunk Merge 353 | if: env.TRUNK_CHECK_MODE == 'trunk_merge' 354 | shell: bash 355 | run: | 356 | # Run 'trunk check' on Trunk Merge 357 | if [[ "${{ inputs.timeout-seconds }}" != "0" ]]; then 358 | timeout ${{ inputs.timeout-seconds }} ${GITHUB_ACTION_PATH}/trunk_merge.sh 359 | else 360 | ${GITHUB_ACTION_PATH}/trunk_merge.sh 361 | fi 362 | 363 | - name: Cat Trunk Cli / Daemon logs 364 | if: always() && inputs.cat-trunk-debug-logs == 'true' 365 | shell: bash 366 | run: | 367 | echo "::group::.trunk/logs/cli.log" 368 | if [[ -f .trunk/logs/cli.log ]]; then 369 | cat .trunk/logs/cli.log 370 | else 371 | echo ".trunk/logs/cli.log doesn't exist" 372 | fi 373 | echo "::endgroup::" 374 | 375 | echo "::group::.trunk/logs/daemon.log" 376 | if [[ -f .trunk/logs/daemon.log ]]; then 377 | cat .trunk/logs/daemon.log 378 | else 379 | echo ".trunk/logs/daemon.log doesn't exist" 380 | fi 381 | echo "::endgroup::" 382 | 383 | - name: Run trunk install to populate the GitHub Actions cache 384 | if: env.TRUNK_CHECK_MODE == 'populate_cache_only' 385 | shell: bash 386 | run: | 387 | # Run 'trunk install' to populate the GitHub Actions cache 388 | ${GITHUB_ACTION_PATH}/populate_cache_only.sh 389 | 390 | - name: Upload annotations artifact 391 | if: always() && env.TRUNK_UPLOAD_ANNOTATIONS == 'true' 392 | uses: actions/upload-artifact@v4 393 | with: 394 | name: trunk-annotations 395 | overwrite: true 396 | path: ${{ env.TRUNK_TMPDIR }}/annotations.bin 397 | 398 | - name: Download annotations artifact 399 | if: inputs.post-annotations == 'true' 400 | uses: actions/github-script@v7 401 | with: 402 | # TODO(chris): We can't use the official download artifact action yet: https://github.com/actions/download-artifact/issues/172 403 | script: | 404 | let artifacts = await github.rest.actions.listWorkflowRunArtifacts({ 405 | owner: context.repo.owner, 406 | repo: context.repo.repo, 407 | run_id: ${{ github.event.workflow_run.id }}, 408 | }); 409 | let matchArtifact = artifacts.data.artifacts.filter((artifact) => { 410 | return artifact.name == "trunk-annotations" 411 | })[0]; 412 | if (matchArtifact) { 413 | let download = await github.rest.actions.downloadArtifact({ 414 | owner: context.repo.owner, 415 | repo: context.repo.repo, 416 | artifact_id: matchArtifact.id, 417 | archive_format: 'zip', 418 | }); 419 | let fs = require('fs'); 420 | fs.writeFileSync('${{ env.TRUNK_TMPDIR }}/annotations.zip', Buffer.from(download.data)); 421 | } 422 | 423 | - name: Unpack annotations artifact 424 | if: inputs.post-annotations == 'true' 425 | run: | 426 | # Unpack annotations artifact 427 | cd ${{ env.TRUNK_TMPDIR }} && unzip annotations.zip 428 | shell: bash 429 | 430 | - name: Post annotations 431 | if: inputs.post-annotations == 'true' 432 | shell: bash 433 | run: | 434 | # Post annotations 435 | ${GITHUB_ACTION_PATH}/annotate.sh 436 | env: 437 | GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} 438 | 439 | - name: Upload landing state 440 | if: env.INPUT_UPLOAD_LANDING_STATE == 'true' 441 | continue-on-error: true 442 | uses: actions/upload-artifact@v4 443 | with: 444 | name: landing-state.json 445 | path: .trunk/landing-state.json 446 | overwrite: true 447 | if-no-files-found: warn 448 | 449 | - name: Cleanup temporary files 450 | if: always() 451 | shell: bash 452 | run: | 453 | # Cleanup temporary files 454 | ${GITHUB_ACTION_PATH}/cleanup.sh 455 | -------------------------------------------------------------------------------- /action_tests/all_test_payload.json: -------------------------------------------------------------------------------- 1 | { 2 | "trunkPath": "./local-action/action_tests/stub.js", 3 | "targetRefName": "main", 4 | "targetCheckoutRef": "main", 5 | "checkMode": "all", 6 | "trunkToken": "fake-token", 7 | "version": "0.0.0", 8 | "arguments": " --replace", 9 | "githubToken": "fake-token", 10 | "cache": true, 11 | "cacheKey": "trunk-check", 12 | "cachePath": "~/.cache/trunk/tools/ruby", 13 | "trunkApiAddress": "localhost-will-not-work:5021", 14 | "checkJobName": "action-test/trunk-action/all", 15 | "checkJobRunsOn": ["self-hosted", "linux", "public", "x86", "2xlarge"], 16 | "checkWorkflowRunName": "action-test-all", 17 | "concurrencyGroup": "trunk-action/all/main", 18 | "debug": true 19 | } 20 | -------------------------------------------------------------------------------- /action_tests/assert.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const chai = require("chai"); 4 | const fs = require("fs"); 5 | const path = require("path"); 6 | 7 | const { expect } = chai; 8 | 9 | const stubLog = fs.readFileSync(process.env.TRUNK_STUB_LOGS, "utf8").split("\n"); 10 | 11 | // The last element of the split() should be an empty string 12 | expect(stubLog.slice(-1)).to.deep.equal([""]); 13 | 14 | const getHtlFactoriesPath = () => { 15 | const tmpdirContents = fs.readdirSync(process.env.TMPDIR); 16 | 17 | if (tmpdirContents.length === 0) { 18 | throw new Error( 19 | `TMPDIR=${process.env.TMPDIR} was empty; could not infer what --htl-factories-path should have been`, 20 | ); 21 | } 22 | 23 | if (tmpdirContents.length > 1) { 24 | throw new Error( 25 | `TMPDIR=${process.env.TMPDIR} had multiple entries (${JSON.stringify( 26 | tmpdirContents, 27 | )}); could not infer what --htl-factories-path should have been`, 28 | ); 29 | } 30 | 31 | return path.join(process.env.TMPDIR, tmpdirContents[0]); 32 | }; 33 | 34 | const EXPECTED_CLI_CALL_FACTORIES = { 35 | "trunk-merge": () => [ 36 | [ 37 | "trunk", 38 | "check", 39 | "--ci", 40 | "--upstream", 41 | process.env.EXPECTED_UPSTREAM, 42 | "--github-commit", 43 | process.env.EXPECTED_GITHUB_COMMIT, 44 | "--github-label", 45 | "", 46 | ], 47 | ], 48 | "trunk-merge-annotate": () => [ 49 | ["trunk", "version"], 50 | [ 51 | "trunk", 52 | "check", 53 | "--ci", 54 | "--upstream", 55 | process.env.EXPECTED_UPSTREAM, 56 | "--github-commit", 57 | process.env.EXPECTED_GITHUB_COMMIT, 58 | "--github-label", 59 | "", 60 | "--trunk-annotate=8675309", 61 | ], 62 | ], 63 | "trunk-merge-annotate-old-cli": () => [["trunk", "version"]], 64 | "pull-request-trunk-annotate": () => [ 65 | ["trunk", "version"], 66 | [ 67 | "trunk", 68 | "check", 69 | "--ci", 70 | "--upstream", 71 | process.env.EXPECTED_UPSTREAM, 72 | "--github-commit", 73 | process.env.EXPECTED_GITHUB_COMMIT, 74 | "--github-label", 75 | "", 76 | "--trunk-annotate=8675309", 77 | ], 78 | ], 79 | "pull-request-trunk-annotate-old-cli": () => [["trunk", "version"]], 80 | "pull-request-github-annotate-file": () => [ 81 | [ 82 | "trunk", 83 | "check", 84 | "--ci", 85 | "--upstream", 86 | process.env.EXPECTED_UPSTREAM, 87 | "--github-commit", 88 | process.env.EXPECTED_GITHUB_COMMIT, 89 | "--github-label", 90 | "", 91 | "--github-annotate-file=/tmp/trunk/annotations.bin", 92 | ], 93 | ], 94 | "pull-request-merge": () => [ 95 | [ 96 | "trunk", 97 | "check", 98 | "--ci", 99 | "--upstream", 100 | process.env.EXPECTED_UPSTREAM, 101 | "--github-commit", 102 | process.env.EXPECTED_GITHUB_COMMIT, 103 | "--github-label", 104 | "", 105 | "--github-annotate", 106 | ], 107 | ], 108 | "all-hold-the-line-new-series": () => [ 109 | ["trunk", "check", "get-latest-raw-output", "--series", "series-name", getHtlFactoriesPath()], 110 | ["trunk", "version"], 111 | [ 112 | "trunk", 113 | "check", 114 | "--all", 115 | "--upload", 116 | "--upload-id", 117 | "test-upload-id", 118 | "--series", 119 | "series-name", 120 | ], 121 | ], 122 | "all-hold-the-line-existing-series": () => [ 123 | ["trunk", "check", "get-latest-raw-output", "--series", "series-name", getHtlFactoriesPath()], 124 | ["trunk", "version"], 125 | [ 126 | "trunk", 127 | "check", 128 | "--all", 129 | "--upload", 130 | `--htl-factories-path=${getHtlFactoriesPath()}`, 131 | "--upload-id", 132 | "test-upload-id", 133 | "--series", 134 | "series-name", 135 | ], 136 | ], 137 | // the stub hands back an old version in env.TRUNK_CLI_VERSION for this test 138 | "all-hold-the-line-old-cli-version": () => [ 139 | ["trunk", "check", "get-latest-raw-output", "--series", "series-name", getHtlFactoriesPath()], 140 | ["trunk", "version"], 141 | ], 142 | "all-hold-the-line-no-upload-id": () => [ 143 | ["trunk", "check", "get-latest-raw-output", "--series", "series-name", getHtlFactoriesPath()], 144 | ["trunk", "check", "--all", "--upload", "--series", "series-name"], 145 | ], 146 | "pull-request-autofix": () => [ 147 | ["trunk", "version"], 148 | [ 149 | "trunk", 150 | "check", 151 | "--ci", 152 | "--upstream", 153 | process.env.EXPECTED_UPSTREAM, 154 | "--fix", 155 | "--trunk-annotate=12345678", 156 | ], 157 | ], 158 | "pull-request-payload": () => [ 159 | ["trunk", "version"], 160 | ["trunk", "--ci", "init"], 161 | ["trunk", "version"], 162 | [ 163 | "trunk", 164 | "check", 165 | "--ci", 166 | "--upstream", 167 | process.env.EXPECTED_UPSTREAM, 168 | "--github-commit", 169 | process.env.EXPECTED_GITHUB_COMMIT, 170 | "--github-label", 171 | "", 172 | "--trunk-annotate=14235603498", 173 | ], 174 | ], 175 | "trunk-merge-payload": () => [ 176 | ["trunk", "version"], 177 | ["trunk", "--ci", "init"], 178 | ["trunk", "version"], 179 | [ 180 | "trunk", 181 | "check", 182 | "--ci", 183 | "--upstream", 184 | process.env.EXPECTED_UPSTREAM, 185 | "--github-commit", 186 | process.env.EXPECTED_GITHUB_COMMIT, 187 | "--github-label", 188 | "", 189 | "--trunk-annotate=14235603498", 190 | ], 191 | ], 192 | "all-payload": () => [ 193 | ["trunk", "version"], 194 | ["trunk", "--ci", "init"], 195 | [ 196 | "trunk", 197 | "check", 198 | "--all", 199 | "--upload", 200 | "--series", 201 | "main", 202 | "--token", 203 | process.env.INPUT_TRUNK_TOKEN, 204 | "--replace", 205 | ], 206 | ], 207 | }; 208 | 209 | const testCase = process.argv[2]; 210 | const expectedCliCalls = EXPECTED_CLI_CALL_FACTORIES[testCase](); 211 | 212 | // Strip the last element before JSON.parse, because '' is not valid JSON. 213 | const actualCliCalls = stubLog.slice(0, -1).map(JSON.parse); 214 | 215 | expect(actualCliCalls).to.deep.equal(expectedCliCalls); 216 | 217 | console.log(`Test passed: ${testCase}\n\nCLI calls were:\n${JSON.stringify(actualCliCalls)}`); 218 | -------------------------------------------------------------------------------- /action_tests/pull_request_test_payload.json: -------------------------------------------------------------------------------- 1 | { 2 | "trunkPath": "./local-action/action_tests/stub.js", 3 | "targetRefName": "1/merge", 4 | "targetCheckoutRef": "refs/pull/1/merge", 5 | "checkMode": "pull_request", 6 | "trunkToken": "fake-token", 7 | "pullRequest": { 8 | "number": 1, 9 | "head": { 10 | "sha": "fake-head-sha", 11 | "ref": "feature-branch" 12 | }, 13 | "base": { 14 | "sha": "fake-base-sha", 15 | "ref": "main" 16 | } 17 | }, 18 | "checkRunId": 14235603498, 19 | "version": "0.0.0", 20 | "githubToken": "fake-token", 21 | "cache": true, 22 | "cacheKey": "trunk-check", 23 | "cachePath": "~/.cache/trunk/tools/ruby", 24 | "trunkApiAddress": "localhost-will-not-work:5021", 25 | "checkJobName": "repo-under-test/pull_request", 26 | "checkJobRunsOn": ["self-hosted", "linux", "public", "x86", "2xlarge"], 27 | "checkWorkflowRunName": "action-test-pull-request", 28 | "concurrencyGroup": "repo-under-test/1", 29 | "debug": true 30 | } 31 | -------------------------------------------------------------------------------- /action_tests/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | src_repo=$1 6 | output_repo=$2 7 | 8 | git config --global init.defaultBranch main 9 | 10 | ## Set up repo in `src_repo` 11 | 12 | mkdir -p "${src_repo}" 13 | ( 14 | cd "${src_repo}" 15 | 16 | git init 17 | 18 | git config user.name 'trunk-io/trunk-action action_tests' 19 | git config user.email 'action_tests@trunk-action.trunk.io' 20 | 21 | echo "This is a README." >>readme.md 22 | git add . 23 | git commit --all --message 'First commit' 24 | 25 | echo "These are contribution guidelines." >>contributing.md 26 | git add . 27 | git commit --all --message 'Second commit' 28 | 29 | ## Prepare a branch `feature-branch` 30 | 31 | git checkout -b feature-branch main^ 32 | 33 | echo "markdown file for merge test" >>merge-test.md 34 | git add . 35 | git commit --all --message 'add file for merge test setup' 36 | 37 | ## Prepare a merge graph commit 38 | 39 | git checkout -b trunk-merge/of-feature-branch main 40 | 41 | git merge --no-ff --no-edit feature-branch 42 | 43 | ## Prepare a branch for payload pull_request 44 | 45 | git checkout feature-branch 46 | 47 | git checkout -b 1/merge main 48 | 49 | git merge --no-ff --no-edit feature-branch 50 | 51 | ## Go back to `main` 52 | 53 | git checkout main 54 | 55 | ## Dump the state of the repo 56 | 57 | git log --graph --pretty=oneline trunk-merge/of-feature-branch 58 | git log --graph --pretty=oneline 1/merge 59 | ) 60 | 61 | ## Set up repo in `output_repo` 62 | 63 | git clone "${src_repo}" "${output_repo}" 64 | 65 | ## Force mktemp to point at TMPDIR 66 | 67 | mkdir -p "${TMPDIR}" 68 | -------------------------------------------------------------------------------- /action_tests/stub.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require("fs"); 4 | const path = require("node:path"); 5 | 6 | const getArgv = () => { 7 | if (path.basename(process.argv[1]) === "stub.js") { 8 | return ["trunk"].concat(process.argv.slice(2)); 9 | } 10 | 11 | fs.appendFileSync( 12 | process.env.TRUNK_STUB_LOGS, 13 | JSON.stringify({ 14 | error: "Failed to sanitize argv", 15 | argv: process.argv, 16 | }), 17 | ); 18 | fs.appendFileSync(process.env.TRUNK_STUB_LOGS, "\n"); 19 | return process.argv; 20 | }; 21 | 22 | // process.argv will look like ['/abs/path/to/node', '/abs/path/to/stub.js', ...] 23 | // We only want to assert that the calls look like ['trunk', 'check', '--ci', ...], hence the rewrite 24 | const argv = getArgv(); 25 | 26 | fs.appendFileSync(process.env.TRUNK_STUB_LOGS, JSON.stringify(argv)); 27 | fs.appendFileSync(process.env.TRUNK_STUB_LOGS, "\n"); 28 | 29 | if (argv[1] === "check" && argv[2] === "get-latest-raw-output") { 30 | process.stdout.write(process.env.STUB_GET_LATEST_RAW_OUTPUT_STDOUT); 31 | } 32 | 33 | if (argv[1] === "version") { 34 | process.stdout.write(process.env.TRUNK_CLI_VERSION || "99.99.99"); 35 | } 36 | -------------------------------------------------------------------------------- /action_tests/trunk_merge_test_payload.json: -------------------------------------------------------------------------------- 1 | { 2 | "trunkPath": "./local-action/action_tests/stub.js", 3 | "targetRefName": "trunk-merge/of-feature-branch", 4 | "targetCheckoutRef": "refs/heads/trunk-merge/of-feature-branch", 5 | "checkMode": "trunk_merge", 6 | "trunkToken": "fake-token", 7 | "checkRunId": 14235603498, 8 | "version": "0.0.0", 9 | "githubToken": "fake-token", 10 | "cache": true, 11 | "cacheKey": "trunk-check", 12 | "cachePath": "~/.cache/trunk/tools/ruby", 13 | "trunkApiAddress": "localhost-will-not-work:5021", 14 | "checkJobName": "action-test/trunk-action/trunk_merge", 15 | "checkJobRunsOn": ["self-hosted", "linux", "public", "x86", "2xlarge"], 16 | "checkWorkflowRunName": "action-test-trunk-merge", 17 | "concurrencyGroup": "trunk-action/trunk_merge/trunk-merge/of-feature-branch", 18 | "debug": true 19 | } 20 | -------------------------------------------------------------------------------- /all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | if [[ ${INPUT_DEBUG} == "true" ]]; then 8 | set -x 9 | fi 10 | 11 | fetch() { 12 | git -c protocol.version=2 fetch -q \ 13 | --no-tags \ 14 | --no-recurse-submodules \ 15 | "$@" 16 | } 17 | 18 | MINIMUM_UPLOAD_ID_VERSION=1.12.3 19 | 20 | echo "::warning::Check uploads and check all mode is no longer supported. Please see https://docs.trunk.io/code-quality/setup-and-installation/prevent-new-issues/migration-guide for more information." 21 | if [[ -z ${INPUT_TRUNK_TOKEN} ]]; then 22 | "${TRUNK_PATH}" check \ 23 | --ci \ 24 | --all \ 25 | --github-commit "${GITHUB_SHA}" \ 26 | ${INPUT_ARGUMENTS} 27 | elif [[ ${INPUT_CHECK_ALL_MODE} == "hold-the-line" ]]; then 28 | latest_raw_upload="$(mktemp)" 29 | prev_ref="$("${TRUNK_PATH}" check get-latest-raw-output \ 30 | --series "${INPUT_UPLOAD_SERIES:-${GITHUB_REF_NAME}}" \ 31 | "${latest_raw_upload}")" 32 | if [[ ${prev_ref} =~ .*"new series".* ]]; then 33 | echo "${prev_ref}" 34 | htl_arg="" 35 | else 36 | htl_arg="--htl-factories-path=${latest_raw_upload}" 37 | fetch origin "${prev_ref}" 38 | fi 39 | if [[ -n ${INPUT_UPLOAD_ID-} ]]; then # if upload ID unset, skip it instead of erroring 40 | upload_id_arg="--upload-id ${INPUT_UPLOAD_ID}" 41 | trunk_version="$(${TRUNK_PATH} version)" 42 | # trunk-ignore-begin(shellcheck/SC2312): the == will fail if anything inside the $() fails 43 | if sort_result=$(printf "%s\n%s\n" "${MINIMUM_UPLOAD_ID_VERSION}" "${trunk_version}" | sort --version-sort); then 44 | if [[ $(echo "${sort_result}" | head -n 1) == "${trunk_version}" ]]; then 45 | echo "::error::Please update your CLI to ${MINIMUM_UPLOAD_ID_VERSION} or higher (current version ${trunk_version})." 46 | exit 1 47 | fi 48 | else 49 | echo "::warning::sort --version-sort failed - continuing without checking CLI version" 50 | fi 51 | # trunk-ignore-end(shellcheck/SC2312) 52 | else 53 | upload_id_arg="" 54 | fi 55 | "${TRUNK_PATH}" check \ 56 | --all \ 57 | --upload \ 58 | ${htl_arg} \ 59 | ${upload_id_arg} \ 60 | --series "${INPUT_UPLOAD_SERIES:-${GITHUB_REF_NAME}}" \ 61 | ${INPUT_ARGUMENTS} 62 | else 63 | "${TRUNK_PATH}" check \ 64 | --all \ 65 | --upload \ 66 | --series "${INPUT_UPLOAD_SERIES:-${INPUT_GITHUB_REF_NAME}}" \ 67 | --token "${INPUT_TRUNK_TOKEN}" \ 68 | ${INPUT_ARGUMENTS} 69 | fi 70 | -------------------------------------------------------------------------------- /annotate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | "${TRUNK_PATH}" check github_annotate \ 8 | --ci \ 9 | --upstream HEAD \ 10 | --github-commit "${GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA}" \ 11 | --github-label "${INPUT_LABEL}" \ 12 | "${TRUNK_TMPDIR}/annotations.bin" \ 13 | ${INPUT_ARGUMENTS} 14 | -------------------------------------------------------------------------------- /caching.md: -------------------------------------------------------------------------------- 1 | # Caching Semantics 2 | 3 | ## Invoked from a GitHub workflow 4 | 5 | We cache the contents of `~/.cache/trunk/` if `inputs.cache === true`. 6 | 7 | Note that the GitHub Actions cache only caches results on a per-branch/per-PR basis, so the first 8 | time `Trunk Check` runs on a given branch, it will be uncached. Subsequent runs will read from 9 | cache. 10 | 11 | ## Invoked inside the `.trunk` repo 12 | 13 | We only cache the contents of `~/.cache/trunk/tools/ruby/` (Ruby is the only tool install that is 14 | painfully slow, since it has to be built from scratch on every single install). 15 | 16 | Although we _could_ cache all of `~/.cache/trunk/`, doing so would yield no benefit: 17 | 18 | - GitHub starts evicting cache entries once the size of all GitHub Actions cache entries for a repo 19 | exceeds 10GiB ([documentation][gha-cache-limits]). 20 | 21 | - We expect the cache size to be dominated by `~/.cache/trunk/tools/`, which for all tools in a repo 22 | usually reaches into multiple GiB, even compressed. 23 | 24 | - Since Trunk Check will run for all repos in a given GitHub org in workflows in `your-org/.trunk`, 25 | all such repos end up sharing the `.trunk` GitHub Actions cache, eventually the sizes of each 26 | repo's cache entry will cause them to stomp on each other. 27 | 28 | Experimentally, installing all tools from scratch (except Ruby) only takes ~1 min, so we don't 29 | believe there will be any noticeable benefit to caching the contents of the tools cache. 30 | 31 | We don't expect caching linter results to be a significant improvement either. 32 | 33 | [gha-cache-limits]: 34 | https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy 35 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ -n ${TRUNK_TMPDIR+x} ]]; then 6 | rm -rf "${TRUNK_TMPDIR}" 7 | fi 8 | -------------------------------------------------------------------------------- /determine_check_mode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ ${INPUT_DEBUG} == "true" ]]; then 6 | set -x 7 | fi 8 | 9 | check_mode="${INPUT_CHECK_MODE}" 10 | if [[ -z ${check_mode} ]]; then 11 | if [[ ${GITHUB_EVENT_NAME} == "pull_request" || ${GITHUB_EVENT_NAME} == "pull_request_target" ]]; then 12 | check_mode="pull_request" 13 | elif [[ ${GITHUB_EVENT_NAME} == "push" && (${GITHUB_REF_NAME} == trunk-merge/* || ${GITHUB_REF_NAME} == trunk-merge-beta/*) ]]; then 14 | check_mode="trunk_merge" 15 | elif [[ ${GITHUB_EVENT_NAME} == "push" ]]; then 16 | check_mode="push" 17 | elif [[ ${GITHUB_EVENT_NAME} == "workflow_dispatch" && (${GITHUB_REF_NAME} == trunk-merge/* || ${GITHUB_REF_NAME} == trunk-merge-beta/*) ]]; then 18 | check_mode="trunk_merge" 19 | elif [[ ${GITHUB_EVENT_NAME} == "workflow_dispatch" || ${GITHUB_EVENT_NAME} == "schedule" ]]; then 20 | check_mode="all" 21 | else 22 | check_mode="none" 23 | fi 24 | elif [[ ${check_mode} != "all" && ${check_mode} != "none" && ${check_mode} != "populate_cache_only" && ${check_mode} != "pull_request" && ${check_mode} != "push" && ${check_mode} != "trunk_merge" ]]; then 25 | echo "check-mode must be one of: 'all', 'none', 'populate_cache_only', 'pull_request', 'push', or 'trunk_merge'" 26 | exit 1 27 | fi 28 | 29 | echo "TRUNK_CHECK_MODE=${check_mode}" >>"${GITHUB_ENV}" 30 | -------------------------------------------------------------------------------- /install/action.yaml: -------------------------------------------------------------------------------- 1 | name: Trunk Check 2 | author: trunk.io 3 | description: Install trunk and managed tools to PATH 4 | 5 | inputs: 6 | tools: 7 | description: specific tools to install (if not specified will install all enabled tools) 8 | required: false 9 | 10 | branding: 11 | icon: check 12 | color: green 13 | 14 | runs: 15 | using: composite 16 | steps: 17 | - name: get trunk 18 | shell: bash 19 | run: ${GITHUB_ACTION_PATH}/get_trunk.sh 20 | 21 | - name: clean up possible dead symlink 22 | shell: bash 23 | run: | 24 | tools_path=".trunk/tools" 25 | if [ -L "${tools_path}" ] && [ ! -e "${tools_path}" ] ; then 26 | rm "${tools_path}" 27 | fi 28 | 29 | - name: Trunk install 30 | shell: bash 31 | run: trunk tools install --ci ${{ inputs.tools }} 32 | 33 | - name: Add .trunk/tools to path 34 | shell: bash 35 | run: echo ".trunk/tools" >> $GITHUB_PATH 36 | -------------------------------------------------------------------------------- /install/get_trunk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ ${INPUT_DEBUG:-false} == "true" ]]; then 6 | set -x 7 | fi 8 | 9 | tmpdir="$(mktemp -d)" 10 | echo "TRUNK_TMPDIR=${tmpdir}" >>"${GITHUB_ENV}" 11 | 12 | curl -fsSL https://trunk.io/releases/trunk -o "${tmpdir}/trunk" 13 | chmod u+x "${tmpdir}/trunk" 14 | trunk_path="${tmpdir}/trunk" 15 | 16 | echo "TRUNK_PATH=${trunk_path}" >>"${GITHUB_ENV}" 17 | echo "${tmpdir}" >>"${GITHUB_PATH}" 18 | 19 | # Ensure that trunk CLI is downloaded before subsequent steps (swallow output of version command) 20 | (${trunk_path} version >/dev/null 2>&1) || echo "::warning::${trunk_path} does not exist!" 21 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trunk-action", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "chai": "^4.3.7" 9 | }, 10 | "engines": { 11 | "node": "20.8.1" 12 | } 13 | }, 14 | "node_modules/assertion-error": { 15 | "version": "1.1.0", 16 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 17 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 18 | "engines": { 19 | "node": "*" 20 | } 21 | }, 22 | "node_modules/chai": { 23 | "version": "4.3.10", 24 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", 25 | "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", 26 | "dependencies": { 27 | "assertion-error": "^1.1.0", 28 | "check-error": "^1.0.3", 29 | "deep-eql": "^4.1.3", 30 | "get-func-name": "^2.0.2", 31 | "loupe": "^2.3.6", 32 | "pathval": "^1.1.1", 33 | "type-detect": "^4.0.8" 34 | }, 35 | "engines": { 36 | "node": ">=4" 37 | } 38 | }, 39 | "node_modules/check-error": { 40 | "version": "1.0.3", 41 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", 42 | "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", 43 | "dependencies": { 44 | "get-func-name": "^2.0.2" 45 | }, 46 | "engines": { 47 | "node": "*" 48 | } 49 | }, 50 | "node_modules/deep-eql": { 51 | "version": "4.1.3", 52 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 53 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 54 | "dependencies": { 55 | "type-detect": "^4.0.0" 56 | }, 57 | "engines": { 58 | "node": ">=6" 59 | } 60 | }, 61 | "node_modules/get-func-name": { 62 | "version": "2.0.2", 63 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", 64 | "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", 65 | "engines": { 66 | "node": "*" 67 | } 68 | }, 69 | "node_modules/loupe": { 70 | "version": "2.3.6", 71 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", 72 | "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", 73 | "dependencies": { 74 | "get-func-name": "^2.0.0" 75 | } 76 | }, 77 | "node_modules/pathval": { 78 | "version": "1.1.1", 79 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 80 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 81 | "engines": { 82 | "node": "*" 83 | } 84 | }, 85 | "node_modules/type-detect": { 86 | "version": "4.0.8", 87 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 88 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 89 | "engines": { 90 | "node": ">=4" 91 | } 92 | } 93 | }, 94 | "dependencies": { 95 | "assertion-error": { 96 | "version": "1.1.0", 97 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 98 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" 99 | }, 100 | "chai": { 101 | "version": "4.3.10", 102 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", 103 | "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", 104 | "requires": { 105 | "assertion-error": "^1.1.0", 106 | "check-error": "^1.0.3", 107 | "deep-eql": "^4.1.3", 108 | "get-func-name": "^2.0.2", 109 | "loupe": "^2.3.6", 110 | "pathval": "^1.1.1", 111 | "type-detect": "^4.0.8" 112 | } 113 | }, 114 | "check-error": { 115 | "version": "1.0.3", 116 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", 117 | "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", 118 | "requires": { 119 | "get-func-name": "^2.0.2" 120 | } 121 | }, 122 | "deep-eql": { 123 | "version": "4.1.3", 124 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", 125 | "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", 126 | "requires": { 127 | "type-detect": "^4.0.0" 128 | } 129 | }, 130 | "get-func-name": { 131 | "version": "2.0.2", 132 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", 133 | "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" 134 | }, 135 | "loupe": { 136 | "version": "2.3.6", 137 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", 138 | "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", 139 | "requires": { 140 | "get-func-name": "^2.0.0" 141 | } 142 | }, 143 | "pathval": { 144 | "version": "1.1.1", 145 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 146 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" 147 | }, 148 | "type-detect": { 149 | "version": "4.0.8", 150 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 151 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "chai": "^4.3.7" 4 | }, 5 | "engines": { 6 | "node": "20.8.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /populate_cache_only.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | "${TRUNK_PATH}" install \ 8 | --ci \ 9 | ${INPUT_ARGUMENTS} 10 | -------------------------------------------------------------------------------- /pull_request.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | if [[ ${INPUT_DEBUG} == "true" ]]; then 8 | set -x 9 | fi 10 | 11 | fetch() { 12 | git -c protocol.version=2 fetch -q \ 13 | --no-tags \ 14 | --no-recurse-submodules \ 15 | "$@" 16 | } 17 | 18 | MINIMUM_CHECK_RUN_ID_VERSION=1.7.0 19 | 20 | if [[ ${INPUT_GITHUB_REF_NAME} == "${GITHUB_EVENT_PULL_REQUEST_NUMBER}/merge" ]]; then 21 | # If we have checked out the merge commit then fetch enough history to use HEAD^1 as the upstream. 22 | # We use this instead of github.event.pull_request.base.sha which can be incorrect sometimes. 23 | head_sha=$(git rev-parse HEAD) 24 | fetch --depth=2 origin "${head_sha}" 25 | upstream=$(git rev-parse HEAD^1) 26 | git_commit=$(git rev-parse HEAD^2) 27 | echo "Detected merge commit, using HEAD^1 (${upstream}) as upstream and HEAD^2 (${git_commit}) as github commit" 28 | fi 29 | 30 | if [[ -z ${upstream+x} ]]; then 31 | # Otherwise use github.event.pull_request.base.sha as the upstream. 32 | upstream="${GITHUB_EVENT_PULL_REQUEST_BASE_SHA}" 33 | git_commit="${GITHUB_EVENT_PULL_REQUEST_HEAD_SHA}" 34 | fetch origin "${upstream}" 35 | fi 36 | 37 | save_annotations=${INPUT_SAVE_ANNOTATIONS} 38 | if [[ ${save_annotations} == "auto" && ${GITHUB_EVENT_PULL_REQUEST_HEAD_REPO_FORK} == "true" ]]; then 39 | echo "Fork detected, saving annotations to an artifact." 40 | save_annotations=true 41 | fi 42 | 43 | if [[ -n ${INPUT_CHECK_RUN_ID} ]]; then 44 | trunk_version="$(${TRUNK_PATH} version)" 45 | # trunk-ignore-begin(shellcheck/SC2312): the == will fail if anything inside the $() fails 46 | if sort_result=$(printf "%s\n%s\n" "${MINIMUM_CHECK_RUN_ID_VERSION}" "${trunk_version}" | sort --version-sort); then 47 | if [[ $(echo "${sort_result}" | head -n 1) == "${trunk_version}" ]]; then 48 | echo "::error::Please update your CLI to ${MINIMUM_CHECK_RUN_ID_VERSION} or higher (current version ${trunk_version})." 49 | exit 1 50 | fi 51 | else 52 | echo "::warning::sort --version-sort failed - continuing without checking CLI version" 53 | fi 54 | # trunk-ignore-end(shellcheck/SC2312) 55 | annotation_argument=--trunk-annotate=${INPUT_CHECK_RUN_ID} 56 | elif [[ ${save_annotations} == "true" ]]; then 57 | annotation_argument=--github-annotate-file=${TRUNK_TMPDIR}/annotations.bin 58 | # Signal that we need to upload an annotations artifact 59 | echo "TRUNK_UPLOAD_ANNOTATIONS=true" >>"${GITHUB_ENV}" 60 | else 61 | annotation_argument=--github-annotate 62 | fi 63 | 64 | if [[ -n ${INPUT_AUTOFIX_AND_PUSH} ]]; then 65 | "${TRUNK_PATH}" check --ci --upstream "${upstream}" --fix "${annotation_argument}" ${INPUT_ARGUMENTS} 66 | git config --global user.email "" 67 | git config --global user.name "${GITHUB_ACTOR}" 68 | git commit --all --allow-empty --message "Trunk Check applied autofixes" 69 | git push origin "${INPUT_GITHUB_REF_NAME}" 70 | else 71 | "${TRUNK_PATH}" check \ 72 | --ci \ 73 | --upstream "${upstream}" \ 74 | --github-commit "${git_commit}" \ 75 | --github-label "${INPUT_LABEL}" \ 76 | "${annotation_argument}" \ 77 | ${INPUT_ARGUMENTS} 78 | fi 79 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | if [[ ${INPUT_DEBUG} == "true" ]]; then 8 | set -x 9 | fi 10 | 11 | fetch() { 12 | git -c protocol.version=2 fetch -q \ 13 | --no-tags \ 14 | --no-recurse-submodules \ 15 | "$@" 16 | } 17 | 18 | if [[ ${GITHUB_EVENT_BEFORE} == "0000000000000000000000000000000000000000" ]]; then 19 | # Github will send us all 0s for the before hash in a few circumstances, such as the first commit to a repo 20 | # or pushing a tag. In these instances we will check the whole repo. 21 | "${TRUNK_PATH}" check \ 22 | --ci \ 23 | --all \ 24 | --github-commit "${GITHUB_EVENT_AFTER}" \ 25 | ${INPUT_ARGUMENTS} 26 | exit 27 | fi 28 | 29 | if [[ ${GITHUB_REF_NAME} == gh-readonly-queue/* ]]; then 30 | # If we are running via the GH merge queue then we use HEAD^1 as the commit as github.event.before will be inaccurate. 31 | head_sha=$(git rev-parse HEAD) 32 | fetch --depth=2 origin "${head_sha}" 33 | upstream=$(git rev-parse HEAD^1) 34 | echo "Detected merge queue commit, using HEAD^1 (${upstream}) as upstream" 35 | fi 36 | 37 | if [[ -z ${upstream+x} ]]; then 38 | # Otherwise use github.event.before as the upstream. 39 | upstream="${GITHUB_EVENT_BEFORE}" 40 | fetch origin "${upstream}" 41 | fi 42 | 43 | "${TRUNK_PATH}" check \ 44 | --ci \ 45 | --upstream "${upstream}" \ 46 | --github-commit "${GITHUB_EVENT_AFTER}" \ 47 | ${INPUT_ARGUMENTS} 48 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![Trunk.io](https://github.com/user-attachments/assets/c98a90ee-439b-4a9c-bb9a-69dc0e7e2c7e)](https://trunk.io) 4 | 5 | [![docs](https://img.shields.io/badge/-docs-darkgreen?logo=readthedocs&logoColor=ffffff)][docs] 6 | [![vscode](https://img.shields.io/visual-studio-marketplace/i/trunk.io?color=0078d7&label=vscode&logo=visualstudiocode)][vscode] 7 | [![slack](https://img.shields.io/badge/-slack-611f69?logo=slack)][slack] 8 | [![openssf](https://api.securityscorecards.dev/projects/github.com/trunk-io/trunk-action/badge)](https://api.securityscorecards.dev/projects/github.com/trunk-io/trunk-action) 9 | 10 | > **💡Tip** 11 | > 12 | > 🎉 New: [Trunk Flaky Tests](https://trunk.io/flaky-tests) detects, quarantines, and eliminates 13 | > flaky tests. 14 | 15 | # Trunk.io GitHub Action 16 | 17 | > **Note** 18 | > 19 | > We strongly encourage using Trunk Code Quality's integration with GitHub to run Trunk Code Quality 20 | > on CI. [Get started here!](https://docs.trunk.io/code-quality/ci-setup) 21 | 22 | This action runs and shows inline annotations of issues found by 23 | [Trunk Code Quality](https://docs.trunk.io/code-quality), a powerful meta linter and formatter. 24 | Trunk runs hermetically, _locally_ or on CI, so you can always quickly see lint, formatting, and 25 | security issues _before_ pushing your changes. See all supported linters 26 | [here](https://docs.trunk.io/code-quality/linters/supported). 27 | 28 | Trunk Code Quality is free for individual use, **free for open source projects**, and has a free 29 | tier for team use in private repos. (See [pricing](https://trunk.io/pricing)) 30 | 31 |

32 | 33 |
34 | Example annotations 35 |

36 | 37 | ## Get Started 38 | 39 | [Follow these instructions to set up Trunk Code Quality CI for your GitHub repository](https://docs.trunk.io/code-quality/ci-setup) 40 | 41 | ## Run it Yourself 42 | 43 | To run Trunk Code Quality on your pull requests, add this file to your repo as 44 | `.github/workflows/trunk-check.yaml`: 45 | 46 | ```yaml 47 | name: Pull Request 48 | on: [pull_request] 49 | concurrency: 50 | group: ${{ github.head_ref || github.run_id }} 51 | cancel-in-progress: true 52 | 53 | permissions: read-all 54 | 55 | jobs: 56 | trunk_check: 57 | name: Trunk Code Quality Runner 58 | runs-on: ubuntu-latest 59 | permissions: 60 | checks: write # For trunk to post annotations 61 | contents: read # For repo checkout 62 | 63 | steps: 64 | - name: Checkout 65 | uses: actions/checkout@v3 66 | 67 | - name: Trunk Code Quality 68 | uses: trunk-io/trunk-action@v1 69 | ``` 70 | 71 | See this repo's 72 | [`pr.yaml`](https://github.com/trunk-io/trunk-action/blob/main/.github/workflows/pr.yaml) workflow 73 | for further reference. 74 | 75 | ### Advanced 76 | 77 | You can get a lot more out of Trunk Code Quality if you install it locally and commit a Trunk 78 | configuration in your repository: 79 | 80 | 1. Install Trunk → `curl https://get.trunk.io -fsSL | bash` 81 | 2. Setup Trunk in your repo → `trunk init` 82 | 3. Locally check your changes for issues → `git commit -m "Create initial Trunk config" .trunk/` 83 | 84 | You'll see that in `.trunk/trunk.yaml`, we implement strict versioning of the Trunk CLI and every 85 | linter you're running. This allows you to control all linter versioning using `.trunk/trunk.yaml`, 86 | as well as enable linters which require manual configuration. 87 | 88 | By default, `trunk-io/trunk-action` will run all linters which we can automatically initialize and 89 | set up for you. This works well in many cases, but there are some cases where it is insufficient. 90 | 91 | For example, if you already have ESLint set up and depend on ESLint plugins such as 92 | `@typescript-eslint/eslint-plugin`, you'll need to `trunk check enable eslint` and also 93 | [add a custom setup action](#custom-setup) to install your `eslint` dependencies. 94 | 95 | ### Custom Setup 96 | 97 | If you define a composite action in your repository at `.trunk/setup-ci/action.yaml`, we will 98 | automatically run it before we run any linters. This can be important if, for example, a linter 99 | needs some generated code to be present before it can run: 100 | 101 | ```yaml 102 | name: Trunk Code Quality setup 103 | description: Set up dependencies for Trunk Code Quality 104 | runs: 105 | using: composite 106 | steps: 107 | - name: Build required trunk check inputs 108 | shell: bash 109 | run: bazel build ... --build_tag_filters=pre-lint 110 | 111 | - name: Install eslint dependencies 112 | shell: bash 113 | run: npm install 114 | ``` 115 | 116 | Alternatively, you can handle setup as a separate step in your workflow before running 117 | `trunk-io/trunk-action`; note however that this approach is not compatible with Trunk's 118 | GitHub-native integrations. 119 | 120 | If you've setup basic testing on CI, you're already doing this for other CI jobs; do it here too 😉. 121 | 122 | ### Caching 123 | 124 | To use GitHub Actions caching for Trunk, create a new workflow (for example, 125 | `.github/worksflows/cache_trunk.yaml`) to run on any change to your Trunk configuration: 126 | 127 | ```yaml 128 | on: 129 | push: 130 | branches: [main] 131 | paths: [.trunk/trunk.yaml] 132 | 133 | permissions: read-all 134 | 135 | jobs: 136 | cache_trunk: 137 | name: Cache Trunk 138 | runs-on: ubuntu-latest 139 | permissions: 140 | actions: write 141 | 142 | steps: 143 | - name: Checkout 144 | uses: actions/checkout@v3 145 | 146 | - name: Trunk Check 147 | uses: trunk-io/trunk-action@v1 148 | with: 149 | check-mode: populate_cache_only 150 | ``` 151 | 152 | If you are using long-lived self-hosted runners you should _not_ create the above workflow, and you 153 | should also disable caching by passing `cache: false` when running Trunk on your PRs: 154 | 155 | ```yaml 156 | - name: Trunk Code Quality 157 | uses: trunk-io/trunk-action@v3 158 | with: 159 | cache: false 160 | ``` 161 | 162 | ### Getting Inline Annotations for Fork PRs 163 | 164 | Create an additional _new GitHub workflow_ to post annotations from fork PRs. This workflow needs to 165 | be merged into your main branch before fork PRs will see annotations. It's important that the name 166 | of the workflow in the workflow_runs section (here "Pull Request") matches the workflow which runs 167 | `trunk check`: 168 | 169 | ```yaml 170 | name: Annotate PR with trunk issues 171 | 172 | on: 173 | workflow_run: 174 | workflows: ["Pull Request"] 175 | types: [completed] 176 | 177 | jobs: 178 | trunk_check: 179 | name: Trunk Code Quality Annotate 180 | runs-on: ubuntu-latest 181 | 182 | steps: 183 | - name: Checkout 184 | uses: actions/checkout@v3 185 | 186 | - name: Trunk Check 187 | uses: trunk-io/trunk-action@v1 188 | with: 189 | post-annotations: true # only for fork PRs 190 | ``` 191 | 192 | This setup is necessitated by GitHub for 193 | [security reasons](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). 194 | The Trunk Action auto-detects this situation and uploads its results as an artifact instead of 195 | trying to post them. Creating the new GitHub workflow above downloads this artifact and posts the 196 | annotations. 197 | 198 | This also works if you use both fork and non-fork PRs in your repo. In that case, non-fork PRs post 199 | annotations in the regular manner, and fork PRs post annotations via the above workflow. 200 | 201 | ## Trunk Versioning 202 | 203 | After you run `trunk init`, the `.trunk/trunk.yaml` file will contain a pinned version of Trunk to 204 | use for your repo. When you run `trunk`, it will automatically detect which version you should be 205 | running for a particular repo and download+run it. This means that everyone working in a repo, and 206 | CI, all get the same results and the same experience - no more _"doesn't happen on my machine"_. 207 | When you want to upgrade to a newer version, just run `trunk upgrade` and commit the updated 208 | `trunk.yaml`. 209 | 210 | ## Run Trunk Outside of GitHub Actions 211 | 212 | Trunk has a dead simple install, is totally self-contained, doesn't require docker, and runs on 213 | macOS and all common flavors of Linux. 214 | 215 | 1. Install Trunk → `curl https://get.trunk.io -fsSL | bash` 216 | 2. Setup Trunk in your repo → `trunk init` 217 | 3. Check your changes for issues → `trunk check` 218 | 4. Format your changes → `trunk fmt` 219 | 5. Upgrade the pinned trunk version in your repo → `trunk upgrade` 220 | 221 | Check out the [setup docs](https://docs.trunk.io/code-quality/setup-and-installation) for more info. 222 | 223 | ## Running Trunk Code Quality on all files 224 | 225 | By default, `trunk check` will run on only changed files. When triggered by a pull request this will 226 | be _all files changed in the PR_. When triggered by a push this will be _all files changed in that 227 | push_. If you would like to run `trunk check` on all files in a repo, you can set the `check-mode` 228 | to `all`. For example: 229 | 230 | ```yaml 231 | - name: Trunk Code Quality 232 | uses: trunk-io/trunk-action@v1 233 | with: 234 | check-mode: all 235 | ``` 236 | 237 | If you're running an hourly or nightly job on a branch, `check-mode` is automatically inferred to be 238 | `all`. 239 | 240 | ## Uploading results to the Trunk web app (deprecated) 241 | 242 | The Trunk Code Quality web app has been deprecated and the service will be shut down on July 243 | 27, 2025. 244 | 245 | If you are uploading to the Trunk web app you can stop by removing `trunk-token` from your config: 246 | 247 | ```yaml 248 | - name: Trunk Code Quality 249 | uses: trunk-io/trunk-action@v1 250 | # remove trunk-token from your action 251 | with: 252 | trunk-token: ${{ secrets.TRUNK_TOKEN }} 253 | ``` 254 | 255 | You can continue to run this action nightly using a `schedule` worflow dispatch and 256 | `check-mode: all`. 257 | [See the example](https://github.com/trunk-io/trunk-action/blob/main/.github/workflows/nightly.yaml). 258 | 259 | For more information on the deprecation, 260 | [see the migration guide](https://docs.trunk.io/code-quality/setup-and-installation/prevent-new-issues/migration-guide). 261 | 262 | ## Running Trunk Code Quality on multiple platforms 263 | 264 | If you'd like to run multiple Trunk Code Quality jobs on different platforms at the same time, you 265 | can pass `label` to each job to distinguish them. For example: 266 | 267 | ```yaml 268 | - name: Trunk Code Quality 269 | uses: trunk-io/trunk-action@v1 270 | with: 271 | arguments: --github-label=${{ runner.os }} 272 | ``` 273 | 274 | ## Annotating Existing Issues 275 | 276 | By default, the Trunk Action will only annotate new issues, but if you also want to annotate 277 | existing issues you can pass `--github-annotate-new-only=false` to Trunk Code Quality. For example: 278 | 279 | ```yaml 280 | - name: Trunk Code Quality 281 | uses: trunk-io/trunk-action@v1 282 | with: 283 | arguments: --github-annotate-new-only=false 284 | ``` 285 | 286 | ## Usage with the GitHub Merge Queue 287 | 288 | Trunk auto-detects when it is running from the GitHub merge queue and will check only the files 289 | being merged. The "Merge commit" and "Squash and merge" 290 | [strategies](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue#about-merge-queues) 291 | are currently supported. "Rebase and merge" does not yet work correctly. 292 | 293 | ## Automatic Upgrades 294 | 295 | Once you have a `.trunk/trunk.yaml` checked into your repo, the following action will automatically 296 | upgrade Trunk and its tools. 297 | 298 | ```yaml 299 | name: Nightly 300 | on: 301 | schedule: 302 | - cron: 0 8 * * 1-5 303 | workflow_dispatch: {} 304 | permissions: read-all 305 | jobs: 306 | trunk_upgrade: 307 | name: Upgrade Trunk 308 | runs-on: ubuntu-latest 309 | permissions: 310 | contents: write # For trunk to create PRs 311 | pull-requests: write # For trunk to create PRs 312 | steps: 313 | - name: Checkout 314 | uses: actions/checkout@v3 315 | # >>> Install your own deps here (npm install, etc) <<< 316 | - name: Trunk Upgrade 317 | uses: trunk-io/trunk-action/upgrade@v1 318 | ``` 319 | 320 | We recommend that you only run the upgrade action on a nightly or weekly cadence, running from your 321 | main branch. You can also set the `arguments` field to filter particular upgrades and set `base` to 322 | define the branch to create a PR against (default `main`). 323 | 324 | You must also enable the repository setting to "Allow GitHub Actions to create and approve pull 325 | requests". If you have checks that run on pull requests, you will need to supply a `github-token` to 326 | the upgrade action to run those checks. For more information, see 327 | [create-pull-request](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs). 328 | 329 | ## Automatic trunk setup 330 | 331 | To install trunk on your CI machine 332 | 333 | ```yaml 334 | jobs: 335 | trunk_install: 336 | name: Install trunk 337 | runs-on: ubuntu-latest 338 | steps: 339 | - name: Checkout 340 | uses: actions/checkout@v3 341 | # >>> After this step, trunk is available as the env var TRUNK_PATH <<< 342 | - name: Trunk install 343 | uses: trunk-io/trunk-action/setup@v1 344 | ``` 345 | 346 | ## Feedback 347 | 348 | Join the [Trunk Community Slack][slack]. ❤️ 349 | 350 | [slack]: https://slack.trunk.io 351 | [docs]: https://docs.trunk.io 352 | [vscode]: https://marketplace.visualstudio.com/items?itemName=Trunk.io 353 | -------------------------------------------------------------------------------- /repo_tests/check_for_task_failures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | import sys 6 | 7 | def main(github_env_path, repo_test_name, repo_test_description): 8 | try: 9 | landing_state = json.load(open('/tmp/landing-state.json')) 10 | except FileNotFoundError as e: 11 | print("Failed to open /tmp/landing-state.json - did `trunk check` run?") 12 | sys.exit(1) 13 | return 14 | 15 | lint_action_count = len(landing_state.get("lintActions", [])) 16 | task_failure_count = len(landing_state.get("taskFailures", [])) 17 | 18 | print("::group::.trunk/trunk.yaml") 19 | print(open(".trunk/trunk.yaml").read()) 20 | print("::endgroup::") 21 | 22 | print(f'lint_action_count={lint_action_count}') 23 | print(f'task_failure_count={task_failure_count}') 24 | 25 | if lint_action_count == 0: 26 | print("No lint actions were run - something went wrong.") 27 | sys.exit(1) 28 | 29 | if task_failure_count > 0: 30 | print('Failures can be viewed in the logs for the previous step') 31 | sys.exit(1) 32 | 33 | print("No task failures!") 34 | 35 | if __name__ == '__main__': 36 | main(sys.argv[1], sys.argv[2], sys.argv[3]) 37 | -------------------------------------------------------------------------------- /repo_tests/flask.yaml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | lint: 3 | ignore: 4 | - linters: [prettier] 5 | paths: 6 | - examples/javascript/js_example/templates/xhr.html 7 | -------------------------------------------------------------------------------- /repo_tests/highlightjs.yaml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | lint: 3 | ignore: 4 | - linters: [prettier] 5 | paths: 6 | - demo/index.html 7 | - test/fixtures/index.html 8 | -------------------------------------------------------------------------------- /repo_tests/yaml_cpp.yaml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | lint: 3 | ignore: 4 | - linters: [clang-tidy] 5 | paths: 6 | - test/** 7 | - util/read.cpp 8 | - util/api.cpp 9 | - util/parse.cpp 10 | - util/sandbox.cpp 11 | - linters: [prettier] 12 | paths: 13 | - test/** 14 | -------------------------------------------------------------------------------- /security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We do not actively support patches onto previously released version of the trunk-action repository. 6 | Instead we recommend all users upgrade to the latest release as it comes out. 7 | 8 | | Version | Supported | 9 | | -------------------------- | --------- | 10 | | > 1.0.6 :white_check_mark: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Please report (suspected) security vulnerabilities to security@trunk.io. You will receive a response 15 | from the team within 48 hours. If the issue is confirmed, we will create a new release as soon as 16 | possible. 17 | -------------------------------------------------------------------------------- /setup-env/action.yaml: -------------------------------------------------------------------------------- 1 | name: Setup environment 2 | author: trunk.io 3 | description: Automatic setup for trunk check dependencies (e.g. Node) 4 | 5 | inputs: 6 | cache-key: 7 | description: 8 | Cache key for setup (either passed into .trunk/setup-ci/, or used to cache node_modules in 9 | this action). 10 | required: false 11 | default: "" 12 | 13 | runs: 14 | using: composite 15 | steps: 16 | - name: Detect npm/yarn/pnpm & custom setup 17 | shell: bash 18 | run: | 19 | if [ -e package-lock.json ]; then 20 | cat >>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV <>$GITHUB_ENV < /dev/null; then 66 | echo "Detected existing node install" 67 | cat >>$GITHUB_ENV </dev/null; then 79 | PNPM_VERSION=$(jq -r '.packageManager|split("@")[1]' package.json || echo "") 80 | fi 81 | if [ -z "${PNPM_VERSION}" ]; then 82 | PNPM_VERSION=latest 83 | fi 84 | echo "PNPM_VERSION=${PNPM_VERSION}" >>$GITHUB_ENV 85 | 86 | - name: Install pnpm 87 | if: env.PACKAGE_MANAGER == 'pnpm' 88 | uses: pnpm/action-setup@v2 89 | with: 90 | version: ${{ env.PNPM_VERSION }} 91 | 92 | - name: Install Node dependencies 93 | id: setup_node 94 | if: env.PACKAGE_MANAGER && env.NODE_VERSION_FILE 95 | uses: actions/setup-node@v4 96 | with: 97 | node-version-file: ${{ env.NODE_VERSION_FILE }} 98 | continue-on-error: true 99 | 100 | - name: Check for node installation 101 | if: env.PACKAGE_MANAGER && env.NODE_VERSION_FILE 102 | shell: bash 103 | run: | 104 | if [ ${{ steps.setup_node.outcome }} == "success" ]; then 105 | exit 0 106 | fi 107 | echo "::warning::Failed to install specified node version." 108 | echo "FAILED_NODE_INSTALL=true" >>$GITHUB_ENV 109 | if ! command -v node >/dev/null; then 110 | echo "::warning::No existing node install detected - installing latest node instead." 111 | echo "INSTALL_LATEST_NODE=true" >>$GITHUB_ENV 112 | fi 113 | 114 | - name: Install backup node version 115 | if: env.PACKAGE_MANAGER && env.NODE_VERSION_FILE && env.INSTALL_LATEST_NODE == 'true' 116 | uses: actions/setup-node@v4 117 | with: 118 | node-version: latest 119 | 120 | - name: Cache node_modules 121 | if: inputs.cache-key && env.PACKAGE_MANAGER 122 | uses: actions/cache@v3 123 | with: 124 | path: node_modules/ 125 | key: 126 | ${{ env.PACKAGE_MANAGER }}-${{ runner.os }}-${{ inputs.cache-key }}-${{ 127 | hashFiles(env.HASH_GLOB) }} 128 | 129 | - name: Install ${{ env.PACKAGE_MANAGER }} packages 130 | id: install_packages 131 | if: env.PACKAGE_MANAGER && (env.NODE_VERSION_FILE || env.RUN_INSTALL_NODE_PACKAGES) 132 | shell: bash 133 | run: ${{ env.INSTALL_CMD }} 134 | continue-on-error: true 135 | 136 | - name: Check for package install 137 | if: env.PACKAGE_MANAGER && (env.NODE_VERSION_FILE || env.RUN_INSTALL_NODE_PACKAGES) 138 | shell: bash 139 | run: | 140 | if [ ${{ steps.install_packages.outcome }} == "success" ]; then 141 | exit 0 142 | fi 143 | echo "FAILED_NODE_PACKAGE_INSTALL=true" >>$GITHUB_ENV 144 | 145 | if [[ -z "${INITIALIZED_TRUNK}" ]]; then 146 | echo "::error::Failed to install node packages." 147 | echo "::error::Aborting because this repo has an existing trunk.yaml file." 148 | exit 1 149 | fi 150 | echo "::warning::Failed to install node packages." 151 | echo "::warning::Disabling linters that depend on node packages." 152 | ${TRUNK_PATH} check disable eslint stylelint 153 | -------------------------------------------------------------------------------- /setup/action.yaml: -------------------------------------------------------------------------------- 1 | name: Trunk Check 2 | author: trunk.io 3 | description: The official trunk.io GitHub action to install trunk 4 | 5 | inputs: 6 | trunk-path: 7 | description: 8 | Path to Trunk Launcher. If not provided, we'll look for it the repo root, `.trunk/bin` and 9 | `tools/`. If it can't be found anywhere and is not provided explicitly, we'll download it on 10 | demand. 11 | required: false 12 | 13 | branding: 14 | icon: check 15 | color: green 16 | 17 | runs: 18 | using: composite 19 | steps: 20 | - name: Locate trunk 21 | shell: bash 22 | run: ${GITHUB_ACTION_PATH}/locate_trunk.sh 23 | env: 24 | INPUT_TRUNK_PATH: ${{ inputs.trunk-path }} 25 | -------------------------------------------------------------------------------- /setup/locate_trunk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | if [[ ${INPUT_DEBUG:-false} == "true" ]]; then 6 | set -x 7 | fi 8 | 9 | tmpdir="$(mktemp -d)" 10 | echo "TRUNK_TMPDIR=${tmpdir}" >>"${GITHUB_ENV}" 11 | 12 | trunk_path="${INPUT_TRUNK_PATH}" 13 | if [[ -z ${trunk_path} ]]; then 14 | if [[ -f .trunk/bin/trunk && -x .trunk/bin/trunk ]]; then 15 | trunk_path=.trunk/bin/trunk 16 | elif [[ -f tools/trunk && -x tools/trunk ]]; then 17 | trunk_path=tools/trunk 18 | elif [[ -f trunk && -x trunk ]]; then 19 | trunk_path=./trunk 20 | else 21 | curl -fsSL https://trunk.io/releases/trunk -o "${tmpdir}/trunk" 22 | chmod u+x "${tmpdir}/trunk" 23 | trunk_path="${tmpdir}/trunk" 24 | fi 25 | fi 26 | echo "TRUNK_PATH=${trunk_path}" >>"${GITHUB_ENV}" 27 | # Ensure that trunk CLI is downloaded before subsequent steps 28 | ${trunk_path} version || echo "::warning::${trunk_path} does not exist!" 29 | -------------------------------------------------------------------------------- /trunk_merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shellcheck disable=SC2086 4 | 5 | set -euo pipefail 6 | 7 | if [[ ${INPUT_DEBUG} == "true" ]]; then 8 | set -x 9 | fi 10 | 11 | fetch() { 12 | git -c protocol.version=2 fetch -q \ 13 | --no-tags \ 14 | --no-recurse-submodules \ 15 | "$@" 16 | } 17 | 18 | MINIMUM_CHECK_RUN_ID_VERSION=1.7.0 19 | 20 | head_sha=$(git rev-parse HEAD) 21 | fetch --depth=2 origin "${head_sha}" 22 | upstream=$(git rev-parse HEAD^1) 23 | git_commit=$(git rev-parse HEAD^2) 24 | echo "Detected merge queue commit, using HEAD^1 (${upstream}) as upstream and HEAD^2 (${git_commit}) as github commit" 25 | 26 | if [[ -n ${INPUT_CHECK_RUN_ID} ]]; then 27 | trunk_version="$(${TRUNK_PATH} version)" 28 | # trunk-ignore-begin(shellcheck/SC2312): the == will fail if anything inside the $() fails 29 | if sort_result=$(printf "%s\n%s\n" "${MINIMUM_CHECK_RUN_ID_VERSION}" "${trunk_version}" | sort --version-sort); then 30 | if [[ $(echo "${sort_result}" | head -n 1) == "${trunk_version}" ]]; then 31 | echo "::error::Please update your CLI to ${MINIMUM_CHECK_RUN_ID_VERSION} or higher (current version ${trunk_version})." 32 | exit 1 33 | fi 34 | else 35 | echo "::warning::sort --version-sort failed - continuing without checking CLI version" 36 | fi 37 | # trunk-ignore-end(shellcheck/SC2312) 38 | annotation_argument=--trunk-annotate=${INPUT_CHECK_RUN_ID} 39 | else 40 | annotation_argument="" 41 | fi 42 | 43 | "${TRUNK_PATH}" check \ 44 | --ci \ 45 | --upstream "${upstream}" \ 46 | --github-commit "${git_commit}" \ 47 | --github-label "${INPUT_LABEL}" \ 48 | ${annotation_argument} \ 49 | ${INPUT_ARGUMENTS} 50 | -------------------------------------------------------------------------------- /upgrade/action.yaml: -------------------------------------------------------------------------------- 1 | name: Trunk Upgrade 2 | author: trunk.io 3 | description: Upgrade trunk and its tools 4 | 5 | branding: 6 | icon: check 7 | color: green 8 | 9 | inputs: 10 | trunk-path: 11 | description: 12 | Path to Trunk Launcher. If not provided, we'll look for it the repo root, `.trunk/bin` and 13 | `tools/`. If it can't be found anywhere and is not provided explicitly, we'll download it on 14 | demand. 15 | required: false 16 | 17 | prefix: 18 | description: Prefix to be added in the PR title 19 | required: false 20 | 21 | arguments: 22 | description: Extra arguments to pass to trunk upgrade 23 | required: false 24 | 25 | base: 26 | description: The base branch to create a PR against 27 | required: false 28 | default: main 29 | 30 | github-token: 31 | description: 32 | A GitHub token to allow created PRs to run pull_request workflows. See 33 | https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs 34 | for more information. 35 | required: false 36 | default: ${{ github.token }} 37 | 38 | setup-deps: 39 | description: 40 | Install dependencies for trunk check that the trunk CLI does not manage. This is only 41 | necessary if you have Node dependencies in your package.json that your Node linters need (e.g. 42 | eslint dependencies, or @types packages). 43 | required: false 44 | default: "false" 45 | 46 | branch-name: 47 | description: The branch name to generate the PR from 48 | default: trunk-io/update-trunk 49 | required: false 50 | 51 | assignees: 52 | description: A comma or newline separated list of GitHub assignee usernames 53 | required: false 54 | 55 | reviewers: 56 | description: A comma or newline separated list of GitHub reviewer usernames 57 | required: false 58 | 59 | labels: 60 | description: A comma or newline separated list of GitHub labels that should be added to the PR 61 | default: trunk 62 | required: false 63 | 64 | add-paths: 65 | description: Specific paths to add to the created pull request. Comma separated. 66 | required: false 67 | default: .trunk 68 | 69 | lowercase-title: 70 | description: A boolean to decide if the PR and commit message title should be in lowercase 71 | required: false 72 | default: false 73 | 74 | signoff: 75 | description: A boolean to add a Signed-off-by line to the commit message 76 | required: false 77 | default: false 78 | 79 | sign-commits: 80 | description: 81 | A boolean to sign commits. See 82 | https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#commit-signature-verification-for-bots 83 | required: false 84 | default: false 85 | 86 | outputs: 87 | pull-request-number: 88 | description: The pull request number 89 | value: ${{ steps.cpr.outputs.pull-request-number }} 90 | 91 | pull-request-url: 92 | description: The URL of the pull request. 93 | value: ${{ steps.cpr.outputs.pull-request-url }} 94 | 95 | pull-request-operation: 96 | description: 97 | The pull request operation performed by the action, `created`, `updated` or `closed`. 98 | value: ${{ steps.cpr.outputs.pull-request-operation }} 99 | 100 | pull-request-head-sha: 101 | description: The commit SHA of the pull request branch. 102 | value: ${{ steps.cpr.outputs.pull-request-head-sha }} 103 | 104 | runs: 105 | using: composite 106 | steps: 107 | - name: Locate trunk 108 | shell: bash 109 | run: | 110 | # Locate trunk 111 | ${{ github.action_path }}/../setup/locate_trunk.sh 112 | env: 113 | INPUT_TRUNK_PATH: ${{ inputs.trunk-path }} 114 | 115 | - name: Detect trunk 116 | id: auto_init 117 | shell: bash 118 | run: | 119 | if [ ! -e .trunk/trunk.yaml ]; then 120 | echo "Unable to run 'trunk upgrade'. Please run 'trunk init' and commit the generated '.trunk/trunk.yaml'." 121 | exit 1 122 | fi 123 | 124 | - name: Detect setup strategy 125 | shell: bash 126 | run: | 127 | if [ -e .trunk/setup-ci ]; then 128 | echo "SETUP_DEPS=true" >>$GITHUB_ENV 129 | else 130 | mkdir -p .trunk 131 | ln -s ${{ github.action_path }}/../setup-env .trunk/setup-ci 132 | echo .trunk/setup-ci >>.git/info/exclude 133 | fi 134 | 135 | - name: Set up env 136 | uses: ./.trunk/setup-ci 137 | if: env.SETUP_DEPS == 'true' || inputs.setup-deps == 'true' 138 | 139 | - name: Run upgrade 140 | id: upgrade 141 | shell: bash 142 | run: | 143 | # Run trunk upgrade 144 | ${{ github.action_path }}/upgrade.sh 145 | env: 146 | UPGRADE_ARGUMENTS: ${{ inputs.arguments }} 147 | LOWERCASE_TITLE: ${{ inputs.lowercase-title }} 148 | 149 | - name: Cleanup temporary files 150 | if: always() 151 | shell: bash 152 | run: | 153 | # Cleanup temporary files 154 | ${{ github.action_path }}/../cleanup.sh 155 | 156 | - name: Create Pull Request 157 | id: cpr 158 | uses: peter-evans/create-pull-request@v7 159 | with: 160 | title: ${{ inputs.prefix }}${{ env.PR_TITLE }} 161 | body: ${{ env.PR_DESCRIPTION }} 162 | base: ${{ inputs.base }} 163 | branch: ${{ inputs.branch-name }} 164 | labels: ${{ inputs.labels }} 165 | add-paths: ${{ inputs.add-paths }} 166 | commit-message: ${{ inputs.prefix }}${{ env.PR_TITLE }} 167 | delete-branch: true 168 | assignees: ${{ inputs.assignees }} 169 | reviewers: ${{ inputs.reviewers }} 170 | token: ${{ inputs.github-token }} 171 | branch-token: ${{ inputs.github-token }} 172 | signoff: ${{ inputs.signoff }} 173 | sign-commits: ${{ inputs.sign-commits }} 174 | -------------------------------------------------------------------------------- /upgrade/upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Step 1: Run upgrade and strip ANSI coloring. 6 | # trunk-ignore(shellcheck/SC2086): pass arguments directly as is 7 | upgrade_output=$(${TRUNK_PATH} upgrade --no-progress -n ${UPGRADE_ARGUMENTS} | sed -e 's/\x1b\[[0-9;]*m//g') 8 | 9 | # Step 2a: Parse output. If up to date, exit successfully. 10 | if [[ ${upgrade_output} == *"Already up to date"* ]]; then 11 | echo "Already up to date." 12 | exit 0 13 | fi 14 | 15 | # Step 2b: Parse output. Strip launcher downloading messages and parse cli upgrade if present. 16 | trimmed_upgrade_output=$(echo "${upgrade_output}" | grep "upgrade" -A 500) 17 | title_message="Upgrade trunk" 18 | 19 | if [[ ${trimmed_upgrade_output} == *"cli upgrade"* ]]; then 20 | new_cli_version=$(echo "${trimmed_upgrade_output}" | grep "cli upgrade" | awk '{print $NF}') 21 | title_message="Upgrade trunk to ${new_cli_version}" 22 | fi 23 | 24 | if [[ ${LOWERCASE_TITLE} == "true" ]]; then 25 | title_message=$(echo "${title_message}" | tr '[:upper:]' '[:lower:]') 26 | fi 27 | 28 | # Step 3: Prepare for pull request creation action. 29 | # Avoid triggering a git-hook, and avoid resetting git hook config via daemon 30 | ${TRUNK_PATH} daemon shutdown 31 | git config --local --unset core.hooksPath || true 32 | rm -f .trunk/landing-state.json 33 | 34 | # Step 4: Format upgrade output for PR. 35 | # Replace space indentation with bulleted list (including sub-bullets) 36 | # trunk-ignore(shellcheck/SC2001): more complicated sed parsing required 37 | formatted_output=$(echo "${trimmed_upgrade_output}" | sed -e 's/^\( \)\{0,1\} /\1- /') 38 | 39 | # Step 5: Generate markdown 40 | description=$(echo "${formatted_output}" | sed -e '/^UPGRADE_CONTENTS/{ 41 | r /dev/stdin 42 | d 43 | }' "${GITHUB_ACTION_PATH}"/upgrade_pr.md) 44 | 45 | # Step 6: Write outputs 46 | { 47 | echo "PR_DESCRIPTION<>"${GITHUB_ENV}" 51 | 52 | echo "PR_TITLE=${title_message}" >>"${GITHUB_ENV}" 53 | -------------------------------------------------------------------------------- /upgrade/upgrade_pr.md: -------------------------------------------------------------------------------- 1 | [![Trunk](https://static.trunk.io/assets/trunk_action_upgrade_banner.png)](https://trunk.io) 2 | 3 | UPGRADE_CONTENTS 4 | 5 | This PR was generated by the [Trunk Action]. For more info, see our [docs] or reach out on [Slack]. 6 | 7 | [Trunk Action]: https://github.com/trunk-io/trunk-action 8 | [docs]: https://docs.trunk.io 9 | [Slack]: https://slack.trunk.io/ 10 | --------------------------------------------------------------------------------