From 3faaae5bd83a36ec166bc61dbc1e69a8e72390e9 Mon Sep 17 00:00:00 2001 From: Joe Lust Date: Wed, 20 Jul 2022 12:23:07 -0400 Subject: [PATCH] [IST-460] Helpful Doc Improvements and Moment Update (#55) --- .github/workflows/pr-workflow.yaml | 2 +- .github/workflows/push-workflow.yaml | 2 +- README.md | 12 +++++--- package-lock.json | 6 ++-- package.json | 4 +-- src/mablApiClient.ts | 31 ++++++++++++++++--- test/suite.test.ts | 46 +++++++++++++++++++++++++++- 7 files changed, 87 insertions(+), 16 deletions(-) diff --git a/.github/workflows/pr-workflow.yaml b/.github/workflows/pr-workflow.yaml index 68ff3e4..e5a173f 100644 --- a/.github/workflows/pr-workflow.yaml +++ b/.github/workflows/pr-workflow.yaml @@ -6,7 +6,7 @@ jobs: name: Mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@main + - uses: actions/checkout@v3 - name: Install dependencies run: npm ci diff --git a/.github/workflows/push-workflow.yaml b/.github/workflows/push-workflow.yaml index 141a746..77f35fb 100644 --- a/.github/workflows/push-workflow.yaml +++ b/.github/workflows/push-workflow.yaml @@ -7,7 +7,7 @@ jobs: name: Mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@main + - uses: actions/checkout@v3 - name: Install dependencies run: npm ci diff --git a/README.md b/README.md index 44fdf20..596b211 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ test runs associated with that deployment and waiting for their results. For more complex use cases, see the [setup-mabl-cli](https://github.com/marketplace/actions/setup-mabl-cli) Action to access the CLI directly. +To view rich GitHub commit and pull requests information in the mabl app, [install the mabl GitHub App](https://help.mabl.com/docs/github-integration-setup) in _addition_ to using this action. + ### Example workflow: Simple ``` @@ -19,12 +21,13 @@ jobs: name: mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Functional test deployment id: mabl-test-deployment uses: mablhq/github-run-tests-action@v1 env: + # Use a "CI/CD Integration" type of mabl API key MABL_API_KEY: ${{ secrets.MABL_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -46,12 +49,13 @@ jobs: name: mabl Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Functional test deployment id: mabl-test-deployment uses: mablhq/github-run-tests-action@v1 env: + # Use a "CI/CD Integration" type of mabl API key MABL_API_KEY: ${{ secrets.MABL_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -78,8 +82,8 @@ jobs: ### Environment variables -- `MABL_API_KEY` {string} - Your mabl API key - [available here](https://app.mabl.com/workspaces/-/settings/apis) This should +- `MABL_API_KEY` {string} - Create a "CI/CD Integration" type mabl API key + [here](https://app.mabl.com/workspaces/-/settings/apis). This should be installed as a secret in your GitHub repository. - `GITHUB_TOKEN` {string} (optional) - The GitHub token for your repository. If provided, the mabl action will associate a pull request with the deployment if diff --git a/package-lock.json b/package-lock.json index 42c4e14..cb2c8b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3587,9 +3587,9 @@ "dev": true }, "moment": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", - "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "ms": { "version": "2.1.2", diff --git a/package.json b/package.json index 11c9a0b..117a6a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mabl-github-deployments-action", - "version": "1.11.0", + "version": "1.12.0", "description": "mabl github action for GitHub pipelines integration", "main": "lib/src/index.js", "scripts": { @@ -21,7 +21,7 @@ "async-retry": "1.3.3", "axios": "0.26.1", "cli-table3": "0.6.1", - "moment": "2.29.2" + "moment": "2.29.4" }, "devDependencies": { "@types/async-retry": "1.4.3", diff --git a/src/mablApiClient.ts b/src/mablApiClient.ts index 70f7289..cbeadb5 100644 --- a/src/mablApiClient.ts +++ b/src/mablApiClient.ts @@ -2,7 +2,7 @@ import retry from 'async-retry'; import {Application} from './entities/Application'; import {Deployment, DeploymentProperties} from './entities/Deployment'; import {ExecutionResult} from './entities/ExecutionResult'; -import axios, {AxiosInstance, AxiosRequestConfig} from 'axios'; +import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios'; import {Environment} from './entities/Environment'; import {USER_AGENT} from './constants'; @@ -30,6 +30,29 @@ export class MablApiClient { this.httpClient = axios.create(config); } + /** + * Throw helpful error messages, if possible, otherwise throw generic error + * @param response error response + */ + static throwHumanizedError(response: AxiosResponse): never { + switch (response.status) { + case 401: + throw new Error( + `Unauthorized API error, are you sure you passed the correct API key? Is the key "enabled"?`, + ); + case 403: + throw new Error( + `Forbidden API error, are you sure you used a "CI/CD Integration" type API key? Ensure this key is for the same workspace you're testing.`, + ); + case 404: + throw new Error( + `Not Found API error, please ensure any environment or application IDs in your Action config are correct.`, + ); + default: + throw new Error(`[${response.status} - ${response.statusText}]`); + } + } + async makeGetRequest(url: string): Promise { return retry( async () => { @@ -37,7 +60,7 @@ export class MablApiClient { timeout: GET_REQUEST_TIMEOUT_MILLIS, }); if ((response.status ?? 400) >= 400) { - throw new Error(`[${response.status} - ${response.statusText}]`); + MablApiClient.throwHumanizedError(response); } return response.data; }, @@ -69,7 +92,7 @@ export class MablApiClient { async getApplication(id: string): Promise { try { return await this.makeGetRequest( - `${this.baseUrl}/v1/applications/${id}`, + `${this.baseUrl}/applications/${id}`, ); } catch (error) { throw new Error( @@ -81,7 +104,7 @@ export class MablApiClient { async getEnvironment(id: string): Promise { try { return await this.makeGetRequest( - `${this.baseUrl}/v1/environments/${id}`, + `${this.baseUrl}/environments/${id}`, ); } catch (error) { throw new Error( diff --git a/test/suite.test.ts b/test/suite.test.ts index f288342..1d74dce 100644 --- a/test/suite.test.ts +++ b/test/suite.test.ts @@ -1,5 +1,5 @@ import {MablApiClient} from '../src/mablApiClient'; -import { booleanInput, optionalArrayInput, optionalInput, run } from "../src"; +import { booleanInput, optionalArrayInput, optionalInput, run } from '../src'; import { ActionInputs } from '../src/constants'; describe('GitHub Action tests', () => { @@ -66,6 +66,50 @@ describe('GitHub Action tests', () => { expect(optionalInput(ActionInputs.ApplicationId)).toEqual('BAZ'); }); + it('humanizes 403 errors', () => { + expect(() => MablApiClient.throwHumanizedError({ + status: 403, + statusText: 'This is an error', + config: {}, + headers: {}, + data: 10, + request: {} + })).toThrow("Forbidden API error, are you sure you used a \"CI/CD Integration\" type API key? Ensure this key is for the same workspace you're testing."); + }); + + it('humanizes 401 errors', () => { + expect(() => MablApiClient.throwHumanizedError({ + status: 401, + statusText: 'This is an error', + config: {}, + headers: {}, + data: 10, + request: {} + })).toThrow('Unauthorized API error, are you sure you passed the correct API key? Is the key "enabled"?'); + }); + + it('humanizes 404 errors', () => { + expect(() => MablApiClient.throwHumanizedError({ + status: 404, + statusText: 'This is an error', + config: {}, + headers: {}, + data: 10, + request: {} + })).toThrow('Not Found API error, please ensure any environment or application IDs in your Action config are correct.'); + }); + + it('humanizes non-specific errors', () => { + expect(() => MablApiClient.throwHumanizedError({ + status: 500, + statusText: 'This is an error', + config: {}, + headers: {}, + data: 10, + request: {} + })).toThrow('[500 - This is an error]'); + }); + it('builds the request correctly with all options', () => { const expected = { environment_id: 'env',