Skip to content
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
14 changes: 10 additions & 4 deletions .github/workflows/chores.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,20 @@ jobs:
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git switch -c "update-sfdc-api-v$VERSION"
git switch -C "update-sfdc-api-v$VERSION"
git add cumulusci/cumulusci.yml
git commit -m "Automated update to sfdc API version $VERSION"
git push origin "update-sfdc-api-v$VERSION"
- env:
git push --force-with-lease origin "update-sfdc-api-v$VERSION"
- name: Create or update PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr create --fill --label 'auto-pr'
existing_pr=$(gh pr list --head "update-sfdc-api-v$VERSION" --json number -q '.[0].number')
if [ -n "$existing_pr" ]; then
echo "PR #$existing_pr already exists for update-sfdc-api-v$VERSION"
else
gh pr create --fill --label 'auto-pr'
fi
test_sfdx_release_candidate:
uses: ./.github/workflows/release_test_sfdx.yml
with:
Expand Down
16 changes: 9 additions & 7 deletions .github/workflows/feature_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Set up Python 3.11
- name: Set up Python 3.13
id: py
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
- name: Set up uv
uses: SFDO-Tooling/setup-uv@v8.0.0-sfdo.1
with:
Expand All @@ -42,11 +42,12 @@ jobs:
unit_tests:
name: "Unit tests: ${{ matrix.os }}-${{ matrix.python-version }}"
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.python-version == '3.14' }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, SFDO-Tooling-Ubuntu, SFDO-Tooling-Windows]
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand All @@ -66,11 +67,12 @@ jobs:
unit_tests_opt_deps:
name: "Unit tests with optional dependencies: ${{ matrix.os }}-${{ matrix.python-version }}"
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.python-version == '3.14' }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, SFDO-Tooling-Ubuntu, SFDO-Tooling-Windows]
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand All @@ -92,17 +94,17 @@ jobs:
runs-on: SFDO-Tooling-Ubuntu
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
- name: Set up uv
uses: SFDO-Tooling/setup-uv@v8.0.0-sfdo.1
with:
version: "0.8.4"
enable-cache: true
- name: Install dependencies
run: uv sync -p 3.11
run: uv sync -p 3.13
- name: Install sfdx
run: |
mkdir sfdx
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ jobs:
runs-on: SFDO-Tooling-Ubuntu
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
cache: pip
- name: Install build tool
run: python -m pip install hatch
Expand Down Expand Up @@ -54,7 +54,7 @@ jobs:
python utility/update-history.py
- name: Lint history
run: |
npm install prettier
npm install prettier@3
npx prettier --write docs/history.md
- name: Commit changes
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
runs-on: SFDO-Tooling-Ubuntu
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
cache: pip
- name: Install build tools
run: python -m pip install hatch tomli tomli-w
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
runs-on: SFDO-Tooling-Ubuntu
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
cache: pip
cache-dependency-path: "pyproject.toml"
- name: Install build tools
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release_test_sfdx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ jobs:
concurrency: release
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
- name: Set up uv
uses: SFDO-Tooling/setup-uv@v8.0.0-sfdo.1
with:
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/slow_integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ jobs:
runs-on: SFDO-Tooling-Ubuntu
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
- name: Set up uv
uses: SFDO-Tooling/setup-uv@v8.0.0-sfdo.1
with:
version: "0.8.4"
enable-cache: true
- name: Install dependencies
run: uv sync -p 3.11
run: uv sync -p 3.13
- name: Install Salesforce CLI
run: |
mkdir sfdx
Expand Down Expand Up @@ -74,17 +74,17 @@ jobs:
# org-shape: "prerelease"
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.13
- name: Set up uv
uses: SFDO-Tooling/setup-uv@v8.0.0-sfdo.1
with:
version: "0.8.4"
enable-cache: true
- name: Install Python dependencies
run: uv sync -p 3.11
run: uv sync -p 3.13
- name: Install Salesforce CLI
run: |
mkdir sfdx
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update_dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ jobs:
update_python_dependencies:
uses: SFDO-Tooling/.github/.github/workflows/update_python_dependencies.yml@main
with:
python-version: 3.11
python-version: 3.13
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# OS cruft
.DS_Store

# Git worktrees
.worktrees/

# CumulusCI config and output
.cci
docs/api/
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ repos:
- id: isort
args: ["--profile", "black", "--filter-files"]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.5.1
rev: v3.1.0
hooks:
- id: prettier
- repo: local
Expand Down
6 changes: 5 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
Test*.yaml
Test*.yaml
docs/diagram/
**/*.min.js
**/*.min.css
cumulusci/files/templates/
2 changes: 1 addition & 1 deletion cumulusci/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "4.9.0"
__version__ = "4.10.0"
23 changes: 19 additions & 4 deletions cumulusci/cli/robot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import importlib.metadata
import shutil
import sys

import click
Expand Down Expand Up @@ -37,9 +38,19 @@ def robot_install_playwright(runtime, dry_run):
def robot_uninstall_playwright():
"""Attempt to uninstall playwright"""
p1 = sarge.Command([sys.executable, "-m", "Browser.entry", "clean-node"])
p2 = sarge.Command(
[sys.executable, "-m", "pip", "uninstall", "robotframework-browser", "--yes"]
)
if shutil.which("uv"):
p2 = sarge.Command(["uv", "pip", "uninstall", "robotframework-browser"])
else:
p2 = sarge.Command(
[
sys.executable,
"-m",
"pip",
"uninstall",
"robotframework-browser",
"--yes",
]
)

