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

Interactive mode #165

Merged
merged 41 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9970af6
[add] boilerplate for interactive mode.
vmarcella Dec 14, 2023
36be07a
[update] parser to grab codeblock descriptions from the last paragraph.
vmarcella Dec 19, 2023
585a7ee
[add] inspect command before refactoring interactive mode for user in…
vmarcella Dec 20, 2023
44ba2a2
[update] interactive implementation to support commands & and command…
vmarcella Jan 5, 2024
965741b
[update] formatting for steps.
vmarcella Jan 5, 2024
0af5f88
[update] keyboard listening implementation to only listen for single …
vmarcella Jan 5, 2024
1ff75c5
[update] status updates for interactive and execute modes in the portal.
vmarcella Jan 10, 2024
61d63a2
Merge remote-tracking branch 'origin' into vmarcella/interactive-mode
vmarcella Jan 11, 2024
d22217b
[add] bubbletea + bubbles, rework interactive mode to use bubbletea, …
vmarcella Jan 16, 2024
81fbd3b
[update] synchronous commands and add old ui back for testing.
vmarcella Jan 22, 2024
26caf8e
[update] completion states for the entire scenario.
vmarcella Jan 22, 2024
12a662f
[add] a temporary global to allow for us to release control of stdin/…
vmarcella Jan 22, 2024
cff08fe
[update] tea program to use the alt mode again.
vmarcella Jan 22, 2024
a0e247b
[remove] commands & modules no longer needed.
vmarcella Jan 22, 2024
b1bbd9f
[remove] kubenertes commands.
vmarcella Jan 22, 2024
df5fab1
[update] increment to happen before the status update is executed.
vmarcella Jan 23, 2024
ebe732f
[update] status update to increment after successful execution and no…
vmarcella Jan 23, 2024
5c2259f
[update] interactive mode to clean environment variables after execut…
vmarcella Jan 23, 2024
95bc66f
[update] failed commands to immediately quit.
vmarcella Jan 23, 2024
2d9b775
[update] interactive to not use alt mode.
vmarcella Jan 23, 2024
1594045
[add] clear screen events to occur after window resizes.
vmarcella Jan 23, 2024
43914d2
Merge remote-tracking branch 'origin' into vmarcella/interactive-mode
vmarcella Jan 30, 2024
cbde7c4
[add] logging.
vmarcella Jan 31, 2024
87137f7
[add] the ability to go to previous/next commands.
vmarcella Feb 2, 2024
44a9a4b
[update] interactive mode initialization code to be less abstracted &…
vmarcella Feb 2, 2024
64e24df
[refactor] tea commands to be in their own module.
vmarcella Feb 5, 2024
140e65c
[add] scenario title to rendering output.
vmarcella Feb 7, 2024
d2a0de9
[add] glamour for rendering the step section with nice formatting, re…
vmarcella Feb 7, 2024
bc2f5ac
[remove] spacing.
vmarcella Feb 7, 2024
1404c56
Merge branch 'main' into vmarcella/interactive-mode
vmarcella Feb 7, 2024
868a629
[remove] clear screen command.
vmarcella Feb 14, 2024
23b601f
[fix] formatting for ssh doc, update clear screen to happen before wi…
vmarcella Feb 14, 2024
b13d9de
[update] clear screen command to use builtin.
vmarcella Feb 14, 2024
7a97ceb
[update] rendering to remove output when running in the portal.
vmarcella Feb 14, 2024
8469678
[update] spacing.
vmarcella Feb 14, 2024
b06aaee
[update] help.
vmarcella Feb 14, 2024
849566d
[add] executing section.
vmarcella Feb 14, 2024
c796b30
[add] more spacing.
vmarcella Feb 14, 2024
562f6c6
[update] step number to start at one.
vmarcella Feb 14, 2024
68af8f6
[update] step number to start at one.
vmarcella Feb 14, 2024
3dc88d7
[update] test.
vmarcella Feb 16, 2024
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
62 changes: 2 additions & 60 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build-ie build-api build-all run-ie run-api clean test-all test all
.PHONY: build-ie build-all run-ie clean test-all test all

BINARY_DIR := bin
IE_BINARY := $(BINARY_DIR)/ie
Expand All @@ -10,15 +10,8 @@ build-ie:
@echo "Building the Innovation Engine CLI..."
@CGO_ENABLED=0 go build -o "$(IE_BINARY)" cmd/ie/ie.go

build-api:
@echo "Building the Innovation Engine API..."
@CGO_ENABLED=0 go build -o "$(API_BINARY)" cmd/api/main.go

build-runner: build-ie build-api
@echo "Building the Innovation Engine Runner..."
@CGO_ENABLED=0 go build -o "$(BINARY_DIR)/runner" cmd/runner/main.go

