-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Piotr <piotrzan@gmail.com>
- Loading branch information
Showing
5 changed files
with
227 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import json | ||
import os | ||
import inquirer | ||
|
||
# Define environment and backend options | ||
environments = { | ||
"ubuntu": "Ubuntu 20.04 with Docker and Podman", | ||
"ubuntu-4GB": "Ubuntu 20.04 with Docker and Podman, 4GB environment", | ||
"kubernetes-kubeadm-1node": "Kubeadm cluster with one control plane, taint removed, ready to schedule workload, 2GB environment", | ||
"kubernetes-kubeadm-1node-4GB": "Kubeadm cluster with one control plane, taint removed, ready to schedule workload, 4GB environment", | ||
"kubernetes-kubeadm-2nodes": "Kubeadm cluster with one control plane and one node, ready to schedule workload, 4GB environment" | ||
} | ||
|
||
backends = { | ||
"kubernetes-kubeadm-1node": "Kubernetes kubeadm 1 node", | ||
"kubernetes-kubeadm-2nodes": "Kubernetes kubeadm 2 nodes", | ||
"ubuntu": "Ubuntu 20.04" | ||
} | ||
|
||
time_choices = [f"{i} minutes" for i in range(15, 50, 5)] | ||
difficulty_choices = ["beginner", "intermediate", "advanced"] | ||
|
||
def get_value(prompt, value_type, choices=None): | ||
if choices: | ||
question = [inquirer.List('choice', message=prompt, choices=choices)] | ||
answer = inquirer.prompt(question) | ||
return answer['choice'] | ||
else: | ||
if value_type == "boolean": | ||
question = [inquirer.Confirm('confirm', message=prompt, default=True)] | ||
answer = inquirer.prompt(question) | ||
return answer['confirm'] | ||
else: | ||
question = [inquirer.Text('value', message=prompt)] | ||
answer = inquirer.prompt(question) | ||
return answer['value'] | ||
|
||
def populate_schema(schema, parent_key=""): | ||
result = {} | ||
for key, value_type in schema.items(): | ||
full_key = f"{parent_key}.{key}" if parent_key else key | ||
if isinstance(value_type, dict): | ||
result[key] = populate_schema(value_type, full_key) | ||
elif isinstance(value_type, list): | ||
if full_key == "details.steps" or full_key == "details.assets.host01": | ||
result[key] = [] # Initialize as empty list | ||
else: | ||
result[key] = [] | ||
while True: | ||
add_item = get_value(f"Do you want to add an item to the list '{full_key}'?", "boolean") | ||
if add_item: | ||
result[key].append(populate_schema(value_type[0], full_key)) | ||
else: | ||
break | ||
else: | ||
if full_key == "time": | ||
result[key] = get_value(f"Select value for {full_key}", value_type, time_choices) | ||
elif full_key == "difficulty": | ||
result[key] = get_value(f"Select value for {full_key}", value_type, difficulty_choices) | ||
elif full_key == "backend.imageid": | ||
result[key] = get_value(f"Select value for {full_key}", value_type, backends) | ||
else: | ||
result[key] = get_value(f"Enter value for {full_key}", value_type) | ||
return result | ||
|
||
def init_project(): | ||
"""initialize a new project by creating index.json file""" | ||
if os.path.exists("index.json"): | ||
print("The 'index.json' file already exists. Please edit the existing file.") | ||
return | ||
|
||
schema = { | ||
"title": "string", | ||
"description": "string", | ||
"difficulty": "string", | ||
"time": "string", | ||
"details": { | ||
"steps": [ | ||
{} | ||
], | ||
"assets": { | ||
"host01": [ | ||
{} | ||
] | ||
} | ||
}, | ||
"backend": { | ||
"imageid": "string" | ||
} | ||
} | ||
|
||
populated_data = populate_schema(schema) | ||
|
||
# Set static values for intro and finish | ||
populated_data["details"]["intro"] = {"text": "intro.md"} | ||
populated_data["details"]["finish"] = {"text": "finish.md"} | ||
|
||
if get_value("Do you want to enable Theia?", "boolean"): | ||
populated_data["interface"] = {"layout": "ide"} | ||
|
||
with open("index.json", "w") as index_file: | ||
json.dump(populated_data, index_file, ensure_ascii=False, indent=4) | ||
|
||
# Create intro.md and finish.md if they don't exist | ||
if not os.path.exists("intro.md"): | ||
with open("intro.md", "w") as intro_file: | ||
intro_file.write("# Introduction\n") | ||
|
||
if not os.path.exists("finish.md"): | ||
with open("finish.md", "w") as finish_file: | ||
finish_file.write("# Finish\n") | ||
|
||
print("Project initialized successfully. Please edit the 'index.json' file to add steps.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import unittest | ||
from unittest import mock | ||
from unittest.mock import patch | ||
from killercoda_cli import scenario_init | ||
|
||
class TestScenarioInit(unittest.TestCase): | ||
|
||
@patch("inquirer.prompt") | ||
@patch("os.path.exists", return_value=False) | ||
@patch("builtins.open", new_callable=mock.mock_open) | ||
@patch("json.dump") | ||
def test_init_project(self, mock_json_dump, mock_open, mock_exists, mock_prompt): | ||
mock_prompt.side_effect = [ | ||
{'value': 'Project Title'}, | ||
{'value': 'Project Description'}, | ||
{'choice': 'beginner'}, | ||
{'choice': '15 minutes'}, | ||
{'choice': 'kubernetes-kubeadm-1node'}, | ||
{'confirm': True} | ||
] | ||
|
||
scenario_init.init_project() | ||
|
||
expected_data = { | ||
"title": "Project Title", | ||
"description": "Project Description", | ||
"difficulty": "beginner", | ||
"time": "15 minutes", | ||
"details": { | ||
"intro": {"text": "intro.md"}, | ||
"finish": {"text": "finish.md"}, | ||
"steps": [], | ||
"assets": {"host01": []} | ||
}, | ||
"backend": {"imageid": "kubernetes-kubeadm-1node"}, | ||
"interface": {"layout": "ide"} | ||
} | ||
|
||
# Check that the index.json file was created with the expected data | ||
calls = [ | ||
mock.call("index.json", "w"), | ||
mock.call("intro.md", "w"), | ||
mock.call("finish.md", "w") | ||
] | ||
mock_open.assert_has_calls(calls, any_order=True) | ||
mock_json_dump.assert_called_once_with(expected_data, mock.ANY, ensure_ascii=False, indent=4) | ||
|
||
@patch("os.path.exists", return_value=True) | ||
@patch("builtins.print") | ||
def test_init_project_existing_index(self, mock_print, mock_exists): | ||
scenario_init.init_project() | ||
mock_print.assert_called_once_with("The 'index.json' file already exists. Please edit the existing file.") | ||
|
||
@patch("os.path.exists", side_effect=lambda path: path == "intro.md") | ||
@patch("builtins.open", new_callable=mock.mock_open) | ||
@patch("inquirer.prompt") | ||
def test_init_project_create_finish_md(self, mock_prompt, mock_open, mock_exists): | ||
mock_prompt.side_effect = [ | ||
{'value': 'Project Title'}, | ||
{'value': 'Project Description'}, | ||
{'choice': 'beginner'}, | ||
{'choice': '15 minutes'}, | ||
{'choice': 'kubernetes-kubeadm-1node'}, | ||
{'confirm': True} | ||
] | ||
|
||
scenario_init.init_project() | ||
mock_open.assert_any_call("finish.md", "w") | ||
mock_open().write.assert_any_call("# Finish\n") | ||
|
||
@patch("os.path.exists", side_effect=lambda path: path == "finish.md") | ||
@patch("builtins.open", new_callable=mock.mock_open) | ||
@patch("inquirer.prompt") | ||
def test_init_project_create_intro_md(self, mock_prompt, mock_open, mock_exists): | ||
mock_prompt.side_effect = [ | ||
{'value': 'Project Title'}, | ||
{'value': 'Project Description'}, | ||
{'choice': 'beginner'}, | ||
{'choice': '15 minutes'}, | ||
{'choice': 'kubernetes-kubeadm-1node'}, | ||
{'confirm': True} | ||
] | ||
|
||
scenario_init.init_project() | ||
mock_open.assert_any_call("intro.md", "w") | ||
mock_open().write.assert_any_call("# Introduction\n") | ||
|
||
@patch("os.path.exists", return_value=False) | ||
@patch("builtins.open", new_callable=mock.mock_open) | ||
@patch("json.dump") | ||
@patch("inquirer.prompt") | ||
def test_init_project_files_created(self, mock_prompt, mock_json_dump, mock_open, mock_exists): | ||
mock_prompt.side_effect = [ | ||
{'value': 'Project Title'}, | ||
{'value': 'Project Description'}, | ||
{'choice': 'beginner'}, | ||
{'choice': '15 minutes'}, | ||
{'choice': 'kubernetes-kubeadm-1node'}, | ||
{'confirm': True} | ||
] | ||
|
||
scenario_init.init_project() | ||
mock_open.assert_any_call("intro.md", "w") | ||
mock_open().write.assert_any_call("# Introduction\n") | ||
mock_open.assert_any_call("finish.md", "w") | ||
mock_open().write.assert_any_call("# Finish\n") | ||
|
||
if __name__ == "__main__": | ||
unittest.main() |