Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment URL Improvements #129

Merged
merged 6 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ As seen above, we have two steps. One for a noop deploy, and one for a regular d
| `global_lock_flag` | `false` | `--global` | The flag to pass into the lock command to lock all environments. Example: "--global" |
| `environment` | `false` | `production` | The name of the default environment to deploy to. Example: by default, if you type `.deploy`, it will assume "production" as the default environment |
| `environment_targets` | `false` | `production,development,staging` | Optional (or additional) target environments to select for use with deployments. Example, "production,development,staging". Example usage: `.deploy to development`, `.deploy to production`, `.deploy to staging` |
| `environment_urls` | `false` | `""` | Optional target environment URLs to use with deployments. This input option is a mapping of environment names to URLs and the environment names **must** match the `environment_targets` input option. This option is a comma separated list with pipes (`\|`) separating the environment from the URL. Format: `"<environment1>\|<url1>,<environment2>\|<url2>,etc"` Example: `"production\|https://myapp.com,development\|https://dev.myapp.com,staging\|https://staging.myapp.com"` |
| `environment_urls` | `false` | `""` | Optional target environment URLs to use with deployments. This input option is a mapping of environment names to URLs and the environment names **must** match the `environment_targets` input option. This option is a comma separated list with pipes (`\|`) separating the environment from the URL. Note: `disabled` is a special keyword to disable an environment url if you enable this option. Format: `"<environment1>\|<url1>,<environment2>\|<url2>,etc"` Example: `"production\|https://myapp.com,development\|https://dev.myapp.com,staging\|disabled"` - See the [environment urls](#environment-urls) section for more details |
| `environment_url_in_comment` | `false` | `"true` | If the `environment_url` detected in the deployment should be appended to the successful deployment comment or not. Examples: `"true"` or `"false"` - See the [environment urls](#environment-urls) section for more details |
| `production_environment` | `false` | `production` | The name of the production environment. Example: "production". By default, GitHub will set the "production_environment" to "true" if the environment name is "production". This option allows you to override that behavior so you can use "prod", "prd", "main", etc. as your production environment name. |
| `stable_branch` | `false` | `main` | The name of a stable branch to deploy to (rollbacks). Example: "main" |
| `prefix_only` | `false` | `"true"` | If "false", the trigger can match anywhere in the comment |
Expand Down Expand Up @@ -399,14 +400,18 @@ Environment URLs can be confirgured and mapped to matching `environment_targets`

This input option is a mapping of environment names to URLs and the environment names **must** match the [`environment_targets`](https://github.com/github/branch-deploy#environment-targets) input option. This option is a comma separated list with pipes (`|`) separating the environment from the URL.

Note: `disabled` is a special keyword to disable an environment url if you enable this option but not all environments have a url.

Format: `"<environment1>|<url1>,<environment2>|<url2>,etc"`

Example: `"production|https://myapp.com,development|https://dev.myapp.com,staging|https://staging.myapp.com"`
Example: `"production|https://myapp.com,development|https://dev.myapp.com,staging|disabled"`

> This option is especially useful when your deployment targets are services with a URL (website, API, etc)

By enabling this option, you will get a "clickable" link on success (non-noop) deployment messages on pull requests. You will also be able to click the "View deployment" button in your repository's deployments page and be taken to the URL of the environment you deployed to.

If you wish to disable the "clickable" link on the successful deloyment message, you can set the `environment_url_in_comment` input to `"false"`.

## Rollbacks 🔄

This Action supports rollback deployments out of the box. This is useful when you run a branch deployment (`.deploy`) and something goes wrong and you need to rollback to a previous known working state.
Expand Down
2 changes: 1 addition & 1 deletion __tests__/functions/deployment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test('creates an in_progress deployment status', async () => {
deployment_id: deploymentId,
state: 'in_progress',
environment: environment,
environment_url: '',
environment_url: null,
INPUT_LOG_URL: logUrl
})
})
129 changes: 99 additions & 30 deletions __tests__/functions/environment-targets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as actionStatus from '../../src/functions/action-status'
import * as core from '@actions/core'
import dedent from 'dedent-js'

const infoMock = jest.spyOn(core, 'info').mockImplementation(() => {})
const debugMock = jest.spyOn(core, 'debug').mockImplementation(() => {})
const warningMock = jest.spyOn(core, 'warning').mockImplementation(() => {})
const saveStateMock = jest.spyOn(core, 'saveState').mockImplementation(() => {})
Expand All @@ -24,7 +25,7 @@ const trigger = '.deploy'
const noop_trigger = 'noop'
const stable_branch = 'main'
const environmentUrls =
'production|example.com,development|dev.example.com,staging|staging.example.com'
'production|https://example.com,development|https://dev.example.com,staging|http://staging.example.com'

test('checks the comment body and does not find an explicit environment target', async () => {
expect(
Expand All @@ -35,7 +36,7 @@ test('checks the comment body and does not find an explicit environment target',
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for branch deployment'
)
Expand All @@ -50,7 +51,7 @@ test('checks the comment body and finds an explicit environment target for devel
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'development', environmentUrl: ''})
).toStrictEqual({environment: 'development', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for branch deploy: development'
)
Expand All @@ -65,7 +66,7 @@ test('checks the comment body and finds an explicit environment target for stagi
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'staging', environmentUrl: ''})
).toStrictEqual({environment: 'staging', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for noop trigger: staging'
)
Expand All @@ -87,18 +88,21 @@ test('checks the comment body and finds an explicit environment target for stagi
)
).toStrictEqual({
environment: 'staging',
environmentUrl: 'staging.example.com'
environmentUrl: 'http://staging.example.com'
})
expect(infoMock).toHaveBeenCalledWith(
'environment url detected: http://staging.example.com'
)
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for noop trigger: staging'
)
expect(saveStateMock).toHaveBeenCalledWith(
'environment_url',
'staging.example.com'
'http://staging.example.com'
)
expect(setOutputMock).toHaveBeenCalledWith(
'environment_url',
'staging.example.com'
'http://staging.example.com'
)
})

