From 05371ad1a93d6c47428dab11124cbcbbcb39e8b3 Mon Sep 17 00:00:00 2001 From: Ata Sahin Date: Sat, 3 Jan 2026 02:16:51 +0300 Subject: [PATCH] Add --gha option to sbase mkdir --- examples/unit_tests/test_sb_mkdir.py | 183 +++++++++++++++++++ seleniumbase/console_scripts/ReadMe.md | 215 ++++++++++++----------- seleniumbase/console_scripts/run.py | 5 + seleniumbase/console_scripts/sb_mkdir.py | 96 +++++++++- 4 files changed, 395 insertions(+), 104 deletions(-) create mode 100644 examples/unit_tests/test_sb_mkdir.py diff --git a/examples/unit_tests/test_sb_mkdir.py b/examples/unit_tests/test_sb_mkdir.py new file mode 100644 index 00000000000..a6f7ee52fff --- /dev/null +++ b/examples/unit_tests/test_sb_mkdir.py @@ -0,0 +1,183 @@ +import os +import sys +import tempfile +import shutil +import yaml + + +def test_mkdir_with_gha_flag(): + from seleniumbase.console_scripts import sb_mkdir + import sys as sys_module + + original_argv = sys_module.argv + original_cwd = os.getcwd() + + temp_dir = tempfile.mkdtemp() + try: + os.chdir(temp_dir) + + test_dir = "test_gha_dir" + sys_module.argv = ["sbase", "mkdir", test_dir, "--gha"] + + sb_mkdir.main() + + workflow_file = os.path.join(test_dir, ".github", "workflows", "seleniumbase.yml") + assert os.path.exists(workflow_file), "Workflow file should be created" + + with open(workflow_file, "r") as f: + content = f.read() + + assert "name: SeleniumBase Tests" in content + assert "on:" in content + assert "push:" in content + assert "pull_request:" in content + assert "jobs:" in content + assert "test:" in content + assert "runs-on: ${{ matrix.os }}" in content + assert "strategy:" in content + assert "matrix:" in content + assert "python-version:" in content + assert "browser:" in content + assert "os:" in content + assert "actions/checkout@v3" in content + assert "actions/setup-python@v4" in content + assert "cache: 'pip'" in content + assert "pip install -r requirements.txt" in content + assert "pytest --browser=${{ matrix.browser }} --headless" in content + assert "actions/upload-artifact@v3" in content + assert "latest_logs/**" in content + + workflow_data = yaml.safe_load(content) + assert "on" in workflow_data + assert "jobs" in workflow_data + assert "test" in workflow_data["jobs"] + assert "steps" in workflow_data["jobs"]["test"] + + finally: + os.chdir(original_cwd) + sys_module.argv = original_argv + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + + +def test_mkdir_with_gha_custom_params(): + from seleniumbase.console_scripts import sb_mkdir + import sys as sys_module + + original_argv = sys_module.argv + original_cwd = os.getcwd() + + temp_dir = tempfile.mkdtemp() + try: + os.chdir(temp_dir) + + test_dir = "test_gha_custom" + sys_module.argv = [ + "sbase", "mkdir", test_dir, "--gha", + "--gha-browsers=chrome,firefox", + "--gha-python=3.10,3.11", + "--gha-os=ubuntu-latest,windows-latest" + ] + + sb_mkdir.main() + + workflow_file = os.path.join(test_dir, ".github", "workflows", "seleniumbase.yml") + assert os.path.exists(workflow_file), "Workflow file should be created" + + with open(workflow_file, "r") as f: + content = f.read() + + assert '"chrome"' in content + assert '"firefox"' in content + assert '"3.10"' in content + assert '"3.11"' in content + assert '"ubuntu-latest"' in content + assert '"windows-latest"' in content + + workflow_data = yaml.safe_load(content) + matrix = workflow_data["jobs"]["test"]["strategy"]["matrix"] + assert "chrome" in matrix["browser"] + assert "firefox" in matrix["browser"] + assert "3.10" in matrix["python-version"] + assert "3.11" in matrix["python-version"] + assert "ubuntu-latest" in matrix["os"] + assert "windows-latest" in matrix["os"] + + finally: + os.chdir(original_cwd) + sys_module.argv = original_argv + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + + +def test_mkdir_with_basic_and_gha(): + from seleniumbase.console_scripts import sb_mkdir + import sys as sys_module + + original_argv = sys_module.argv + original_cwd = os.getcwd() + + temp_dir = tempfile.mkdtemp() + try: + os.chdir(temp_dir) + + test_dir = "test_basic_gha" + sys_module.argv = ["sbase", "mkdir", test_dir, "--basic", "--gha"] + + sb_mkdir.main() + + workflow_file = os.path.join(test_dir, ".github", "workflows", "seleniumbase.yml") + assert os.path.exists(workflow_file), "Workflow file should be created with --basic --gha" + + requirements_file = os.path.join(test_dir, "requirements.txt") + assert os.path.exists(requirements_file), "requirements.txt should exist in basic mode" + + pytest_ini_file = os.path.join(test_dir, "pytest.ini") + assert os.path.exists(pytest_ini_file), "pytest.ini should exist in basic mode" + + test_files_exist = any( + f.endswith("_test.py") or f.startswith("test_") + for f in os.listdir(test_dir) + if os.path.isfile(os.path.join(test_dir, f)) + ) + assert not test_files_exist, "No test files should exist in basic mode" + + finally: + os.chdir(original_cwd) + sys_module.argv = original_argv + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + + +def test_mkdir_gha_workflow_already_exists_error(): + from seleniumbase.console_scripts import sb_mkdir + import sys as sys_module + + original_argv = sys_module.argv + original_cwd = os.getcwd() + + temp_dir = tempfile.mkdtemp() + try: + os.chdir(temp_dir) + + test_dir = "test_gha_exists" + os.makedirs(test_dir) + workflow_dir = os.path.join(test_dir, ".github", "workflows") + os.makedirs(workflow_dir, exist_ok=True) + workflow_file = os.path.join(workflow_dir, "seleniumbase.yml") + with open(workflow_file, "w") as f: + f.write("existing workflow") + + sys_module.argv = ["sbase", "mkdir", test_dir, "--gha"] + try: + sb_mkdir.main() + assert False, "Should raise an error when directory already exists" + except Exception as e: + assert "already exists" in str(e).lower() or "ERROR" in str(e) + + finally: + os.chdir(original_cwd) + sys_module.argv = original_argv + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir) + diff --git a/seleniumbase/console_scripts/ReadMe.md b/seleniumbase/console_scripts/ReadMe.md index 53c89351c2e..15113159978 100644 --- a/seleniumbase/console_scripts/ReadMe.md +++ b/seleniumbase/console_scripts/ReadMe.md @@ -4,11 +4,11 @@ 🌟 SeleniumBase console scripts can do many things, such as downloading web drivers, creating test directories with config files, activating the SeleniumBase Recorder, launching the SeleniumBase Commander, translating tests into other languages, running a Selenium Grid, and more. -* Usage: ``seleniumbase [COMMAND] [PARAMETERS]`` +- Usage: `seleniumbase [COMMAND] [PARAMETERS]` -* (simplified): ``sbase [COMMAND] [PARAMETERS]`` +- (simplified): `sbase [COMMAND] [PARAMETERS]` -* To list all commands: ``seleniumbase --help`` +- To list all commands: `seleniumbase --help` (For running tests, [use pytest with SeleniumBase](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md).) @@ -50,14 +50,14 @@ COMMANDS:

