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

Run config improvements #999

Merged
merged 8 commits into from
Jan 10, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import com.intellij.openapi.application.EDT
import com.intellij.openapi.project.Project
import com.intellij.openapi.rd.util.lifetime
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.util.application
import com.jetbrains.rd.util.reactive.adviseOnce
import com.jetbrains.rider.run.configurations.runnableProjectsModelIfAvailable
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.FunctionLaunchProfilesService
import com.microsoft.azure.toolkit.intellij.legacy.function.localsettings.FunctionLocalSettingsService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
Expand All @@ -20,9 +18,6 @@ class FunctionWarmupStartupActivity : ProjectActivity {
override suspend fun execute(project: Project) {
withContext(Dispatchers.EDT) {
project.runnableProjectsModelIfAvailable?.projects?.adviseOnce(project.lifetime) {
application.runReadAction {
FunctionLaunchProfilesService.getInstance(project).initialize(it)
}
FunctionLocalSettingsService.getInstance(project).initialize(it)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,39 @@ import com.intellij.execution.configurations.ConfigurationTypeUtil
import com.intellij.execution.executors.DefaultDebugExecutor
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.ActionUiKind
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.client.ClientProjectSession
import com.intellij.openapi.project.Project
import com.jetbrains.rd.protocol.SolutionExtListener
import com.jetbrains.rd.ui.bedsl.extensions.valueOrEmpty
import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rd.util.threading.coroutines.adviseSuspend
import com.jetbrains.rider.azure.model.FunctionAppDaemonModel
import com.jetbrains.rider.model.RunnableProject
import com.jetbrains.rider.model.runnableProjectsModel
import com.jetbrains.rider.projectView.solution
import com.jetbrains.rider.run.configurations.launchSettings.LaunchSettingsJsonService
import com.microsoft.azure.toolkit.intellij.legacy.function.actions.TriggerAzureFunctionAction
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.*
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getApplicationUrl
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getArguments
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getEnvironmentVariables
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getWorkingDirectory
import com.microsoft.azure.toolkit.intellij.legacy.function.runner.localRun.*
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getFirstOrNullLaunchProfileProfileSuspend
import com.microsoft.azure.toolkit.intellij.legacy.function.runner.localRun.FunctionRunConfiguration
import com.microsoft.azure.toolkit.intellij.legacy.function.runner.localRun.FunctionRunConfigurationFactory
import com.microsoft.azure.toolkit.intellij.legacy.function.runner.localRun.FunctionRunConfigurationType
import kotlinx.coroutines.Dispatchers

class FunctionAppSolutionExtListener : SolutionExtListener<FunctionAppDaemonModel> {
override fun extensionCreated(lifetime: Lifetime, session: ClientProjectSession, model: FunctionAppDaemonModel) {
model.runFunctionApp.advise(lifetime) {
model.runFunctionApp.adviseSuspend(lifetime, Dispatchers.Main) {
runConfiguration(
functionName = it.functionName,
runnableProject = getRunnableProject(session.project, it.projectFilePath),
executor = DefaultRunExecutor.getRunExecutorInstance(),
project = session.project
)
}
model.debugFunctionApp.advise(lifetime) {
model.debugFunctionApp.adviseSuspend(lifetime, Dispatchers.Main) {
runConfiguration(
functionName = it.functionName,
runnableProject = getRunnableProject(session.project, it.projectFilePath),
Expand All @@ -57,11 +60,17 @@ class FunctionAppSolutionExtListener : SolutionExtListener<FunctionAppDaemonMode
triggerType = it.triggerType,
httpTriggerAttribute = it.httpTriggerAttribute
)
ActionUtil.invokeAction(
val actionEvent = AnActionEvent.createEvent(
triggerAction,
SimpleDataContext.getProjectContext(session.project),
ActionPlaces.EDITOR_GUTTER_POPUP,
null,
ActionPlaces.EDITOR_GUTTER_POPUP,
ActionUiKind.POPUP,
null
)
ActionUtil.invokeAction(
triggerAction,
actionEvent,
null
)
}
Expand All @@ -78,7 +87,7 @@ class FunctionAppSolutionExtListener : SolutionExtListener<FunctionAppDaemonMode
)
}

private fun runConfiguration(
private suspend fun runConfiguration(
functionName: String?,
runnableProject: RunnableProject,
executor: Executor,
Expand Down Expand Up @@ -121,7 +130,7 @@ class FunctionAppSolutionExtListener : SolutionExtListener<FunctionAppDaemonMode
}
}

private fun createFunctionAppRunConfiguration(
private suspend fun createFunctionAppRunConfiguration(
project: Project,
functionName: String?,
runnableProject: RunnableProject
Expand All @@ -143,35 +152,22 @@ class FunctionAppSolutionExtListener : SolutionExtListener<FunctionAppDaemonMode
return configuration
}

private fun patchConfigurationParameters(
private suspend fun patchConfigurationParameters(
project: Project,
configuration: FunctionRunConfiguration,
runnableProject: RunnableProject,
functionName: String?
) {
val projectOutput = runnableProject.projectOutputs.firstOrNull()
val launchProfile = FunctionLaunchProfilesService
val launchProfile = LaunchSettingsJsonService
.getInstance(project)
.getLaunchProfiles(runnableProject)
.firstOrNull()

configuration.parameters.apply {
projectFilePath = runnableProject.projectFilePath
projectTfm = projectOutput?.tfm?.presentableName ?: ""
profileName = launchProfile?.name ?: ""
functionNames = if (functionName.isNullOrEmpty()) "" else functionName
trackArguments = true
arguments = getArguments(launchProfile?.content, projectOutput)
trackWorkingDirectory = true
workingDirectory = getWorkingDirectory(launchProfile?.content, projectOutput)
trackEnvs = true
envs = getEnvironmentVariables(launchProfile?.content)
useExternalConsole = false
trackUrl = true
startBrowserParameters.apply {
url = getApplicationUrl(launchProfile?.content, projectOutput, null)
startAfterLaunch = launchProfile?.content?.launchBrowser ?: false
}
}
.getFirstOrNullLaunchProfileProfileSuspend(runnableProject)

configuration.parameters.setUpFromRunnableProject(
runnableProject,
projectOutput,
launchProfile,
functionName
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2018-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles

import com.jetbrains.rider.model.RunnableProject
import com.jetbrains.rider.run.configurations.controls.LaunchProfile
import com.jetbrains.rider.run.configurations.launchSettings.LaunchSettingsJsonService
import kotlin.collections.asSequence
import kotlin.collections.component1
import kotlin.collections.component2

fun LaunchSettingsJsonService.getFirstOrNullLaunchProfileProfile(runnableProject: RunnableProject): LaunchProfile? {
val profiles = loadLaunchSettings(runnableProject)?.profiles ?: return null

return profiles
.asSequence()
.filter { it.value.commandName.equals("Project", true) }
.firstOrNull()
?.let { LaunchProfile(it.key, it.value) }
}

suspend fun LaunchSettingsJsonService.getFirstOrNullLaunchProfileProfileSuspend(runnableProject: RunnableProject): LaunchProfile? {
val profiles = loadLaunchSettingsSuspend(runnableProject)?.profiles ?: return null

return profiles
.asSequence()
.filter { it.value.commandName.equals("Project", true) }
.firstOrNull()
?.let { LaunchProfile(it.key, it.value) }
}

suspend fun LaunchSettingsJsonService.getProjectLaunchProfiles(runnableProject: RunnableProject): List<LaunchProfile> {
val profiles = loadLaunchSettingsSuspend(runnableProject)?.profiles ?: return emptyList()

return profiles
.asSequence()
.filter { it.value.commandName.equals("Project", true) }
.map { (name, content) -> LaunchProfile(name, content) }
.sortedBy { it.name }
.toList()
}

suspend fun LaunchSettingsJsonService.getProjectLaunchProfileByName(
runnableProject: RunnableProject,
launchProfileName: String?
): LaunchProfile? {
val profiles = loadLaunchSettingsSuspend(runnableProject)?.profiles ?: return null

return profiles
.asSequence()
.filter { it.value.commandName.equals("Project", true) }
.firstOrNull { it.key == launchProfileName }
?.let { (name, content) -> LaunchProfile(name, content) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent
import com.intellij.execution.configurations.RuntimeConfigurationError
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.JDOMExternalizerUtil
import com.jetbrains.rd.util.reactive.hasTrueValue
import com.jetbrains.rider.model.ProjectOutput
import com.jetbrains.rider.model.RunnableProject
import com.jetbrains.rider.model.runnableProjectsModel
import com.jetbrains.rider.projectView.solution
import com.jetbrains.rider.run.RiderRunBundle
import com.jetbrains.rider.run.configurations.controls.LaunchProfile
import com.jetbrains.rider.run.configurations.project.DotNetProjectConfigurationParameters
import com.jetbrains.rider.run.configurations.project.DotNetStartBrowserParameters
import com.microsoft.azure.toolkit.intellij.legacy.function.daemon.AzureRunnableProjectKinds
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getApplicationUrl
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getArguments
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getEnvironmentVariables
import com.microsoft.azure.toolkit.intellij.legacy.function.launchProfiles.getWorkingDirectory
import com.microsoft.azure.toolkit.intellij.legacy.function.localsettings.FunctionLocalSettings
import org.jdom.Element
import java.io.File

Expand Down Expand Up @@ -62,17 +71,19 @@ class FunctionRunConfigurationParameters(
}

fun validate() {
if (project.solution.isLoaded.valueOrNull != true) {
throw RuntimeConfigurationError("Solution is loading, please wait for a few seconds.")
if (!project.solution.isLoaded.hasTrueValue) {
throw RuntimeConfigurationError(DotNetProjectConfigurationParameters.SOLUTION_IS_LOADING)
}

val runnableProjects = project.solution.runnableProjectsModel.projects.valueOrNull
if (project.solution.isLoaded.valueOrNull != true || runnableProjects == null) {
throw RuntimeConfigurationError(DotNetProjectConfigurationParameters.SOLUTION_IS_LOADING)
?: throw RuntimeConfigurationError(DotNetProjectConfigurationParameters.SOLUTION_IS_LOADING)

if (projectFilePath.isEmpty()) {
throw RuntimeConfigurationError(DotNetProjectConfigurationParameters.PROJECT_NOT_SPECIFIED)
}
val project = runnableProjects.singleOrNull {
it.projectFilePath == projectFilePath && it.kind == AzureRunnableProjectKinds.AzureFunctions
} ?: throw RuntimeConfigurationError(DotNetProjectConfigurationParameters.PROJECT_NOT_SPECIFIED)
} ?: throw RuntimeConfigurationError(RiderRunBundle.message("selected.project.not.found"))

if (!trackWorkingDirectory) {
val workingDirectoryFile = File(workingDirectory)
if (!workingDirectoryFile.exists() || !workingDirectoryFile.isDirectory)
Expand All @@ -83,6 +94,7 @@ class FunctionRunConfigurationParameters(
)
)
}

if (!project.problems.isNullOrEmpty()) {
throw RuntimeConfigurationError(project.problems)
}
Expand Down Expand Up @@ -141,4 +153,29 @@ class FunctionRunConfigurationParameters(
trackUrl,
startBrowserParameters.copy()
)

fun setUpFromRunnableProject(
runnableProject: RunnableProject,
projectOutput: ProjectOutput?,
launchProfile: LaunchProfile?,
functionName: String? = null,
localFunctionSettings: FunctionLocalSettings? = null
) {
projectFilePath = runnableProject.projectFilePath
projectTfm = projectOutput?.tfm?.presentableName ?: ""
profileName = launchProfile?.name ?: ""
functionNames = if (functionName.isNullOrEmpty()) "" else functionName
trackArguments = true
arguments = getArguments(launchProfile?.content, projectOutput)
trackWorkingDirectory = true
workingDirectory = getWorkingDirectory(launchProfile?.content, projectOutput)
trackEnvs = true
envs = getEnvironmentVariables(launchProfile?.content)
useExternalConsole = false
trackUrl = true
startBrowserParameters.apply {
url = getApplicationUrl(launchProfile?.content, projectOutput, localFunctionSettings)
startAfterLaunch = launchProfile?.content?.launchBrowser == true
}
}
}
Loading
Loading