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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,26 @@ After pushing changes, GitHub will automatically build the firmware for you. Run

From this page, you can click on a build (the latest is at the top) to view its status. If the build succeeded, you can download the firmware from the "Artifacts" section at the bottom of the build summary page.

## ZMK Version Management

The `zmk version` command manages the version of ZMK you are using:

```sh
zmk version # Print the current ZMK version
zmk version --list # List the available versions
zmk version <revision> # Switch to the version given by <revision>
```

You can set the revision to any Git tag, branch, or commit:

```sh
zmk version v0.3 # Switch to tag "v0.3"
zmk version main # Switch to branch "main"
zmk version 1958217 # Switch to commit "1958217"
```

Note that `zmk version --list` will only list tagged versions.

## Configuration

The `zmk config` command manages settings for ZMK CLI:
Expand Down
3 changes: 2 additions & 1 deletion zmk/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import typer

from . import cd, code, config, download, init, keyboard, module, west
from . import cd, code, config, download, init, keyboard, module, version, west


def register(app: typer.Typer) -> None:
Expand All @@ -15,6 +15,7 @@ def register(app: typer.Typer) -> None:
app.command()(download.download)
app.command(name="dl")(download.download)
app.command()(init.init)
app.command(name="version")(version.version)
app.command()(west.update)
app.command(
add_help_option=False,
Expand Down
2 changes: 1 addition & 1 deletion zmk/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def config(
),
] = False,
) -> None:
"""Get and set ZMK CLI settings."""
"""Get or set ZMK CLI settings."""

cfg = get_config(ctx)

Expand Down
20 changes: 1 addition & 19 deletions zmk/commands/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@

import webbrowser

import giturlparse
import typer

from ..config import get_config
from ..exceptions import FatalError
from ..repo import Repo


def download(ctx: typer.Context) -> None:
Expand All @@ -18,19 +15,4 @@ def download(ctx: typer.Context) -> None:
cfg = get_config(ctx)
repo = cfg.get_repo()

actions_url = _get_actions_url(repo)

webbrowser.open(actions_url)


def _get_actions_url(repo: Repo):
remote_url = repo.get_remote_url()

p = giturlparse.parse(remote_url)

match p.platform:
case "github":
return f"https://github.com/{p.owner}/{p.repo}/actions/workflows/build.yml"

case _:
raise FatalError(f"Unsupported remote URL: {remote_url}")
webbrowser.open(repo.get_remote().firmware_download_url)
40 changes: 37 additions & 3 deletions zmk/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import subprocess
import webbrowser
from pathlib import Path
from typing import Annotated
from urllib.parse import urlparse

import rich
Expand All @@ -29,7 +30,24 @@
TEXT_WIDTH = 80


def init(ctx: typer.Context) -> None:
def init(
ctx: typer.Context,
url: Annotated[
str | None, typer.Argument(help="URL of an existing repository to clone.")
] = None,
name: Annotated[
str | None,
typer.Argument(help="Directory name where the repo should be cloned."),
] = None,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth making one of these an Option, e.g. to be able to specify the name without the url. I'd vote for url to be an option and name to stay an argument.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following https://git-scm.com/docs/git-clone for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess using the interactive mode asks for both separately, so it isn't very important either way.

revision: Annotated[
str | None,
typer.Option(
"--zmk-version",
metavar="REVISION",
help="Use the specified version of ZMK instead of the default.",
),
] = None,
) -> None:
"""Create a new ZMK config repo or clone an existing one."""

console = rich.get_console()
Expand All @@ -38,12 +56,28 @@ def init(ctx: typer.Context) -> None:
_check_dependencies()
_check_for_existing_repo(cfg)

url = _get_repo_url()
name = _get_directory_name(url)
if url is None:
url = _get_repo_url()

if name is None:
name = _get_directory_name(url)

_clone_repo(url, name)

repo = Repo(Path() / name)