build-all: build-ie build-api build-runner
build-all: build-ie

# ------------------------------ Install targets -------------------------------

Expand Down Expand Up @@ -67,58 +60,7 @@ run-ie: build-ie
@echo "Running the Innovation Engine CLI"
@"$(IE_BINARY)"

run-api: build-api
@echo "Running the Innovation Engine API"
@"$(API_BINARY)"

clean:
@echo "Cleaning up"
@rm -rf "$(BINARY_DIR)"

# ----------------------------- Docker targets ---------------------------------

API_IMAGE_TAG ?= latest

# Builds the API container.
build-api-container:
@echo "Building the Innovation Engine API container"
@docker build -t innovation-engine-api:$(API_IMAGE_TAG) -f infra/api/Dockerfile .


# ----------------------------- Kubernetes targets -----------------------------

# Applies the ingress controller to the cluster and waits for it to be ready.
k8s-deploy-ingress-controller:
@echo "Deploying the ingress controller to your local cluster..."
@kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.1/deploy/static/provider/cloud/deploy.yaml
@kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=120s

# Deploys the API deployment, service, and ingress specifications to the
# cluster, allowing the API to be accessed via the ingress controller.
k8s-deploy-api: build-api-container
@echo "Deploying the Innovation Engine API container to your local cluster..."
@kubectl apply -f infra/api/deployment.yaml
@kubectl apply -f infra/api/service.yaml
@kubectl apply -f infra/api/ingress.yaml

k8s-initialize-cluster: k8s-deploy-ingress-controller k8s-deploy-api
@echo "Set up Kubernetes cluster for local development."

k8s-delete-ingress-controller:
@echo "Deleting the ingress controller from your local cluster..."
@kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.1/deploy/static/provider/cloud/deploy.yaml

k8s-delete-api:
@echo "Deleting the Innovation Engine API container from your local cluster..."
@kubectl delete -f infra/api/deployment.yaml
@kubectl delete -f infra/api/service.yaml
@kubectl delete -f infra/api/ingress.yaml

k8s-refresh-api: k8s-delete-api k8s-deploy-api
@echo "Refreshed the Innovation Engine API container in your local cluster..."

k8s-delete-cluster: k8s-delete-api k8s-delete-ingress-controller
@echo "Deleted Kubernetes cluster for local development."

k8s-refresh-cluster: k8s-delete-cluster k8s-initialize-cluster
@echo "Refreshed Kubernetes cluster for local development."
55 changes: 0 additions & 55 deletions cmd/api/main.go

This file was deleted.

11 changes: 0 additions & 11 deletions cmd/api/types.go

This file was deleted.

109 changes: 109 additions & 0 deletions cmd/ie/commands/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package commands

import (
"fmt"
"os"
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/Azure/InnovationEngine/internal/ui"
"github.com/spf13/cobra"
)

// Register the command with our command runner.
func init() {
rootCommand.AddCommand(inspectCommand)

// String flags
inspectCommand.PersistentFlags().
String("correlation-id", "", "Adds a correlation ID to the user agent used by a scenarios azure-cli commands.")
inspectCommand.PersistentFlags().
String("subscription", "", "Sets the subscription ID used by a scenarios azure-cli commands. Will rely on the default subscription if not set.")
inspectCommand.PersistentFlags().
String("working-directory", ".", "Sets the working directory for innovation engine to operate out of. Restores the current working directory when finished.")

// StringArray flags
inspectCommand.PersistentFlags().
StringArray("var", []string{}, "Sets an environment variable for the scenario. Format: --var <key>=<value>")
}

