Skip to content

Commit

Permalink
Merge pull request #4 from espressif/feat/support_build_with_profiles
Browse files Browse the repository at this point in the history
Feat/support build with profiles
  • Loading branch information
hfudev authored Jan 10, 2025
2 parents b9cd40d + 9addf0e commit 0c838b8
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 100 deletions.
4 changes: 3 additions & 1 deletion idf_ci/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from .idf_pytest.models import PytestApp, PytestCase
from .idf_pytest.plugin import IdfPytestPlugin
from .idf_pytest.script import get_pytest_cases
from .idf_pytest.scripts import get_pytest_cases
from .profiles import IniProfileManager, TomlProfileManager
from .scripts import build
from .settings import CiSettings

__all__ = [
Expand All @@ -14,5 +15,6 @@
'PytestApp',
'PytestCase',
'TomlProfileManager',
'build',
'get_pytest_cases',
]
65 changes: 57 additions & 8 deletions idf_ci/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import os
import shutil

import click

from .build_profile import build_profile
from .ci_profile import ci_profile
from .completions import completions
from .test_profile import test_profile
from .build import build
from .test import test

_CLI_SETTINGS = {
'show_default': True,
Expand All @@ -19,10 +19,59 @@ def cli():
pass


cli.add_command(build_profile)
cli.add_command(ci_profile)
cli.add_command(completions)
cli.add_command(test_profile)
@cli.command()
@click.option('--path', default=os.getcwd(), help='Path to create the CI profile')
def init_profile(path: str):
"""
Create .idf_ci.toml with default values at the given folder
"""
if os.path.isdir(path):
filepath = os.path.join(path, '.idf_ci.toml')
else:
filepath = path

shutil.copyfile(os.path.join(os.path.dirname(__file__), '..', 'templates', 'default_ci_profile.toml'), filepath)
click.echo(f'Created CI profile at {filepath}')


@cli.command()
def completions():
"""
Instructions to enable shell completions for idf-ci
"""

help_message = """
To enable autocomplete run the following command:
Bash:
1. Run this command once
_IDF_CI_COMPLETE=bash_source idf-ci > ~/.idf-ci-complete.bash
2. Add the following line to your .bashrc
. ~/.idf-ci-complete.bash
Zsh:
1. Run this command once
_IDF_CI_COMPLETE=zsh_source idf-ci > ~/.idf-ci-complete.zsh
2. Add the following line to your .zshrc
. ~/.idf-ci-complete.zsh
Fish:
1. Run this command once
_IDF_CI_COMPLETE=fish_source idf-ci > ~/.config/fish/completions/idf-ci.fish
After modifying the shell config, you need to start a new shell in order for the changes to be loaded.
"""
click.echo(help_message)


cli.add_command(build)
cli.add_command(test)


__all__ = ['cli']
45 changes: 45 additions & 0 deletions idf_ci/cli/_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0

import click

_OPTION_PATHS_HELP = """
List of directories to process. Support passing multiple times.
\b
Example:
--paths component_1 --paths component_2
-p component_1 -p component_2
"""


def option_paths(func):
return click.option(
'--paths',
'-p',
multiple=True,
type=click.Path(dir_okay=True, file_okay=False, exists=True),
help=_OPTION_PATHS_HELP,
)(func)


_OPTION_PROFILES_HELP = """
\b
List of profiles to apply. Could be "default" or file path to a custom profile.
Support passing multiple times. The later profiles will override the previous ones.
[default: default]
\b
Example:
--profiles default --profiles custom.toml
"""


def option_profiles(func):
return click.option(
'--profiles',
multiple=True,
default=['default'],
show_default=False,
help=_OPTION_PROFILES_HELP,
)(func)
26 changes: 21 additions & 5 deletions idf_ci/cli/build_profile.py → idf_ci/cli/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,36 @@

import click

from idf_ci import build as build_cmd

from ._options import option_paths, option_profiles


@click.group()
def build_profile():
def build():
"""
Group of commands for managing build profiles for idf-build-apps
Group of build related commands
"""
pass


@build_profile.command()
@build.command()
@option_paths
@click.option('--target', '-t', default='all', help='Target to be built. Or "all" to build all targets.')
@option_profiles
def run(paths, target, profiles):
"""
Run build according to the given profiles
"""
click.echo(f'Building {target} with profiles {profiles} at {paths}')
build_cmd(paths, target, profiles=profiles)


@build.command()
@click.option('--path', default=os.getcwd(), help='Path to create the build profile')
def init(path: str):
def init_profile(path: str):
"""
Create a build profile at the given folder
Create .idf_build_apps.toml with default values at the given folder
"""
if os.path.isdir(path):
# here don't use idf_build_apps.constants.IDF_BUILD_APPS_TOML_FN
Expand Down
30 changes: 0 additions & 30 deletions idf_ci/cli/ci_profile.py

This file was deleted.

38 changes: 0 additions & 38 deletions idf_ci/cli/completions.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,2 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0

import click


@click.command()
def completions():
"""
Instructions to enable shell completions for idf-ci
"""

help_message = """
To enable autocomplete run the following command:
Bash:
1. Run this command once
_IDF_CI_COMPLETE=bash_source idf-ci > ~/.idf-ci-complete.bash
2. Add the following line to your .bashrc
. ~/.idf-ci-complete.bash
Zsh:
1. Run this command once
_IDF_CI_COMPLETE=zsh_source idf-ci > ~/.idf-ci-complete.zsh
2. Add the following line to your .zshrc
. ~/.idf-ci-complete.zsh
Fish:
1. Run this command once
_IDF_CI_COMPLETE=fish_source idf-ci > ~/.config/fish/completions/idf-ci.fish
After modifying the shell config, you need to start a new shell in order for the changes to be loaded.
"""
click.echo(help_message)
10 changes: 5 additions & 5 deletions idf_ci/cli/test_profile.py → idf_ci/cli/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@


@click.group()
def test_profile():
def test():
"""
Group of commands for managing CI templates for idf-ci
Group of test related commands
"""
pass


@test_profile.command()
@test.command()
@click.option('--path', default=os.getcwd(), help='Path to create the CI profile')
def init(path: str):
def init_profile(path: str):
"""
Create a CI profile at the given folder
Create pytest.ini with default values at the given folder
"""
if os.path.isdir(path):
filepath = os.path.join(path, 'pytest.ini')
Expand Down
3 changes: 2 additions & 1 deletion idf_ci/idf_pytest/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
from functools import cached_property

from _pytest.python import Function
from idf_build_apps.utils import to_list
from pytest_embedded.plugin import parse_multi_dut_args

from idf_ci.utils import to_list

LOGGER = logging.getLogger(__name__)


Expand Down
File renamed without changes.
8 changes: 5 additions & 3 deletions idf_ci/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def _merge_dicts(source: t.Dict, target: t.Dict) -> t.Dict:


class ProfileManager:
suffix: t.ClassVar[t.Literal['.ini', '.toml']] = '.toml'

def __init__(self, profiles: t.List[PathLike], default_profile_path: PathLike):
self.profiles = profiles
self.default_profile_path = default_profile_path
Expand All @@ -51,15 +53,15 @@ def merge(self) -> None:

@contextmanager
def _merged_profile_writer(self) -> t.Generator[t.IO[str], None, None]:
# seems like .ini suffix is required to let pytest recognize that this is a config file
# otherwise -c won't work
with tempfile.NamedTemporaryFile(suffix='.ini', mode='w', delete=False) as fw:
with tempfile.NamedTemporaryFile(suffix=self.suffix, mode='w', delete=False) as fw:
yield fw

self._merged_profile_path = fw.name


class IniProfileManager(ProfileManager):
suffix: t.ClassVar[t.Literal['.ini', '.toml']] = '.ini'

def read(self, profile: PathLike) -> t.Dict:
config = configparser.ConfigParser()

Expand Down
41 changes: 41 additions & 0 deletions idf_ci/scripts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0

import os.path
import subprocess
import typing as t

from ._compat import UNDEF, PathLike, Undefined
from .profiles import TomlProfileManager


def build(
paths: t.List[str],
target: str,
*,
profiles: t.List[PathLike] = UNDEF, # type: ignore
):
if isinstance(profiles, Undefined):
profiles = ['default']

profile_o = TomlProfileManager(
profiles=profiles,
default_profile_path=os.path.join(os.path.dirname(__file__), 'templates', 'default_build_profile.toml'),
)

print(profile_o.merged_profile_path)

subprocess.run(
[
'idf-build-apps',
'build',
'-p',
*paths,
'-t',
target,
'--config-file',
profile_o.merged_profile_path,
'-vvv',
],
check=True,
)
Loading

0 comments on commit 0c838b8

Please sign in to comment.