if revision:
try:
repo.ensure_west_ready()
repo.set_zmk_version(revision)
except ValueError as ex:
console.print()
console.print(
f'[yellow]Failed to switch to ZMK revision "{revision}":[/yellow]'
)
console.print(ex)
console.print()

repo.run_west("update")

console.print()
Expand Down
6 changes: 2 additions & 4 deletions zmk/commands/module/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import typer
from rich.console import Console
from rich.prompt import InvalidResponse, Prompt, PromptBase
from west.manifest import ImportFlag, Manifest
from west.manifest import Manifest

from ...config import get_config
from ...exceptions import FatalError
Expand Down Expand Up @@ -37,9 +37,7 @@ def module_add(
cfg = get_config(ctx)
repo = cfg.get_repo()

manifest = Manifest.from_topdir(
topdir=repo.west_path, import_flags=ImportFlag.IGNORE
)
manifest = repo.get_west_manifest()

if name:
_error_if_existing_name(manifest, name)
Expand Down
5 changes: 1 addition & 4 deletions zmk/commands/module/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import typer
from rich import box
from rich.table import Table
from west.manifest import ImportFlag, Manifest

from ...config import get_config

Expand All @@ -19,9 +18,7 @@ def module_list(ctx: typer.Context) -> None:
cfg = get_config(ctx)
repo = cfg.get_repo()

manifest = Manifest.from_topdir(
topdir=repo.west_path, import_flags=ImportFlag.IGNORE
)
manifest = repo.get_west_manifest()

table = Table(box=box.SQUARE, border_style="dim blue", header_style="bright_cyan")
table.add_column("Name")
Expand Down
6 changes: 2 additions & 4 deletions zmk/commands/module/remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import rich
import typer
from west.manifest import ImportFlag, Manifest, Project
from west.manifest import Project

from ...config import get_config
from ...exceptions import FatalError
Expand All @@ -32,9 +32,7 @@ def module_remove(
cfg = get_config(ctx)
repo = cfg.get_repo()

manifest = Manifest.from_topdir(
topdir=repo.west_path, import_flags=ImportFlag.IGNORE
)
manifest = repo.get_west_manifest()

# Don't allow deleting ZMK, or the repo won't build anymore.
projects = [p for p in manifest.projects[1:] if p.name != "zmk"]
Expand Down
76 changes: 76 additions & 0 deletions zmk/commands/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
"zmk version" command.
"""

from typing import Annotated

import rich
import typer
from rich.table import Table

from ..config import get_config
from ..exceptions import FatalError
from ..remote import Remote
from ..repo import Repo


def version(
ctx: typer.Context,
revision: Annotated[
str | None,
typer.Argument(
help="Switch to this ZMK version. Prints the current ZMK version if omitted.",
),
] = None,
list_versions: Annotated[
bool | None,
typer.Option("--list", "-l", help="Print the available versions and exit."),
] = False,
) -> None:
"""Get or set the ZMK version."""

cfg = get_config(ctx)
repo = cfg.get_repo()

if list_versions:
_print_versions(repo)
elif revision is None:
_print_current_version(repo)
else:
_set_version(repo, revision)


def _print_versions(repo: Repo):
zmk = repo.get_west_zmk_project()
remote = Remote(zmk.url)

if not remote.repo_exists():
raise FatalError(f"Invalid repository URL: {zmk.url}")

tags = remote.get_tags()

if not tags:
raise FatalError(f"{zmk.url} does not have any tagged commits.")

for tag in tags:
print(tag)


def _print_current_version(repo: Repo):
zmk = repo.get_west_zmk_project()

grid = Table.grid()
grid.add_column()
grid.add_column()
grid.add_row("[bright_blue]Remote: [/bright_blue]", zmk.url)
grid.add_row("[bright_blue]Revision: [/bright_blue]", zmk.revision)

rich.print(grid)


def _set_version(repo: Repo, revision: str):
repo.set_zmk_version(revision)
repo.run_west("update")

rich.print()
rich.print(f'ZMK is now using revision "{revision}"')
Loading