Skip to content

Commit 924c6fe

Browse files
authored
Allow deploying SAM templates from the CloudFormation node (#2465)
- Add the Serverless Deploy action to the CloudFormation root node - Opens a file browser to select a template and runs all the same checks that the normal path does. The reason this wasn't refactored is the checking logic is all over the place.
1 parent 097d1e9 commit 924c6fe

File tree

6 files changed

+163
-146
lines changed

6 files changed

+163
-146
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Allow deploying SAM templates from the CloudFormaton node (#2166)"
4+
}

jetbrains-core/resources/META-INF/plugin.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ with what features/services are supported.
293293
class="software.aws.toolkits.jetbrains.services.lambda.actions.DeleteFunctionAction"/>
294294
</group>
295295

296+
<group id="aws.toolkit.explorer.cloudformation" popup="true" compact="false">
297+
<action id="cloudformation.serverless.deploy" class="software.aws.toolkits.jetbrains.services.lambda.actions.DeployServerlessApplicationAction" />
298+
</group>
299+
296300
<group id="aws.toolkit.explorer.cloudformation.stack" popup="true" compact="false">
297301
<action id="cloudformation.stack.view"
298302
class="software.aws.toolkits.jetbrains.services.cloudformation.stack.OpenStackUiAction"/>

jetbrains-core/src/software/aws/toolkits/jetbrains/core/explorer/ExplorerToolWindow.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class ExplorerToolWindow(project: Project) : SimpleToolWindowPanel(true, true),
224224

225225
val actionGroup = DefaultActionGroup(totalActions)
226226
if (actionGroup.childrenCount > 0) {
227-
val popupMenu = actionManager.createActionPopupMenu("ExplorerToolWindow", actionGroup)
227+
val popupMenu = actionManager.createActionPopupMenu(explorerToolWindowPlace, actionGroup)
228228
popupMenu.component.show(comp, x, y)
229229
}
230230
}
@@ -304,6 +304,7 @@ class ExplorerToolWindow(project: Project) : SimpleToolWindowPanel(true, true),
304304

305305
companion object {
306306
fun getInstance(project: Project): ExplorerToolWindow = ServiceManager.getService(project, ExplorerToolWindow::class.java)
307+
const val explorerToolWindowPlace = "ExplorerToolWindow"
307308
}
308309
}
309310

jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/actions/DeployServerlessApplicationAction.kt

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,25 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys
1010
import com.intellij.openapi.application.ApplicationManager
1111
import com.intellij.openapi.application.runInEdt
1212
import com.intellij.openapi.application.runReadAction
13+
import com.intellij.openapi.fileChooser.FileChooser
14+
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
1315
import com.intellij.openapi.fileEditor.FileDocumentManager
1416
import com.intellij.openapi.module.ModuleUtil
1517
import com.intellij.openapi.project.Project
18+
import com.intellij.openapi.project.guessProjectDir
1619
import com.intellij.openapi.roots.ModuleRootManager
1720
import com.intellij.openapi.vfs.VirtualFile
1821
import icons.AwsIcons
1922
import kotlinx.coroutines.runBlocking
2023
import kotlinx.coroutines.withContext
24+
import org.jetbrains.yaml.YAMLFileType
2125
import software.amazon.awssdk.services.cloudformation.CloudFormationClient
2226
import software.aws.toolkits.jetbrains.core.awsClient
2327
import software.aws.toolkits.jetbrains.core.credentials.AwsConnectionManager
2428
import software.aws.toolkits.jetbrains.core.executables.ExecutableInstance
2529
import software.aws.toolkits.jetbrains.core.executables.ExecutableManager
2630
import software.aws.toolkits.jetbrains.core.executables.getExecutable
31+
import software.aws.toolkits.jetbrains.core.explorer.ExplorerToolWindow
2732
import software.aws.toolkits.jetbrains.core.explorer.refreshAwsTree
2833
import software.aws.toolkits.jetbrains.services.cloudformation.describeStack
2934
import software.aws.toolkits.jetbrains.services.cloudformation.executeChangeSetAndWait
@@ -67,21 +72,30 @@ class DeployServerlessApplicationAction : AnAction(
6772
}
6873

