fix(dashboard): onboarding slack configuration token field fixes NV-7796 #20841
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Check pull request | |
| concurrency: | |
| group: '${{ github.workflow }}-${{ github.ref }}' | |
| cancel-in-progress: true | |
| env: | |
| NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} | |
| on: | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| dependency-review: | |
| name: Dependency review | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| environment: Linting | |
| steps: | |
| - name: 'Checkout Repository' | |
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - name: 'Dependency Review' | |
| uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4 | |
| find-flags: | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| name: Find LaunchDarkly feature flags in diff | |
| # Skip on fork PRs: `LD_ACCESS_TOKEN` is unavailable, so LaunchDarkly's | |
| # find-code-references action fails with "`access-token` is required". | |
| # Same `head.repo.fork` gate as pr-labeler.yml. | |
| if: ${{ github.event.pull_request.head.repo.fork != true }} | |
| environment: Linting | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - name: Find flags | |
| uses: launchdarkly/find-code-references-in-pull-request@30f4c4ab2949bbf258b797ced2fbf6dea34df9ce # v2 | |
| id: find-flags | |
| with: | |
| project-key: default | |
| environment-key: production | |
| access-token: ${{ secrets.LD_ACCESS_TOKEN }} | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| get-affected: | |
| name: Get Affected Packages | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| outputs: | |
| test-unit: ${{ steps.get-projects-arrays.outputs.test-unit }} | |
| test-e2e: ${{ steps.get-projects-arrays.outputs.test-e2e }} | |
| test-e2e-ee: ${{ steps.get-projects-arrays.outputs.test-e2e-ee }} | |
| test-cypress: ${{ steps.get-projects-arrays.outputs.test-cypress }} | |
| test-providers: ${{ steps.get-projects-arrays.outputs.test-providers }} | |
| test-packages: ${{ steps.get-projects-arrays.outputs.test-packages }} | |
| test-libs: ${{ steps.get-projects-arrays.outputs.test-libs }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| deployments: write | |
| id-token: write | |
| steps: | |
| # Get current branch name | |
| - name: Get branch name | |
| id: branch-name | |
| uses: tj-actions/branch-names@e497ceb8ccd43fd9573cf2e375216625bc411d1f # v9.0.0 | |
| # Get base branch name to compare with. Base branch on a PR, "main" branch on pushing. | |
| - name: Get base branch name | |
| id: get-base-branch-name | |
| run: | | |
| if [[ "${{github.event.pull_request.base.ref}}" != "" ]]; then | |
| echo "branch=${{github.event.pull_request.base.ref}}" >> $GITHUB_OUTPUT | |
| else | |
| echo "branch=main" >> $GITHUB_OUTPUT | |
| fi | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| with: | |
| # Fetch enough history to find the merge base between base and head | |
| # This is typically much faster than fetch-depth: 0 | |
| fetch-depth: 50 | |
| # Also fetch the base branch to ensure we have the comparison point | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| # Ensure we have the base branch for comparison | |
| - name: Fetch base branch | |
| if: github.event.pull_request.base.ref != '' | |
| run: | | |
| git fetch origin ${{ github.event.pull_request.base.ref }} --depth=50 | |
| - uses: ./.github/actions/setup-project-minimal | |
| # Configure Nx to be able to detect changes between branches when we are in a PR | |
| - name: Derive appropriate SHAs for base and head for `nx affected` commands | |
| uses: nrwl/nx-set-shas@59075b03c42ae79986d96d761eeb15094df7a76e # v2 | |
| with: | |
| main-branch-name: ${{steps.get-base-branch-name.outputs.branch}} | |
| - name: Get affected | |
| id: get-projects-arrays | |
| # When not in a PR and the current branch is main, pass --all flag. Otherwise pass the base branch | |
| run: | | |
| if [[ "${{github.event.pull_request.base.ref}}" == "" && "${{steps.branch-name.outputs.current_branch}}" == "main" ]]; then | |
| echo "Running ALL" | |
| echo "test-unit=$(pnpm run get-affected test:unit --all | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-e2e=$(pnpm run get-affected test:e2e --all | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-e2e-ee=$(pnpm run get-affected test:e2e:ee --all | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-cypress=$(pnpm run get-affected cypress:run --all | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-providers=$(pnpm run get-affected test --all providers | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-packages=$(pnpm run get-affected test --all packages | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-libs=$(pnpm run get-affected test --all libs | tail -n +5)" >> $GITHUB_OUTPUT | |
| else | |
| echo "Running PR origin/${{steps.get-base-branch-name.outputs.branch}}" | |
| echo "test-unit=$(pnpm run get-affected test origin/${{steps.get-base-branch-name.outputs.branch}} | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-e2e=$(pnpm run get-affected test:e2e origin/${{steps.get-base-branch-name.outputs.branch}} | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-e2e-ee=$(pnpm run get-affected test:e2e:ee origin/${{steps.get-base-branch-name.outputs.branch}} | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-cypress=$(pnpm run get-affected cypress:run origin/${{steps.get-base-branch-name.outputs.branch}} | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-providers=$(pnpm run get-affected test origin/${{steps.get-base-branch-name.outputs.branch}} providers | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-packages=$(pnpm run get-affected test origin/${{steps.get-base-branch-name.outputs.branch}} packages | tail -n +5)" >> $GITHUB_OUTPUT | |
| echo "test-libs=$(pnpm run get-affected test origin/${{steps.get-base-branch-name.outputs.branch}} libs | tail -n +5)" >> $GITHUB_OUTPUT | |
| fi | |
| test_unit_providers: | |
| name: Unit test @novu/providers | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| needs: [get-affected] | |
| if: ${{ fromJson(needs.get-affected.outputs.test-providers)[0] }} | |
| timeout-minutes: 80 | |
| steps: | |
| - run: echo '${{ needs.get-affected.outputs.test-providers }}' | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - uses: ./.github/actions/setup-project | |
| with: | |
| slim: 'true' | |
| - uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| env: | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: lint,build,test | |
| parallel: 5 | |
| projects: ${{join(fromJson(needs.get-affected.outputs.test-providers), ',')}} | |
| test_unit_packages: | |
| name: Unit test @novu public NPM packages (except providers) | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| needs: [get-affected] | |
| if: ${{ fromJson(needs.get-affected.outputs.test-packages)[0] }} | |
| timeout-minutes: 80 | |
| permissions: | |
| contents: read | |
| packages: write | |
| deployments: write | |
| id-token: write | |
| steps: | |
| - name: Affected packages | |
| run: echo '${{ needs.get-affected.outputs.test-packages }}' | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - uses: ./.github/actions/setup-project | |
| with: | |
| slim: 'true' | |
| - name: Build | |
| uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| env: | |
| LOG_LEVEL: 'info' | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: build | |
| projects: '@novu/api' | |
| - name: Run Lint, Build, Test | |
| uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| env: | |
| LOG_LEVEL: 'info' | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: lint,build,test | |
| projects: ${{join(fromJson(needs.get-affected.outputs.test-packages), ',')}} | |
| test_unit_libs: | |
| name: Unit test @novu internal packages | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| needs: [get-affected] | |
| if: ${{ fromJson(needs.get-affected.outputs.test-libs)[0] }} | |
| timeout-minutes: 80 | |
| steps: | |
| - name: Affected libs | |
| run: echo '${{ needs.get-affected.outputs.test-libs }}' | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - uses: ./.github/actions/setup-project | |
| - name: Run Lint, Build, Test | |
| uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| env: | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: lint,build,test | |
| projects: ${{join(fromJson(needs.get-affected.outputs.test-libs), ',')}} | |
| test_unit_services: | |
| name: Unit test backend services | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| needs: [get-affected] | |
| if: ${{ fromJson(needs.get-affected.outputs.test-unit)[0] }} | |
| timeout-minutes: 80 | |
| strategy: | |
| # One job for each different project and node version | |
| matrix: | |
| projectName: ${{ fromJson(needs.get-affected.outputs.test-unit) }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| deployments: write | |
| id-token: write | |
| steps: | |
| - run: echo ${{ matrix.projectName }} | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| name: Checkout with submodules | |
| with: | |
| submodules: true | |
| token: ${{ secrets.SUBMODULES_TOKEN }} | |
| - uses: ./.github/actions/setup-project | |
| with: | |
| # Don't run redis and etc... for other unit tests | |
| slim: ${{ !contains(matrix.projectName, '@novu/api-service') && !contains(matrix.projectName, '@novu/worker') && !contains(matrix.projectName, '@novu/ws') && !contains(matrix.projectName, '@novu/inbound-mail')}} | |
| - uses: ./.github/actions/setup-redis-cluster | |
| - uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| name: Lint and build and test | |
| env: | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: build | |
| projects: '@novu/api' | |
| args: '' | |
| - uses: mansagroup/nrwl-nx-action@a531870269e0c1eeb7af6247c4a206c31cae82cc # v3 | |
| name: Lint and build and test | |
| env: | |
| NX_NO_CLOUD: ${{ secrets.NX_CLOUD_ACCESS_TOKEN == '' && 'true' || 'false' }} | |
| with: | |
| targets: lint,build,test | |
| projects: ${{matrix.projectName}} | |
| args: '' | |
| validate_openapi: | |
| name: Validate OpenAPI | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| needs: [get-affected] | |
| if: ${{ fromJson(needs.get-affected.outputs.test-unit)[0] }} | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| packages: write | |
| deployments: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - uses: ./.github/actions/setup-project | |
| - uses: ./.github/actions/setup-redis-cluster | |
| - uses: ./.github/actions/run-api | |
| with: | |
| launch_darkly_sdk_key: ${{ secrets.LAUNCH_DARKLY_SDK_KEY }} | |
| - uses: ./.github/actions/validate-openapi | |
| test_e2e_api: | |
| name: E2E test API | |
| needs: [get-affected] | |
| uses: ./.github/workflows/reusable-api-e2e.yml | |
| with: | |
| # PRs opened from forks (community contributions) do not receive repo | |
| # secrets — even after a maintainer approves the run — so the EE branch, | |
| # which checks out the private enterprise submodule using | |
| # ${{ secrets.SUBMODULES_TOKEN }}, fails immediately with | |
| # "Input required and not supplied: token". Fall back to the non-EE e2e | |
| # suite (Novu V1) for fork PRs so the change still gets validated. | |
| ee: ${{ github.event.pull_request.head.repo.fork != true }} | |
| secrets: inherit | |
| # Aggregator / "all-green" gate. This job depends on every other job in | |
| # this workflow and reports a single success/failure status that can be | |
| # used as the one required status check in branch protection (and for | |
| # GitHub auto-merge). It must always run so that even when a dependency | |
| # is skipped — e.g. dynamic jobs that have nothing to do because no | |
| # affected projects were detected — the gate still produces a result. | |
| # | |
| # Skipped jobs are treated as success. Failure or cancellation of any | |
| # required dependency will fail the gate. | |
| # | |
| # IMPORTANT: the `needs:` list below must contain every other job in this | |
| # workflow. The first step in this job parses this very file and fails | |
| # the run if the list ever drifts (a job is added/removed but `needs:` | |
| # is not updated). That guard prevents the gate from going falsely green | |
| # because of a forgotten dependency. | |
| pr-checks-passed: | |
| name: PR Checks Passed | |
| runs-on: ubuntu-latest | |
| if: ${{ always() }} | |
| needs: | |
| - dependency-review | |
| - find-flags | |
| - get-affected | |
| - test_unit_providers | |
| - test_unit_packages | |
| - test_unit_libs | |
| - test_unit_services | |
| - validate_openapi | |
| - test_e2e_api | |
| steps: | |
| - name: Checkout workflow source | |
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| with: | |
| # We only need the workflow file itself to validate the needs list. | |
| fetch-depth: 1 | |
| sparse-checkout: | | |
| .github/workflows/on-pr.yml | |
| sparse-checkout-cone-mode: false | |
| - name: Validate aggregator `needs` list matches workflow jobs | |
| # Uses `yq` and `jq`, both pre-installed on GitHub-hosted ubuntu | |
| # runners — no `pip install` or other dependency setup, so the | |
| # check runs in well under a second. | |
| env: | |
| WORKFLOW: .github/workflows/on-pr.yml | |
| AGGREGATOR: pr-checks-passed | |
| run: | | |
| set -euo pipefail | |
| workflow_json=$(yq -o=json '.' "$WORKFLOW") | |
| if ! echo "$workflow_json" | jq -e --arg agg "$AGGREGATOR" '.jobs[$agg]' > /dev/null; then | |
| echo "::error file=$WORKFLOW::aggregator job '$AGGREGATOR' not found in workflow" | |
| exit 1 | |
| fi | |
| diff_json=$(echo "$workflow_json" | jq --arg agg "$AGGREGATOR" ' | |
| .jobs as $jobs | |
| | ($jobs[$agg].needs // []) as $declared | |
| | ($jobs | keys | map(select(. != $agg))) as $expected | |
| | { | |
| missing: ($expected - $declared), | |
| extra: ($declared - $expected), | |
| total: ($expected | length) | |
| } | |
| ') | |
| missing=$(echo "$diff_json" | jq -r '.missing | join(", ")') | |
| extra=$(echo "$diff_json" | jq -r '.extra | join(", ")') | |
| total=$(echo "$diff_json" | jq -r '.total') | |
| status=0 | |
| if [ -n "$missing" ]; then | |
| echo "::error file=$WORKFLOW::$AGGREGATOR.needs is missing jobs that exist in the workflow: $missing. Add them so the gate can't go falsely green." | |
| status=1 | |
| fi | |
| if [ -n "$extra" ]; then | |
| echo "::error file=$WORKFLOW::$AGGREGATOR.needs lists jobs that don't exist in the workflow: $extra. Remove them." | |
| status=1 | |
| fi | |
| if [ "$status" -eq 0 ]; then | |
| echo "$AGGREGATOR.needs correctly covers all $total other jobs in the workflow." | |
| fi | |
| exit "$status" | |
| - name: Verify required jobs succeeded or were skipped | |
| env: | |
| NEEDS_JSON: ${{ toJson(needs) }} | |
| run: | | |
| set -euo pipefail | |
| echo "Aggregated job results:" | |
| echo "$NEEDS_JSON" | jq -r 'to_entries[] | " - \(.key): \(.value.result)"' | |
| failed=$(echo "$NEEDS_JSON" | jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled") | .key] | join(", ")') | |
| if [ -n "$failed" ]; then | |
| echo "::error::The following required jobs failed or were cancelled: $failed" | |
| exit 1 | |
| fi | |
| echo "All required jobs passed (or were skipped because they were not affected)." | |
| #test_e2e_dashboard: | |
| # name: E2E test Dashboard app | |
| # needs: [get-affected] | |
| # if: ${{ contains(fromJson(needs.get-affected.outputs.test-e2e), '@novu/dashboard') }} | |
| # uses: ./.github/workflows/reusable-dashboard-e2e.yml | |
| # secrets: inherit | |
| # with: | |
| # ee: true | |
| # test_e2e_widget: | |
| # name: E2E test Widget | |
| # needs: [get-affected] | |
| # uses: ./.github/workflows/reusable-widget-e2e.yml | |
| # with: | |
| # ee: true | |
| # if: ${{ contains(fromJson(needs.get-affected.outputs.test-unit), '@novu/ws') }} | |
| # secrets: inherit |