click.echo("removing node modules...")
click.echo(f"running {' '.join(p1.args)}")
Expand All @@ -53,7 +64,11 @@ def robot_uninstall_playwright():


def _install_browser_library(dry_run=False):
pip_cmd = [sys.executable, "-m", "pip", "install", "robotframework-browser"]
if shutil.which("uv"):
pip_cmd = ["uv", "pip", "install", "robotframework-browser"]
else:
pip_cmd = [sys.executable, "-m", "pip", "install", "robotframework-browser"]

click.echo("installing robotframework-browser ...")
if dry_run:
click.echo(f"would run {' '.join(pip_cmd)}")
Expand Down
40 changes: 36 additions & 4 deletions cumulusci/cli/tests/test_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ def test_is_package_installed(mock_distribution):
assert result is False


@mock.patch("cumulusci.cli.robot.shutil.which")
@mock.patch("cumulusci.cli.robot.sarge")
def test_happy_path(sarge):
def test_happy_path(sarge, which):
"""Verify the happy path is indeed happy"""
which.return_value = False
sarge.Command.side_effect = mock_Command()
with mock.patch("cumulusci.cli.robot._is_package_installed", return_value=False):
run_cli_command("robot", "install_playwright")
Expand All @@ -80,6 +82,30 @@ def test_happy_path(sarge):
assert actual_calls == expected_calls, msg


@mock.patch("cumulusci.cli.robot.shutil.which")
@mock.patch("cumulusci.cli.robot.sarge")
def test_happy_path_uv(sarge, which):
"""Verify the happy path is indeed happy with uv"""
which.return_value = True
sarge.Command.side_effect = mock_Command()
with mock.patch("cumulusci.cli.robot._is_package_installed", return_value=False):
run_cli_command("robot", "install_playwright")
actual_calls = [call.args[0] for call in sarge.Command.mock_calls]
expected_calls = [
"npm --version",
[
"uv",
"pip",
"install",
"robotframework-browser",
],
[sys.executable, "-m", "Browser.entry", "init"],
]
msg = f"\n-- expected --\n{expected_calls}\n\n-- actual --\n{actual_calls}"

assert actual_calls == expected_calls, msg


@mock.patch("sys.exit")
def test_bogus_subcommand(sys_exit):
"""Verify a bogus subcommand returns a UsageError"""
Expand All @@ -100,9 +126,11 @@ def test_no_npm(sarge):
assert sarge.Command.mock_calls[0].args[0] == "npm --version"


@mock.patch("cumulusci.cli.robot.shutil.which")
@mock.patch("cumulusci.cli.robot.sarge")
def test_playwright_dry_run(sarge):
def test_playwright_dry_run(sarge, which):
"""Verify the output of a dry run"""
which.return_value = False
sarge.Command.side_effect = mock_Command(returncodes={"npm --version": 0})
with mock.patch("cumulusci.cli.robot._is_package_installed", return_value=False):
result = run_cli_command("robot", "install_playwright", "--dry_run")
Expand Down Expand Up @@ -130,9 +158,11 @@ def test_playwright_failure_to_initialize_browser_library(sarge):
run_cli_command("robot", "install_playwright")


@mock.patch("cumulusci.cli.robot.shutil.which")
@mock.patch("cumulusci.cli.robot.sarge")
def test_playwright_failure_to_install_browser_library(sarge):
def test_playwright_failure_to_install_browser_library(sarge, which):
"""Verify we raise an exception if we can't install playwright"""
which.return_value = False
cmd = str([sys.executable, "-m", "pip", "install", "robotframework-browser"])
sarge.Command.side_effect = mock_Command(returncodes={cmd: 1})
with mock.patch("cumulusci.cli.robot._is_package_installed", return_value=False):
Expand All @@ -154,9 +184,11 @@ def test_playwright_already_installed(sarge):
)


@mock.patch("cumulusci.cli.robot.shutil.which")
@mock.patch("cumulusci.cli.robot.sarge")
def test_uninstall_playwright(sarge):
def test_uninstall_playwright(sarge, which):
"""Verify calling 'robot uninstall_playwright' calls the right utilities"""
which.return_value = False
sarge.Command.side_effect = mock_Command()
with mock.patch("cumulusci.cli.robot._is_package_installed", return_value=False):
run_cli_command("robot", "uninstall_playwright")
Expand Down
28 changes: 28 additions & 0 deletions cumulusci/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,31 @@ def task_context(org_config, project_config):
return TaskContext(
org_config=org_config, project_config=project_config, logger=getLogger()
)


@pytest.fixture()
def capture_orgid_using_task(create_task, tmp_path):
"""Returns a callable that captures the org ID by running a SOQL query task.

Moved from test_integration_infrastructure.py to ensure pytest 8.x
discovers this fixture when tests run with --org.
"""

def _capture_orgid_using_task():
from cumulusci.tasks.salesforce import SOQLQuery

csv_output = Path(tmp_path) / "foo.csv"
t = create_task(
SOQLQuery,
{
"query": "select Id from Organization",
"object": "Organization",
"result_file": csv_output,
},
)
t()
assert csv_output.exists()
org_id = csv_output.read_text().split("\n")[1].split(",")[0]
return org_id.strip('"')

return _capture_orgid_using_task
Loading
Loading