get / install

-* Usage: +- Usage: ```zsh sbase get [DRIVER] [OPTIONS] sbase install [DRIVER] [OPTIONS] ``` -* Examples: +- Examples: ```zsh sbase get chromedriver @@ -73,41 +73,41 @@ sbase get cft 131 sbase get chs ``` -(Drivers: ``chromedriver``, ``cft``, ``uc_driver``, - ``edgedriver``, ``chs``, ``geckodriver``) +(Drivers: `chromedriver`, `cft`, `uc_driver`, +`edgedriver`, `chs`, `geckodriver`) -(Options: A specific driver version or major version integer. - If not set, the driver version matches the browser. - ``-p`` / ``--path``: Also copy to "/usr/local/bin".) +(Options: A specific driver version or major version integer. +If not set, the driver version matches the browser. +`-p` / `--path`: Also copy to "/usr/local/bin".) -* Output: +- Output: -Downloads the webdriver to ``seleniumbase/drivers/`` -(``chromedriver`` is required for Chrome automation) -(``geckodriver`` is required for Firefox automation) -(``edgedriver`` is required for MS__Edge automation) +Downloads the webdriver to `seleniumbase/drivers/` +(`chromedriver` is required for Chrome automation) +(`geckodriver` is required for Firefox automation) +(`edgedriver` is required for MS\_\_Edge automation)

