├── .anvil.lock ├── .editorconfig ├── .github ├── FUNDING.yml ├── auto_assign.yml ├── issue_template.md ├── pull_request_template.md ├── renovate.json ├── settings.yml └── workflows │ ├── autoassign.yml │ ├── automerge.yml │ ├── go.yaml │ ├── notify.yml │ ├── stale.yml │ └── tag.yml ├── .gitignore ├── .go-version ├── .golangci.yml ├── .img ├── callbacks.png ├── callbacks.xml └── gopher.png ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── examples ├── README.md ├── simple-http-server-funcs │ ├── go.mod │ ├── go.sum │ └── main.go ├── simple-http-server-packages │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── plugins │ │ └── responder.go └── simple-http-server │ ├── go.mod │ ├── go.sum │ └── main.go ├── gen ├── format.go ├── generate.go ├── template_markdown.go.tmpl ├── template_params.go ├── template_webhook_event.go.tmpl ├── template_webhook_event_tests.go.tmpl └── template_webhook_event_types.go.tmpl ├── githubevents ├── events.go ├── events_branch_protection_rule.go ├── events_branch_protection_rule_test.go ├── events_check_run.go ├── events_check_run_test.go ├── events_check_suite.go ├── events_check_suite_test.go ├── events_commit_comment.go ├── events_commit_comment_test.go ├── events_create.go ├── events_create_test.go ├── events_custom_property.go ├── events_custom_property_test.go ├── events_custom_property_values.go ├── events_custom_property_values_test.go ├── events_delete.go ├── events_delete_test.go ├── events_deploy_key.go ├── events_deploy_key_test.go ├── events_deployment.go ├── events_deployment_status.go ├── events_deployment_status_test.go ├── events_deployment_test.go ├── events_discussion.go ├── events_discussion_test.go ├── events_fork.go ├── events_fork_test.go ├── events_github_app_authorization.go ├── events_github_app_authorization_test.go ├── events_gollum.go ├── events_gollum_test.go ├── events_installation.go ├── events_installation_repositories.go ├── events_installation_repositories_test.go ├── events_installation_test.go ├── events_issue_comment.go ├── events_issue_comment_test.go ├── events_issues.go ├── events_issues_test.go ├── events_label.go ├── events_label_test.go ├── events_marketplace_purchase.go ├── events_marketplace_purchase_test.go ├── events_member.go ├── events_member_test.go ├── events_membership.go ├── events_membership_test.go ├── events_merge_group_event.go ├── events_merge_group_event_test.go ├── events_meta.go ├── events_meta_test.go ├── events_milestone.go ├── events_milestone_test.go ├── events_org_block.go ├── events_org_block_test.go ├── events_organization.go ├── events_organization_test.go ├── events_package.go ├── events_package_test.go ├── events_page_build.go ├── events_page_build_test.go ├── events_ping.go ├── events_ping_test.go ├── events_project_v2.go ├── events_project_v2_item.go ├── events_project_v2_item_test.go ├── events_project_v2_test.go ├── events_public.go ├── events_public_test.go ├── events_pull_request.go ├── events_pull_request_review.go ├── events_pull_request_review_comment.go ├── events_pull_request_review_comment_test.go ├── events_pull_request_review_test.go ├── events_pull_request_test.go ├── events_push.go ├── events_push_test.go ├── events_release.go ├── events_release_test.go ├── events_repository.go ├── events_repository_dispatch.go ├── events_repository_dispatch_test.go ├── events_repository_ruleset.go ├── events_repository_ruleset_test.go ├── events_repository_test.go ├── events_repository_vulnerability_alert.go ├── events_repository_vulnerability_alert_test.go ├── events_star.go ├── events_star_test.go ├── events_status.go ├── events_status_test.go ├── events_team.go ├── events_team_add.go ├── events_team_add_test.go ├── events_team_test.go ├── events_watch.go ├── events_watch_test.go ├── events_workflow_dispatch.go ├── events_workflow_dispatch_test.go ├── events_workflow_job.go ├── events_workflow_job_test.go ├── events_workflow_run.go └── events_workflow_run_test.go ├── go.mod └── go.sum /.anvil.lock: -------------------------------------------------------------------------------- 1 | { 2 | "generated_at": "2025-05-15T20:52:16.267888961Z", 3 | "version": "1.2.29", 4 | "files": [ 5 | { 6 | "path": ".editorconfig" 7 | }, 8 | { 9 | "path": ".github/FUNDING.yml" 10 | }, 11 | { 12 | "path": ".github/auto_assign.yml" 13 | }, 14 | { 15 | "path": ".github/issue_template.md" 16 | }, 17 | { 18 | "path": ".github/pull_request_template.md" 19 | }, 20 | { 21 | "path": ".github/renovate.json" 22 | }, 23 | { 24 | "path": ".github/settings.yml" 25 | }, 26 | { 27 | "path": ".github/workflows/autoassign.yml" 28 | }, 29 | { 30 | "path": ".github/workflows/automerge.yml" 31 | }, 32 | { 33 | "path": ".github/workflows/notify.yml" 34 | }, 35 | { 36 | "path": ".github/workflows/stale.yml" 37 | }, 38 | { 39 | "path": ".github/workflows/tag.yml" 40 | }, 41 | { 42 | "path": "CODEOWNERS" 43 | }, 44 | { 45 | "path": "CONTRIBUTING.md" 46 | }, 47 | { 48 | "path": "LICENSE" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [Makefile] 11 | indent_style = tab 12 | indent_size = 4 13 | 14 | [*.go] 15 | indent_style = tab 16 | indent_size = 4 17 | 18 | [*.md] 19 | trim_trailing_whitespace = true 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: chrisbargmann 4 | 5 | -------------------------------------------------------------------------------- /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # Set to true to add reviewers to pull requests 2 | addReviewers: true 3 | 4 | # Set to true to add assignees to pull requests 5 | addAssignees: false 6 | 7 | # A list of reviewers to be added to pull requests (GitHub user name) 8 | reviewers: 9 | - cbrgm 10 | 11 | # A number of reviewers added to the pull request 12 | # Set 0 to add all the reviewers (default: 0) 13 | numberOfReviewers: 1 14 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>cbrgm/cbrgm//renovate/preset" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | --- 2 | repository: 3 | name: githubevents 4 | description: GitHub webhook events toolset for Go 🚀 5 | homepage: https://cbrgm.net 6 | topics: github, go, golang, webhooks, events, module, webhook, codegen, go-library 7 | 8 | private: false 9 | has_issues: true 10 | has_wiki: false 11 | has_downloads: false 12 | 13 | default_branch: main 14 | 15 | allow_squash_merge: true 16 | allow_merge_commit: true 17 | allow_rebase_merge: true 18 | 19 | allow_update_branch: true 20 | allow_auto_merge: true 21 | delete_branch_on_merge: true 22 | enable_automated_security_fixes: true 23 | enable_vulnerability_alerts: true 24 | 25 | branches: 26 | - name: main 27 | protection: 28 | required_pull_request_reviews: null 29 | required_status_checks: 30 | strict: true 31 | contexts: 32 | - testing 33 | enforce_admins: true 34 | ... 35 | -------------------------------------------------------------------------------- /.github/workflows/autoassign.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: add-reviews 3 | 4 | on: 5 | pull_request_target: 6 | types: [opened, ready_for_review] 7 | 8 | permissions: 9 | pull-requests: write 10 | 11 | jobs: 12 | add-reviews: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: kentaro-m/auto-assign-action@f4648c0a9fdb753479e9e75fc251f507ce17bb7e # v2.0.0 16 | ... 17 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: automerge 3 | 4 | on: pull_request 5 | 6 | permissions: 7 | contents: write 8 | pull-requests: write 9 | 10 | jobs: 11 | dependabot: 12 | runs-on: ubuntu-latest 13 | if: github.actor == 'dependabot[bot]' 14 | 15 | steps: 16 | 17 | - name: Fetch metadata 18 | id: metadata 19 | uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b # v2.4.0 20 | with: 21 | github-token: ${{ secrets.BOT_PAT_TOKEN }} 22 | 23 | - name: Approve request 24 | id: approve 25 | run: gh pr review --approve ${{ github.event.pull_request.html_url }} 26 | env: 27 | GH_TOKEN: ${{ secrets.BOT_PAT_TOKEN }} 28 | 29 | - name: Enable automerge 30 | id: automerge 31 | run: gh pr merge --rebase --auto ${{ github.event.pull_request.html_url }} 32 | env: 33 | GH_TOKEN: ${{ secrets.BOT_PAT_TOKEN }} 34 | 35 | renovate: 36 | runs-on: ubuntu-latest 37 | if: github.actor == 'renovate[bot]' 38 | 39 | steps: 40 | - name: Approve request 41 | id: approve 42 | run: gh pr review --approve ${{ github.event.pull_request.html_url }} 43 | env: 44 | GH_TOKEN: ${{ secrets.BOT_PAT_TOKEN }} 45 | 46 | - name: Enable automerge 47 | id: automerge 48 | run: gh pr merge --rebase --auto ${{ github.event.pull_request.html_url }} 49 | env: 50 | GH_TOKEN: ${{ secrets.BOT_PAT_TOKEN }} 51 | 52 | cbrgm: 53 | runs-on: ubuntu-latest 54 | if: github.actor == 'cbrgm' && contains(github.event.pull_request.labels.*.name, 'auto-merge') 55 | 56 | steps: 57 | - name: Enable automerge 58 | id: automerge 59 | run: gh pr merge --rebase --auto ${{ github.event.pull_request.html_url }} 60 | env: 61 | GH_TOKEN: ${{ secrets.BOT_PAT_TOKEN }} 62 | ... 63 | -------------------------------------------------------------------------------- /.github/workflows/go.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ main ] 4 | pull_request: 5 | branches: [ main ] 6 | name: generate-and-test 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: checkout 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 13 | 14 | - name: install Go 15 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 16 | with: 17 | go-version-file: .go-version 18 | 19 | - name: get modules 20 | run: go mod vendor 21 | 22 | - name: generate 23 | run: make generate 24 | 25 | - name: format 26 | run: make format && git diff --exit-code 27 | 28 | - name: golangci-lint 29 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 30 | with: 31 | version: v2.1.2 32 | 33 | - name: run tests 34 | run: make test 35 | -------------------------------------------------------------------------------- /.github/workflows/notify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release-notification 3 | 4 | on: 5 | release: 6 | types: [published] 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | notify-on-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Send Telegram Notification on new release 16 | uses: cbrgm/telegram-github-action@ae9dc892701436bfa54e34f5e8a49b1816c1a6c8 # v1.3.5 17 | with: 18 | token: ${{ secrets.TELEGRAM_TOKEN }} 19 | to: ${{ secrets.TELEGRAM_CHAT_ID }} 20 | message: | 21 | 🚀 New Release Published! 22 | Release Name: ${{ github.event.release.name }} 23 | Tag: ${{ github.event.release.tag_name }} 24 | Actor: ${{ github.actor }} 25 | Repository: ${{ github.repository }} 26 | Check it out: ${{ github.event.release.html_url }} 27 | 28 | - name: Send Mastodon Status on new release 29 | id: mastodon 30 | uses: cbrgm/mastodon-github-action@740aa5979f7dd752b329e3d3e3492166e5ada890 # v2.1.16 31 | if: ${{ !github.event.repository.private }} 32 | with: 33 | access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} 34 | url: ${{ secrets.MASTODON_URL }} 35 | language: "en" 36 | message: | 37 | 🚀 ${{ github.repository }} ${{ github.event.release.name }} published! 38 | Check it out: ${{ github.event.release.html_url }} 39 | ... 40 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: stale-issues-prs-branches 3 | on: 4 | schedule: 5 | - cron: 0 0 * * * 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | contents: write 11 | 12 | jobs: 13 | label-issues: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 17 | name: Setting issue as idle 18 | with: 19 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 20 | stale-issue-message: "This issue is idle because it has been open for 60 days with no activity." 21 | stale-issue-label: idle 22 | days-before-stale: 60 23 | days-before-close: 7 24 | operations-per-run: 100 25 | exempt-issue-labels: backlog 26 | 27 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 28 | name: Setting PR as idle 29 | with: 30 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 31 | stale-pr-message: "This PR is idle because it has been open for 60 days with no activity." 32 | stale-pr-label: idle 33 | days-before-stale: 60 34 | days-before-close: 7 35 | operations-per-run: 100 36 | 37 | - name: Cleanup Stale Branches 38 | uses: cbrgm/cleanup-stale-branches-action@main 39 | with: 40 | token: ${{ secrets.GITHUB_TOKEN }} 41 | repository: ${{ github.repository }} 42 | dry-run: false 43 | ... 44 | -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: publish-release-tag 3 | 4 | on: 5 | schedule: 6 | - cron: '0 12 1 * *' # At 12:00 (12 PM) on the 1st day of every month 7 | 8 | workflow_dispatch: 9 | inputs: 10 | bump-level: 11 | required: true 12 | type: choice 13 | description: 'The semver bump level' 14 | options: 15 | - 'major' 16 | - 'minor' 17 | - 'patch' 18 | - 'premajor' 19 | - 'preminor' 20 | - 'prepatch' 21 | - 'prerelease' 22 | default: 'patch' 23 | 24 | prerelease-tag: 25 | required: false 26 | description: 'The tag to use for prereleases' 27 | default: 'alpha' 28 | 29 | permissions: 30 | contents: write 31 | 32 | jobs: 33 | publish-release-tag: 34 | runs-on: ubuntu-latest 35 | steps: 36 | 37 | - name: Checkout 38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | with: 40 | token: ${{ secrets.BOT_PAT_TOKEN }} 41 | 42 | - name: Get Latest Tag 43 | id: current 44 | run: | 45 | git fetch --tags 46 | latest_tag=$(git tag | sort -V | tail -n 1) 47 | echo "current version is: $latest_tag" 48 | echo "latest_tag=$latest_tag" >> $GITHUB_ENV 49 | 50 | - name: Bump Version 51 | id: bump-semver 52 | uses: cbrgm/semver-bump-action@main 53 | with: 54 | current-version: ${{ env.latest_tag }} 55 | bump-level: ${{ github.event.inputs.bump-level || 'patch' }} 56 | prerelease-tag: ${{ github.event.inputs.prerelease-tag }} 57 | 58 | - name: Publish Git Tag 59 | run: | 60 | git fetch --tags 61 | latest_tag=$(git tag | sort -V | tail -n 1) 62 | new_tag=${{ steps.bump-semver.outputs.new_version }} 63 | if [[ $(git rev-list $latest_tag..HEAD --count) -gt 0 ]]; then 64 | git config user.name "GitHub Actions" 65 | git config user.email "github-actions@users.noreply.github.com" 66 | git tag $new_tag 67 | git push origin $new_tag 68 | else 69 | echo "No new commits since last tag. Skipping tag push. ($new_tag)" 70 | fi 71 | ... 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | *.exe 21 | *.test 22 | *.prof 23 | 24 | .idea 25 | 26 | /.env 27 | /dist/ 28 | /vendor 29 | /results 30 | /bin 31 | /out 32 | -------------------------------------------------------------------------------- /.go-version: -------------------------------------------------------------------------------- 1 | 1.24.4 2 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | go: "1.24" 4 | modules-download-mode: readonly 5 | tests: false 6 | linters: 7 | enable: 8 | - gocyclo 9 | - godot 10 | - misspell 11 | - revive 12 | - whitespace 13 | settings: 14 | gocyclo: 15 | min-complexity: 20 16 | gosec: 17 | excludes: 18 | - G404 19 | - G114 20 | misspell: 21 | locale: US 22 | revive: 23 | severity: warning 24 | rules: 25 | - name: unexported-return 26 | severity: warning 27 | disabled: true 28 | exclusions: 29 | generated: lax 30 | rules: 31 | - linters: 32 | - errcheck 33 | path: _test.go 34 | paths: 35 | - cdk.out 36 | - vendor 37 | - third_party$ 38 | - builtin$ 39 | - examples$ 40 | formatters: 41 | enable: 42 | - gofumpt 43 | settings: 44 | gofumpt: 45 | extra-rules: true 46 | exclusions: 47 | generated: lax 48 | paths: 49 | - cdk.out 50 | - vendor 51 | - third_party$ 52 | - builtin$ 53 | - examples$ 54 | 55 | 56 | -------------------------------------------------------------------------------- /.img/callbacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbrgm/githubevents/326cf0385c22f1d2e0f8bca7d157c9f15b2846f2/.img/callbacks.png -------------------------------------------------------------------------------- /.img/callbacks.xml: -------------------------------------------------------------------------------- 1 | 7RvbcuI29Gt46QyMLV95DJdsO93MZLrttPuUEbYw6toWK4sA+/WVbBlbliHOxpBLSSbBOjqSpXM/R2JgTZPdJwrXqzsSongAjHA3sGYDAEzTd/mHgOwLiOP7BSCiOJRIFeAL/oEk0JDQDQ5RpiAyQmKG1yowIGmKAqbAIKVkq6ItSay+dQ0jpAG+BDDWoX/jkK3KfbnjquNXhKOVfLUPvKIjgSWy3Em2giHZ1kDWfGBNKSGseEp2UxQL4pV0KcbdHuk9LIyilHUZsEpmd7//tV5Ef8zwDXMt4hIyLFf7COON3LFcLduXJKBkk4ZIzGIMrMl2hRn6soaB6N1ypnPYiiUxb5n8cYnjeEpiQnk7JSlHmsg3IMrQ7ujazQNFuCghkiBG9xxFDrBdpxgipQjYkqjbiie2IXFWNXaYvkSEUg6iw9wVqfiDpNYzKGc675JyNuhIOeCdi3KWRicUcp2TTULZikQkhfG8gk5USlY4nwlZS/r9ixjbSwMCN4yo1OXkovt/5Pi88VU0Rk7ZnO3qnbN9vXWPKOZ7R1QCiw2IVZ/mCt8k2dAAnRIjadMgjRA7pajtXKYohgw/quvoX9Z9TdYZxVHECdLGys9wwb2AQn4Y4yjlzwEnkCDjRAg15mb2RnYkOAwLTqMM/4CLfD5B6zXBKcs35EwGzuyUVkgfIAdXlrfOl+MSeVSFhsbIcAygqJGU4c7kl5Pfi83UUMhymXG2N/lzWMMLWPa0dcq+IRasWsk84ZSbFn+c5GAqICPgtADbYJ4ONHU0/mG2vaEJbIN5OtDU0USrXLUKbIN5jr7i5mizZbTZGJ3LKNmwGKdoeohKBI2XJGWlhR8Ai//eCo5OIgpDjJS+21v71p/U+maY8okwSXPvQIXpVjwGHzOZmpbjcnjGKPmGaj3L/If3hDBbHaxoqYK5ut6TDMvpF4QxkrToKBO2Vlflug/jO5Qm2ARlW0qceCXM1gU5lngn1jHhQdFadCa7SMSPI7jN7BE3AbnZ/C0Q6xEWoXhSsbI068dFHjxdGVz4/sjRnKTn6z6yhPVucJ3XcJE9ejXQ0avZr+nVwFizkVvKQzQOWnBaBuIhhAx+DB/nPOnjbGCrevDWfRxo8XFuzKTdUXjmft+QsmOY5RpwwxHG613Vx58i8YkSiONhIQJDChkaCikY5rJByzfwBRcvKcZcnet7cq6ePzfs5znXmeFMTe9/41xjmCxC2I9/dQxPtStjPQW9qHe1L2k3uhqMVqE+t0i1SIg1CvcpTMhDuNC1AMw9a+K3aFV/BQvP6RSNAV1e/LOlv4YmMJ8oXMKUM9f4k+L16Jer/b+g/b+S8225U8u2fXDNVU+404TbigiFDxmijzhAD0tCHyJpQs5iNR3Pe+0c1uxQgkJpeCMOaQSLYphlOFB5pOa0aIdZXsItqra89VXiieeqgCsa+1rjjOXbMv16MtM1j9QYa9wpWVjnTgn72SSsDMFsVTysZnG/2KgcVT9EakzkG+pEttGYqCCENhHnMtzX0KQJ77xg2zFOrquJ75jjhgAXK+i3xqofnpUFhPndLf8vXoCD7GMUEMzTFmhojEzf9XoRV7UOMQbq+DMWzfWKAkUM4vRQCTK45eb/LSOH7HXWcnKzRoyteDgZKLcc9nXnfttBomopz+BRbEvP2sYtFssyjnP7Zf7E0pgzjckm3EIRaL/ddCqoFqmFQZ4znraGVf3lU45RRIZKcKCz0gdlvFBn5tg6FzPbcvB+goNaaFAFCq8SHJjvIzjQNN3tKzgwuwUHvZlvVxOqLKBCJT+GAz5yWiKnN0aGb6qe882fUh9U6XXughwab+MuSOdk4qXHZkfUt5kklG7jQupbvq6mvt83KN+ZcL1ineXJ3AcJqZ9w3Tykto13dyinF0ufW133u1XXZXZ1PZj7OJXE68HcZQ/m7JyD9ZCt5WLtRauG4HSWJ45bWu8dXvO9I7eZbAu0VIIvnO6B/tO9N3qft5Tfpy/0Gu1svEzO51oNKWnek++a87l+U9wum/MBPef7UFeTwemkT9zbsuzGlyN6kZDGgJ8JGHmz+npLgV59Scia/wc= -------------------------------------------------------------------------------- /.img/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbrgm/githubevents/326cf0385c22f1d2e0f8bca7d157c9f15b2846f2/.img/gopher.png -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # github codeowners file 2 | # 3 | # https://help.github.com/articles/about-codeowners/ 4 | # 5 | # These owners will be the default owners for everything in 6 | # the repo. Unless a later match takes precedence, 7 | # mentioned account names will be requested for 8 | # review when someone opens a pull request. 9 | * @cbrgm 10 | 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | ## Table of Contents 4 | - [Introduction](#introduction) 5 | - [Feature Requests](#feature-requests) 6 | - [Bug Reports](#bug-reports) 7 | - [Pull Requests](#pull-requests) 8 | - [Collaboration](#collaboration) 9 | - [Additional Contributions](#additional-contributions) 10 | - [Collaborator Status](#collaborator-status) 11 | - [Final Notes](#final-notes) 12 | 13 | ## Introduction 14 | - Explore [Feature Requests](#feature-requests), [Bug Reports](#bug-reports), and [Pull Requests](#pull-requests) to contribute. 15 | - Got Questions? Email: . 16 | 17 | ## Feature Requests 18 | - Check ***[existing requests](https://github.com/cbrgm/githubevents/issues)***. 19 | - Submit a new request if needed, explaining benefits and relevance. 20 | 21 | ## Bug Reports 22 | - Verify if the bug is already reported via ***[open bugs](https://github.com/cbrgm/githubevents/issues)***. 23 | - Report new bugs with: 24 | - **Description**: Summary of the issue. 25 | - **Steps to Reproduce**: Clear steps. 26 | - **Expected vs. Actual Results**. 27 | - **Version Info**. 28 | 29 | ## Pull Requests 30 | - Review ***[existing PRs](https://github.com/cbrgm/githubevents/pulls)*** first. 31 | - Submit small, well-tested PRs anytime. 32 | - PRs undergo thorough reviews; responsiveness is key. 33 | 34 | ## Collaboration 35 | - **Engage** with feedback and reviews. 36 | - **Small, Focused Commits**: Easier to review and test. 37 | - **Respectful Interaction**: Collaboration thrives on patience. 38 | 39 | ## Additional Contributions 40 | - Improve documentation or suggest feature enhancements. 41 | - Report serious security issues to . Use PRs for less critical fixes. 42 | 43 | ## Collaborator Status 44 | - **After a PR is Merged**: Potential "collaborator status." 45 | - **Responsibilities**: Review PRs, resolve issues, and submit new contributions. 46 | - **Inactive Collaborators**: May be temporarily removed for security but reinstated later. 47 | 48 | Your ideas, reports, and contributions make this project valuable for everyone. Thank you so much for your help! :-) 49 | 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGES = $(shell go list ./...) 2 | GO := CGO_ENABLED=0 go 3 | 4 | .PHONY: all 5 | all: build 6 | 7 | .PHONY: clean 8 | clean: 9 | $(GO) clean -i ./... 10 | rm -rf ./bin/ 11 | 12 | .PHONY: format 13 | format: go/fmt 14 | 15 | .PHONY: go/fmt 16 | go/fmt: 17 | $(GO) fmt $(PACKAGES) 18 | 19 | .PHONY: test 20 | test: 21 | @for PKG in $(PACKAGES); do $(GO) test -cover $$PKG || exit 1; done; 22 | 23 | .PHONY: generate 24 | generate: build 25 | ./bin/githubhook-gen --output=githubevents 26 | 27 | .PHONY: build 28 | build: \ 29 | bin/gen 30 | 31 | .PHONY: bin/gen 32 | bin/gen: 33 | mkdir -p bin 34 | $(GO) build -v -ldflags '-w $(LDFLAGS)' -o ./bin/githubhook-gen ./gen/*.go 35 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This folder provides usage examples for `cbrgm/githubevents`. 4 | 5 | Feel free to contribute! 6 | -------------------------------------------------------------------------------- /examples/simple-http-server-funcs/go.mod: -------------------------------------------------------------------------------- 1 | module simple-http-server-funcs 2 | 3 | go 1.24.0 4 | 5 | require github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 6 | 7 | require ( 8 | github.com/google/go-github/v69 v69.2.0 // indirect 9 | github.com/google/go-querystring v1.1.0 // indirect 10 | golang.org/x/sync v0.11.0 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /examples/simple-http-server-funcs/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 h1:E/yQPdllmKN7w5OYmVUUqgsQ4zpxcpv+H9q5Amb0tl4= 2 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3/go.mod h1:mD3XFxVIniUlfEuJ0jae1Vn8wmPKUwOb2W1StYP6xVc= 3 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 5 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 6 | github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= 7 | github.com/google/go-github/v69 v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM= 8 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 9 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 10 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= 11 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 12 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 13 | -------------------------------------------------------------------------------- /examples/simple-http-server-funcs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/cbrgm/githubevents/v2/githubevents" 9 | ) 10 | 11 | func main() { 12 | handle := githubevents.New("") 13 | 14 | // pass the eventHandler to funcs that define callbacks 15 | newPing(handle) 16 | newPong(handle) 17 | 18 | http.HandleFunc("/hook", func(w http.ResponseWriter, r *http.Request) { 19 | err := handle.HandleEventRequest(r) 20 | if err != nil { 21 | fmt.Println("error") 22 | } 23 | }) 24 | 25 | if err := http.ListenAndServe(":8080", nil); err != nil { 26 | panic(err) 27 | } 28 | } 29 | 30 | func newPing(handle *githubevents.EventHandler) { 31 | handle.OnBeforeAny( 32 | func(ctx context.Context, deliveryID, eventName string, event any) error { 33 | fmt.Println("ping!") 34 | return nil 35 | }, 36 | ) 37 | } 38 | 39 | func newPong(handle *githubevents.EventHandler) { 40 | handle.OnBeforeAny( 41 | func(ctx context.Context, deliveryID, eventName string, event any) error { 42 | fmt.Println("pong!") 43 | return nil 44 | }, 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /examples/simple-http-server-packages/go.mod: -------------------------------------------------------------------------------- 1 | module simple-http-server-packages 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 7 | github.com/google/go-github/v72 v72.0.0 8 | ) 9 | 10 | require ( 11 | github.com/google/go-github/v69 v69.2.0 // indirect 12 | github.com/google/go-querystring v1.1.0 // indirect 13 | golang.org/x/sync v0.11.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /examples/simple-http-server-packages/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 h1:E/yQPdllmKN7w5OYmVUUqgsQ4zpxcpv+H9q5Amb0tl4= 2 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3/go.mod h1:mD3XFxVIniUlfEuJ0jae1Vn8wmPKUwOb2W1StYP6xVc= 3 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 5 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 6 | github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= 7 | github.com/google/go-github/v69 v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM= 8 | github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= 9 | github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= 10 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 11 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 12 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= 13 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 14 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 15 | -------------------------------------------------------------------------------- /examples/simple-http-server-packages/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/cbrgm/githubevents/v2/githubevents" 8 | 9 | "simple-http-server-packages/plugins" 10 | ) 11 | 12 | func main() { 13 | handle := githubevents.New("") 14 | 15 | // return handleFuncs from other packages 16 | // and use them ad "plugins" 17 | handle.OnIssueCommentCreated( 18 | plugins.NewResponder("ping!"), 19 | plugins.NewResponder("pong!"), 20 | ) 21 | 22 | http.HandleFunc("/hook", func(w http.ResponseWriter, r *http.Request) { 23 | err := handle.HandleEventRequest(r) 24 | if err != nil { 25 | fmt.Println("error") 26 | } 27 | }) 28 | 29 | if err := http.ListenAndServe(":8080", nil); err != nil { 30 | panic(err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/simple-http-server-packages/plugins/responder.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/cbrgm/githubevents/v2/githubevents" 8 | "github.com/google/go-github/v72/github" 9 | ) 10 | 11 | func NewResponder(msg string) githubevents.IssueCommentEventHandleFunc { 12 | // do some configuration here 13 | // ... 14 | return func(ctx context.Context, deliveryID, eventName string, event *github.IssueCommentEvent) error { 15 | fmt.Printf("commenting %s", msg) 16 | return nil 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/simple-http-server/go.mod: -------------------------------------------------------------------------------- 1 | module simple-http-server 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 7 | github.com/google/go-github/v72 v72.0.0 8 | ) 9 | 10 | require ( 11 | github.com/google/go-github/v69 v69.2.0 // indirect 12 | github.com/google/go-querystring v1.1.0 // indirect 13 | golang.org/x/sync v0.11.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /examples/simple-http-server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3 h1:E/yQPdllmKN7w5OYmVUUqgsQ4zpxcpv+H9q5Amb0tl4= 2 | github.com/cbrgm/githubevents/v2 v2.0.0-20250304131238-cf5ca4a066d3/go.mod h1:mD3XFxVIniUlfEuJ0jae1Vn8wmPKUwOb2W1StYP6xVc= 3 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 5 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 6 | github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= 7 | github.com/google/go-github/v69 v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM= 8 | github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= 9 | github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= 10 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 11 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 12 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= 13 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 14 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 15 | -------------------------------------------------------------------------------- /examples/simple-http-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/cbrgm/githubevents/v2/githubevents" 9 | "github.com/google/go-github/v72/github" 10 | ) 11 | 12 | func main() { 13 | handle := githubevents.New("") 14 | 15 | handle.OnIssueCommentCreated(func(ctx context.Context, deliveryID, eventName string, event *github.IssueCommentEvent) error { 16 | fmt.Printf("%s has commented on issue %d", *event.Sender.Login, *event.Issue.ID) 17 | return nil 18 | }) 19 | 20 | http.HandleFunc("/hook", func(w http.ResponseWriter, r *http.Request) { 21 | err := handle.HandleEventRequest(r) 22 | if err != nil { 23 | fmt.Println("error") 24 | } 25 | }) 26 | 27 | if err := http.ListenAndServe(":8080", nil); err != nil { 28 | panic(err) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /gen/format.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "os" 7 | "os/exec" 8 | ) 9 | 10 | // format formats a template using gofmt. 11 | func format(in io.Reader) (io.Reader, error) { 12 | var out bytes.Buffer 13 | 14 | gofmt := exec.Command("gofmt", "-s") 15 | gofmt.Stdin = in 16 | gofmt.Stdout = &out 17 | gofmt.Stderr = os.Stderr 18 | err := gofmt.Run() 19 | return &out, err 20 | } 21 | -------------------------------------------------------------------------------- /gen/generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | _ "embed" 6 | "flag" 7 | "io" 8 | "os" 9 | "path/filepath" 10 | "text/template" 11 | ) 12 | 13 | //go:embed template_markdown.go.tmpl 14 | var webhookMarkdownTemplate string 15 | 16 | //go:embed template_webhook_event.go.tmpl 17 | var webhookEventTemplate string 18 | 19 | //go:embed template_webhook_event_tests.go.tmpl 20 | var webhookTestsTemplate string 21 | 22 | //go:embed template_webhook_event_types.go.tmpl 23 | var webhookTypesTemplate string 24 | 25 | func main() { 26 | outputDir := flag.String("output", "githubevents", "output directory") 27 | docs := flag.Bool("docs", false, "generate markdown docs") 28 | 29 | flag.Parse() 30 | if *outputDir == "" { 31 | panic("output directory is empty") 32 | } 33 | 34 | // when -docs is set, create a list of all supported markdown events as yaml on stdout 35 | // todo(cbrgm): clean this up a little bit 36 | if *docs { 37 | err := ExecuteMarkdownTemplate("", webhookMarkdownTemplate, params) 38 | if err != nil { 39 | panic(err) 40 | } 41 | return 42 | } 43 | 44 | out := filepath.Join(".", *outputDir) 45 | err := os.MkdirAll(out, os.ModePerm) 46 | if err != nil { 47 | panic("failed to create output directory") 48 | } 49 | 50 | // create events.go 51 | err = ExecuteWebhookEventTemplate(filepath.Join(out, "events"), params) 52 | if err != nil { 53 | panic(err) 54 | } 55 | 56 | // create individual files for each webhook event type 57 | // webhook events_*.go files and events_*_test.go files are generated 58 | for _, param := range params.Webhooks { 59 | fileName := "events_" + param.Name 60 | outFile := filepath.Join(out, fileName) 61 | err := ExecuteWebhookEventTypesTemplate(outFile, TemplateParameters{ 62 | Webhooks: []GithubWebhooks{param}, 63 | }) 64 | if err != nil { 65 | panic(err) 66 | } 67 | } 68 | } 69 | 70 | func ExecuteWebhookEventTemplate(file string, data any) error { 71 | err := ExecuteTemplate(file+".go", webhookEventTemplate, data) 72 | if err != nil { 73 | return err 74 | } 75 | return nil 76 | } 77 | 78 | func ExecuteWebhookEventTypesTemplate(file string, data any) error { 79 | err := ExecuteTemplate(file+".go", webhookTypesTemplate, data) 80 | if err != nil { 81 | return err 82 | } 83 | err = ExecuteTemplate(file+"_test.go", webhookTestsTemplate, data) 84 | if err != nil { 85 | return err 86 | } 87 | return nil 88 | } 89 | 90 | // ExecuteWebhookEventTypesTemplate renders the named template and writes to io.Writer wr. 91 | func ExecuteTemplate(file, tmpl string, data any) error { 92 | wr := os.Stdout 93 | if output := file; output != "" { 94 | wri, err := os.Create(output) 95 | if err != nil { 96 | return err 97 | } 98 | wr = wri 99 | defer func() { 100 | _ = wr.Close() 101 | }() 102 | } 103 | 104 | buf := new(bytes.Buffer) 105 | 106 | t, err := template.New("").Parse(tmpl) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | err = t.ExecuteTemplate(buf, "", data) 112 | if err != nil { 113 | return err 114 | } 115 | 116 | src, err := format(buf) 117 | if err != nil { 118 | return err 119 | } 120 | _, err = io.Copy(wr, src) 121 | return err 122 | } 123 | 124 | // ExecuteMarkdownTemplate renders the named template and writes to io.Writer wr. 125 | func ExecuteMarkdownTemplate(_, tmpl string, data any) error { 126 | wr := os.Stdout 127 | buf := new(bytes.Buffer) 128 | t, err := template.New("").Parse(tmpl) 129 | if err != nil { 130 | return err 131 | } 132 | err = t.ExecuteTemplate(buf, "", data) 133 | if err != nil { 134 | return err 135 | } 136 | _, err = io.Copy(wr, buf) 137 | return err 138 | } 139 | -------------------------------------------------------------------------------- /gen/template_markdown.go.tmpl: -------------------------------------------------------------------------------- 1 | {{ range $_, $webhook := .Webhooks }} 2 | * ***[{{ $webhook.Name }}](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#{{ $webhook.Name }})*** 3 | {{ end }} 4 | ` 5 | -------------------------------------------------------------------------------- /githubevents/events_create.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // CreateEvent is the event name of github.CreateEvent's 20 | CreateEvent = "create" 21 | 22 | // CreateEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.CreateEvent 24 | CreateEventAnyAction = "*" 25 | ) 26 | 27 | // CreateEventHandleFunc represents a callback function triggered on github.CreateEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.CreateEvent) is the webhook payload. 31 | type CreateEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error 32 | 33 | // OnCreateEventAny registers callbacks listening to any events of type github.CreateEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnCreateEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#create 42 | func (g *EventHandler) OnCreateEventAny(callbacks ...CreateEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onCreateEvent == nil { 49 | g.onCreateEvent = make(map[string][]CreateEventHandleFunc) 50 | } 51 | g.onCreateEvent[CreateEventAnyAction] = append( 52 | g.onCreateEvent[CreateEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnCreateEventAny registers callbacks listening to any events of type github.CreateEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnCreateEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#create 67 | func (g *EventHandler) SetOnCreateEventAny(callbacks ...CreateEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onCreateEvent == nil { 74 | g.onCreateEvent = make(map[string][]CreateEventHandleFunc) 75 | } 76 | g.onCreateEvent[CreateEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleCreateEventAny(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onCreateEvent[CreateEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onCreateEvent[CreateEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // CreateEvent handles github.CreateEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnCreateEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) CreateEvent(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleCreateEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_create_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnCreateEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []CreateEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single CreateEventHandleFunc", 28 | args: args{ 29 | []CreateEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple CreateEventHandleFuncs", 38 | args: args{ 39 | []CreateEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnCreateEventAny(tt.args.callbacks...) 54 | if len(g.onCreateEvent[CreateEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onCreateEvent[CreateEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnCreateEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []CreateEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single CreateEventHandleFunc", 72 | args: args{ 73 | []CreateEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple CreateEventHandleFuncs", 83 | args: args{ 84 | []CreateEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnCreateEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 101 | return nil 102 | }) 103 | g.SetOnCreateEventAny(tt.args.callbacks...) 104 | if len(g.onCreateEvent[CreateEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onCreateEvent[CreateEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleCreateEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.CreateEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "create", 130 | 131 | event: &github.CreateEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "create", 142 | 143 | event: &github.CreateEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "create", 154 | 155 | event: &github.CreateEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "create", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnCreateEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleCreateEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleCreateEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestCreateEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.CreateEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger CreateEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onCreateEvent: map[string][]CreateEventHandleFunc{ 229 | CreateEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.CreateEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: CreateEvent, 241 | 242 | event: &github.CreateEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.CreateEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("CreateEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // DeleteEvent is the event name of github.DeleteEvent's 20 | DeleteEvent = "delete" 21 | 22 | // DeleteEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.DeleteEvent 24 | DeleteEventAnyAction = "*" 25 | ) 26 | 27 | // DeleteEventHandleFunc represents a callback function triggered on github.DeleteEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.DeleteEvent) is the webhook payload. 31 | type DeleteEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error 32 | 33 | // OnDeleteEventAny registers callbacks listening to any events of type github.DeleteEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnDeleteEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#delete 42 | func (g *EventHandler) OnDeleteEventAny(callbacks ...DeleteEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onDeleteEvent == nil { 49 | g.onDeleteEvent = make(map[string][]DeleteEventHandleFunc) 50 | } 51 | g.onDeleteEvent[DeleteEventAnyAction] = append( 52 | g.onDeleteEvent[DeleteEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnDeleteEventAny registers callbacks listening to any events of type github.DeleteEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnDeleteEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#delete 67 | func (g *EventHandler) SetOnDeleteEventAny(callbacks ...DeleteEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onDeleteEvent == nil { 74 | g.onDeleteEvent = make(map[string][]DeleteEventHandleFunc) 75 | } 76 | g.onDeleteEvent[DeleteEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleDeleteEventAny(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onDeleteEvent[DeleteEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onDeleteEvent[DeleteEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // DeleteEvent handles github.DeleteEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnDeleteEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) DeleteEvent(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleDeleteEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_delete_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnDeleteEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []DeleteEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single DeleteEventHandleFunc", 28 | args: args{ 29 | []DeleteEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple DeleteEventHandleFuncs", 38 | args: args{ 39 | []DeleteEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnDeleteEventAny(tt.args.callbacks...) 54 | if len(g.onDeleteEvent[DeleteEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onDeleteEvent[DeleteEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnDeleteEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []DeleteEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single DeleteEventHandleFunc", 72 | args: args{ 73 | []DeleteEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple DeleteEventHandleFuncs", 83 | args: args{ 84 | []DeleteEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnDeleteEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 101 | return nil 102 | }) 103 | g.SetOnDeleteEventAny(tt.args.callbacks...) 104 | if len(g.onDeleteEvent[DeleteEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onDeleteEvent[DeleteEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleDeleteEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.DeleteEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "delete", 130 | 131 | event: &github.DeleteEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "delete", 142 | 143 | event: &github.DeleteEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "delete", 154 | 155 | event: &github.DeleteEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "delete", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnDeleteEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleDeleteEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleDeleteEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestDeleteEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.DeleteEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger DeleteEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onDeleteEvent: map[string][]DeleteEventHandleFunc{ 229 | DeleteEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeleteEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: DeleteEvent, 241 | 242 | event: &github.DeleteEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.DeleteEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("DeleteEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_deployment.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // DeploymentEvent is the event name of github.DeploymentEvent's 20 | DeploymentEvent = "deployment" 21 | 22 | // DeploymentEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.DeploymentEvent 24 | DeploymentEventAnyAction = "*" 25 | ) 26 | 27 | // DeploymentEventHandleFunc represents a callback function triggered on github.DeploymentEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.DeploymentEvent) is the webhook payload. 31 | type DeploymentEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error 32 | 33 | // OnDeploymentEventAny registers callbacks listening to any events of type github.DeploymentEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnDeploymentEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#deployment 42 | func (g *EventHandler) OnDeploymentEventAny(callbacks ...DeploymentEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onDeploymentEvent == nil { 49 | g.onDeploymentEvent = make(map[string][]DeploymentEventHandleFunc) 50 | } 51 | g.onDeploymentEvent[DeploymentEventAnyAction] = append( 52 | g.onDeploymentEvent[DeploymentEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnDeploymentEventAny registers callbacks listening to any events of type github.DeploymentEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnDeploymentEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#deployment 67 | func (g *EventHandler) SetOnDeploymentEventAny(callbacks ...DeploymentEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onDeploymentEvent == nil { 74 | g.onDeploymentEvent = make(map[string][]DeploymentEventHandleFunc) 75 | } 76 | g.onDeploymentEvent[DeploymentEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleDeploymentEventAny(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onDeploymentEvent[DeploymentEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onDeploymentEvent[DeploymentEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // DeploymentEvent handles github.DeploymentEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnDeploymentEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) DeploymentEvent(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleDeploymentEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_deployment_status.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // DeploymentStatusEvent is the event name of github.DeploymentStatusEvent's 20 | DeploymentStatusEvent = "deployment_status" 21 | 22 | // DeploymentStatusEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.DeploymentStatusEvent 24 | DeploymentStatusEventAnyAction = "*" 25 | ) 26 | 27 | // DeploymentStatusEventHandleFunc represents a callback function triggered on github.DeploymentStatusEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.DeploymentStatusEvent) is the webhook payload. 31 | type DeploymentStatusEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error 32 | 33 | // OnDeploymentStatusEventAny registers callbacks listening to any events of type github.DeploymentStatusEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnDeploymentStatusEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#deployment_status 42 | func (g *EventHandler) OnDeploymentStatusEventAny(callbacks ...DeploymentStatusEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onDeploymentStatusEvent == nil { 49 | g.onDeploymentStatusEvent = make(map[string][]DeploymentStatusEventHandleFunc) 50 | } 51 | g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction] = append( 52 | g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnDeploymentStatusEventAny registers callbacks listening to any events of type github.DeploymentStatusEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnDeploymentStatusEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#deployment_status 67 | func (g *EventHandler) SetOnDeploymentStatusEventAny(callbacks ...DeploymentStatusEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onDeploymentStatusEvent == nil { 74 | g.onDeploymentStatusEvent = make(map[string][]DeploymentStatusEventHandleFunc) 75 | } 76 | g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleDeploymentStatusEventAny(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // DeploymentStatusEvent handles github.DeploymentStatusEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnDeploymentStatusEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) DeploymentStatusEvent(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleDeploymentStatusEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_deployment_status_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnDeploymentStatusEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []DeploymentStatusEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single DeploymentStatusEventHandleFunc", 28 | args: args{ 29 | []DeploymentStatusEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple DeploymentStatusEventHandleFuncs", 38 | args: args{ 39 | []DeploymentStatusEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnDeploymentStatusEventAny(tt.args.callbacks...) 54 | if len(g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnDeploymentStatusEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []DeploymentStatusEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single DeploymentStatusEventHandleFunc", 72 | args: args{ 73 | []DeploymentStatusEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple DeploymentStatusEventHandleFuncs", 83 | args: args{ 84 | []DeploymentStatusEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnDeploymentStatusEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 101 | return nil 102 | }) 103 | g.SetOnDeploymentStatusEventAny(tt.args.callbacks...) 104 | if len(g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onDeploymentStatusEvent[DeploymentStatusEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleDeploymentStatusEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.DeploymentStatusEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "deployment_status", 130 | 131 | event: &github.DeploymentStatusEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "deployment_status", 142 | 143 | event: &github.DeploymentStatusEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "deployment_status", 154 | 155 | event: &github.DeploymentStatusEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "deployment_status", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnDeploymentStatusEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleDeploymentStatusEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleDeploymentStatusEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestDeploymentStatusEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.DeploymentStatusEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger DeploymentStatusEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onDeploymentStatusEvent: map[string][]DeploymentStatusEventHandleFunc{ 229 | DeploymentStatusEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentStatusEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: DeploymentStatusEvent, 241 | 242 | event: &github.DeploymentStatusEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.DeploymentStatusEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("DeploymentStatusEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_deployment_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnDeploymentEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []DeploymentEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single DeploymentEventHandleFunc", 28 | args: args{ 29 | []DeploymentEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple DeploymentEventHandleFuncs", 38 | args: args{ 39 | []DeploymentEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnDeploymentEventAny(tt.args.callbacks...) 54 | if len(g.onDeploymentEvent[DeploymentEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onDeploymentEvent[DeploymentEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnDeploymentEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []DeploymentEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single DeploymentEventHandleFunc", 72 | args: args{ 73 | []DeploymentEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple DeploymentEventHandleFuncs", 83 | args: args{ 84 | []DeploymentEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnDeploymentEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 101 | return nil 102 | }) 103 | g.SetOnDeploymentEventAny(tt.args.callbacks...) 104 | if len(g.onDeploymentEvent[DeploymentEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onDeploymentEvent[DeploymentEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleDeploymentEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.DeploymentEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "deployment", 130 | 131 | event: &github.DeploymentEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "deployment", 142 | 143 | event: &github.DeploymentEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "deployment", 154 | 155 | event: &github.DeploymentEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "deployment", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnDeploymentEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleDeploymentEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleDeploymentEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestDeploymentEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.DeploymentEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger DeploymentEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onDeploymentEvent: map[string][]DeploymentEventHandleFunc{ 229 | DeploymentEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.DeploymentEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: DeploymentEvent, 241 | 242 | event: &github.DeploymentEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.DeploymentEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("DeploymentEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_fork.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // ForkEvent is the event name of github.ForkEvent's 20 | ForkEvent = "fork" 21 | 22 | // ForkEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.ForkEvent 24 | ForkEventAnyAction = "*" 25 | ) 26 | 27 | // ForkEventHandleFunc represents a callback function triggered on github.ForkEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.ForkEvent) is the webhook payload. 31 | type ForkEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error 32 | 33 | // OnForkEventAny registers callbacks listening to any events of type github.ForkEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnForkEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#fork 42 | func (g *EventHandler) OnForkEventAny(callbacks ...ForkEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onForkEvent == nil { 49 | g.onForkEvent = make(map[string][]ForkEventHandleFunc) 50 | } 51 | g.onForkEvent[ForkEventAnyAction] = append( 52 | g.onForkEvent[ForkEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnForkEventAny registers callbacks listening to any events of type github.ForkEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnForkEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#fork 67 | func (g *EventHandler) SetOnForkEventAny(callbacks ...ForkEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onForkEvent == nil { 74 | g.onForkEvent = make(map[string][]ForkEventHandleFunc) 75 | } 76 | g.onForkEvent[ForkEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleForkEventAny(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onForkEvent[ForkEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onForkEvent[ForkEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // ForkEvent handles github.ForkEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnForkEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) ForkEvent(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleForkEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_fork_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnForkEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []ForkEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single ForkEventHandleFunc", 28 | args: args{ 29 | []ForkEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple ForkEventHandleFuncs", 38 | args: args{ 39 | []ForkEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnForkEventAny(tt.args.callbacks...) 54 | if len(g.onForkEvent[ForkEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onForkEvent[ForkEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnForkEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []ForkEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single ForkEventHandleFunc", 72 | args: args{ 73 | []ForkEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple ForkEventHandleFuncs", 83 | args: args{ 84 | []ForkEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnForkEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 101 | return nil 102 | }) 103 | g.SetOnForkEventAny(tt.args.callbacks...) 104 | if len(g.onForkEvent[ForkEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onForkEvent[ForkEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleForkEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.ForkEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "fork", 130 | 131 | event: &github.ForkEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "fork", 142 | 143 | event: &github.ForkEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "fork", 154 | 155 | event: &github.ForkEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "fork", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnForkEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleForkEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleForkEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestForkEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.ForkEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger ForkEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onForkEvent: map[string][]ForkEventHandleFunc{ 229 | ForkEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.ForkEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: ForkEvent, 241 | 242 | event: &github.ForkEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.ForkEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("ForkEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_gollum.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // GollumEvent is the event name of github.GollumEvent's 20 | GollumEvent = "gollum" 21 | 22 | // GollumEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.GollumEvent 24 | GollumEventAnyAction = "*" 25 | ) 26 | 27 | // GollumEventHandleFunc represents a callback function triggered on github.GollumEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.GollumEvent) is the webhook payload. 31 | type GollumEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error 32 | 33 | // OnGollumEventAny registers callbacks listening to any events of type github.GollumEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnGollumEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#gollum 42 | func (g *EventHandler) OnGollumEventAny(callbacks ...GollumEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onGollumEvent == nil { 49 | g.onGollumEvent = make(map[string][]GollumEventHandleFunc) 50 | } 51 | g.onGollumEvent[GollumEventAnyAction] = append( 52 | g.onGollumEvent[GollumEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnGollumEventAny registers callbacks listening to any events of type github.GollumEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnGollumEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#gollum 67 | func (g *EventHandler) SetOnGollumEventAny(callbacks ...GollumEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onGollumEvent == nil { 74 | g.onGollumEvent = make(map[string][]GollumEventHandleFunc) 75 | } 76 | g.onGollumEvent[GollumEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleGollumEventAny(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onGollumEvent[GollumEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onGollumEvent[GollumEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // GollumEvent handles github.GollumEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnGollumEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) GollumEvent(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleGollumEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_gollum_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnGollumEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []GollumEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single GollumEventHandleFunc", 28 | args: args{ 29 | []GollumEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple GollumEventHandleFuncs", 38 | args: args{ 39 | []GollumEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnGollumEventAny(tt.args.callbacks...) 54 | if len(g.onGollumEvent[GollumEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onGollumEvent[GollumEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnGollumEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []GollumEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single GollumEventHandleFunc", 72 | args: args{ 73 | []GollumEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple GollumEventHandleFuncs", 83 | args: args{ 84 | []GollumEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnGollumEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 101 | return nil 102 | }) 103 | g.SetOnGollumEventAny(tt.args.callbacks...) 104 | if len(g.onGollumEvent[GollumEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onGollumEvent[GollumEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleGollumEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.GollumEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "gollum", 130 | 131 | event: &github.GollumEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "gollum", 142 | 143 | event: &github.GollumEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "gollum", 154 | 155 | event: &github.GollumEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "gollum", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnGollumEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleGollumEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleGollumEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestGollumEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.GollumEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger GollumEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onGollumEvent: map[string][]GollumEventHandleFunc{ 229 | GollumEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.GollumEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: GollumEvent, 241 | 242 | event: &github.GollumEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.GollumEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("GollumEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // MetaEvent is the event name of github.MetaEvent's 20 | MetaEvent = "meta" 21 | 22 | // MetaEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.MetaEvent 24 | MetaEventAnyAction = "*" 25 | ) 26 | 27 | // MetaEventHandleFunc represents a callback function triggered on github.MetaEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.MetaEvent) is the webhook payload. 31 | type MetaEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error 32 | 33 | // OnMetaEventAny registers callbacks listening to any events of type github.MetaEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnMetaEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#meta 42 | func (g *EventHandler) OnMetaEventAny(callbacks ...MetaEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onMetaEvent == nil { 49 | g.onMetaEvent = make(map[string][]MetaEventHandleFunc) 50 | } 51 | g.onMetaEvent[MetaEventAnyAction] = append( 52 | g.onMetaEvent[MetaEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnMetaEventAny registers callbacks listening to any events of type github.MetaEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnMetaEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#meta 67 | func (g *EventHandler) SetOnMetaEventAny(callbacks ...MetaEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onMetaEvent == nil { 74 | g.onMetaEvent = make(map[string][]MetaEventHandleFunc) 75 | } 76 | g.onMetaEvent[MetaEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleMetaEventAny(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onMetaEvent[MetaEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onMetaEvent[MetaEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // MetaEvent handles github.MetaEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnMetaEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) MetaEvent(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleMetaEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_meta_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnMetaEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []MetaEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single MetaEventHandleFunc", 28 | args: args{ 29 | []MetaEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple MetaEventHandleFuncs", 38 | args: args{ 39 | []MetaEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnMetaEventAny(tt.args.callbacks...) 54 | if len(g.onMetaEvent[MetaEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onMetaEvent[MetaEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnMetaEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []MetaEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single MetaEventHandleFunc", 72 | args: args{ 73 | []MetaEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple MetaEventHandleFuncs", 83 | args: args{ 84 | []MetaEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnMetaEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 101 | return nil 102 | }) 103 | g.SetOnMetaEventAny(tt.args.callbacks...) 104 | if len(g.onMetaEvent[MetaEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onMetaEvent[MetaEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleMetaEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.MetaEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "meta", 130 | 131 | event: &github.MetaEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "meta", 142 | 143 | event: &github.MetaEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "meta", 154 | 155 | event: &github.MetaEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "meta", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnMetaEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleMetaEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleMetaEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestMetaEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.MetaEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger MetaEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onMetaEvent: map[string][]MetaEventHandleFunc{ 229 | MetaEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.MetaEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: MetaEvent, 241 | 242 | event: &github.MetaEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.MetaEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("MetaEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_page_build.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // PageBuildEvent is the event name of github.PageBuildEvent's 20 | PageBuildEvent = "page_build" 21 | 22 | // PageBuildEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.PageBuildEvent 24 | PageBuildEventAnyAction = "*" 25 | ) 26 | 27 | // PageBuildEventHandleFunc represents a callback function triggered on github.PageBuildEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.PageBuildEvent) is the webhook payload. 31 | type PageBuildEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error 32 | 33 | // OnPageBuildEventAny registers callbacks listening to any events of type github.PageBuildEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnPageBuildEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#page_build 42 | func (g *EventHandler) OnPageBuildEventAny(callbacks ...PageBuildEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onPageBuildEvent == nil { 49 | g.onPageBuildEvent = make(map[string][]PageBuildEventHandleFunc) 50 | } 51 | g.onPageBuildEvent[PageBuildEventAnyAction] = append( 52 | g.onPageBuildEvent[PageBuildEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnPageBuildEventAny registers callbacks listening to any events of type github.PageBuildEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnPageBuildEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#page_build 67 | func (g *EventHandler) SetOnPageBuildEventAny(callbacks ...PageBuildEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onPageBuildEvent == nil { 74 | g.onPageBuildEvent = make(map[string][]PageBuildEventHandleFunc) 75 | } 76 | g.onPageBuildEvent[PageBuildEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handlePageBuildEventAny(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onPageBuildEvent[PageBuildEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onPageBuildEvent[PageBuildEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // PageBuildEvent handles github.PageBuildEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnPageBuildEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) PageBuildEvent(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handlePageBuildEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_page_build_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnPageBuildEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []PageBuildEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single PageBuildEventHandleFunc", 28 | args: args{ 29 | []PageBuildEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple PageBuildEventHandleFuncs", 38 | args: args{ 39 | []PageBuildEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnPageBuildEventAny(tt.args.callbacks...) 54 | if len(g.onPageBuildEvent[PageBuildEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onPageBuildEvent[PageBuildEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnPageBuildEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []PageBuildEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single PageBuildEventHandleFunc", 72 | args: args{ 73 | []PageBuildEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple PageBuildEventHandleFuncs", 83 | args: args{ 84 | []PageBuildEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnPageBuildEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 101 | return nil 102 | }) 103 | g.SetOnPageBuildEventAny(tt.args.callbacks...) 104 | if len(g.onPageBuildEvent[PageBuildEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onPageBuildEvent[PageBuildEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandlePageBuildEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.PageBuildEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "page_build", 130 | 131 | event: &github.PageBuildEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "page_build", 142 | 143 | event: &github.PageBuildEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "page_build", 154 | 155 | event: &github.PageBuildEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "page_build", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnPageBuildEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handlePageBuildEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandlePageBuildEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestPageBuildEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.PageBuildEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger PageBuildEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onPageBuildEvent: map[string][]PageBuildEventHandleFunc{ 229 | PageBuildEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.PageBuildEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: PageBuildEvent, 241 | 242 | event: &github.PageBuildEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.PageBuildEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("PageBuildEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_ping.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // PingEvent is the event name of github.PingEvent's 20 | PingEvent = "ping" 21 | 22 | // PingEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.PingEvent 24 | PingEventAnyAction = "*" 25 | ) 26 | 27 | // PingEventHandleFunc represents a callback function triggered on github.PingEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.PingEvent) is the webhook payload. 31 | type PingEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error 32 | 33 | // OnPingEventAny registers callbacks listening to any events of type github.PingEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnPingEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#ping 42 | func (g *EventHandler) OnPingEventAny(callbacks ...PingEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onPingEvent == nil { 49 | g.onPingEvent = make(map[string][]PingEventHandleFunc) 50 | } 51 | g.onPingEvent[PingEventAnyAction] = append( 52 | g.onPingEvent[PingEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnPingEventAny registers callbacks listening to any events of type github.PingEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnPingEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#ping 67 | func (g *EventHandler) SetOnPingEventAny(callbacks ...PingEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onPingEvent == nil { 74 | g.onPingEvent = make(map[string][]PingEventHandleFunc) 75 | } 76 | g.onPingEvent[PingEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handlePingEventAny(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onPingEvent[PingEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onPingEvent[PingEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // PingEvent handles github.PingEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnPingEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) PingEvent(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handlePingEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_ping_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnPingEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []PingEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single PingEventHandleFunc", 28 | args: args{ 29 | []PingEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple PingEventHandleFuncs", 38 | args: args{ 39 | []PingEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnPingEventAny(tt.args.callbacks...) 54 | if len(g.onPingEvent[PingEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onPingEvent[PingEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnPingEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []PingEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single PingEventHandleFunc", 72 | args: args{ 73 | []PingEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple PingEventHandleFuncs", 83 | args: args{ 84 | []PingEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnPingEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 101 | return nil 102 | }) 103 | g.SetOnPingEventAny(tt.args.callbacks...) 104 | if len(g.onPingEvent[PingEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onPingEvent[PingEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandlePingEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.PingEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "ping", 130 | 131 | event: &github.PingEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "ping", 142 | 143 | event: &github.PingEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "ping", 154 | 155 | event: &github.PingEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "ping", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnPingEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handlePingEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandlePingEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestPingEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.PingEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger PingEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onPingEvent: map[string][]PingEventHandleFunc{ 229 | PingEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.PingEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: PingEvent, 241 | 242 | event: &github.PingEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.PingEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("PingEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_public.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // PublicEvent is the event name of github.PublicEvent's 20 | PublicEvent = "public" 21 | 22 | // PublicEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.PublicEvent 24 | PublicEventAnyAction = "*" 25 | ) 26 | 27 | // PublicEventHandleFunc represents a callback function triggered on github.PublicEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.PublicEvent) is the webhook payload. 31 | type PublicEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error 32 | 33 | // OnPublicEventAny registers callbacks listening to any events of type github.PublicEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnPublicEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#public 42 | func (g *EventHandler) OnPublicEventAny(callbacks ...PublicEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onPublicEvent == nil { 49 | g.onPublicEvent = make(map[string][]PublicEventHandleFunc) 50 | } 51 | g.onPublicEvent[PublicEventAnyAction] = append( 52 | g.onPublicEvent[PublicEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnPublicEventAny registers callbacks listening to any events of type github.PublicEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnPublicEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#public 67 | func (g *EventHandler) SetOnPublicEventAny(callbacks ...PublicEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onPublicEvent == nil { 74 | g.onPublicEvent = make(map[string][]PublicEventHandleFunc) 75 | } 76 | g.onPublicEvent[PublicEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handlePublicEventAny(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onPublicEvent[PublicEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onPublicEvent[PublicEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // PublicEvent handles github.PublicEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnPublicEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) PublicEvent(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handlePublicEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_public_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnPublicEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []PublicEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single PublicEventHandleFunc", 28 | args: args{ 29 | []PublicEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple PublicEventHandleFuncs", 38 | args: args{ 39 | []PublicEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnPublicEventAny(tt.args.callbacks...) 54 | if len(g.onPublicEvent[PublicEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onPublicEvent[PublicEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnPublicEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []PublicEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single PublicEventHandleFunc", 72 | args: args{ 73 | []PublicEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple PublicEventHandleFuncs", 83 | args: args{ 84 | []PublicEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnPublicEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 101 | return nil 102 | }) 103 | g.SetOnPublicEventAny(tt.args.callbacks...) 104 | if len(g.onPublicEvent[PublicEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onPublicEvent[PublicEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandlePublicEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.PublicEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "public", 130 | 131 | event: &github.PublicEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "public", 142 | 143 | event: &github.PublicEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "public", 154 | 155 | event: &github.PublicEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "public", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnPublicEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handlePublicEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandlePublicEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestPublicEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.PublicEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger PublicEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onPublicEvent: map[string][]PublicEventHandleFunc{ 229 | PublicEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.PublicEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: PublicEvent, 241 | 242 | event: &github.PublicEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.PublicEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("PublicEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_push.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // PushEvent is the event name of github.PushEvent's 20 | PushEvent = "push" 21 | 22 | // PushEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.PushEvent 24 | PushEventAnyAction = "*" 25 | ) 26 | 27 | // PushEventHandleFunc represents a callback function triggered on github.PushEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.PushEvent) is the webhook payload. 31 | type PushEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error 32 | 33 | // OnPushEventAny registers callbacks listening to any events of type github.PushEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnPushEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push 42 | func (g *EventHandler) OnPushEventAny(callbacks ...PushEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onPushEvent == nil { 49 | g.onPushEvent = make(map[string][]PushEventHandleFunc) 50 | } 51 | g.onPushEvent[PushEventAnyAction] = append( 52 | g.onPushEvent[PushEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnPushEventAny registers callbacks listening to any events of type github.PushEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnPushEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push 67 | func (g *EventHandler) SetOnPushEventAny(callbacks ...PushEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onPushEvent == nil { 74 | g.onPushEvent = make(map[string][]PushEventHandleFunc) 75 | } 76 | g.onPushEvent[PushEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handlePushEventAny(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onPushEvent[PushEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onPushEvent[PushEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // PushEvent handles github.PushEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnPushEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) PushEvent(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handlePushEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_push_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnPushEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []PushEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single PushEventHandleFunc", 28 | args: args{ 29 | []PushEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple PushEventHandleFuncs", 38 | args: args{ 39 | []PushEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnPushEventAny(tt.args.callbacks...) 54 | if len(g.onPushEvent[PushEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onPushEvent[PushEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnPushEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []PushEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single PushEventHandleFunc", 72 | args: args{ 73 | []PushEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple PushEventHandleFuncs", 83 | args: args{ 84 | []PushEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnPushEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 101 | return nil 102 | }) 103 | g.SetOnPushEventAny(tt.args.callbacks...) 104 | if len(g.onPushEvent[PushEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onPushEvent[PushEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandlePushEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.PushEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "push", 130 | 131 | event: &github.PushEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "push", 142 | 143 | event: &github.PushEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "push", 154 | 155 | event: &github.PushEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "push", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnPushEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handlePushEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandlePushEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestPushEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.PushEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger PushEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onPushEvent: map[string][]PushEventHandleFunc{ 229 | PushEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.PushEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: PushEvent, 241 | 242 | event: &github.PushEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.PushEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("PushEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_repository_dispatch.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // RepositoryDispatchEvent is the event name of github.RepositoryDispatchEvent's 20 | RepositoryDispatchEvent = "repository_dispatch" 21 | 22 | // RepositoryDispatchEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.RepositoryDispatchEvent 24 | RepositoryDispatchEventAnyAction = "*" 25 | ) 26 | 27 | // RepositoryDispatchEventHandleFunc represents a callback function triggered on github.RepositoryDispatchEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.RepositoryDispatchEvent) is the webhook payload. 31 | type RepositoryDispatchEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.RepositoryDispatchEvent) error 32 | 33 | // OnRepositoryDispatchEventAny registers callbacks listening to any events of type github.RepositoryDispatchEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnRepositoryDispatchEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#repository_dispatch 42 | func (g *EventHandler) OnRepositoryDispatchEventAny(callbacks ...RepositoryDispatchEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onRepositoryDispatchEvent == nil { 49 | g.onRepositoryDispatchEvent = make(map[string][]RepositoryDispatchEventHandleFunc) 50 | } 51 | g.onRepositoryDispatchEvent[RepositoryDispatchEventAnyAction] = append( 52 | g.onRepositoryDispatchEvent[RepositoryDispatchEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnRepositoryDispatchEventAny registers callbacks listening to any events of type github.RepositoryDispatchEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnRepositoryDispatchEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#repository_dispatch 67 | func (g *EventHandler) SetOnRepositoryDispatchEventAny(callbacks ...RepositoryDispatchEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onRepositoryDispatchEvent == nil { 74 | g.onRepositoryDispatchEvent = make(map[string][]RepositoryDispatchEventHandleFunc) 75 | } 76 | g.onRepositoryDispatchEvent[RepositoryDispatchEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleRepositoryDispatchEventAny(ctx context.Context, deliveryID string, eventName string, event *github.RepositoryDispatchEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onRepositoryDispatchEvent[RepositoryDispatchEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onRepositoryDispatchEvent[RepositoryDispatchEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // RepositoryDispatchEvent handles github.RepositoryDispatchEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnRepositoryDispatchEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) RepositoryDispatchEvent(ctx context.Context, deliveryID string, eventName string, event *github.RepositoryDispatchEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleRepositoryDispatchEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_status.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // StatusEvent is the event name of github.StatusEvent's 20 | StatusEvent = "status" 21 | 22 | // StatusEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.StatusEvent 24 | StatusEventAnyAction = "*" 25 | ) 26 | 27 | // StatusEventHandleFunc represents a callback function triggered on github.StatusEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.StatusEvent) is the webhook payload. 31 | type StatusEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error 32 | 33 | // OnStatusEventAny registers callbacks listening to any events of type github.StatusEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnStatusEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#status 42 | func (g *EventHandler) OnStatusEventAny(callbacks ...StatusEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onStatusEvent == nil { 49 | g.onStatusEvent = make(map[string][]StatusEventHandleFunc) 50 | } 51 | g.onStatusEvent[StatusEventAnyAction] = append( 52 | g.onStatusEvent[StatusEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnStatusEventAny registers callbacks listening to any events of type github.StatusEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnStatusEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#status 67 | func (g *EventHandler) SetOnStatusEventAny(callbacks ...StatusEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onStatusEvent == nil { 74 | g.onStatusEvent = make(map[string][]StatusEventHandleFunc) 75 | } 76 | g.onStatusEvent[StatusEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleStatusEventAny(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onStatusEvent[StatusEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onStatusEvent[StatusEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // StatusEvent handles github.StatusEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnStatusEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) StatusEvent(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleStatusEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_status_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnStatusEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []StatusEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single StatusEventHandleFunc", 28 | args: args{ 29 | []StatusEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple StatusEventHandleFuncs", 38 | args: args{ 39 | []StatusEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnStatusEventAny(tt.args.callbacks...) 54 | if len(g.onStatusEvent[StatusEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onStatusEvent[StatusEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnStatusEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []StatusEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single StatusEventHandleFunc", 72 | args: args{ 73 | []StatusEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple StatusEventHandleFuncs", 83 | args: args{ 84 | []StatusEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnStatusEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 101 | return nil 102 | }) 103 | g.SetOnStatusEventAny(tt.args.callbacks...) 104 | if len(g.onStatusEvent[StatusEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onStatusEvent[StatusEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleStatusEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.StatusEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "status", 130 | 131 | event: &github.StatusEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "status", 142 | 143 | event: &github.StatusEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "status", 154 | 155 | event: &github.StatusEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "status", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnStatusEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleStatusEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleStatusEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestStatusEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.StatusEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger StatusEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onStatusEvent: map[string][]StatusEventHandleFunc{ 229 | StatusEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.StatusEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: StatusEvent, 241 | 242 | event: &github.StatusEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.StatusEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("StatusEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_team_add.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // TeamAddEvent is the event name of github.TeamAddEvent's 20 | TeamAddEvent = "team_add" 21 | 22 | // TeamAddEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.TeamAddEvent 24 | TeamAddEventAnyAction = "*" 25 | ) 26 | 27 | // TeamAddEventHandleFunc represents a callback function triggered on github.TeamAddEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.TeamAddEvent) is the webhook payload. 31 | type TeamAddEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error 32 | 33 | // OnTeamAddEventAny registers callbacks listening to any events of type github.TeamAddEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnTeamAddEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#team_add 42 | func (g *EventHandler) OnTeamAddEventAny(callbacks ...TeamAddEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onTeamAddEvent == nil { 49 | g.onTeamAddEvent = make(map[string][]TeamAddEventHandleFunc) 50 | } 51 | g.onTeamAddEvent[TeamAddEventAnyAction] = append( 52 | g.onTeamAddEvent[TeamAddEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnTeamAddEventAny registers callbacks listening to any events of type github.TeamAddEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnTeamAddEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#team_add 67 | func (g *EventHandler) SetOnTeamAddEventAny(callbacks ...TeamAddEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onTeamAddEvent == nil { 74 | g.onTeamAddEvent = make(map[string][]TeamAddEventHandleFunc) 75 | } 76 | g.onTeamAddEvent[TeamAddEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleTeamAddEventAny(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onTeamAddEvent[TeamAddEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onTeamAddEvent[TeamAddEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // TeamAddEvent handles github.TeamAddEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnTeamAddEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) TeamAddEvent(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleTeamAddEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_team_add_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnTeamAddEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []TeamAddEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single TeamAddEventHandleFunc", 28 | args: args{ 29 | []TeamAddEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple TeamAddEventHandleFuncs", 38 | args: args{ 39 | []TeamAddEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnTeamAddEventAny(tt.args.callbacks...) 54 | if len(g.onTeamAddEvent[TeamAddEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onTeamAddEvent[TeamAddEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnTeamAddEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []TeamAddEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single TeamAddEventHandleFunc", 72 | args: args{ 73 | []TeamAddEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple TeamAddEventHandleFuncs", 83 | args: args{ 84 | []TeamAddEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnTeamAddEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 101 | return nil 102 | }) 103 | g.SetOnTeamAddEventAny(tt.args.callbacks...) 104 | if len(g.onTeamAddEvent[TeamAddEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onTeamAddEvent[TeamAddEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleTeamAddEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.TeamAddEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "team_add", 130 | 131 | event: &github.TeamAddEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "team_add", 142 | 143 | event: &github.TeamAddEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "team_add", 154 | 155 | event: &github.TeamAddEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "team_add", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnTeamAddEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleTeamAddEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleTeamAddEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestTeamAddEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.TeamAddEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger TeamAddEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onTeamAddEvent: map[string][]TeamAddEventHandleFunc{ 229 | TeamAddEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.TeamAddEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: TeamAddEvent, 241 | 242 | event: &github.TeamAddEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.TeamAddEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("TeamAddEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_watch.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // WatchEvent is the event name of github.WatchEvent's 20 | WatchEvent = "watch" 21 | 22 | // WatchEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.WatchEvent 24 | WatchEventAnyAction = "*" 25 | ) 26 | 27 | // WatchEventHandleFunc represents a callback function triggered on github.WatchEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.WatchEvent) is the webhook payload. 31 | type WatchEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error 32 | 33 | // OnWatchEventAny registers callbacks listening to any events of type github.WatchEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnWatchEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#watch 42 | func (g *EventHandler) OnWatchEventAny(callbacks ...WatchEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onWatchEvent == nil { 49 | g.onWatchEvent = make(map[string][]WatchEventHandleFunc) 50 | } 51 | g.onWatchEvent[WatchEventAnyAction] = append( 52 | g.onWatchEvent[WatchEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnWatchEventAny registers callbacks listening to any events of type github.WatchEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnWatchEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#watch 67 | func (g *EventHandler) SetOnWatchEventAny(callbacks ...WatchEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onWatchEvent == nil { 74 | g.onWatchEvent = make(map[string][]WatchEventHandleFunc) 75 | } 76 | g.onWatchEvent[WatchEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleWatchEventAny(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onWatchEvent[WatchEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onWatchEvent[WatchEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // WatchEvent handles github.WatchEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnWatchEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) WatchEvent(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleWatchEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /githubevents/events_watch_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/google/go-github/v72/github" 14 | "sync" 15 | "testing" 16 | ) 17 | 18 | func TestOnWatchEventAny(t *testing.T) { 19 | type args struct { 20 | callbacks []WatchEventHandleFunc 21 | } 22 | tests := []struct { 23 | name string 24 | args args 25 | }{ 26 | { 27 | name: "must add single WatchEventHandleFunc", 28 | args: args{ 29 | []WatchEventHandleFunc{ 30 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 31 | return nil 32 | }, 33 | }, 34 | }, 35 | }, 36 | { 37 | name: "must add multiple WatchEventHandleFuncs", 38 | args: args{ 39 | []WatchEventHandleFunc{ 40 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 41 | return nil 42 | }, 43 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 44 | return nil 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | for _, tt := range tests { 51 | t.Run(tt.name, func(t *testing.T) { 52 | g := New("fake") 53 | g.OnWatchEventAny(tt.args.callbacks...) 54 | if len(g.onWatchEvent[WatchEventAnyAction]) == 0 { 55 | t.Errorf("failed to add callbacks, got %d", len(g.onWatchEvent[WatchEventAnyAction])) 56 | } 57 | }) 58 | } 59 | } 60 | 61 | func TestSetOnWatchEventAny(t *testing.T) { 62 | type args struct { 63 | callbacks []WatchEventHandleFunc 64 | } 65 | tests := []struct { 66 | name string 67 | args args 68 | want int 69 | }{ 70 | { 71 | name: "must add single WatchEventHandleFunc", 72 | args: args{ 73 | []WatchEventHandleFunc{ 74 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 75 | return nil 76 | }, 77 | }, 78 | }, 79 | want: 1, 80 | }, 81 | { 82 | name: "must add multiple WatchEventHandleFuncs", 83 | args: args{ 84 | []WatchEventHandleFunc{ 85 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 86 | return nil 87 | }, 88 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 89 | return nil 90 | }, 91 | }, 92 | }, 93 | want: 2, 94 | }, 95 | } 96 | for _, tt := range tests { 97 | t.Run(tt.name, func(t *testing.T) { 98 | g := New("fake") 99 | // add callbacks to be overwritten 100 | g.SetOnWatchEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 101 | return nil 102 | }) 103 | g.SetOnWatchEventAny(tt.args.callbacks...) 104 | if len(g.onWatchEvent[WatchEventAnyAction]) != tt.want { 105 | t.Errorf("failed to add callbacks, got %d, want %d", len(g.onWatchEvent[WatchEventAnyAction]), tt.want) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func TestHandleWatchEventAny(t *testing.T) { 112 | 113 | type args struct { 114 | deliveryID string 115 | eventName string 116 | event *github.WatchEvent 117 | fail bool 118 | panic bool 119 | } 120 | tests := []struct { 121 | name string 122 | args args 123 | wantErr bool 124 | }{ 125 | { 126 | name: "must pass", 127 | args: args{ 128 | deliveryID: "42", 129 | eventName: "watch", 130 | 131 | event: &github.WatchEvent{}, 132 | 133 | fail: false, 134 | }, 135 | wantErr: false, 136 | }, 137 | { 138 | name: "must fail with error", 139 | args: args{ 140 | deliveryID: "42", 141 | eventName: "watch", 142 | 143 | event: &github.WatchEvent{}, 144 | 145 | fail: true, 146 | }, 147 | wantErr: true, 148 | }, 149 | { 150 | name: "must fail with error on panic recover", 151 | args: args{ 152 | deliveryID: "42", 153 | eventName: "watch", 154 | 155 | event: &github.WatchEvent{}, 156 | 157 | fail: false, 158 | panic: true, 159 | }, 160 | wantErr: true, 161 | }, 162 | { 163 | name: "must fail event nil", 164 | args: args{ 165 | deliveryID: "42", 166 | eventName: "watch", 167 | event: nil, 168 | fail: false, 169 | }, 170 | wantErr: true, 171 | }, 172 | } 173 | for _, tt := range tests { 174 | t.Run(tt.name, func(t *testing.T) { 175 | g := New("fake") 176 | g.OnWatchEventAny(func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 177 | if tt.args.fail { 178 | return errors.New("fake error") 179 | } 180 | if tt.args.panic { 181 | panic("fake panic") 182 | } 183 | return nil 184 | }) 185 | if err := g.handleWatchEventAny(context.Background(), tt.args.deliveryID, tt.args.deliveryID, tt.args.event); (err != nil) != tt.wantErr { 186 | t.Errorf("TestHandleWatchEventAny() error = %v, wantErr %v", err, tt.wantErr) 187 | } 188 | }) 189 | } 190 | } 191 | 192 | func TestWatchEvent(t *testing.T) { 193 | type fields struct { 194 | handler *EventHandler 195 | } 196 | type args struct { 197 | deliveryID string 198 | eventName string 199 | event *github.WatchEvent 200 | } 201 | tests := []struct { 202 | name string 203 | fields fields 204 | args args 205 | wantErr bool 206 | }{ 207 | { 208 | name: "must trigger WatchEventAny with unknown event action", 209 | fields: fields{ 210 | handler: &EventHandler{ 211 | WebhookSecret: "fake", 212 | onBeforeAny: map[string][]EventHandleFunc{ 213 | EventAnyAction: { 214 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 215 | t.Log("onBeforeAny called") 216 | return nil 217 | }, 218 | }, 219 | }, 220 | onAfterAny: map[string][]EventHandleFunc{ 221 | EventAnyAction: { 222 | func(ctx context.Context, deliveryID string, eventName string, event any) error { 223 | t.Log("onAfterAny called") 224 | return nil 225 | }, 226 | }, 227 | }, 228 | onWatchEvent: map[string][]WatchEventHandleFunc{ 229 | WatchEventAnyAction: { 230 | func(ctx context.Context, deliveryID string, eventName string, event *github.WatchEvent) error { 231 | t.Log("onAny action called") 232 | return nil 233 | }, 234 | }, 235 | }, 236 | }, 237 | }, 238 | args: args{ 239 | deliveryID: "42", 240 | eventName: WatchEvent, 241 | 242 | event: &github.WatchEvent{}, 243 | }, 244 | wantErr: false, 245 | }, 246 | } 247 | for _, tt := range tests { 248 | t.Run(tt.name, func(t *testing.T) { 249 | g := &EventHandler{ 250 | WebhookSecret: "fake", 251 | mu: sync.RWMutex{}, 252 | } 253 | if err := g.WatchEvent(context.Background(), tt.args.deliveryID, tt.args.eventName, tt.args.event); (err != nil) != tt.wantErr { 254 | t.Errorf("WatchEvent() error = %v, wantErr %v", err, tt.wantErr) 255 | } 256 | }) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /githubevents/events_workflow_dispatch.go: -------------------------------------------------------------------------------- 1 | // Code generated by gen/generate.go. DO NOT EDIT. 2 | // make edits in gen/generate.go 3 | 4 | // Copyright 2022 The GithubEvents Authors. All rights reserved. 5 | // Use of this source code is governed by the MIT License 6 | // that can be found in the LICENSE file. 7 | 8 | package githubevents 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/google/go-github/v72/github" 14 | "golang.org/x/sync/errgroup" 15 | ) 16 | 17 | // Actions are used to identify registered callbacks. 18 | const ( 19 | // WorkflowDispatchEvent is the event name of github.WorkflowDispatchEvent's 20 | WorkflowDispatchEvent = "workflow_dispatch" 21 | 22 | // WorkflowDispatchEventAnyAction is used to identify callbacks 23 | // listening to all events of type github.WorkflowDispatchEvent 24 | WorkflowDispatchEventAnyAction = "*" 25 | ) 26 | 27 | // WorkflowDispatchEventHandleFunc represents a callback function triggered on github.WorkflowDispatchEvent's. 28 | // 'deliveryID' (type: string) is the unique webhook delivery ID. 29 | // 'eventName' (type: string) is the name of the event. 30 | // 'event' (type: *github.WorkflowDispatchEvent) is the webhook payload. 31 | type WorkflowDispatchEventHandleFunc func(ctx context.Context, deliveryID string, eventName string, event *github.WorkflowDispatchEvent) error 32 | 33 | // OnWorkflowDispatchEventAny registers callbacks listening to any events of type github.WorkflowDispatchEvent 34 | // 35 | // This function appends the callbacks passed as arguments to already existing ones. 36 | // If already existing callbacks are to be overwritten, SetOnWorkflowDispatchEventAny must be used. 37 | // 38 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 39 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 40 | // 41 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_dispatch 42 | func (g *EventHandler) OnWorkflowDispatchEventAny(callbacks ...WorkflowDispatchEventHandleFunc) { 43 | g.mu.Lock() 44 | defer g.mu.Unlock() 45 | if callbacks == nil || len(callbacks) == 0 { 46 | panic("callbacks is nil or empty") 47 | } 48 | if g.onWorkflowDispatchEvent == nil { 49 | g.onWorkflowDispatchEvent = make(map[string][]WorkflowDispatchEventHandleFunc) 50 | } 51 | g.onWorkflowDispatchEvent[WorkflowDispatchEventAnyAction] = append( 52 | g.onWorkflowDispatchEvent[WorkflowDispatchEventAnyAction], 53 | callbacks..., 54 | ) 55 | } 56 | 57 | // SetOnWorkflowDispatchEventAny registers callbacks listening to any events of type github.WorkflowDispatchEvent 58 | // and overwrites already registered callbacks. 59 | // 60 | // This function overwrites all previously registered callbacks. 61 | // If already registered callbacks are not to be overwritten, OnWorkflowDispatchEventAny must be used. 62 | // 63 | // Callbacks are executed in parallel. This function blocks until all callbacks executed in parallel have returned, 64 | // then returns the first non-nil error (if any) from them. If OnError callbacks have been set, they will be called when an error occurs. 65 | // 66 | // Reference: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_dispatch 67 | func (g *EventHandler) SetOnWorkflowDispatchEventAny(callbacks ...WorkflowDispatchEventHandleFunc) { 68 | g.mu.Lock() 69 | defer g.mu.Unlock() 70 | if callbacks == nil || len(callbacks) == 0 { 71 | panic("callbacks is nil or empty") 72 | } 73 | if g.onWorkflowDispatchEvent == nil { 74 | g.onWorkflowDispatchEvent = make(map[string][]WorkflowDispatchEventHandleFunc) 75 | } 76 | g.onWorkflowDispatchEvent[WorkflowDispatchEventAnyAction] = callbacks 77 | } 78 | 79 | func (g *EventHandler) handleWorkflowDispatchEventAny(ctx context.Context, deliveryID string, eventName string, event *github.WorkflowDispatchEvent) error { 80 | if event == nil { 81 | return fmt.Errorf("event was empty or nil") 82 | } 83 | if _, ok := g.onWorkflowDispatchEvent[WorkflowDispatchEventAnyAction]; !ok { 84 | return nil 85 | } 86 | eg := new(errgroup.Group) 87 | for _, h := range g.onWorkflowDispatchEvent[WorkflowDispatchEventAnyAction] { 88 | handle := h 89 | eg.Go(func() (err error) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | err = fmt.Errorf("recovered from panic: %v", r) 93 | } 94 | }() 95 | err = handle(ctx, deliveryID, eventName, event) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | if err := eg.Wait(); err != nil { 103 | return err 104 | } 105 | return nil 106 | } 107 | 108 | // WorkflowDispatchEvent handles github.WorkflowDispatchEvent. 109 | // 110 | // Callbacks are executed in the following order: 111 | // 112 | // 1) All callbacks registered with OnBeforeAny are executed in parallel. 113 | // 2) All callbacks registered with OnWorkflowDispatchEvent... are executed in parallel in case the Event has actions. 114 | // 3) All callbacks registered with OnAfterAny are executed in parallel. 115 | // 116 | // on any error all callbacks registered with OnError are executed in parallel. 117 | func (g *EventHandler) WorkflowDispatchEvent(ctx context.Context, deliveryID string, eventName string, event *github.WorkflowDispatchEvent) error { 118 | 119 | if event == nil { 120 | return fmt.Errorf("event action was empty or nil") 121 | } 122 | 123 | err := g.handleBeforeAny(ctx, deliveryID, eventName, event) 124 | if err != nil { 125 | return g.handleError(ctx, deliveryID, eventName, event, err) 126 | } 127 | 128 | err = g.handleWorkflowDispatchEventAny(ctx, deliveryID, eventName, event) 129 | if err != nil { 130 | return g.handleError(ctx, deliveryID, eventName, event, err) 131 | } 132 | 133 | err = g.handleAfterAny(ctx, deliveryID, eventName, event) 134 | if err != nil { 135 | return g.handleError(ctx, deliveryID, eventName, event, err) 136 | } 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cbrgm/githubevents/v2 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/google/go-github/v72 v72.0.0 7 | golang.org/x/sync v0.15.0 8 | ) 9 | 10 | require github.com/google/go-querystring v1.1.0 // indirect 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 2 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 3 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 4 | github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= 5 | github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= 6 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 7 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 8 | golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= 9 | golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 10 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 11 | --------------------------------------------------------------------------------