Expand All @@ -116,12 +120,24 @@ test('checks the comment body and uses the default production environment target
false, // lockChecks disabled
environmentUrls
)
).toStrictEqual({environment: 'production', environmentUrl: 'example.com'})
).toStrictEqual({
environment: 'production',
environmentUrl: 'https://example.com'
})
expect(infoMock).toHaveBeenCalledWith(
'environment url detected: https://example.com'
)
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for branch deployment'
)
expect(saveStateMock).toHaveBeenCalledWith('environment_url', 'example.com')
expect(setOutputMock).toHaveBeenCalledWith('environment_url', 'example.com')
expect(saveStateMock).toHaveBeenCalledWith(
'environment_url',
'https://example.com'
)
expect(setOutputMock).toHaveBeenCalledWith(
'environment_url',
'https://example.com'
)
})

test('checks the comment body and finds an explicit environment target for a production deploy with environment_urls set but no valid url', async () => {
Expand All @@ -138,15 +154,68 @@ test('checks the comment body and finds an explicit environment target for a pro
false, // lockChecks disabled
'evil-production|example.com,development|dev.example.com,staging|'
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for branch deploy: production'
)
expect(warningMock).toHaveBeenCalledWith(
"no environment URL found for environment: production - setting environment URL to empty string - please check your 'environment_urls' input"
"no valid environment URL found for environment: production - setting environment URL to 'null' - please check your 'environment_urls' input"
)
expect(saveStateMock).toHaveBeenCalledWith('environment_url', 'null')
expect(setOutputMock).toHaveBeenCalledWith('environment_url', 'null')
})

test('checks the comment body and finds an explicit environment target for a production deploy with environment_urls set but a url with a non-http(s) schema is provided', async () => {
expect(
await environmentTargets(
environment,
'.deploy production',
trigger,
noop_trigger,
stable_branch,
null,
null,
null,
false, // lockChecks disabled
'production|example.com,development|dev.example.com,staging|'
)
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for branch deploy: production'
)
expect(warningMock).toHaveBeenCalledWith(
'environment url does not match http(s) schema: example.com'
)
expect(warningMock).toHaveBeenCalledWith(
"no valid environment URL found for environment: production - setting environment URL to 'null' - please check your 'environment_urls' input"
)
expect(saveStateMock).toHaveBeenCalledWith('environment_url', 'null')
expect(setOutputMock).toHaveBeenCalledWith('environment_url', 'null')
})

