diff --git a/.github/actions/frontend/runtime/e2e_pending_status/README.md b/.github/actions/frontend/runtime/e2e_pending_status/README.md new file mode 100644 index 00000000..f1867d94 --- /dev/null +++ b/.github/actions/frontend/runtime/e2e_pending_status/README.md @@ -0,0 +1,25 @@ +# Frontend Runtime - E2E Pending Status + +This [composite action](./action.yml) is responsible for reporting that the E2E tests have begun and are pending via a status check in the PR, providing a quick feedback loop for developers. + +## Inputs + +This action takes the following inputs: + +| Name | Type | Default | Required | Description | +| --------------------------- | ------- | ---------------------------- | --------- | --------------------------------------------------------- | +| `github_token` | String | | True | Github access token + +## Outputs + +No outputs provided. + +## Example Usage + +```yaml +steps: + - name: e2e_status + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status + with: + github_token: ${{ secrets.GITHUB_TOKEN }} +``` diff --git a/.github/actions/frontend/runtime/e2e_pending_status/action.yml b/.github/actions/frontend/runtime/e2e_pending_status/action.yml new file mode 100644 index 00000000..5cd2a8f7 --- /dev/null +++ b/.github/actions/frontend/runtime/e2e_pending_status/action.yml @@ -0,0 +1,24 @@ +name: Set the status of the PR when E2E tests have been triggered + +inputs: + github_token: + type: string + required: true + +runs: + using: "composite" + steps: + - name: e2e_pr_status_inputs + shell: bash + run: | + echo "github_token=${{ inputs.github_token }}" + - name: get_branch_of_pr + id: get_branch_of_pr + uses: xt0rted/pull-request-comment-branch@v2 + - name: set_status_as_pending + uses: myrotvorets/set-commit-status-action@v2.0.0 + with: + sha: ${{ steps.get_branch_of_pr.outputs.head_sha }} + token: ${{ inputs.github_token }} + status: pending + context: 'pr / E2E Status' \ No newline at end of file diff --git a/.github/actions/frontend/runtime/e2e_pending_status/mocks.ts b/.github/actions/frontend/runtime/e2e_pending_status/mocks.ts new file mode 100644 index 00000000..d6e136cf --- /dev/null +++ b/.github/actions/frontend/runtime/e2e_pending_status/mocks.ts @@ -0,0 +1,9 @@ +/* +This file is automatically leveraged when tests are run to determine which +steps should be skipped in the composite action. If these steps were not +mocked, they would break the test. +*/ +export const E2E_PENDING_STATUS_MOCK_STEPS = [ + { name: 'get_branch_of_pr' }, + { name: 'set_status_as_pending' }, +]; diff --git a/.github/actions/frontend/runtime/e2e_status/README.md b/.github/actions/frontend/runtime/e2e_status/README.md index 401f9c2f..711d4d0a 100644 --- a/.github/actions/frontend/runtime/e2e_status/README.md +++ b/.github/actions/frontend/runtime/e2e_status/README.md @@ -1,6 +1,6 @@ # Frontend Runtime - E2E Status -This [composite action](./action.yml) is responsible for reporting the status of the E2E run. Specifically it is configurable to allow a PR to still be merged even if the E2E tests fail (if `e2e_pass_on_error: true`). By default this job is never reached if E2E tests fail and `e2e_pass_on_error` is set to `false`. +This [composite action](./action.yml) is responsible for reporting the status of the E2E run as both a comment on the PR as well as updating the status check. Specifically it is configurable to allow a PR to still be merged even if the E2E tests fail (if `e2e_pass_on_error: true`). By default this job is never reached if E2E tests fail and `e2e_pass_on_error` is set to `false`. ## Inputs @@ -9,7 +9,6 @@ This action takes the following inputs: | Name | Type | Default | Required | Description | | --------------------------- | ------- | ---------------------------- | --------- | --------------------------------------------------------- | | `github_token` | String | | True | Github access token -| `e2e_passed` | Boolean | | True | The status of the e2e_run | `e2e_pass_on_error` | Boolean | False | False | Pass the workflow even if the E2E test fail. Should be defined as an input at the workflow level. ## Outputs @@ -24,6 +23,5 @@ steps: uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status with: github_token: ${{ secrets.GITHUB_TOKEN }} - e2e_passed: ${{ needs.e2e_run.outputs.test_passed }} e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} ``` diff --git a/.github/actions/frontend/runtime/e2e_status/action.yml b/.github/actions/frontend/runtime/e2e_status/action.yml index 8aab4660..b6c874e2 100644 --- a/.github/actions/frontend/runtime/e2e_status/action.yml +++ b/.github/actions/frontend/runtime/e2e_status/action.yml @@ -4,9 +4,6 @@ inputs: github_token: type: string required: true - e2e_passed: - type: boolean - required: true e2e_pass_on_error: type: boolean required: false @@ -19,19 +16,38 @@ runs: shell: bash run: | echo "github_token=${{ inputs.github_token }}" - echo "e2e_passed=${{ inputs.e2e_passed }}" echo "e2e_pass_on_error=${{ inputs.e2e_pass_on_error }}" - - name: pr_status - uses: Sibz/github-status-action@v1 - continue-on-error: ${{ fromJSON(inputs.e2e_pass_on_error) }} + - name: add_result_as_pr_comment + uses: actions/github-script@v6 with: - authToken: ${{ inputs.github_token }} - context: 'E2E Test Status' - description: ${{ (fromJSON(inputs.e2e_passed) && 'E2E Test Passed') || 'E2E Test Failed' }} - state: ${{ (fromJSON(inputs.e2e_passed) && 'success') || 'failures' }} - sha: ${{ github.sha }} - # We have to manually output an exit code of 0 to ensure the action passes if e2e_pass_on_error is true - - name: pass_with_failures - shell: bash + script: | + const name = 'pr / E2E Status'; + const url = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'; + const success = '${{ inputs.job_status }}' === 'success'; + const body = `${name}: ${success ? 'succeeded ✅' : 'failed ❌'}\n${url}`; + + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) + - name: get_branch_of_pr + id: get_branch_of_pr + uses: xt0rted/pull-request-comment-branch@v2 + - name: set_commit_status + uses: myrotvorets/set-commit-status-action@v2.0.0 + with: + sha: ${{ steps.get_branch_of_pr.outputs.head_sha }} + token: ${{ inputs.github_token }} + status: ${{ job.status }} + context: 'pr / E2E Status' + # Manually set the commit status to success to allow the PR to be merged + - name: force_status_as_success + uses: myrotvorets/set-commit-status-action@v2.0.0 if: ${{ fromJSON(inputs.e2e_pass_on_error) }} - run: exit 0 \ No newline at end of file + with: + sha: ${{ inputs.branch_sha }} + token: ${{ inputs.github_token }} + status: success + context: 'pr / E2E Status' \ No newline at end of file diff --git a/.github/actions/frontend/runtime/e2e_status/mocks.ts b/.github/actions/frontend/runtime/e2e_status/mocks.ts index 942bf689..f9d5512c 100644 --- a/.github/actions/frontend/runtime/e2e_status/mocks.ts +++ b/.github/actions/frontend/runtime/e2e_status/mocks.ts @@ -4,5 +4,8 @@ steps should be skipped in the composite action. If these steps were not mocked, they would break the test. */ export const E2E_STATUS_MOCK_STEPS = [ - { name: 'pr_status' }, + { name: 'add_result_as_pr_comment' }, + { name: 'get_branch_of_pr' }, + { name: 'set_commit_status' }, + { name: 'force_status_as_success' }, ]; diff --git a/.github/actions/frontend/runtime/e2e_status/test/action.test.ts b/.github/actions/frontend/runtime/e2e_status/test/action.test.ts index 89868eed..472adeff 100644 --- a/.github/actions/frontend/runtime/e2e_status/test/action.test.ts +++ b/.github/actions/frontend/runtime/e2e_status/test/action.test.ts @@ -11,7 +11,7 @@ afterEach(async () => { await mockGithub.teardown(); }); -test('pass_with_failures is not called when e2e_passed is false', async () => { +test('force_status_as_success is not called when e2e_passed is false', async () => { mockGithub = new MockGithub(getCompositeActionConfig({ directory: __dirname, repoName, actionTriggeringComposite: 'action_test_fail.yml' })); await mockGithub.setup(); @@ -22,12 +22,12 @@ test('pass_with_failures is not called when e2e_passed is false', async () => { originDirectory: __dirname }); - const result = getTestResult({ results, name: 'pass_with_failures' }); + const result = getTestResult({ results, name: 'force_status_as_success' }); expect(result).toBeUndefined(); }); -test('e2e_pass_on_error allows pass_with_failures to be called when e2e_passed is false', async () => { +test('e2e_pass_on_error allows force_status_as_success to be called when e2e_passed is false', async () => { mockGithub = new MockGithub(getCompositeActionConfig({ directory: __dirname, repoName, actionTriggeringComposite: 'action_test_pass.yml' })); await mockGithub.setup(); @@ -38,7 +38,7 @@ test('e2e_pass_on_error allows pass_with_failures to be called when e2e_passed i originDirectory: __dirname }); - const result = getTestResult({ results, name: 'pass_with_failures' }); + const result = getTestResult({ results, name: 'force_status_as_success' }); expect(result).not.toBeUndefined(); }); diff --git a/.github/actions/frontend/runtime/magic_url/README.md b/.github/actions/frontend/runtime/magic_url/README.md index 9ff95cec..971d7522 100644 --- a/.github/actions/frontend/runtime/magic_url/README.md +++ b/.github/actions/frontend/runtime/magic_url/README.md @@ -21,9 +21,10 @@ No outputs provided. ```yaml permissions: id-token: write - contents: read - pull-requests: write statuses: write + contents: read + issues: read + pull-requests: read steps: - name: magic_url uses: jupiterone/.github/.github/actions/frontend/runtime/magic_url diff --git a/.github/actions/frontend/runtime/magic_url/action.yml b/.github/actions/frontend/runtime/magic_url/action.yml index 35f91131..3dd1a144 100644 --- a/.github/actions/frontend/runtime/magic_url/action.yml +++ b/.github/actions/frontend/runtime/magic_url/action.yml @@ -36,12 +36,14 @@ runs: # This bucket file location is static and editing it will break the Magic URL. This pushes the entire directory which includes the bundle and remote types if applicable run: | aws s3 sync deploy/dist s3://apps.dev.jupiterone.io/static/manual-deploy/${{ github.event.repository.name }}@${{ inputs.migration_number }}/PR-${{ github.event.number }}/ + - name: get_branch_of_pr + id: get_branch_of_pr + uses: xt0rted/pull-request-comment-branch@v2 - name: show_magic_url_in_pr - uses: Sibz/github-status-action@v1 - with: - authToken: ${{ inputs.github_token }} - state: 'success' + uses: myrotvorets/set-commit-status-action@v2.0.0 + with: + sha: ${{ steps.get_branch_of_pr.outputs.head_sha }} + token: ${{ inputs.github_token }} + status: success context: 'Magic URL' - description: "Use the 'Details' link to view this PR in dev" - target_url: https://apps.dev.jupiterone.io${{ inputs.magic_url_route }}?magic2=%7B%22${{ github.event.repository.name }}%40${{ inputs.migration_number }}%22:%22PR-${{ github.event.pull_request.number }}%22%7D - sha: ${{github.event.pull_request.head.sha || github.sha}} \ No newline at end of file + targetUrl: https://apps.dev.jupiterone.io${{ inputs.magic_url_route }}?magic2=%7B%22${{ github.event.repository.name }}%40${{ inputs.migration_number }}%22:%22PR-${{ github.event.pull_request.number }}%22%7D \ No newline at end of file diff --git a/.github/actions/frontend/runtime/magic_url/mocks.ts b/.github/actions/frontend/runtime/magic_url/mocks.ts index 47f70374..ab810613 100644 --- a/.github/actions/frontend/runtime/magic_url/mocks.ts +++ b/.github/actions/frontend/runtime/magic_url/mocks.ts @@ -7,5 +7,6 @@ export const MAGIC_URL_MOCK_STEPS = [ { name: 'npm_build' }, { name: 'configure_aws_credentials' }, { name: 'deploy_artifacts_to_s3' }, + { name: 'get_branch_of_pr' }, { name: 'show_magic_url_in_pr' }, ]; diff --git a/.github/workflows/docs/frontend/frontend_npm_pr.md b/.github/workflows/docs/frontend/frontend_npm_pr.md index 47262fe2..2f96221d 100644 --- a/.github/workflows/docs/frontend/frontend_npm_pr.md +++ b/.github/workflows/docs/frontend/frontend_npm_pr.md @@ -1,6 +1,6 @@ # Default flow for an NPM package when a PR is opened -This is the [default workflow](../../frontend_npm_pr.yml@v#) that is run when a `PR is opened` for an `npm package`. It is meant to test the quality and safety of the code being committed. +This is the [default workflow](../../frontend_npm_pr.yml) that is run when a `PR is opened` for an `npm package`. It is meant to test the quality and safety of the code being committed. ## Inputs diff --git a/.github/workflows/docs/frontend/frontend_npm_release.md b/.github/workflows/docs/frontend/frontend_npm_release.md index cab320e8..3a34f7e9 100644 --- a/.github/workflows/docs/frontend/frontend_npm_release.md +++ b/.github/workflows/docs/frontend/frontend_npm_release.md @@ -1,6 +1,6 @@ # Default flow for an NPM package when its merged to mai -This is the [default workflow](../../frontend_npm_release.yml@v#) that is run when a `PR is merged to main` for an `npm package`. It is meant to release the package and capture information in Cortex related to the package. +This is the [default workflow](../../frontend_npm_release.yml) that is run when a `PR is merged to main` for an `npm package`. It is meant to release the package and capture information in Cortex related to the package. ## Inputs diff --git a/.github/workflows/docs/frontend/frontend_runtime_application_manual_e2e_run.md b/.github/workflows/docs/frontend/frontend_runtime_application_manual_e2e_run.md new file mode 100644 index 00000000..7e855c69 --- /dev/null +++ b/.github/workflows/docs/frontend/frontend_runtime_application_manual_e2e_run.md @@ -0,0 +1,84 @@ +# Default workflow for running E2E tests when a PR comment is left + + +This is the [default workflow](../../frontend_runtime_application_manual_e2e_run.yml) that is leveraged to trigger E2E tests for for an `application runtime`. Specifically, when a PR is opened and a comment of `/run-e2e-tests` is left, it will trigger an E2E test run. + +## Inputs + +This action takes the following inputs: + +| Name | Type | Default | Required | Description | +| --------------------------- | ------- | ---------------------------- | --------- | -------------------------------------------------------------------------------------- | +| `fallback_runner` | String | False | False | If true will leverage ubuntu-latest, otherwise will fall back to the J1 in-house runner +| `use_magic_url` | Boolean | True | False | Deploy to dev via a query param, required for normal SPAs +| `use_e2e` | Boolean | False | False | Run E2E test, in most case we want this +| `e2e_filter_tags` | String | | False | Tests will be filtered based on the tags defined here +| `e2e_containers` | String | '["1"]' | False | The number of tests that you want Cypress to run in parallel. For example to run your tests via 3 containers you would set the value to the following: '["1", "2", "3"]'. +| `e2e_pass_on_error` | Boolean | False | False | Pass the workflow even if the E2E test fail +| `e2e_artemis_config_path` | String | cypress/artemis-config.yaml | False | Used to determine the path to the artemis config file +| `spec_to_run` | String | cypress/e2e/**/*.feature | False | Used to determine which test to run +| `magic_url_route` | String | '/' | False | The relative route the magic url should go to +| `auto_cancel_after_failures` | Number | 2 | False | Cancel the tests after this many failures + +## Secrets + +This action takes the following secrets: + +| Name | Required | Description | +| --------------------------- | --------- | ----------------------------------------- | +| `NPM_TOKEN` | True | A J1 npm.com Publish token +| `CYPRESS_RECORD_KEY` | True | The record key associated with the project in Cypress. +| `CYPRESS_PROJECT_ID` | True | The project ID associated with the project in Cypress +| `CYPRESS_PASSWORD` | False | The password of the E2E username +| `DOCKER_HUB_SRE` | True | The password to login to docker hub sre + +## Example Usage + +### Default Flow + +#### Usage + +```yaml +# Triggered by adding a comment to a PR +on: + issue_comment: + types: [created] + +jobs: + e2e_run: + # Check if the comments come from pull request and contains '/run-e2e-test' + if: github.event.issue.pull_request && contains(github.event.comment.body, '/run-e2e-tests') + uses: jupiterone/.github/.github/workflows/frontend_runtime_application_manual_e2e_run.yml@v# + secrets: + NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + DOCKER_HUB_SRE: ${{ secrets.DOCKER_HUB_SRE }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} +``` + +#### Diagram + +```mermaid +graph LR; + A[start flow]; + + B[migration_number]; + C[e2e_pending_status]; + D[e2e_prepare]; + + E[magic_url]; + + F[e2e_run]; + G[e2e_status]; + + A --> B; + A --> C; + A --> D; + + B --> E; + D --> F; + E --> F; + + F --> G; + C --> G; +``` diff --git a/.github/workflows/docs/frontend/frontend_runtime_application_pr.md b/.github/workflows/docs/frontend/frontend_runtime_application_pr.md index 78c85cd9..36c2bc36 100644 --- a/.github/workflows/docs/frontend/frontend_runtime_application_pr.md +++ b/.github/workflows/docs/frontend/frontend_runtime_application_pr.md @@ -1,7 +1,7 @@ # Default workflow for a runtime application when a PR is opened -This is the [default workflow](../../frontend_runtime_application_pr.yml@v#) that is run when a `PR is opened` for an `application runtime`. It is meant to test the quality and safety of the code being committed. +This is the [default workflow](../../frontend_runtime_application_pr.yml) that is run when a `PR is opened` for an `application runtime`. It is meant to test the quality and safety of the code being committed. ## Inputs @@ -13,14 +13,7 @@ This action takes the following inputs: | `use_validate` | Boolean | True | False | Run validation, in most case we want this | `use_chromatic` | Boolean | False | False | Run VRT Storybook tests with chromatic | `use_magic_url` | Boolean | True | False | Deploy to dev via a query param, required for normal SPAs -| `use_e2e` | Boolean | False | False | Run E2E test, in most case we want this -| `e2e_filter_tags` | String | | False | Tests will be filtered based on the tags defined here -| `e2e_containers` | String | '["1"]' | False | The number of tests that you want Cypress to run in parallel (ex. 1, 2, 3, ...) -| `e2e_pass_on_error` | Boolean | False | False | Pass the workflow even if the E2E test fail -| `e2e_artemis_config_path` | String | cypress/artemis-config.yaml | False | Used to determine the path to the artemis config file -| `spec_to_run` | String | cypress/e2e/**/*.feature | False | Used to determine which test to run | `magic_url_route` | String | '/' | False | The relative route the magic url should go to -| `auto_cancel_after_failures` | Number | 2 | False | Cancel the tests after this many failures ## Secrets @@ -30,10 +23,6 @@ This action takes the following secrets: | --------------------------- | --------- | ----------------------------------------- | | `NPM_TOKEN` | True | A J1 npm.com Publish token | `CHROMATIC_PROJECT_TOKEN` | False | The Chromatic API token -| `CYPRESS_RECORD_KEY` | False | The record key associated with the project in Cypress. -| `CYPRESS_PROJECT_ID` | False | The project ID associated with the project in Cypress -| `CYPRESS_PASSWORD` | False | The password of the E2E username -| `DOCKER_HUB_SRE` | True | The password to login to docker hub sre ## Example Usage @@ -49,7 +38,6 @@ jobs: magic_url_route: '/home' secrets: NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - DOCKER_HUB_SRE: ${{ secrets.DOCKER_HUB_SRE }} ``` #### Diagram @@ -81,7 +69,6 @@ jobs: use_chromatic: true secrets: NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - DOCKER_HUB_SRE: ${{ secrets.DOCKER_HUB_SRE }} CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} ``` @@ -102,48 +89,3 @@ graph LR; B --> C; A --> F ``` - -### With E2E Tests - -#### Usage - -```yaml -jobs: - pr: - uses: jupiterone/.github/.github/workflows/frontend_runtime_application_pr.yml@v# - with: - magic_url_route: '/home' - use_e2e: true - secrets: - NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - DOCKER_HUB_SRE: ${{ secrets.DOCKER_HUB_SRE }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} -``` - -#### Diagram - -```mermaid -graph LR; - A[start flow]; - - B[migration_number]; - C[validate]; - D[magic_url]; - E[e2e_prepare]; - F[e2e_run]; - G[e2e_status]; - H[security]; - - B --> D; - B --> E; - D --> F; - E --> F; - - F --> G; - - A --> B; - A --> C; - - A --> H -``` diff --git a/.github/workflows/docs/frontend/frontend_runtime_deploy.md b/.github/workflows/docs/frontend/frontend_runtime_deploy.md index 8791e47a..67007cbc 100644 --- a/.github/workflows/docs/frontend/frontend_runtime_deploy.md +++ b/.github/workflows/docs/frontend/frontend_runtime_deploy.md @@ -1,7 +1,7 @@ # Frontend Runtime Deploy -This is the [default workflow](../../frontend_runtime_application_pr.yml@v#) that is run when a `PR is merged to main` for a `runtime`. +This is the [default workflow](../../frontend_runtime_application_pr.yml) that is run when a `PR is merged to main` for a `runtime`. **NOTE:** Our current workflow mostly goes through Jenkins at the moment. However the long term goal is to transition our entire deploy flow to Github actions, where the following flow becomes single source of truth. diff --git a/.github/workflows/docs/frontend/frontend_runtime_e2e_trigger_response.md b/.github/workflows/docs/frontend/frontend_runtime_e2e_trigger_response.md index 24822d5a..3f536034 100644 --- a/.github/workflows/docs/frontend/frontend_runtime_e2e_trigger_response.md +++ b/.github/workflows/docs/frontend/frontend_runtime_e2e_trigger_response.md @@ -1,6 +1,6 @@ # PR flow running E2E tests when triggered by an external repo -This is the [default workflow](../../frontend_runtime_application_pr.yml@v#) that is run when E2E tests are triggered by an external repo. +This is the [default workflow](../../frontend_runtime_application_pr.yml) that is run when E2E tests are triggered by an external repo. ## Inputs diff --git a/.github/workflows/docs/frontend/frontend_runtime_utility_manual_e2e_trigger.md b/.github/workflows/docs/frontend/frontend_runtime_utility_manual_e2e_trigger.md new file mode 100644 index 00000000..6cc8408b --- /dev/null +++ b/.github/workflows/docs/frontend/frontend_runtime_utility_manual_e2e_trigger.md @@ -0,0 +1,59 @@ +# Default workflow for triggering E2E tests when a PR comment is left + +This is the [default workflow](../../frontend_runtime_utility_manual_e2e_trigger.yml) that is leveraged to trigger E2E tests for for a `utility runtime`. Specifically, when a PR is opened and a comment of `/run-e2e-tests` is left, it will trigger E2E tests in other repos. + +## Inputs + +This action takes the following inputs: + +| Name | Type | Default | Required | Description | +| --------------------------- | ------- | ---------------------------- | --------- | -------------------------------------------------------------------------------------- | +| `fallback_runner` | String | False | False | If true will leverage ubuntu-latest, otherwise will fall back to the J1 in-house runner +| `e2e_pass_on_error` | Boolean | false | False | Pass the workflow even if the E2E test fail +| `repos_to_test` | String | | False | The relative route the magic url should go to + +## Secrets + +This action takes the following secrets: + +| Name | Required | Description | +| --------------------------- | --------- | ----------------------------------------- | +| `NPM_TOKEN` | True | A J1 npm.com Publish token +| `E2E_AUTO` | False | A J1 token for kicking off cypress tests in other repos + +## Example Usage + +### Default Flow + +#### Usage + +```yaml +# Triggered by adding a comment to a PR +on: + issue_comment: + types: [created] + +jobs: + trigger_e2e_tests: + # Check if the comments come from pull request and contains '/run-e2e-test' + if: github.event.issue.pull_request && contains(github.event.comment.body, '/run-e2e-tests') + uses: jupiterone/.github/.github/workflows/frontend_runtime_application_pr.yml@v# + secrets: + NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + E2E_AUTO: ${{ secrets.E2E_AUTO }} +``` + +#### Diagram + +```mermaid +graph LR; + A[start flow]; + B[e2e_pending_status]; + C[migration_number]; + D[magic_url]; + E[e2e_trigger_remote_tests]; + F[external_repo]; + G[e2e_status]; + + A --> B --> C --> D --> E -->|trigger E2E tests and wait| F -->|report back status| E --> G; +``` diff --git a/.github/workflows/docs/frontend/frontend_runtime_utility_pr.md b/.github/workflows/docs/frontend/frontend_runtime_utility_pr.md index 27842667..1a1494b5 100644 --- a/.github/workflows/docs/frontend/frontend_runtime_utility_pr.md +++ b/.github/workflows/docs/frontend/frontend_runtime_utility_pr.md @@ -1,7 +1,7 @@ -# Default workflow for a runtime application when a PR is opened +# Default workflow for a utility runtime when a PR is opened -This is the [default workflow](../../frontend_runtime_application_pr.yml@v#) that is run when a `PR is opened` for a `utility runtime`. It is meant to test the quality and safety of the code being committed. +This is the [default workflow](../../frontend_runtime_utility_pr.yml) that is run when a `PR is opened` for a `utility runtime`. It is meant to test the quality and safety of the code being committed. ## Inputs @@ -12,9 +12,6 @@ This action takes the following inputs: | `fallback_runner` | String | False | False | If true will leverage ubuntu-latest, otherwise will fall back to the J1 in-house runner | `use_validate` | Boolean | True | False | Run validation, in most case we want this | `use_chromatic` | Boolean | false | False | Run VRT Storybook tests with chromatic -| `use_e2e_trigger` | Boolean | false | False | Trigger E2E tests in other repos -| `e2e_pass_on_error` | Boolean | false | False | Pass the workflow even if the E2E test fail -| `repos_to_test` | String | | False | The relative route the magic url should go to ## Secrets @@ -24,7 +21,6 @@ This action takes the following secrets: | --------------------------- | --------- | ----------------------------------------- | | `NPM_TOKEN` | True | A J1 npm.com Publish token | `CHROMATIC_PROJECT_TOKEN` | False | The Chromatic API token -| `E2E_AUTO` | False | A J1 token for kicking off cypress tests ## Example Usage @@ -38,7 +34,6 @@ jobs: uses: jupiterone/.github/.github/workflows/frontend_runtime_utility_pr.yml@v# secrets: NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - E2E_AUTO: ${{ secrets.E2E_AUTO }} ``` #### Diagram @@ -69,7 +64,6 @@ jobs: use_chromatic: true secrets: NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - E2E_AUTO: ${{ secrets.E2E_AUTO }} CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} ``` @@ -91,38 +85,3 @@ graph LR; B --> C; ``` -### With E2E Trigger - -#### Usage - -```yaml -jobs: - pr: - uses: jupiterone/.github/.github/workflows/frontend_runtime_application_pr.yml@v# - with: - use_e2e_trigger: true - secrets: - NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - E2E_AUTO: ${{ secrets.E2E_AUTO }} -``` - -#### Diagram - -```mermaid -graph LR; - A[start flow]; - - B[migration_number]; - C[validate]; - D[magic_url]; - E[e2e_trigger_remote_tests]; - F[external_repo]; - G[e2e_status]; - H[security]; - - B --> D --> E -->|trigger E2E tests and wait| F -->|report back status| E --> G; - - A --> B; - A --> C; - A --> H; -``` diff --git a/.github/workflows/frontend_runtime_application_manual_e2e_run.yml b/.github/workflows/frontend_runtime_application_manual_e2e_run.yml new file mode 100644 index 00000000..cd1f5ec1 --- /dev/null +++ b/.github/workflows/frontend_runtime_application_manual_e2e_run.yml @@ -0,0 +1,186 @@ +name: Default workflow for a runtime application when E2E tests get triggred by a comment on the PR + +on: + workflow_call: + inputs: + fallback_runner: + description: "If true will leverage ubuntu-latest, otherwise will fall back to the J1 in-house runner" + default: false + type: boolean + e2e_filter_tags: + description: "Tests will be filtered based on the tags defined here" + type: string + e2e_containers: + description: "The number of tests that you want Cypress to run in parallel. For example to run your tests via 3 containers you would set the value to the following: '[`1`, `2`, `3`]'." + type: string + default: '["1"]' + e2e_pass_on_error: + description: "Pass the workflow even if the E2E test fail" + type: boolean + default: false + e2e_artemis_config_path: + description: 'Used to determine the path to the artemis config file' + type: string + default: 'cypress/artemis-config.yaml' + spec_to_run: + description: 'Used to determine which test to run' + type: string + default: 'cypress/e2e/**/*.feature' + magic_url_route: + description: 'The relative route the magic url should go to' + type: string + default: '/' + auto_cancel_after_failures: + description: 'Cancel the tests after this many failures' + default: 2 + type: number + secrets: + NPM_TOKEN: + description: "A J1 npm.com Publish token" + required: true + CYPRESS_RECORD_KEY: + description: "The record key associated with the project in Cypress" + required: true + CYPRESS_PROJECT_ID: + description: "The project ID associated with the project in Cypress" + required: true + CYPRESS_PASSWORD: + description: "The password of the E2E username" + required: false + DOCKER_HUB_SRE: + description: "The password to login to docker hub sre" + required: true + +env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + e2e_pending_status: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + steps: + - uses: actions/checkout@v3 + - name: e2e_pending_status + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_pending_status + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + migration_number: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + outputs: + migration: ${{ steps.migration_number.outputs.migration }} + steps: + - uses: actions/checkout@v3 + - id: migration_number + name: migration_number + uses: jupiterone/.github/.github/actions/frontend/runtime/migration_number@v2 + + magic_url: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + needs: [migration_number] + permissions: + id-token: write + statuses: write + contents: read + issues: read + pull-requests: read + steps: + - uses: actions/checkout@v3 + - name: setup_env + uses: jupiterone/.github/.github/actions/setup_env@v2 + with: + use_dev: true + - name: build + uses: jupiterone/.github/.github/actions/build@v2 + - name: magic_url + uses: jupiterone/.github/.github/actions/frontend/runtime/magic_url@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + migration_number: ${{ needs.migration_number.outputs.migration }} + magic_url_route: ${{ inputs.magic_url_route }} + + e2e_prepare: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + permissions: + id-token: write + contents: read + outputs: + artemis_account_name: ${{ steps.e2e_prepare.outputs.artemis_account_name }} + artemis_account_id: ${{ steps.e2e_prepare.outputs.artemis_account_id }} + artemis_account_subdomain: ${{ steps.e2e_prepare.outputs.artemis_account_subdomain }} + artemis_users: ${{ steps.e2e_prepare.outputs.artemis_users }} + steps: + - uses: actions/checkout@v3 + - name: setup_env + uses: jupiterone/.github/.github/actions/setup_env@v2 + with: + use_dev: true + - id: e2e_prepare + name: e2e_prepare + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_prepare@v2 + with: + e2e_artemis_config_path: ${{ inputs.e2e_artemis_config_path }} + user_count: $(echo '${{ inputs.e2e_containers }}' | jq '. | length') + + e2e_run: + # Note this is the only job that leverages amd64 + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-amd64' }} + container: + # Available containers here: https://hub.docker.com/r/cypress/browsers/tags + image: cypress/browsers:latest + options: --user 1001 + credentials: + username: jupiteronesre + password: ${{ secrets.DOCKER_HUB_SRE }} + continue-on-error: ${{ inputs.e2e_pass_on_error }} + permissions: write-all + needs: [e2e_prepare, migration_number, magic_url] + strategy: + # when one test fails, DO NOT cancel the other containers, because this will kill Cypress processes + # leaving Cypress Cloud hanging: https://github.com/cypress-io/github-action/issues/48 + fail-fast: false + matrix: + # run copies of the current job in parallel + containers: ${{ fromJson(inputs.e2e_containers) }} + steps: + - uses: actions/checkout@v3 + - name: setup_env + uses: jupiterone/.github/.github/actions/setup_env@v2 + with: + use_dev: true + - id: e2e_run + name: e2e_run + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_run@v2 + timeout-minutes: 120 + with: + artemis_account_name: ${{ needs.e2e_prepare.outputs.artemis_account_name }} + artemis_account_id: ${{ needs.e2e_prepare.outputs.artemis_account_id }} + artemis_account_subdomain: ${{ needs.e2e_prepare.outputs.artemis_account_subdomain }} + artemis_users: ${{ needs.e2e_prepare.outputs.artemis_users }} + cypress_container: ${{ matrix.containers }} + cypress_mailinator_api_key: ${{ secrets.CYPRESS_MAILINATOR_API_KEY }} + cypress_record_key: ${{ secrets.CYPRESS_RECORD_KEY }} + cypress_project_id: ${{ secrets.CYPRESS_PROJECT_ID }} + cypress_password: ${{ secrets.CYPRESS_PASSWORD }} + e2e_filter_tags: ${{ inputs.e2e_filter_tags }} + e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} + github_token: ${{ secrets.GITHUB_TOKEN }} + migration_number: ${{ needs.migration_number.outputs.migration }} + spec_to_run: ${{ inputs.spec_to_run }} + auto_cancel_after_failures: ${{ inputs.auto_cancel_after_failures }} + + e2e_status: + name: E2E Status + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + needs: [e2e_pending_status, e2e_run] + steps: + - uses: actions/checkout@v3 + - name: e2e_status + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status + if: always() + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} diff --git a/.github/workflows/frontend_runtime_application_pr.yml b/.github/workflows/frontend_runtime_application_pr.yml index 68a99f6d..2558dfd1 100644 --- a/.github/workflows/frontend_runtime_application_pr.yml +++ b/.github/workflows/frontend_runtime_application_pr.yml @@ -15,37 +15,10 @@ on: description: "Run VRT Storybook tests with chromatic" default: false type: boolean - use_e2e: - description: "Run E2E test, in most case we want this" - type: boolean - default: false - e2e_filter_tags: - description: "Tests will be filtered based on the tags defined here" - type: string - e2e_containers: - description: "The number of tests that you want Cypress to run in parallel (ex. 1, 2, 3, ...)" - type: string - default: '["1"]' - e2e_pass_on_error: - description: "Pass the workflow even if the E2E test fail" - type: boolean - default: false - e2e_artemis_config_path: - description: 'Used to determine the path to the artemis config file' - type: string - default: 'cypress/artemis-config.yaml' - spec_to_run: - description: 'Used to determine which test to run' - type: string - default: 'cypress/e2e/**/*.feature' magic_url_route: description: 'The relative route the magic url should go to' type: string default: '/' - auto_cancel_after_failures: - description: 'Cancel the tests after this many failures' - default: 2 - type: number secrets: NPM_TOKEN: description: "A J1 npm.com Publish token" @@ -53,18 +26,6 @@ on: CHROMATIC_PROJECT_TOKEN: description: "The Chromatic API token" required: false - CYPRESS_RECORD_KEY: - description: "The record key associated with the project in Cypress" - required: false - CYPRESS_PROJECT_ID: - description: "The project ID associated with the project in Cypress" - required: false - CYPRESS_PASSWORD: - description: "The password of the E2E username" - required: false - DOCKER_HUB_SRE: - description: "The password to login to docker hub sre" - required: true env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -101,9 +62,7 @@ jobs: uses: jupiterone/.github/.github/actions/frontend/runtime/remote_types_install@v2 - name: validate uses: jupiterone/.github/.github/actions/validate@v2 - - name: build - uses: jupiterone/.github/.github/actions/build@v2 - + security: runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-amd64' }} permissions: @@ -141,9 +100,10 @@ jobs: needs: [migration_number] permissions: id-token: write - contents: read - pull-requests: write statuses: write + contents: read + issues: read + pull-requests: read steps: - uses: actions/checkout@v3 - name: setup_env @@ -158,97 +118,3 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} migration_number: ${{ needs.migration_number.outputs.migration }} magic_url_route: ${{ inputs.magic_url_route }} - - e2e_prepare: - runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} - needs: [migration_number] - if: ${{ inputs.use_e2e }} - permissions: - id-token: write - contents: read - outputs: - artemis_account_name: ${{ steps.e2e_prepare.outputs.artemis_account_name }} - artemis_account_id: ${{ steps.e2e_prepare.outputs.artemis_account_id }} - artemis_account_subdomain: ${{ steps.e2e_prepare.outputs.artemis_account_subdomain }} - artemis_users: ${{ steps.e2e_prepare.outputs.artemis_users }} - steps: - - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - - id: e2e_prepare - name: e2e_prepare - uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_prepare@v2 - with: - e2e_artemis_config_path: ${{ inputs.e2e_artemis_config_path }} - user_count: $(echo '${{ inputs.e2e_containers }}' | jq '. | length') - - e2e_run: - # Note this is the only job that leverages amd64 - runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-amd64' }} - container: - # Available containers here: https://hub.docker.com/r/cypress/browsers/tags - image: cypress/browsers:node-20.9.0-chrome-118.0.5993.88-1-ff-118.0.2-edge-118.0.2088.46-1 - options: --user 1001 - credentials: - username: jupiteronesre - password: ${{ secrets.DOCKER_HUB_SRE }} - if: ${{ inputs.use_e2e }} - continue-on-error: ${{ inputs.e2e_pass_on_error }} - permissions: write-all - needs: [migration_number, magic_url, e2e_prepare] - strategy: - # when one test fails, DO NOT cancel the other containers, because this will kill Cypress processes - # leaving Cypress Cloud hanging: https://github.com/cypress-io/github-action/issues/48 - fail-fast: false - matrix: - # run copies of the current job in parallel - containers: ${{ fromJson(inputs.e2e_containers) }} - outputs: - test_passed: ${{ steps.e2e_run.outputs.test_passed }} - steps: - - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - - id: e2e_run - name: e2e_run - uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_run@v2 - timeout-minutes: 120 - with: - artemis_account_name: ${{ needs.e2e_prepare.outputs.artemis_account_name }} - artemis_account_id: ${{ needs.e2e_prepare.outputs.artemis_account_id }} - artemis_account_subdomain: ${{ needs.e2e_prepare.outputs.artemis_account_subdomain }} - artemis_users: ${{ needs.e2e_prepare.outputs.artemis_users }} - cypress_container: ${{ matrix.containers }} - cypress_mailinator_api_key: ${{ secrets.CYPRESS_MAILINATOR_API_KEY }} - cypress_record_key: ${{ secrets.CYPRESS_RECORD_KEY }} - cypress_project_id: ${{ secrets.CYPRESS_PROJECT_ID }} - cypress_password: ${{ secrets.CYPRESS_PASSWORD }} - e2e_filter_tags: ${{ inputs.e2e_filter_tags }} - e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} - github_token: ${{ secrets.GITHUB_TOKEN }} - migration_number: ${{ needs.migration_number.outputs.migration }} - spec_to_run: ${{ inputs.spec_to_run }} - auto_cancel_after_failures: ${{ inputs.auto_cancel_after_failures }} - - # Unless e2e_pass_on_error is true, this will never get hit if an E2E test fails - e2e_status: - # Name targeted by branch protections, do not change - name: E2E Status - runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} - needs: [e2e_run] - steps: - - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - - name: e2e_status - uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status@v2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - e2e_passed: ${{ needs.e2e_run.outputs.test_passed }} - e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} diff --git a/.github/workflows/frontend_runtime_utility_manual_e2e_trigger.yml b/.github/workflows/frontend_runtime_utility_manual_e2e_trigger.yml new file mode 100644 index 00000000..8f1dd0eb --- /dev/null +++ b/.github/workflows/frontend_runtime_utility_manual_e2e_trigger.yml @@ -0,0 +1,112 @@ +name: Default workflow for a runtime utility when a PR is opened + +on: + workflow_call: + inputs: + fallback_runner: + description: "If true will leverage ubuntu-latest, otherwise will fall back to the J1 in-house runner" + default: false + type: boolean + e2e_pass_on_error: + description: "Pass the workflow even if the E2E test fail" + type: boolean + default: false + repos_to_test: + description: "Kick off a n+ spec files within n+ repos" + type: string + secrets: + NPM_TOKEN: + description: "A J1 npm.com Publish token" + required: true + E2E_AUTO: + description: "A J1 token for kicking off cypress tests" + required: false + +env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + e2e_pending_status: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + steps: + - uses: actions/checkout@v3 + - name: e2e_pending_status + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_pending_status + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + migration_number: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + outputs: + migration: ${{ steps.migration_number.outputs.migration }} + steps: + - uses: actions/checkout@v3 + - id: migration_number + name: migration_number + uses: jupiterone/.github/.github/actions/frontend/runtime/migration_number@v2 + + magic_url: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + needs: [migration_number] + permissions: + id-token: write + statuses: write + contents: read + issues: read + pull-requests: read + steps: + - uses: actions/checkout@v3 + - name: setup_env + uses: jupiterone/.github/.github/actions/setup_env@v2 + with: + use_dev: true + - name: build + uses: jupiterone/.github/.github/actions/build@v2 + - name: magic_url + uses: jupiterone/.github/.github/actions/frontend/runtime/magic_url@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + migration_number: ${{ needs.migration_number.outputs.migration }} + # runtime utilities do not have a route of there own, so we default to home + magic_url_route: '/home' + + e2e_trigger_remote_tests: + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + needs: [magic_url] + strategy: + matrix: + repos: ${{ fromJson(inputs.repos_to_test) }} + continue-on-error: ${{ inputs.e2e_pass_on_error }} + outputs: + test_passed: ${{ steps.e2e_trigger_remote_tests.outputs.test_passed }} + steps: + - uses: actions/checkout@v3 + - name: setup_env + uses: jupiterone/.github/.github/actions/setup_env@v2 + with: + use_dev: true + - id: e2e_trigger_remote_tests + name: e2e_trigger_remote_tests + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_trigger_remote_tests@v2 + with: + e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} + e2e_auto: ${{ secrets.E2E_AUTO }} + repo_name: ${{ matrix.repos.repo.name }} + repo_spec: ${{ matrix.repos.repo.spec }} + + e2e_status: + name: E2E Status + runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} + needs: [e2e_pending_status, e2e_trigger_remote_tests] + steps: + - uses: actions/checkout@v3 + - name: e2e_status + uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status + if: always() + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} diff --git a/.github/workflows/frontend_runtime_utility_pr.yml b/.github/workflows/frontend_runtime_utility_pr.yml index 03f0d5df..e9809837 100644 --- a/.github/workflows/frontend_runtime_utility_pr.yml +++ b/.github/workflows/frontend_runtime_utility_pr.yml @@ -15,17 +15,6 @@ on: description: "Run VRT Storybook tests with chromatic" default: false type: boolean - use_e2e_trigger: - description: "Trigger E2E tests in other repos" - type: boolean - default: false - e2e_pass_on_error: - description: "Pass the workflow even if the E2E test fail" - type: boolean - default: false - repos_to_test: - description: "Kick off a n+ spec files within n+ repos" - type: string secrets: NPM_TOKEN: description: "A J1 npm.com Publish token" @@ -33,9 +22,6 @@ on: CHROMATIC_PROJECT_TOKEN: description: "The Chromatic API token" required: false - E2E_AUTO: - description: "A J1 token for kicking off cypress tests" - required: false env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -51,10 +37,6 @@ jobs: migration: ${{ steps.migration_number.outputs.migration }} steps: - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - id: migration_number name: migration_number uses: jupiterone/.github/.github/actions/frontend/runtime/migration_number@v2 @@ -78,8 +60,6 @@ jobs: uses: jupiterone/.github/.github/actions/validate@v2 - name: remote_types_tests uses: jupiterone/.github/.github/actions/frontend/runtime/remote_types_tests@v2 - - name: build - uses: jupiterone/.github/.github/actions/build@v2 security: runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-amd64' }} @@ -118,9 +98,10 @@ jobs: needs: [migration_number] permissions: id-token: write - contents: read - pull-requests: write statuses: write + contents: read + issues: read + pull-requests: read steps: - uses: actions/checkout@v3 - name: setup_env @@ -136,48 +117,3 @@ jobs: migration_number: ${{ needs.migration_number.outputs.migration }} # runtime utilities do not have a route of there own, so we default to home magic_url_route: '/home' - - e2e_trigger_remote_tests: - runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} - needs: [magic_url] - if: ${{ inputs.use_e2e_trigger }} - strategy: - matrix: - repos: ${{ fromJson(inputs.repos_to_test) }} - continue-on-error: ${{ inputs.e2e_pass_on_error }} - outputs: - test_passed: ${{ steps.e2e_trigger_remote_tests.outputs.test_passed }} - steps: - - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - - id: e2e_trigger_remote_tests - name: e2e_trigger_remote_tests - uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_trigger_remote_tests@v2 - with: - e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} - e2e_auto: ${{ secrets.E2E_AUTO }} - repo_name: ${{ matrix.repos.repo.name }} - repo_spec: ${{ matrix.repos.repo.spec }} - - # Unless e2e_pass_on_error is true, this will never get hit if an E2E test fails - e2e_status: - # Name targeted by branch protections, do not change - name: E2E Status - runs-on: ${{ (inputs.fallback_runner && 'ubuntu-latest') || 'scaleset-jupiterone-infra-arm64' }} - needs: [e2e_trigger_remote_tests] - steps: - - uses: actions/checkout@v3 - - name: setup_env - uses: jupiterone/.github/.github/actions/setup_env@v2 - with: - use_dev: true - - name: e2e_status - uses: jupiterone/.github/.github/actions/frontend/runtime/e2e_status@v2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - commit_info_sha: ${{ github.sha }} - e2e_passed: ${{ needs.e2e_trigger_remote_tests.outputs.test_passed }} - e2e_pass_on_error: ${{ inputs.e2e_pass_on_error }} diff --git a/.github/workflows/test/frontend_runtime_application_manual_e2e_run.test.ts b/.github/workflows/test/frontend_runtime_application_manual_e2e_run.test.ts new file mode 100644 index 00000000..22cf938c --- /dev/null +++ b/.github/workflows/test/frontend_runtime_application_manual_e2e_run.test.ts @@ -0,0 +1,117 @@ +import { MockGithub } from '@kie/mock-github'; +import { Act } from '@kie/act-js'; +import { getWorkflowConfig, runWorkflow } from 'tests/utils/setup'; +import { getTestResult, getTestResults, setInputs, setSecrets } from 'tests/utils/helpers'; +import mockPackageJson from 'tests/package.json'; +import mockArtemisRun from '~/actions/frontend/runtime/e2e_prepare/test/artemis-run.json'; +import { resolve } from 'node:path'; +import { cwd } from 'node:process'; + +let mockGithub: MockGithub; + +const repoName = 'frontend_runtime_application_manual_e2e_run'; + +const mockArtemisData = { + id: mockArtemisRun[0].id, + accountName: mockArtemisRun[0].metadata.accountName, + accountSubdomain: mockArtemisRun[0].metadata.accountSubdomain, + users: { + tokenSecret: mockArtemisRun[1].metadata.token.tokenSecret, + tokenCsrf: mockArtemisRun[1].metadata.token.tokenCsrf, + groupName: mockArtemisRun[1].metadata.groupName + } +}; + +beforeEach(async () => { + mockGithub = new MockGithub(getWorkflowConfig({ repoName, additionalFiles: [ + { + src: resolve(cwd(), '.github', 'actions', 'frontend', 'runtime', 'e2e_prepare', 'test', 'artemis-run.json'), + dest: 'artemis-run.json', + } + ] })); + + await mockGithub.setup(); +}); + +afterEach(async () => { + await mockGithub.teardown(); +}); + +test('validate inputs and secrets', async () => { + const act = new Act(mockGithub.repo.getPath(repoName)); + const mockSecrets = [ + 'CYPRESS_MAILINATOR_API_KEY', + 'CYPRESS_RECORD_KEY', + 'CYPRESS_PROJECT_ID', + 'CYPRESS_PASSWORD', + 'DOCKER_HUB_SRE' + ]; + const mockInputs = { + magic_url_route: 'magic_url_route_test', + e2e_artemis_config_path: 'e2e_artemis_config_path_test', + e2e_containers: '["1", "2"]', + e2e_filter_tags: 'e2e_filter_tags_test', + e2e_pass_on_error: true, + spec_to_run: 'spec_to_run_test' + }; + + setSecrets({ act, mockSecrets }); + setInputs({ act, mockInputs }); + + const results = await runWorkflow({ act, repoName, mockGithub }); + + // magic_url + const magic_url_inputs = getTestResult({ results, name: 'magic_url_inputs' }); + + expect(magic_url_inputs.output).toContain(`migration=${mockPackageJson.config.migration}`); + expect(magic_url_inputs.output).toContain(`magic_url_route=${mockInputs.magic_url_route}`); + + // e2e_prepare + const e2e_prepare_inputs = getTestResult({ results, name: 'e2e_prepare_inputs' }); + + expect(e2e_prepare_inputs.output).toContain(`e2e_artemis_config_path=${mockInputs.e2e_artemis_config_path}`); + expect(e2e_prepare_inputs.output).toContain(`user_count=${JSON.parse(mockInputs.e2e_containers).length}`); + + // e2e_run + const e2e_run_inputs = getTestResult({ results, name: 'e2e_run_inputs' }); + + expect(e2e_run_inputs.output).toContain(`artemis_account_name=${mockArtemisData.accountName}`); + expect(e2e_run_inputs.output).toContain(`artemis_account_subdomain=${mockArtemisData.accountSubdomain}`); + expect(e2e_run_inputs.output).toContain(`artemis_account_id=${mockArtemisData.id}`); + expect(e2e_run_inputs.output).toContain(`artemis_users=[${JSON.stringify(mockArtemisData.users).replace(/"([^"]+)"/g, '$1')}]`); + expect(e2e_run_inputs.output).toContain(`cypress_mailinator_api_key=***`); + expect(e2e_run_inputs.output).toContain(`cypress_record_key=***`); + expect(e2e_run_inputs.output).toContain(`cypress_project_id=***`); + expect(e2e_run_inputs.output).toContain(`cypress_password=***`); + expect(e2e_run_inputs.output).toContain(`e2e_filter_tags=${mockInputs.e2e_filter_tags}`); + expect(e2e_run_inputs.output).toContain(`e2e_pass_on_error=${mockInputs.e2e_pass_on_error}`); + expect(e2e_run_inputs.output).toContain(`migration_number=${mockPackageJson.config.migration}`); + expect(e2e_run_inputs.output).toContain(`spec_to_run=${mockInputs.spec_to_run}`); +}); + +test('flow with e2e_pass_on_error set to true to make tests non blocking', async () => { + const act = new Act(mockGithub.repo.getPath(repoName)); + + act.setSecret('DOCKER_HUB_SRE', 'DOCKER_HUB_SRE'); + act.setInput('e2e_pass_on_error', 'true'); + + const results = await runWorkflow({ act, repoName, mockGithub, mockSteps: { + e2e_pending_status: [ { name: 'e2e_pending_status', mockWith: 'echo ""' } ], + migration_number: [ { name: 'migration_number', mockWith: 'echo ""' } ], + magic_url: [ { name: 'magic_url', mockWith: 'echo ""' } ], + e2e_prepare: [ { name: 'e2e_prepare', mockWith: 'echo ""' } ], + // Purposefully fail to test e2e_pass_on_error + e2e_run: [ { name: 'e2e_prepare', mockWith: 'echo "exit 1"' } ], + }}); + + const jobs_found = getTestResults({ results, names: [ + 'e2e_pending_status', + 'migration_number', + 'magic_url', + 'e2e_prepare', + 'e2e_run', + 'e2e_status' + ] }); + + expect(jobs_found.length).toEqual(6); +}); diff --git a/.github/workflows/test/frontend_runtime_application_pr.test.ts b/.github/workflows/test/frontend_runtime_application_pr.test.ts index 943ab819..b75bab85 100644 --- a/.github/workflows/test/frontend_runtime_application_pr.test.ts +++ b/.github/workflows/test/frontend_runtime_application_pr.test.ts @@ -3,32 +3,13 @@ import { Act } from '@kie/act-js'; import { getWorkflowConfig, runWorkflow } from 'tests/utils/setup'; import { getTestResult, getTestResults, setInputs, setSecrets } from 'tests/utils/helpers'; import mockPackageJson from 'tests/package.json'; -import mockArtemisRun from '~/actions/frontend/runtime/e2e_prepare/test/artemis-run.json'; -import { resolve } from 'node:path'; -import { cwd } from 'node:process'; let mockGithub: MockGithub; const repoName = 'frontend_runtime_application_pr'; -const mockArtemisData = { - id: mockArtemisRun[0].id, - accountName: mockArtemisRun[0].metadata.accountName, - accountSubdomain: mockArtemisRun[0].metadata.accountSubdomain, - users: { - tokenSecret: mockArtemisRun[1].metadata.token.tokenSecret, - tokenCsrf: mockArtemisRun[1].metadata.token.tokenCsrf, - groupName: mockArtemisRun[1].metadata.groupName - } -}; - beforeEach(async () => { - mockGithub = new MockGithub(getWorkflowConfig({ repoName, additionalFiles: [ - { - src: resolve(cwd(), '.github', 'actions', 'frontend', 'runtime', 'e2e_prepare', 'test', 'artemis-run.json'), - dest: 'artemis-run.json', - } - ] })); + mockGithub = new MockGithub(getWorkflowConfig({ repoName })); await mockGithub.setup(); }); @@ -40,27 +21,16 @@ afterEach(async () => { test('validate inputs and secrets', async () => { const act = new Act(mockGithub.repo.getPath(repoName)); const mockSecrets = [ - 'CHROMATIC_PROJECT_TOKEN', - 'CYPRESS_MAILINATOR_API_KEY', - 'CYPRESS_RECORD_KEY', - 'CYPRESS_PROJECT_ID', - 'CYPRESS_PASSWORD', - 'DOCKER_HUB_SRE' + 'CHROMATIC_PROJECT_TOKEN' ]; const mockInputs = { - magic_url_route: 'magic_url_route_test', - e2e_artemis_config_path: 'e2e_artemis_config_path_test', - e2e_containers: '["1", "2"]', - e2e_filter_tags: 'e2e_filter_tags_test', - e2e_pass_on_error: true, - spec_to_run: 'spec_to_run_test' + magic_url_route: 'magic_url_route_test' }; setSecrets({ act, mockSecrets }); setInputs({ act, mockInputs }); act.setInput('use_chromatic', 'true'); - act.setInput('use_e2e', 'true'); const results = await runWorkflow({ act, repoName, mockGithub }); @@ -75,28 +45,6 @@ test('validate inputs and secrets', async () => { expect(magic_url_inputs.output).toContain(`migration=${mockPackageJson.config.migration}`); expect(magic_url_inputs.output).toContain(`magic_url_route=${mockInputs.magic_url_route}`); - // e2e_prepare - const e2e_prepare_inputs = getTestResult({ results, name: 'e2e_prepare_inputs' }); - - expect(e2e_prepare_inputs.output).toContain(`e2e_artemis_config_path=${mockInputs.e2e_artemis_config_path}`); - expect(e2e_prepare_inputs.output).toContain(`user_count=${JSON.parse(mockInputs.e2e_containers).length}`); - - // e2e_run - const e2e_run_inputs = getTestResult({ results, name: 'e2e_run_inputs' }); - - expect(e2e_run_inputs.output).toContain(`artemis_account_name=${mockArtemisData.accountName}`); - expect(e2e_run_inputs.output).toContain(`artemis_account_subdomain=${mockArtemisData.accountSubdomain}`); - expect(e2e_run_inputs.output).toContain(`artemis_account_id=${mockArtemisData.id}`); - expect(e2e_run_inputs.output).toContain(`artemis_users=[${JSON.stringify(mockArtemisData.users).replace(/"([^"]+)"/g, '$1')}]`); - expect(e2e_run_inputs.output).toContain(`cypress_mailinator_api_key=***`); - expect(e2e_run_inputs.output).toContain(`cypress_record_key=***`); - expect(e2e_run_inputs.output).toContain(`cypress_project_id=***`); - expect(e2e_run_inputs.output).toContain(`cypress_password=***`); - expect(e2e_run_inputs.output).toContain(`e2e_filter_tags=${mockInputs.e2e_filter_tags}`); - expect(e2e_run_inputs.output).toContain(`e2e_pass_on_error=${mockInputs.e2e_pass_on_error}`); - expect(e2e_run_inputs.output).toContain(`migration_number=${mockPackageJson.config.migration}`); - expect(e2e_run_inputs.output).toContain(`spec_to_run=${mockInputs.spec_to_run}`); - // code_ql const code_ql_inputs = getTestResult({ results, name: 'code_ql_inputs' }); @@ -145,39 +93,3 @@ test('when use_chromatic is true', async () => { expect(jobs_found.length).toEqual(1); }); - -test('flow with e2e_pass_on_error set to true to make tests non blocking', async () => { - const act = new Act(mockGithub.repo.getPath(repoName)); - - act.setSecret('DOCKER_HUB_SRE', 'DOCKER_HUB_SRE'); - act.setInput('use_e2e', 'true'); - act.setInput('e2e_pass_on_error', 'true'); - - const results = await runWorkflow({ act, repoName, mockGithub, mockSteps: { - migration_number: [ { name: 'migration_number', mockWith: 'echo ""' } ], - validate: [ { name: 'validate', mockWith: 'echo ""' } ], - magic_url: [ { name: 'magic_url', mockWith: 'echo ""' } ], - e2e_prepare: [ { name: 'e2e_prepare', mockWith: 'echo ""' } ], - - // Purposefully fail to test e2e_pass_on_error - e2e_run: [{ - name: 'e2e_run', - mockCompositeSteps: [ - { name: 'get_author_name' }, - { name: 'cypress_run', mockWith: 'exit 1' }, - ] - }], - }}); - - const jobs_found = getTestResults({ results, names: [ - 'migration_number', - 'validate', - 'code_ql', - 'magic_url', - 'e2e_prepare', - 'e2e_run', - 'e2e_status' - ] }); - - expect(jobs_found.length).toEqual(7); -}); diff --git a/.github/workflows/test/frontend_runtime_e2e_trigger_response.test.ts b/.github/workflows/test/frontend_runtime_e2e_trigger_response.test.ts index 090fbb3e..fb752076 100644 --- a/.github/workflows/test/frontend_runtime_e2e_trigger_response.test.ts +++ b/.github/workflows/test/frontend_runtime_e2e_trigger_response.test.ts @@ -83,6 +83,8 @@ test('validate inputs and secrets', async () => { test('default flow', async () => { const act = new Act(mockGithub.repo.getPath(repoName)); + act.setSecret('DOCKER_HUB_SRE', 'DOCKER_HUB_SRE'); + const results = await runWorkflow({ act, repoName, mockGithub }); const jobs_found = getTestResults({ results, names: [ diff --git a/.github/workflows/test/frontend_runtime_utility_manual_e2e_trigger.test.ts b/.github/workflows/test/frontend_runtime_utility_manual_e2e_trigger.test.ts new file mode 100644 index 00000000..341b47d4 --- /dev/null +++ b/.github/workflows/test/frontend_runtime_utility_manual_e2e_trigger.test.ts @@ -0,0 +1,75 @@ +import { MockGithub } from '@kie/mock-github'; +import { Act } from '@kie/act-js'; +import { getWorkflowConfig, runWorkflow } from 'tests/utils/setup'; +import { getTestResult, getTestResults, setInputs, setSecrets } from 'tests/utils/helpers'; +import { resolve } from 'node:path'; +import { cwd } from 'node:process'; + +const repoName = 'frontend_runtime_utility_manual_e2e_trigger'; + +let mockGithub: MockGithub; + +beforeEach(async () => { + mockGithub = new MockGithub(getWorkflowConfig({ repoName, additionalFiles: [ + { + src: resolve(cwd(), '.github', 'actions', 'frontend', 'runtime', 'e2e_prepare', 'test', 'artemis-run.json'), + dest: 'artemis-run.json', + } + ] })); + + await mockGithub.setup(); +}); + +afterEach(async () => { + await mockGithub.teardown(); +}); + +test('validate inputs and secrets', async () => { + const act = new Act(mockGithub.repo.getPath(repoName)); + + const mockInputs = { + e2e_pass_on_error: true, + repos_to_test: '[{"repo":{"name":"web-home", "spec":"test/spec" }}]' + }; + + setInputs({ act, mockInputs }); + + setSecrets({ act, mockSecrets: [ + 'E2E_AUTO' + ]}); + + const results = await runWorkflow({ act, repoName, mockGithub }); + + // e2e_run + const e2e_trigger_remote_tests_inputs = getTestResult({ results, name: 'e2e_trigger_remote_tests_inputs' }); + + expect(e2e_trigger_remote_tests_inputs.output).toContain(`e2e_pass_on_error=${mockInputs.e2e_pass_on_error}`); + expect(e2e_trigger_remote_tests_inputs.output).toContain(`e2e_auto=***`); + expect(e2e_trigger_remote_tests_inputs.output).toContain(JSON.parse(mockInputs.repos_to_test)[0].repo.name); + expect(e2e_trigger_remote_tests_inputs.output).toContain(JSON.parse(mockInputs.repos_to_test)[0].repo.spec); +}); + +test.skip('flow with e2e_pass_on_error set to true to make tests non blocking', async () => { + const act = new Act(mockGithub.repo.getPath(repoName)); + + act.setInput('e2e_pass_on_error', 'true'); + + const results = await runWorkflow({ act, repoName, mockGithub, mockSteps: { + e2e_pending_status: [ { name: 'e2e_pending_status', mockWith: 'echo ""' } ], + migration_number: [ { name: 'migration_number', mockWith: 'echo ""' } ], + magic_url: [ { name: 'magic_url', mockWith: 'echo ""' } ], + e2e_prepare: [ { name: 'e2e_prepare', mockWith: 'echo ""' } ], + // Purposefully fail to test e2e_pass_on_error + e2e_trigger_remote_tests: [ { name: 'e2e_prepare', mockWith: 'echo "exit 1"' } ], + }}); + + const jobs_found = getTestResults({ results, names: [ + 'e2e_pending_status', + 'migration_number', + 'magic_url', + 'e2e_trigger_remote_tests', + 'e2e_status' + ] }); + + expect(jobs_found.length).toEqual(5); +}); diff --git a/.github/workflows/test/frontend_runtime_utility_pr.test.ts b/.github/workflows/test/frontend_runtime_utility_pr.test.ts index 71f0994f..2b947a0c 100644 --- a/.github/workflows/test/frontend_runtime_utility_pr.test.ts +++ b/.github/workflows/test/frontend_runtime_utility_pr.test.ts @@ -3,20 +3,13 @@ import { Act } from '@kie/act-js'; import { getWorkflowConfig, runWorkflow } from 'tests/utils/setup'; import { getTestResult, getTestResults, setInputs, setSecrets } from 'tests/utils/helpers'; import mockPackageJson from 'tests/package.json'; -import { resolve } from 'node:path'; -import { cwd } from 'node:process'; const repoName = 'frontend_runtime_utility_pr'; let mockGithub: MockGithub; beforeEach(async () => { - mockGithub = new MockGithub(getWorkflowConfig({ repoName, additionalFiles: [ - { - src: resolve(cwd(), '.github', 'actions', 'frontend', 'runtime', 'e2e_prepare', 'test', 'artemis-run.json'), - dest: 'artemis-run.json', - } - ] })); + mockGithub = new MockGithub(getWorkflowConfig({ repoName })); await mockGithub.setup(); }); @@ -29,17 +22,13 @@ test('validate inputs and secrets', async () => { const act = new Act(mockGithub.repo.getPath(repoName)); const mockInputs = { - use_chromatic: true, - use_e2e_trigger: true, - e2e_pass_on_error: true, - repos_to_test: '[{"repo":{"name":"web-home", "spec":"test/spec" }}]' + use_chromatic: true }; setInputs({ act, mockInputs }); setSecrets({ act, mockSecrets: [ - 'CHROMATIC_PROJECT_TOKEN', - 'E2E_AUTO' + 'CHROMATIC_PROJECT_TOKEN' ]}); const results = await runWorkflow({ act, repoName, mockGithub }); @@ -54,14 +43,6 @@ test('validate inputs and secrets', async () => { expect(magic_url_inputs.output).toContain(`migration=${mockPackageJson.config.migration}`); - // e2e_run - const e2e_trigger_remote_tests_inputs = getTestResult({ results, name: 'e2e_trigger_remote_tests_inputs' }); - - expect(e2e_trigger_remote_tests_inputs.output).toContain(`e2e_pass_on_error=${mockInputs.e2e_pass_on_error}`); - expect(e2e_trigger_remote_tests_inputs.output).toContain(`e2e_auto=***`); - expect(e2e_trigger_remote_tests_inputs.output).toContain(JSON.parse(mockInputs.repos_to_test)[0].repo.name); - expect(e2e_trigger_remote_tests_inputs.output).toContain(JSON.parse(mockInputs.repos_to_test)[0].repo.spec); - // code_ql const code_ql_inputs = getTestResult({ results, name: 'code_ql_inputs' }); @@ -109,62 +90,3 @@ test('when use_chromatic is true', async () => { expect(jobs_found.length).toEqual(1); }); - -test('flow with e2e trigger turned on', async () => { - const act = new Act(mockGithub.repo.getPath(repoName)); - - setInputs({ act, mockInputs: { - use_e2e_trigger: true, - repos_to_test: '[{"repo":{"name":"web-home", "spec":"test/spec" }}]' - }}); - - const results = await runWorkflow({ act, repoName, mockGithub }); - - const jobs_found = getTestResults({ results, names: [ - 'migration_number', - 'validate', - 'code_ql', - 'magic_url', - 'e2e_trigger_remote_tests', - 'e2e_status' - ] }); - - expect(jobs_found.length).toEqual(6); -}); - -test('flow with e2e_pass_on_error set to true to make tests non blocking', async () => { - const act = new Act(mockGithub.repo.getPath(repoName)); - - setInputs({ act, mockInputs: { - use_e2e_trigger: true, - e2e_pass_on_error: true, - repos_to_test: '[{"repo":{"name":"web-home", "spec":"test/spec" }}]' - }}); - - const results = await runWorkflow({ act, repoName, mockGithub, - mockSteps: { - migration_number: [ { name: 'migration_number', mockWith: 'echo ""' } ], - validate: [ { name: 'validate', mockWith: 'echo ""' } ], - magic_url: [ { name: 'magic_url', mockWith: 'echo ""' } ], - - // Purposefully fail trigger to test e2e_pass_on_error - e2e_trigger_remote_tests: [{ - name: 'e2e_trigger_remote_tests', - mockCompositeSteps: [ - { name: 'cypress_run', mockWith: 'exit 1' }, - ] - }], - } - }); - - const jobs_found = getTestResults({ results, names: [ - 'migration_number', - 'validate', - 'code_ql', - 'magic_url', - 'e2e_trigger_remote_tests', - 'e2e_status' - ] }); - - expect(jobs_found.length).toEqual(6); -}); diff --git a/README.md b/README.md index 9a385d82..fe654b31 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ The following workflows are for the entire JupiterOne organization. #### Runtime - [frontend_runtime_application_pr](.github/workflows/docs/frontend/frontend_runtime_application_pr.md) +- [frontend_runtime_application_manual_e2e_run](.github/workflows/docs/frontend/frontend_runtime_application_manual_e2e_run.md) - [frontend_runtime_utility_pr](.github/workflows/docs/frontend/frontend_runtime_utility_pr.md) -- [frontend_runtime_e2e_trigger_response](.github/workflows/docs/frontend/frontend_runtime_e2e_trigger_response.md) +- [frontend_runtime_utility_manual_e2e_trigger](.github/workflows/docs/frontend/frontend_runtime_utility_manual_e2e_trigger.md) - [frontend_runtime_deploy](.github/workflows/docs/frontend/frontend_runtime_deploy.md) #### NPM Packages @@ -42,6 +43,7 @@ The workflows above take advantage of the composite actions listed below, levera #### Runtime +- [e2e_pending_status](.github/actions/frontend/runtime/e2e_pending_status/README.md) - [e2e_prepare](.github/actions/frontend/runtime/e2e_prepare/README.md) - [e2e_run](.github/actions/frontend/runtime/e2e_run/README.md) - [e2e_status](.github/actions/frontend/runtime/e2e_status/README.md)