6974
ExecutableManager.getInstance().getExecutable<SamExecutable>().thenAccept { samExecutable ->
70-
when (samExecutable) {
71-
is ExecutableInstance.InvalidExecutable, is ExecutableInstance.UnresolvedExecutable -> {
72-
notifySamCliNotValidError(
73-
project = project,
74-
content = (samExecutable as ExecutableInstance.BadExecutable).validationError
75+
if (samExecutable is ExecutableInstance.InvalidExecutable || samExecutable is ExecutableInstance.UnresolvedExecutable) {
76+
notifySamCliNotValidError(
77+
project = project,
78+
content = (samExecutable as ExecutableInstance.BadExecutable).validationError
79+
)
80+
return@thenAccept
81+
}
82+
83+
val templateFile = if (e.place == ExplorerToolWindow.explorerToolWindowPlace) {
84+
runBlocking(edtContext) {
85+
FileChooser.chooseFile(
86+
FileChooserDescriptorFactory.createSingleFileDescriptor(YAMLFileType.YML),
87+
project,
88+
project.guessProjectDir()
7589
)
90+
} ?: return@thenAccept
91+
} else {
92+
val file = getSamTemplateFile(e)
93+
if (file == null) {
94+
Exception(message("serverless.application.deploy.toast.template_file_failure"))
95+
.notifyError(message("aws.notification.title"), project)
7696
return@thenAccept
7797
}
78-
}
79-
80-
val templateFile = getSamTemplateFile(e)
81-
if (templateFile == null) {
82-
Exception(message("serverless.application.deploy.toast.template_file_failure"))
83-
.notifyError(message("aws.notification.title"), project)
84-
return@thenAccept
98+
file
8599
}
86100

87101
validateTemplateFile(project, templateFile)?.let {
@@ -196,7 +210,11 @@ class DeployServerlessApplicationAction : AnAction(
196210
e.presentation.isVisible = if (LambdaHandlerResolver.supportedRuntimeGroups().isEmpty()) {
197211
false
198212
} else {
199-
getSamTemplateFile(e) != null
213+
if (e.place == ExplorerToolWindow.explorerToolWindowPlace) {
214+
true
215+
} else {
216+
getSamTemplateFile(e) != null
217+
}
200218
}
201219
}
202220

jetbrains-core/src/software/aws/toolkits/jetbrains/services/lambda/deploy/DeployServerlessApplicationPanel.java

Lines changed: 0 additions & 132 deletions
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package software.aws.toolkits.jetbrains.services.lambda.deploy
4+
5+
import com.intellij.execution.util.EnvVariablesTable
6+
import com.intellij.execution.util.EnvironmentVariable
7+
import com.intellij.openapi.application.ApplicationManager
8+
import com.intellij.openapi.project.Project
9+
import com.intellij.ui.AnActionButton
10+
import com.intellij.ui.IdeBorderFactory
11+
import com.intellij.ui.SimpleListCellRenderer
12+
import com.intellij.ui.ToolbarDecorator
13+
import com.intellij.ui.components.panels.Wrapper
14+
import software.aws.toolkits.jetbrains.services.cloudformation.Parameter
15+
import software.aws.toolkits.jetbrains.services.ecr.resources.EcrResources.LIST_REPOS
16+
import software.aws.toolkits.jetbrains.services.ecr.resources.Repository
17+
import software.aws.toolkits.jetbrains.services.s3.resources.S3Resources.listBucketNamesByActiveRegion
18+
import software.aws.toolkits.jetbrains.ui.ResourceSelector
19+
import software.aws.toolkits.resources.message
20+
import javax.swing.JButton
21+
import javax.swing.JCheckBox
22+
import javax.swing.JLabel
23+
import javax.swing.JPanel
24+
import javax.swing.JRadioButton
25+
import javax.swing.JTextField
26+
27+
class DeployServerlessApplicationPanel(private val project: Project) {
28+
lateinit var newStackName: JTextField
29+
private set
30+
lateinit var createS3BucketButton: JButton
31+
private set
32+
lateinit var content: JPanel
33+
private set
34+
lateinit var s3Bucket: ResourceSelector<String>
35+
private set
36+
lateinit var stacks: ResourceSelector<Stack>
37+
private set
38+
lateinit var updateStack: JRadioButton
39+
private set
40+
lateinit var createStack: JRadioButton
41+
private set
42+
lateinit var requireReview: JCheckBox
43+
private set
44+
lateinit var useContainer: JCheckBox
45+
private set
46+
lateinit var ecrRepo: ResourceSelector<Repository>
47+
private set
48+
lateinit var createEcrRepoButton: JButton
49+
private set
50+
private lateinit var environmentVariablesTable: EnvVariablesTable
51+
private lateinit var ecrLabel: JLabel
52+
private lateinit var stackParameters: Wrapper
53+
private lateinit var parametersPanel: JPanel
54+
private lateinit var capabilitiesPanel: JPanel
55+
val capabilities: CapabilitiesEnumCheckBoxes = CapabilitiesEnumCheckBoxes()
56+
57+
private fun createUIComponents() {
58+
environmentVariablesTable = EnvVariablesTable()
59+
stackParameters = Wrapper()
60+
stacks = ResourceSelector.builder()
61+
.resource(DeployServerlessApplicationDialog.ACTIVE_STACKS)
62+
.awsConnection(project)
63+
.build()
64+
s3Bucket = ResourceSelector.builder()
65+
.resource(listBucketNamesByActiveRegion(project))
66+
.awsConnection(project)
67+
.build()
68+
ecrRepo = ResourceSelector.builder()
69+
.resource(LIST_REPOS)
70+
.awsConnection(project)
71+
.customRenderer(SimpleListCellRenderer.create("", Repository::repositoryName))
72+
.build()
73+
if (!ApplicationManager.getApplication().isUnitTestMode) {
74+
val tableComponent = environmentVariablesTable.component
75+
hideActionButton(ToolbarDecorator.findAddButton(tableComponent))
76+
hideActionButton(ToolbarDecorator.findRemoveButton(tableComponent))
77+
hideActionButton(ToolbarDecorator.findEditButton(tableComponent))
78+
stackParameters.setContent(tableComponent)
79+
}
80+
}
81+
82+
init {
83+
capabilities.checkboxes.forEach { capabilitiesPanel.add(it) }
84+
showImageOptions(false)
85+
}
86+
87+
fun withTemplateParameters(parameters: List<Parameter>): DeployServerlessApplicationPanel {
88+
parametersPanel.border = IdeBorderFactory.createTitledBorder(message("serverless.application.deploy.template.parameters"), false)
89+
environmentVariablesTable.setValues(
90+
parameters.map { parameter: Parameter ->
91+
object : EnvironmentVariable(
92+
parameter.logicalName,
93+
parameter.defaultValue(),
94+
false
95+
) {
96+
override fun getNameIsWriteable(): Boolean = false
97+
override fun getDescription(): String? = parameter.description()
98+
}
99+
}.toList()
100+
)
101+
return this
102+
}
103+
104+
val templateParameters: Map<String, String>
105+
get() {
106+
environmentVariablesTable.stopEditing()
107+
return environmentVariablesTable.environmentVariables.map { envVar -> envVar.name to envVar.value }.toMap()
108+
}
109+
110+
fun showImageOptions(hasImages: Boolean) {
111+
ecrLabel.isVisible = hasImages
112+
ecrRepo.isVisible = hasImages
113+
createEcrRepoButton.isVisible = hasImages
114+
}
115+
116+
private fun hideActionButton(actionButton: AnActionButton?) {
117+
if (actionButton != null) {
118+
actionButton.isEnabled = false
119+
actionButton.isVisible = false
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)