2022-12-12 11:49:25 +00:00
package phases
import (
2024-07-31 12:16:28 +00:00
"context"
2025-01-07 10:49:23 +00:00
"errors"
2024-07-31 12:16:28 +00:00
2023-05-16 16:35:39 +00:00
"github.com/databricks/cli/bundle"
2025-01-13 16:43:48 +00:00
"github.com/databricks/cli/bundle/apps"
2023-05-16 16:35:39 +00:00
"github.com/databricks/cli/bundle/artifacts"
2023-09-14 10:14:13 +00:00
"github.com/databricks/cli/bundle/config"
2023-07-30 12:44:33 +00:00
"github.com/databricks/cli/bundle/config/mutator"
2024-02-07 11:17:17 +00:00
"github.com/databricks/cli/bundle/deploy"
2023-05-16 16:35:39 +00:00
"github.com/databricks/cli/bundle/deploy/files"
"github.com/databricks/cli/bundle/deploy/lock"
Persist deployment metadata in WSFS (#845)
## Changes
This PR introduces a metadata struct that stores a subset of bundle
configuration that we wish to expose to other Databricks services that
wish to integrate with bundles.
This metadata file is uploaded to a file
`${bundle.workspace.state_path}/metadata.json` in the WSFS destination
of the bundle deployment.
Documentation for emitted metadata fields:
* `version`: Version for the metadata file schema
* `config.bundle.git.branch`: Name of the git branch the bundle was
deployed from.
* `config.bundle.git.origin_url`: URL for git remote "origin"
* `config.bundle.git.bundle_root_path`: Relative path of the bundle root
from the root of the git repository. Is set to "." if they are the same.
* `config.bundle.git.commit`: SHA-1 commit hash of the exact commit this
bundle was deployed from. Note, the deployment might not exactly match
this commit version if there are changes that have not been committed to
git at deploy time,
* `file_path`: Path in workspace where we sync bundle files to.
* `resources.jobs.[job-ref].id`: Id of the job
* `resources.jobs.[job-ref].relative_path`: Relative path of the yaml
config file from the bundle root where this job was defined.
Example metadata object when bundle root and git root are the same:
```json
{
"version": 1,
"config": {
"bundle": {
"lock": {},
"git": {
"branch": "master",
"origin_url": "www.host.com",
"commit": "7af8e5d3f5dceffff9295d42d21606ccf056dce0",
"bundle_root_path": "."
}
},
"workspace": {
"file_path": "/Users/shreyas.goenka@databricks.com/.bundle/pipeline-progress/default/files"
},
"resources": {
"jobs": {
"bar": {
"id": "245921165354846",
"relative_path": "databricks.yml"
}
}
},
"sync": {}
}
}
```
Example metadata when the git root is one level above the bundle repo:
```json
{
"version": 1,
"config": {
"bundle": {
"lock": {},
"git": {
"branch": "dev-branch",
"origin_url": "www.my-repo.com",
"commit": "3db46ef750998952b00a2b3e7991e31787e4b98b",
"bundle_root_path": "pipeline-progress"
}
},
"workspace": {
"file_path": "/Users/shreyas.goenka@databricks.com/.bundle/pipeline-progress/default/files"
},
"resources": {
"jobs": {
"bar": {
"id": "245921165354846",
"relative_path": "databricks.yml"
}
}
},
"sync": {}
}
}
```
This unblocks integration to the jobs break glass UI for bundles.
## Tests
Unit tests and integration tests.
2023-10-27 12:55:43 +00:00
"github.com/databricks/cli/bundle/deploy/metadata"
2023-05-16 16:35:39 +00:00
"github.com/databricks/cli/bundle/deploy/terraform"
2023-07-25 11:35:08 +00:00
"github.com/databricks/cli/bundle/libraries"
2023-11-13 11:29:40 +00:00
"github.com/databricks/cli/bundle/permissions"
2023-09-14 10:14:13 +00:00
"github.com/databricks/cli/bundle/scripts"
2024-09-27 09:32:54 +00:00
"github.com/databricks/cli/bundle/trampoline"
2024-07-31 12:16:28 +00:00
"github.com/databricks/cli/libs/cmdio"
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/log"
Add verbose flag to the "bundle deploy" command (#1774)
## Changes
- Extract sync output logic from `cmd/sync` into `lib/sync`
- Add hidden `verbose` flag to the `bundle deploy` command, it's false
by default and hidden from the `--help` output
- Pass output handler to the `deploy/files/upload` mutator if the
verbose option is true
The was an idea to use in-place output overriding each past file sync
event in the output, bit that wont work for the extension, since it
doesn't display deploy logs in the terminal.
Example output:
```
~/tmp/defpy: ~/cli/cli bundle deploy --sync-progress
Building defpy...
Uploading defpy-0.0.1+20240917.112755-py3-none-any.whl...
Uploading bundle files to /Users/ilia.babanov@databricks.com/.bundle/defpy/dev/files...
Action: PUT: requirements-dev.txt, resources/defpy_pipeline.yml, pytest.ini, src/defpy/main.py, src/defpy/__init__.py, src/dlt_pipeline.ipynb, tests/main_test.py, src/notebook.ipynb, setup.py, resources/defpy_job.yml, .vscode/extensions.json, .vscode/settings.json, fixtures/.gitkeep, .vscode/__builtins__.pyi, README.md, .gitignore, databricks.yml
Uploaded tests
Uploaded resources
Uploaded fixtures
Uploaded .vscode
Uploaded src/defpy
Uploaded requirements-dev.txt
Uploaded .gitignore
Uploaded fixtures/.gitkeep
Uploaded src/defpy/__init__.py
Uploaded databricks.yml
Uploaded README.md
Uploaded setup.py
Uploaded .vscode/__builtins__.pyi
Uploaded .vscode/extensions.json
Uploaded src/dlt_pipeline.ipynb
Uploaded .vscode/settings.json
Uploaded resources/defpy_job.yml
Uploaded pytest.ini
Uploaded src/defpy/main.py
Uploaded tests/main_test.py
Uploaded resources/defpy_pipeline.yml
Uploaded src/notebook.ipynb
Initial Sync Complete
Deploying resources...
Updating deployment state...
Deployment complete!
```
Output example in the extension:
<img width="1843" alt="Screenshot 2024-09-19 at 11 07 48"
src="https://github.com/user-attachments/assets/0fafd095-cdc6-44b8-b482-27a38ada0330">
## Tests
Manually for the `sync` and `bundle deploy` commands + vscode extension
sync and deploy flows
2024-09-23 10:09:11 +00:00
"github.com/databricks/cli/libs/sync"
2024-07-31 12:16:28 +00:00
terraformlib "github.com/databricks/cli/libs/terraform"
2024-09-04 11:11:47 +00:00
tfjson "github.com/hashicorp/terraform-json"
2022-12-12 11:49:25 +00:00
)
2024-12-02 21:18:07 +00:00
func filterDeleteOrRecreateActions ( changes [ ] * tfjson . ResourceChange , resourceType string ) [ ] terraformlib . Action {
2024-09-04 11:11:47 +00:00
res := make ( [ ] terraformlib . Action , 0 )
for _ , rc := range changes {
2024-12-02 21:18:07 +00:00
if rc . Type != resourceType {
2024-07-31 12:16:28 +00:00
continue
}
var actionType terraformlib . ActionType
switch {
case rc . Change . Actions . Delete ( ) :
actionType = terraformlib . ActionTypeDelete
case rc . Change . Actions . Replace ( ) :
actionType = terraformlib . ActionTypeRecreate
default :
2024-12-02 21:18:07 +00:00
// Filter other action types..
2024-07-31 12:16:28 +00:00
continue
}
2024-09-04 11:11:47 +00:00
res = append ( res , terraformlib . Action {
2024-07-31 12:16:28 +00:00
Action : actionType ,
ResourceType : rc . Type ,
ResourceName : rc . Name ,
} )
}
2024-09-04 11:11:47 +00:00
return res
}
func approvalForDeploy ( ctx context . Context , b * bundle . Bundle ) ( bool , error ) {
tf := b . Terraform
if tf == nil {
2025-01-07 10:49:23 +00:00
return false , errors . New ( "terraform not initialized" )
2024-09-04 11:11:47 +00:00
}
// read plan file
plan , err := tf . ShowPlanFile ( ctx , b . Plan . Path )
if err != nil {
return false , err
}
2024-12-02 21:18:07 +00:00
schemaActions := filterDeleteOrRecreateActions ( plan . ResourceChanges , "databricks_schema" )
dltActions := filterDeleteOrRecreateActions ( plan . ResourceChanges , "databricks_pipeline" )
volumeActions := filterDeleteOrRecreateActions ( plan . ResourceChanges , "databricks_volume" )
2024-09-04 11:11:47 +00:00
// We don't need to display any prompts in this case.
2024-12-02 21:18:07 +00:00
if len ( schemaActions ) == 0 && len ( dltActions ) == 0 && len ( volumeActions ) == 0 {
2024-07-31 12:16:28 +00:00
return true , nil
}
2024-09-04 11:11:47 +00:00
// One or more UC schema resources will be deleted or recreated.
if len ( schemaActions ) != 0 {
cmdio . LogString ( ctx , "The following UC schemas will be deleted or recreated. Any underlying data may be lost:" )
for _ , action := range schemaActions {
cmdio . Log ( ctx , action )
}
}
// One or more DLT pipelines is being recreated.
if len ( dltActions ) != 0 {
msg := `
This action will result in the deletion or recreation of the following DLT Pipelines along with the
Streaming Tables ( STs ) and Materialized Views ( MVs ) managed by them . Recreating the Pipelines will
restore the defined STs and MVs through full refresh . Note that recreation is necessary when pipeline
properties such as the ' catalog ' or ' storage ' are changed : `
cmdio . LogString ( ctx , msg )
for _ , action := range dltActions {
cmdio . Log ( ctx , action )
}
2024-07-31 12:16:28 +00:00
}
2024-12-02 21:18:07 +00:00
// One or more volumes is being recreated.
if len ( volumeActions ) != 0 {
msg := `
This action will result in the deletion or recreation of the following volumes .
For managed volumes , the files stored in the volume are also deleted from your
cloud tenant within 30 days . For external volumes , the metadata about the volume
is removed from the catalog , but the underlying files are not deleted : `
cmdio . LogString ( ctx , msg )
for _ , action := range volumeActions {
cmdio . Log ( ctx , action )
}
}
2024-07-31 12:16:28 +00:00
if b . AutoApprove {
return true , nil
}
if ! cmdio . IsPromptSupported ( ctx ) {
2025-01-07 10:49:23 +00:00
return false , errors . New ( "the deployment requires destructive actions, but current console does not support prompting. Please specify --auto-approve if you would like to skip prompts and proceed" )
2024-07-31 12:16:28 +00:00
}
cmdio . LogString ( ctx , "" )
approved , err := cmdio . AskYesOrNo ( ctx , "Would you like to proceed?" )
if err != nil {
return false , err
}
return approved , nil
}
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
func deployCore ( ctx context . Context , b * bundle . Bundle ) diag . Diagnostics {
2024-07-31 12:16:28 +00:00
// Core mutators that CRUD resources and modify deployment state. These
// mutators need informed consent if they are potentially destructive.
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
cmdio . LogString ( ctx , "Deploying resources..." )
diags := bundle . Apply ( ctx , b , terraform . Apply ( ) )
// following original logic, continuing with sequence below even if terraform had errors
diags = diags . Extend ( bundle . ApplySeq ( ctx , b ,
terraform . StatePush ( ) ,
terraform . Load ( ) ,
apps . InterpolateVariables ( ) ,
apps . UploadConfig ( ) ,
metadata . Compute ( ) ,
metadata . Upload ( ) ,
) )
if ! diags . HasError ( ) {
cmdio . LogString ( ctx , "Deployment complete!" )
}
2024-07-31 12:16:28 +00:00
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
return diags
}
// The deploy phase deploys artifacts and resources.
func Deploy ( ctx context . Context , b * bundle . Bundle , outputHandler sync . OutputHandler ) ( diags diag . Diagnostics ) {
log . Info ( ctx , "Phase: deploy" )
// Core mutators that CRUD resources and modify deployment state. These
// mutators need informed consent if they are potentially destructive.
diags = bundle . ApplySeq ( ctx , b ,
2023-09-14 10:14:13 +00:00
scripts . Execute ( config . ScriptPreDeploy ) ,
2023-05-16 16:01:50 +00:00
lock . Acquire ( ) ,
2023-05-24 12:45:19 +00:00
)
2023-05-16 16:01:50 +00:00
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
if diags . HasError ( ) {
// lock is not acquired here
return diags
}
// lock is acquired here
defer func ( ) {
diags = diags . Extend ( bundle . Apply ( ctx , b , lock . Release ( lock . GoalDeploy ) ) )
} ( )
diags = bundle . ApplySeq ( ctx , b ,
terraform . StatePull ( ) ,
terraform . CheckDashboardsModifiedRemotely ( ) ,
deploy . StatePull ( ) ,
mutator . ValidateGitDetails ( ) ,
artifacts . CleanUp ( ) ,
2025-02-27 16:32:50 +00:00
// libraries.CheckForSameNameLibraries() needs to be run after we expand glob references so we
// know what are the actual library paths.
// libraries.ExpandGlobReferences() has to be run after the libraries are built and thus this
// mutator is part of the deploy step rather than validate.
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
libraries . ExpandGlobReferences ( ) ,
2025-02-27 16:32:50 +00:00
libraries . CheckForSameNameLibraries ( ) ,
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
libraries . Upload ( ) ,
trampoline . TransformWheelTask ( ) ,
files . Upload ( outputHandler ) ,
deploy . StateUpdate ( ) ,
deploy . StatePush ( ) ,
permissions . ApplyWorkspaceRootPermissions ( ) ,
terraform . Interpolate ( ) ,
terraform . Write ( ) ,
terraform . CheckRunningResource ( ) ,
terraform . Plan ( terraform . PlanGoal ( "deploy" ) ) ,
2022-12-12 11:49:25 +00:00
)
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
if diags . HasError ( ) {
return diags
}
haveApproval , err := approvalForDeploy ( ctx , b )
if err != nil {
diags = diags . Extend ( diag . FromErr ( err ) )
return diags
}
if haveApproval {
diags = diags . Extend ( deployCore ( ctx , b ) )
} else {
cmdio . LogString ( ctx , "Deployment cancelled!" )
}
if diags . HasError ( ) {
return diags
}
return diags . Extend ( bundle . Apply ( ctx , b , scripts . Execute ( config . ScriptPostDeploy ) ) )
2022-12-12 11:49:25 +00:00
}