var inspectCommand = &cobra.Command{
Use: "inspect",
Short: "Execute a document in inspect mode.",
Run: func(cmd *cobra.Command, args []string) {
markdownFile := args[0]
if markdownFile == "" {
logging.GlobalLogger.Errorf("Error: No markdown file specified.")
cmd.Help()
os.Exit(1)
}

environmentVariables, _ := cmd.Flags().GetStringArray("var")
// features, _ := cmd.Flags().GetStringArray("feature")

// Parse the environment variables from the command line into a map
cliEnvironmentVariables := make(map[string]string)
for _, environmentVariable := range environmentVariables {
keyValuePair := strings.SplitN(environmentVariable, "=", 2)
if len(keyValuePair) != 2 {
logging.GlobalLogger.Errorf(
"Error: Invalid environment variable format: %s",
environmentVariable,
)
fmt.Printf("Error: Invalid environment variable format: %s", environmentVariable)
cmd.Help()
os.Exit(1)
}

cliEnvironmentVariables[keyValuePair[0]] = keyValuePair[1]
}
// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-inspect", "terraform"},
cliEnvironmentVariables,
)
if err != nil {
logging.GlobalLogger.Errorf("Error creating scenario: %s", err)
fmt.Printf("Error creating scenario: %s", err)
os.Exit(1)
}

if err != nil {
logging.GlobalLogger.Errorf("Error creating engine: %s", err)
fmt.Printf("Error creating engine: %s", err)
os.Exit(1)
}

fmt.Println(ui.ScenarioTitleStyle.Render(scenario.Name))
for stepNumber, step := range scenario.Steps {
stepTitle := fmt.Sprintf(" %d. %s\n", stepNumber+1, step.Name)
fmt.Println(ui.StepTitleStyle.Render(stepTitle))
for codeBlockNumber, codeBlock := range step.CodeBlocks {
fmt.Println(
ui.InteractiveModeCodeBlockDescriptionStyle.Render(
fmt.Sprintf(
" %d.%d %s",
stepNumber+1,
codeBlockNumber+1,
codeBlock.Description,
),
),
)
fmt.Print(
ui.IndentMultiLineCommand(
fmt.Sprintf(
" %s",
ui.InteractiveModeCodeBlockStyle.Render(
codeBlock.Content,
),
),
6),
)
fmt.Println()
}
}

},
}
100 changes: 96 additions & 4 deletions cmd/ie/commands/interactive.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,107 @@
package commands

import (
"fmt"
"os"
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/spf13/cobra"
)

// Register the command with our command runner.
func init() {
rootCommand.AddCommand(interactiveCommand)

// String flags
interactiveCommand.PersistentFlags().
String("correlation-id", "", "Adds a correlation ID to the user agent used by a scenarios azure-cli commands.")
interactiveCommand.PersistentFlags().
String("subscription", "", "Sets the subscription ID used by a scenarios azure-cli commands. Will rely on the default subscription if not set.")
interactiveCommand.PersistentFlags().
String("working-directory", ".", "Sets the working directory for innovation engine to operate out of. Restores the current working directory when finished.")

// StringArray flags
interactiveCommand.PersistentFlags().
StringArray("var", []string{}, "Sets an environment variable for the scenario. Format: --var <key>=<value>")
}

var interactiveCommand = &cobra.Command{
Use: "interactive",
Short: "Execute a document in interactive mode.",
}
Run: func(cmd *cobra.Command, args []string) {
markdownFile := args[0]
if markdownFile == "" {
logging.GlobalLogger.Errorf("Error: No markdown file specified.")
cmd.Help()
os.Exit(1)
}

// / Register the command with our command runner.
func init() {
rootCommand.AddCommand(interactiveCommand)
verbose, _ := cmd.Flags().GetBool("verbose")
doNotDelete, _ := cmd.Flags().GetBool("do-not-delete")

subscription, _ := cmd.Flags().GetString("subscription")
correlationId, _ := cmd.Flags().GetString("correlation-id")
environment, _ := cmd.Flags().GetString("environment")
workingDirectory, _ := cmd.Flags().GetString("working-directory")

environmentVariables, _ := cmd.Flags().GetStringArray("var")
// features, _ := cmd.Flags().GetStringArray("feature")

// Known features
renderValues := false

// Parse the environment variables from the command line into a map
cliEnvironmentVariables := make(map[string]string)
for _, environmentVariable := range environmentVariables {
keyValuePair := strings.SplitN(environmentVariable, "=", 2)
if len(keyValuePair) != 2 {
logging.GlobalLogger.Errorf(
"Error: Invalid environment variable format: %s",
environmentVariable,
)
fmt.Printf("Error: Invalid environment variable format: %s", environmentVariable)
cmd.Help()
os.Exit(1)
}

cliEnvironmentVariables[keyValuePair[0]] = keyValuePair[1]
}
// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-interactive", "terraform"},
cliEnvironmentVariables,
)
if err != nil {
logging.GlobalLogger.Errorf("Error creating scenario: %s", err)
fmt.Printf("Error creating scenario: %s", err)
os.Exit(1)
}

innovationEngine, err := engine.NewEngine(engine.EngineConfiguration{
Verbose: verbose,
DoNotDelete: doNotDelete,
Subscription: subscription,
CorrelationId: correlationId,
Environment: environment,
WorkingDirectory: workingDirectory,
RenderValues: renderValues,
})

if err != nil {
logging.GlobalLogger.Errorf("Error creating engine: %s", err)
fmt.Printf("Error creating engine: %s", err)
os.Exit(1)
}

// Execute the scenario
err = innovationEngine.InteractWithScenario(scenario)
if err != nil {
logging.GlobalLogger.Errorf("Error executing scenario: %s", err)
fmt.Printf("Error executing scenario: %s", err)
os.Exit(1)
}
},
}
13 changes: 0 additions & 13 deletions cmd/runner/main.go

This file was deleted.

Loading
Loading