Skip to content

fix(dashboard): onboarding slack configuration token field fixes NV-7796 #20841

fix(dashboard): onboarding slack configuration token field fixes NV-7796

fix(dashboard): onboarding slack configuration token field fixes NV-7796 #20841

Workflow file for this run

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