test('checks the comment body and finds an explicit environment target for a production deploy with environment_urls set but the environment url for the given environment is disabled', async () => {
expect(
await environmentTargets(
environment,
'.deploy production',
trigger,
noop_trigger,
stable_branch,
null,
null,
null,
false, // lockChecks disabled
'production|disabled,development|dev.example.com,staging|'
)
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for branch deploy: production'
)
expect(infoMock).toHaveBeenCalledWith(
'environment url for production is explicitly disabled'
)
expect(saveStateMock).toHaveBeenCalledWith('environment_url', '')
expect(setOutputMock).toHaveBeenCalledWith('environment_url', '')
expect(saveStateMock).toHaveBeenCalledWith('environment_url', 'null')
expect(setOutputMock).toHaveBeenCalledWith('environment_url', 'null')
})

test('checks the comment body and finds an explicit environment target for staging on a noop deploy with "to"', async () => {
Expand All @@ -158,7 +227,7 @@ test('checks the comment body and finds an explicit environment target for stagi
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'staging', environmentUrl: ''})
).toStrictEqual({environment: 'staging', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
"Found environment target for noop trigger (with 'to'): staging"
)
Expand All @@ -173,7 +242,7 @@ test('checks the comment body and finds an explicit environment target for produ
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
"Found environment target for branch deploy (with 'to'): production"
)
Expand All @@ -188,7 +257,7 @@ test('checks the comment body on a noop deploy and does not find an explicit env
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for noop trigger'
)
Expand All @@ -203,7 +272,7 @@ test('checks the comment body on a deployment and does not find any matching env
noop_trigger,
stable_branch
)
).toStrictEqual({environment: false, environmentUrl: ''})
).toStrictEqual({environment: false, environmentUrl: null})

const msg = dedent(`
No matching environment target found. Please check your command and try again. You can read more about environment targets in the README of this Action.
Expand All @@ -224,7 +293,7 @@ test('checks the comment body on a stable branch deployment and finds a matching
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
"Found environment target for stable branch deploy (with 'to'): production"
)
Expand All @@ -239,7 +308,7 @@ test('checks the comment body on a stable branch deployment and finds a matching
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for stable branch deploy: production'
)
Expand All @@ -254,7 +323,7 @@ test('checks the comment body on a stable branch deployment and uses the default
noop_trigger,
stable_branch
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for stable branch deployment'
)
Expand All @@ -269,7 +338,7 @@ test('checks the comment body on a stable branch deployment and does not find a
noop_trigger,
stable_branch
)
).toStrictEqual({environment: false, environmentUrl: ''})
).toStrictEqual({environment: false, environmentUrl: null})

const msg = dedent(`
No matching environment target found. Please check your command and try again. You can read more about environment targets in the README of this Action.
Expand All @@ -294,7 +363,7 @@ test('checks the comment body on a lock request and uses the default environment
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for lock request'
)
Expand All @@ -313,7 +382,7 @@ test('checks the comment body on an unlock request and uses the default environm
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for unlock request'
)
Expand All @@ -332,7 +401,7 @@ test('checks the comment body on a lock info alias request and uses the default
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Using default environment for lock info request'
)
Expand All @@ -351,7 +420,7 @@ test('checks the comment body on a lock request and uses the production environm
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'production', environmentUrl: ''})
).toStrictEqual({environment: 'production', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for lock request: production'
)
Expand All @@ -370,7 +439,7 @@ test('checks the comment body on an unlock request and uses the development envi
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'development', environmentUrl: ''})
).toStrictEqual({environment: 'development', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for unlock request: development'
)
Expand All @@ -389,7 +458,7 @@ test('checks the comment body on a lock info alias request and uses the developm
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'development', environmentUrl: ''})
).toStrictEqual({environment: 'development', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for lock info request: development'
)
Expand All @@ -408,7 +477,7 @@ test('checks the comment body on a lock info request and uses the development en
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'development', environmentUrl: ''})
).toStrictEqual({environment: 'development', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for lock request: development'
)
Expand All @@ -427,7 +496,7 @@ test('checks the comment body on a lock info request and uses the development en
null, // reaction_id
true // enable lockChecks
)
).toStrictEqual({environment: 'development', environmentUrl: ''})
).toStrictEqual({environment: 'development', environmentUrl: null})
expect(debugMock).toHaveBeenCalledWith(
'Found environment target for lock request: development'
)
Expand Down
3 changes: 2 additions & 1 deletion __tests__/functions/post-deploy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ test('successfully completes a production branch deployment with an environment
'false',
456,
'production',
'https://example.com' // environment_url
'https://example.com', // environment_url
true // environment url in comment
)
).toBe('success')

Expand Down
Loading