methods

-* Usage: +- Usage: ```zsh sbase methods ``` -* Output: +- Output: Displays common SeleniumBase Python methods.

options

-* Usage: +- Usage: ```zsh sbase options ``` -* Output: +- Output: Displays common pytest command-line options that are available when using SeleniumBase. @@ -168,13 +168,13 @@ For the full list of command-line options, type: "pytest --help".

behave-options

-* Usage: +- Usage: ```zsh sbase behave-options ``` -* Output: +- Output: Displays common Behave command-line options that are available when using SeleniumBase. @@ -226,7 +226,7 @@ For the full list of command-line options, type: "behave --help".

gui / commander

-* Usage: +- Usage: ```zsh sbase gui [OPTIONAL PATH or TEST FILE] @@ -235,14 +235,14 @@ sbase commander [OPTIONAL PATH or TEST FILE]

behave-gui

-* Usage: +- Usage: ```zsh sbase behave-gui [OPTIONAL PATH or TEST FILE] sbase gui-behave [OPTIONAL PATH or TEST FILE] ``` -* Examples: +- Examples: ```zsh sbase behave-gui @@ -251,19 +251,19 @@ sbase behave-gui features/ sbase behave-gui features/calculator.feature ``` -* Output: +- Output: Launches SeleniumBase Commander / GUI for Behave.

caseplans

-* Usage: +- Usage: ```zsh sbase caseplans [OPTIONAL PATH or TEST FILE] ``` -* Examples: +- Examples: ```zsh sbase caseplans @@ -273,31 +273,44 @@ sbase caseplans test_suite.py sbase caseplans offline_examples/ ``` -* Output: +- Output: Launches the SeleniumBase Case Plans Generator.

mkdir

-* Usage: +- Usage: ```zsh sbase mkdir [DIRECTORY] [OPTIONS] ``` -* Example: +- Example: ```zsh sbase mkdir ui_tests ``` -* Options: +- Options: ```zsh -b / --basic (Only config files. No tests added.) +--gha / --github-actions (Generate GitHub Actions workflow) +--gha-browsers=BROWSERS (Comma-separated browsers, default: chrome) +--gha-python=VERSIONS (Comma-separated Python versions, default: 3.11) +--gha-os=OS_LIST (Comma-separated OS list, default: ubuntu-latest) ``` -* Output: +- Examples: + +```zsh +sbase mkdir ui_tests +sbase mkdir ui_tests --gha +sbase mkdir ui_tests --gha --gha-browsers=chrome,firefox --gha-python=3.10,3.11,3.12 +sbase mkdir ui_tests --basic --gha +``` + +- Output: Creates a new folder for running SBase scripts. The new folder contains default config files, @@ -329,7 +342,7 @@ ui_tests/ └── swag_labs_test.py ``` -If running with the ``-b`` or ``--basic`` option: +If running with the `-b` or `--basic` option: ```zsh ui_tests/ @@ -341,19 +354,19 @@ ui_tests/

mkfile

-* Usage: +- Usage: ```zsh sbase mkfile [FILE.py] [OPTIONS] ``` -* Example: +- Example: ```zsh sbase mkfile new_test.py ``` -* Options: +- Options: ```zsh --uc (UC Mode boilerplate using SB context manager) @@ -362,7 +375,7 @@ sbase mkfile new_test.py --url=URL (Makes the test start on a specific page) ``` -* Language Options: +- Language Options: ```zsh --en / --English | --zh / --Chinese @@ -372,7 +385,7 @@ sbase mkfile new_test.py --ru / --Russian | --es / --Spanish ``` -* Syntax Formats: +- Syntax Formats: ```zsh --bc / --basecase (BaseCase class inheritance) @@ -383,7 +396,7 @@ sbase mkfile new_test.py --dm / --driver-manager (Driver manager) ``` -* Output: +- Output: Creates a new SBase test file with boilerplate code. If the file already exists, an error is raised. @@ -397,14 +410,14 @@ UC Mode automatically uses English with SB() format.

mkrec / record / codegen

-* Usage: +- Usage: ```zsh sbase mkrec [FILE.py] [OPTIONS] sbase codegen [FILE.py] [OPTIONS] ``` -* Examples: +- Examples: ```zsh sbase mkrec new_test.py @@ -413,7 +426,7 @@ sbase codegen new_test.py sbase codegen new_test.py --url=wikipedia.org ``` -* Options: +- Options: ```zsh --url=URL (Sets the initial start page URL.) @@ -425,45 +438,45 @@ sbase codegen new_test.py --url=wikipedia.org --behave (Also output Behave/Gherkin files.) ``` -* Output: +- Output: Creates a new SeleniumBase test using the Recorder. If the filename already exists, an error is raised.

recorder

-* Usage: +- Usage: ```zsh sbase recorder [OPTIONS] ``` -* Options: +- Options: ```zsh --uc / --undetected (Use undetectable mode.) --behave (Also output Behave/Gherkin files.) ``` -* Output: +- Output: Launches the SeleniumBase Recorder Desktop App.

mkpres

-* Usage: +- Usage: ```zsh sbase mkpres [FILE.py] [LANG] ``` -* Example: +- Example: ```zsh sbase mkpres new_presentation.py --en ``` -* Language Options: +- Language Options: ```zsh --en / --English | --zh / --Chinese @@ -473,7 +486,7 @@ sbase mkpres new_presentation.py --en --ru / --Russian | --es / --Spanish ``` -* Output: +- Output: Creates a new presentation with 3 example slides. If the file already exists, an error is raised. @@ -483,19 +496,19 @@ The slides can be used as a basic boilerplate.

mkchart

-* Usage: +- Usage: ```zsh sbase mkchart [FILE.py] [LANG] ``` -* Example: +- Example: ```zsh sbase mkchart new_chart.py --en ``` -* Language Options: +- Language Options: ```zsh --en / --English | --zh / --Chinese @@ -505,7 +518,7 @@ sbase mkchart new_chart.py --en --ru / --Russian | --es / --Spanish ``` -* Output: +- Output: Creates a new SeleniumBase chart presentation. If the file already exists, an error is raised. @@ -515,32 +528,32 @@ The chart can be used as a basic boilerplate.

print

-* Usage: +- Usage: ```zsh sbase print [FILE] [OPTIONS] ``` -* Options: +- Options: ```zsh -n (Add line Numbers to the rows) ``` -* Output: +- Output: Prints the code/text of any file with syntax-highlighting.

translate

-* Usage: +- Usage: ```zsh sbase translate [SB_FILE.py] [LANGUAGE] [ACTION] ``` -* Languages: +- Languages: ```zsh --en / --English | --zh / --Chinese @@ -550,7 +563,7 @@ sbase translate [SB_FILE.py] [LANGUAGE] [ACTION] --ru / --Russian | --es / --Spanish ``` -* Actions: +- Actions: ```zsh -p / --print (Print translation output to the screen) @@ -558,33 +571,33 @@ sbase translate [SB_FILE.py] [LANGUAGE] [ACTION] -c / --copy (Copy the translation to a new ``.py`` file) ``` -* Options: +- Options: ```zsh -n (include line Numbers when using the Print action) ``` -* Output: +- Output: Translates a SeleniumBase Python file into the language specified. Method calls and "import" lines get swapped. Both a language and an action must be specified. -The ``-p`` action can be paired with one other action. -When running with ``-c`` (or ``--copy``), the new file name +The `-p` action can be paired with one other action. +When running with `-c` (or `--copy`), the new file name will be the original name appended with an underscore plus the 2-letter language code of the new language. (Example: Translating "test_1.py" into Japanese with -``-c`` will create a new file called "test_1_ja.py".) +`-c` will create a new file called "test_1_ja.py".)

extract-objects

-* Usage: +- Usage: ```zsh sbase extract-objects [SB_FILE.py] ``` -* Output: +- Output: Creates page objects based on selectors found in a seleniumbase Python file and saves those objects to the @@ -592,19 +605,19 @@ seleniumbase Python file and saves those objects to the

inject-objects

-* Usage: +- Usage: ```zsh sbase inject-objects [SB_FILE.py] [OPTIONS] ``` -* Options: +- Options: ```zsh -c / --comments (Add object selectors to the comments.) ``` -* Output: +- Output: Takes the page objects found in the "page_objects.py" file and uses those to replace matching selectors in @@ -612,93 +625,93 @@ the selected seleniumbase Python file.

objectify

-* Usage: +- Usage: ```zsh sbase objectify [SB_FILE.py] [OPTIONS] ``` -* Options: +- Options: ```zsh -c / --comments (Add object selectors to the comments.) ``` -* Output: +- Output: A modified version of the file where the selectors have been replaced with variable names defined in "page_objects.py", supporting the Page Object Pattern. (This has the same outcome as combining -``extract-objects`` with ``inject-objects``) +`extract-objects` with `inject-objects`)

revert-objects

-* Usage: +- Usage: ```zsh sbase revert-objects [SB_FILE.py] [OPTIONS] ``` -* Options: +- Options: ```zsh -c / --comments (Keep existing comments for the lines.) ``` -* Output: +- Output: -Reverts the changes made by ``seleniumbase objectify ...`` or -``seleniumbase inject-objects ...`` when run against a +Reverts the changes made by `seleniumbase objectify ...` or +`seleniumbase inject-objects ...` when run against a seleniumbase Python file. Objects will get replaced by selectors stored in the "page_objects.py" file.

convert

-* Usage: +- Usage: ```zsh sbase convert [WEBDRIVER_UNITTEST_FILE.py] ``` -* Output: +- Output: Converts a Selenium IDE exported WebDriver unittest -file into a SeleniumBase file. Adds ``_SB`` to the +file into a SeleniumBase file. Adds `_SB` to the new filename while keeping the original file intact. Works on both Selenium IDE & Katalon Recorder scripts.

encrypt / obfuscate

-* Usage: +- Usage: -``sbase encrypt`` / ``sbase obfuscate`` +`sbase encrypt` / `sbase obfuscate` -* Output: +- Output: Runs the password encryption/obfuscation tool. (Where you can enter a password to encrypt/obfuscate.)

decrypt / unobfuscate

-* Usage: +- Usage: -``sbase decrypt`` / ``sbase unobfuscate`` +`sbase decrypt` / `sbase unobfuscate` -* Output: +- Output: Runs the password decryption/unobfuscation tool. (Where you can enter an encrypted password to decrypt.)

proxy

-* Usage: +- Usage: ```zsh sbase proxy [OPTIONS] ``` -* Options: +- Options: ```zsh --hostname=HOSTNAME (Set `hostname`) (Default: `127.0.0.1`) @@ -706,40 +719,40 @@ sbase proxy [OPTIONS] --help / -h (Display available `proxy` options.) ``` -* Output: +- Output: Launch a basic proxy server on the current machine. -(Uses ``127.0.0.1:8899`` as the default address.) +(Uses `127.0.0.1:8899` as the default address.)

download

-* Usage: +- Usage: ```zsh sbase download server ``` -* Output: +- Output: Downloads the Selenium Server JAR file for Grid usage. (That JAR file is required when using a Selenium Grid)

grid-hub

-* Usage: +- Usage: ```zsh sbase grid-hub [start|stop|restart] [OPTIONS] ``` -* Options: +- Options: ```zsh -v / --verbose (Increases verbosity of logging output.) --timeout=TIMEOUT (Close idle browser windows after TIMEOUT seconds.) ``` -* Output: +- Output: Controls the Selenium Grid Hub server, which allows for running tests on multiple machines in parallel @@ -749,25 +762,25 @@ You can start, restart, or stop the Grid Hub server.

grid-node

-* Usage: +- Usage: ```zsh sbase grid-node [start|stop|restart] [OPTIONS] ``` -* Options: +- Options: ```zsh --hub=HUB_IP (Grid Hub IP Address. Default: `127.0.0.1`) -v / --verbose (Increases verbosity of logging output.) ``` -* Output: +- Output: Controls the Selenium Grid node, which serves as a worker machine for your Selenium Grid Hub server. You can start, restart, or stop the Grid node. --------- +--- diff --git a/seleniumbase/console_scripts/run.py b/seleniumbase/console_scripts/run.py index b11305d9846..938f4ff93f2 100644 --- a/seleniumbase/console_scripts/run.py +++ b/seleniumbase/console_scripts/run.py @@ -246,8 +246,13 @@ def show_mkdir_usage(): print(" OR: sbase mkdir [DIRECTORY] [OPTIONS]") print(" Example:") print(" sbase mkdir ui_tests") + print(" sbase mkdir ui_tests --gha") print(" Options:") print(" -b / --basic (Only config files. No tests added.)") + print(" --gha / --github-actions (Generate GitHub Actions workflow)") + print(" --gha-browsers=BROWSERS (Comma-separated browsers, default: chrome)") + print(" --gha-python=VERSIONS (Comma-separated Python versions, default: 3.11)") + print(" --gha-os=OS_LIST (Comma-separated OS list, default: ubuntu-latest)") print(" Output:") print(" Creates a new folder for running SBase scripts.") print(" The new folder contains default config files,") diff --git a/seleniumbase/console_scripts/sb_mkdir.py b/seleniumbase/console_scripts/sb_mkdir.py index 0caa4f01a35..103a99a2a32 100644 --- a/seleniumbase/console_scripts/sb_mkdir.py +++ b/seleniumbase/console_scripts/sb_mkdir.py @@ -23,6 +23,62 @@ import sys +def generate_github_actions_workflow(python_versions, browsers, os_versions): + python_list = [v.strip() for v in python_versions.split(",")] + browser_list = [b.strip() for b in browsers.split(",")] + os_list = [o.strip() for o in os_versions.split(",")] + + workflow_lines = [] + workflow_lines.append("name: SeleniumBase Tests") + workflow_lines.append("") + workflow_lines.append("on:") + workflow_lines.append(" push:") + workflow_lines.append(" pull_request:") + workflow_lines.append("") + workflow_lines.append("jobs:") + workflow_lines.append(" test:") + workflow_lines.append(" runs-on: ${{ matrix.os }}") + workflow_lines.append(" strategy:") + workflow_lines.append(" fail-fast: false") + workflow_lines.append(" matrix:") + workflow_lines.append(" python-version:") + for py_ver in python_list: + workflow_lines.append(' - "%s"' % py_ver) + workflow_lines.append(" browser:") + for browser in browser_list: + workflow_lines.append(' - "%s"' % browser) + workflow_lines.append(" os:") + for os_ver in os_list: + workflow_lines.append(' - "%s"' % os_ver) + workflow_lines.append("") + workflow_lines.append(" steps:") + workflow_lines.append(" - uses: actions/checkout@v3") + workflow_lines.append(" - name: Set up Python ${{ matrix.python-version }}") + workflow_lines.append(" uses: actions/setup-python@v4") + workflow_lines.append(" with:") + workflow_lines.append(" python-version: ${{ matrix.python-version }}") + workflow_lines.append(" cache: 'pip'") + workflow_lines.append(" - name: Install dependencies") + workflow_lines.append(" run: |") + workflow_lines.append(" python -m pip install --upgrade pip") + workflow_lines.append(" pip install -r requirements.txt") + workflow_lines.append(" - name: Run tests with ${{ matrix.browser }}") + workflow_lines.append(" run: pytest --browser=${{ matrix.browser }} --headless") + workflow_lines.append(" - name: Upload artifacts on failure") + workflow_lines.append(" if: failure()") + workflow_lines.append(" uses: actions/upload-artifact@v3") + workflow_lines.append(" with:") + workflow_lines.append(" name: test-artifacts-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.browser }}") + workflow_lines.append(" path: |") + workflow_lines.append(" latest_logs/**") + workflow_lines.append(" logs/**") + workflow_lines.append(" archived_logs/**") + workflow_lines.append(" screenshots/**") + workflow_lines.append("") + + return "\n".join(workflow_lines) + + def invalid_run_command(msg=None): exp = " ** mkdir **\n\n" exp += " Usage:\n" @@ -30,8 +86,13 @@ def invalid_run_command(msg=None): exp += " OR sbase mkdir [DIRECTORY] [OPTIONS]\n" exp += " Example:\n" exp += " sbase mkdir ui_tests\n" + exp += " sbase mkdir ui_tests --gha\n" exp += " Options:\n" exp += " -b / --basic (Only config files. No tests added.)\n" + exp += " --gha / --github-actions (Generate GitHub Actions workflow)\n" + exp += " --gha-browsers=BROWSERS (Comma-separated browsers, default: chrome)\n" + exp += " --gha-python=VERSIONS (Comma-separated Python versions, default: 3.11)\n" + exp += " --gha-os=OS_LIST (Comma-separated OS list, default: ubuntu-latest)\n" exp += " Output:\n" exp += " Creates a new folder for running SBase scripts.\n" exp += " The new folder contains default config files,\n" @@ -59,6 +120,10 @@ def main(): cr = colorama.Style.RESET_ALL basic = False + gha = False + gha_browsers = "chrome" + gha_python = "3.11" + gha_os = "ubuntu-latest" help_me = False error_msg = None invalid_cmd = None @@ -84,11 +149,19 @@ def main(): if len(command_args) >= 2: options = command_args[1:] for option in options: - option = option.lower() - if option == "-h" or option == "--help": + option_lower = option.lower() + if option_lower == "-h" or option_lower == "--help": help_me = True - elif option == "-b" or option == "--basic": + elif option_lower == "-b" or option_lower == "--basic": basic = True + elif option_lower == "--gha" or option_lower == "--github-actions": + gha = True + elif option_lower.startswith("--gha-browsers="): + gha_browsers = option[len("--gha-browsers="):] + elif option_lower.startswith("--gha-python="): + gha_python = option[len("--gha-python="):] + elif option_lower.startswith("--gha-os="): + gha_os = option[len("--gha-os="):] else: invalid_cmd = "\n===> INVALID OPTION: >> %s <<\n" % option invalid_cmd = invalid_cmd.replace(">> ", ">>" + c5 + " ") @@ -321,6 +394,23 @@ def main(): file.writelines("\r\n".join(data)) file.close() + if gha: + workflow_dir = "%s/.github/workflows" % dir_name + workflow_file = "%s/seleniumbase.yml" % workflow_dir + if os.path.exists(workflow_file): + error_msg = ( + 'Workflow file "%s" already exists!' % workflow_file + ) + error_msg = c5 + "ERROR: " + error_msg + cr + invalid_run_command(error_msg) + os.makedirs(workflow_dir, exist_ok=True) + workflow_content = generate_github_actions_workflow( + gha_python, gha_browsers, gha_os + ) + file = open(workflow_file, mode="w+", encoding="utf-8") + file.write(workflow_content) + file.close() + if basic: data = [] data.append(" %s/" % dir_name)