diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1798d170f..09bfa2845 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -163,8 +163,4 @@ jobs: run: make docker - name: Run image run: | - docker run docker.io/projectsyn/commodore:test || exit_code=$? - if [ "$exit_code" -ne 2 ]; then - echo "Unexpected exit code $exit_code, expected 2" - exit $exit_code - fi + docker run docker.io/projectsyn/commodore:test version diff --git a/Dockerfile b/Dockerfile index 6da13d087..e78054f83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,7 @@ ARG POETRY_VERSION=1.8.5 RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ curl \ + git \ libffi-dev \ && rm -rf /var/lib/apt/lists/* \ && curl -sSL https://install.python-poetry.org | python - --version ${POETRY_VERSION} \ @@ -37,22 +38,13 @@ RUN sed -i "s/^__git_version__.*$/__git_version__ = '${GITVERSION}'/" commodore/ RUN pip install ./dist/syn_commodore-*-py3-none-any.whl -RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \ - && chmod 700 get_helm.sh \ - && ./get_helm.sh \ - && mv /usr/local/bin/helm /usr/local/bin/helm3 \ - && curl -LO https://git.io/get_helm.sh \ - && chmod 700 get_helm.sh \ - && ./get_helm.sh \ - && mv /usr/local/bin/helm /usr/local/bin/helm2 - ARG KUSTOMIZE_VERSION=5.7.0 ARG JSONNET_BUNDLER_VERSION=v0.6.3 +ARG HELM_VERSION=v3.18.4 -RUN ./tools/install-jb.sh ${JSONNET_BUNDLER_VERSION} \ - && curl -fsSLO "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" \ - && chmod +x install_kustomize.sh \ - && ./install_kustomize.sh ${KUSTOMIZE_VERSION} /usr/local/bin +RUN commodore tool install helm --version ${HELM_VERSION} \ + && commodore tool install kustomize --version ${KUSTOMIZE_VERSION} \ + && commodore tool install jb --version ${JSONNET_BUNDLER_VERSION} FROM base AS runtime @@ -73,12 +65,17 @@ COPY --from=builder \ COPY --from=builder \ /usr/local/bin/kapitan* \ /usr/local/bin/commodore* \ - /usr/local/bin/helm* \ - /usr/local/bin/jb \ - /usr/local/bin/kustomize \ /usr/local/bin/ -RUN ln -s /usr/local/bin/helm3 /usr/local/bin/helm +COPY --from=builder \ + /app/.cache/commodore/tools/ \ + /app/.cache/commodore/tools/ + +RUN ln -s \ + /app/.cache/commodore/tools/helm \ + /app/.cache/commodore/tools/jb \ + /app/.cache/commodore/tools/kustomize \ + /usr/local/bin/ COPY ./tools/entrypoint.sh /usr/local/bin/ diff --git a/commodore/cli/__init__.py b/commodore/cli/__init__.py index 892b2e7fa..4fb54b255 100644 --- a/commodore/cli/__init__.py +++ b/commodore/cli/__init__.py @@ -9,7 +9,8 @@ from reclass_rs import Reclass from dotenv import load_dotenv, find_dotenv -from commodore import __git_version__, __version__ + +from commodore import __git_version__, __version__, tools from commodore.config import Config from commodore.version import version_info @@ -20,6 +21,7 @@ from .inventory import inventory_group from .package import package_group from .oidc import commodore_fetch_token, commodore_login +from .tool import tool_group def _version(): @@ -75,6 +77,7 @@ def commodore(ctx, working_dir, verbose, request_timeout): commodore.add_command(component_group) commodore.add_command(inventory_group) commodore.add_command(package_group) +commodore.add_command(tool_group) commodore.add_command(commodore_login) commodore.add_command(commodore_fetch_token) commodore.add_command(commodore_version) @@ -83,6 +86,7 @@ def commodore(ctx, working_dir, verbose, request_timeout): def main(): multiprocessing.set_start_method("spawn") Reclass.set_thread_count(0) + tools.setup_path() load_dotenv(dotenv_path=find_dotenv(usecwd=True)) commodore.main( diff --git a/commodore/cli/tool.py b/commodore/cli/tool.py new file mode 100644 index 000000000..2ff3fabcd --- /dev/null +++ b/commodore/cli/tool.py @@ -0,0 +1,176 @@ +from typing import Optional + +import click + +import commodore.cli.options as options + +from commodore import tools +from commodore.config import Config + + +@click.group( + name="tool", + short_help="Manage required external tools", +) +@options.verbosity +@options.pass_config +@options.github_token +def tool_group(config: Config, verbose: int, github_token: str): + """Commands to manage required external tools. + + Currently, `helm`, jsonnet-bundler/`jb`, and `kustomize` are required + external tools. + """ + config.update_verbosity(verbose) + config.managed_tools = tools.load_state() + config.github_token = github_token + + +@tool_group.command(name="list", short_help="List external tools") +@options.verbosity +@options.pass_config +@options.github_token +@click.option( + "--version-check/--skip-version-check", + " / -V", + default=True, + help="Query GitHub API to get latest version", +) +def tool_list(config: Config, verbose: int, github_token: str, version_check: bool): + """List the version, location and management state of the required external tools. + + Currently, `helm`, jsonnet-bundler/`jb`, and `kustomize` are required + external tools. By default, the command also queries the GitHub API to + determine the latest available version of each tool and indicates whether an + update is available. + + Optionally, the command accepts a GitHub personal access token (PAT) to + avoid running into the fairly strict unauthenticated GitHub rate limits. + """ + config.update_verbosity(verbose) + config.github_token = github_token + tools.list_tools(config, version_check) + + +@tool_group.command(name="install", short_help="Install external tools") +@options.verbosity +@options.pass_config +@options.github_token +@click.option( + "--version", + default=None, + metavar="VERSION", + help="A version to install for the requested tool. " + + "By default, the latest version is installed.", +) +@click.option( + "--missing", + is_flag=True, + default=False, + help="Install the latest version for all currently unmanaged tools. " + + "This flag and providing a tool name on the command line are mutually exclusive.", +) +@click.argument("tool", required=False, default="") +def tool_install( + config: Config, + verbose: int, + tool: str, + version: Optional[str], + github_token: str, + missing: bool, +): + """Install one of the required tools in `$XDG_CACHE_DIR/commodore/tools`. + + The command will fail for tools which are already managed by Commodore. + + By default, the command will install the latest available tool version. For + `helm` and `kustomize`, the command downloads the official installation + scripts and executes them with appropriate arguments. For `jb`, the command + directly downloads the requested version from the GitHub release page. + + Optionally, the command accepts a tool version to install. The command + accepts versions prefixed with "v" and unprefixed versions. + + Alternatively, the command can install the latest version for all required + tools which aren't managed by Commodore yet by passing flag `--missing`. + This flag is mutually exclusive with providing a tool name. + """ + config.update_verbosity(verbose) + config.github_token = github_token + + if not tool and not missing or tool and missing: + raise click.ClickException( + "`commodore tool install` expects to be called with either a tool name or the `--missing` flag." + ) + if missing and version: + click.secho( + "Flag `--version` has no effect when calling the command with `--missing`.", + fg="yellow", + ) + + if missing: + tools.install_missing_tools(config) + else: + tools.install_tool(config, tool, version) + + +@tool_group.command(name="upgrade", short_help="Upgrade external tools") +@options.verbosity +@options.github_token +@options.pass_config +@click.option( + "--version", + default=None, + metavar="VERSION", + help="A version to upgrade (or downgrade) to for the requested tool. " + + "By default, the tool is upgraded to the latest version.", +) +@click.option( + "--all", + is_flag=True, + default=False, + help="Upgrade all currently managed tools to their latest versions. " + + "This flag and providing a tool name on the command line are mutually exclusive.", +) +@click.argument("tool", required=False, default="") +def tool_upgrade( + config: Config, + verbose: int, + tool: str, + version: Optional[str], + github_token: str, + all: bool, +): + """Upgrade (or downgrade) one of the required tools in `$XDG_CACHE_DIR/commodore/tools`. + + The command will fail for tools which aren't managed by Commodore yet. + + By default, the command will upgrade the tool to the latest available + version. For `helm` and `kustomize`, the command downloads the official + installation scripts and executes them with appropriate arguments. For `jb`, + the command directly downloads the requested version from the GitHub release + page. + + Optionally, the command accepts a tool version to upgrade (or downgrade) to. + The command accepts versions prefixed with "v" and unprefixed versions. + + Alternatively, the command can upgrade all managed tools to their latest + versions by passing flag `--all`. This flag is mutually exclusive with + providing a tool name. + """ + config.update_verbosity(verbose) + config.github_token = github_token + + if not tool and not all or tool and all: + raise click.ClickException( + "`commodore tool upgrade` expects to be called with either a tool name or the `--all` flag." + ) + if all and version: + click.secho( + "Flag `--version` has no effect when calling the command with `--all`.", + fg="yellow", + ) + if all: + tools.upgrade_all_tools(config) + else: + tools.upgrade_tool(config, tool, version) diff --git a/commodore/config.py b/commodore/config.py index 4455b4268..6daa81f65 100644 --- a/commodore/config.py +++ b/commodore/config.py @@ -101,6 +101,7 @@ class Config: _dynamic_facts: dict[str, Any] _github_token: Optional[str] _request_timeout: int + _managed_tools: dict[str, str] oidc_client: Optional[str] oidc_discovery_url: Optional[str] @@ -141,6 +142,7 @@ def __init__( self._dynamic_facts = {} self._github_token = None self._request_timeout = 5 + self._managed_tools = {} @property def verbose(self): @@ -316,6 +318,14 @@ def request_timeout(self) -> int: def request_timeout(self, timeout: int): self._request_timeout = timeout + @property + def managed_tools(self) -> dict[str, str]: + return self._managed_tools + + @managed_tools.setter + def managed_tools(self, managed_tools: dict[str, str]): + self._managed_tools = managed_tools + @property def inventory(self): return self._inventory diff --git a/commodore/tools.py b/commodore/tools.py new file mode 100644 index 000000000..e2485a4f5 --- /dev/null +++ b/commodore/tools.py @@ -0,0 +1,352 @@ +import hashlib +import json +import os +import platform +import shutil +import subprocess # nosec +from copy import deepcopy + +from datetime import datetime +from pathlib import Path +from typing import Optional + +import click +import github +import requests + +from requests.exceptions import ConnectionError, HTTPError +from xdg.BaseDirectory import xdg_cache_home + +from commodore.config import Config + +REQUIRED_TOOLS = ["helm", "jb", "kustomize"] + +_tool_version_arg = { + "jb": ["--version"], + "helm": ["version", "--template", "{{.Version}}"], + "kustomize": ["version"], +} + +TOOL_REPOS = { + "jb": "projectsyn/jsonnet-bundler", + "helm": "helm/helm", + "kustomize": "kubernetes-sigs/kustomize", +} + + +MANAGED_TOOLS_PATH = Path(xdg_cache_home) / "commodore" / "tools" +MANAGED_TOOLS_STATE = MANAGED_TOOLS_PATH / "state.json" + +TOOL_INSTALL_SCRIPT_URL = { + "helm": "https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3", + "kustomize": "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh", +} + + +class ToolInfo: + tool: str + path: Optional[str] + version: Optional[str] + + def __init__(self, tool: str): + if tool not in REQUIRED_TOOLS: + raise ValueError(f"Unknown tool {tool}") + + self.tool = tool + self.path = shutil.which(tool) + self.version = None + if self.path: + self.version = ( + subprocess.run( + [self.path] + _tool_version_arg[tool], + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + ) + .stdout.decode("utf-8") + .strip() + ) + + @property + def available(self) -> bool: + return self.path is not None + + def info(self) -> str: + if not self.path: + return "NOT FOUND IN PATH" + return f"{self.path}, version: {self.version}" + + +def setup_path(): + path = os.environ["PATH"].split(os.pathsep) + if MANAGED_TOOLS_PATH.as_posix() not in path: + path = [MANAGED_TOOLS_PATH.as_posix()] + path + + os.environ["PATH"] = os.pathsep.join(path) + + +def load_state() -> dict[str, str]: + state = {} + if MANAGED_TOOLS_STATE.is_file(): + with open(MANAGED_TOOLS_STATE, "r", encoding="utf-8") as statef: + state = json.load(statef) + + update = False + for tool in REQUIRED_TOOLS: + if tool not in state: + continue + tpath = shutil.which(tool) + if tpath and Path(tpath).parent != MANAGED_TOOLS_PATH: + click.secho( + f"Tool {tool} missing in managed tools path, removing from state", + fg="yellow", + ) + del state[tool] + update = True + + if update: + with open(MANAGED_TOOLS_STATE, "w", encoding="utf-8") as statef: + json.dump(state, statef) + + return state + + +def list_tools(config: Config, version_check: bool): + tool_versions = {} + if version_check: + click.secho("Fetching latest tool versions from GitHub", fg="yellow") + for tool in REQUIRED_TOOLS: + tool_versions[tool] = latest_version(config, tool) + + for tool in REQUIRED_TOOLS: + tinfo = ToolInfo(tool) + if not tinfo.version: + click.secho(f"{tool} missing!", fg="red") + continue + managed = tool in config.managed_tools + updated = config.managed_tools.get(tool, "UNKNOWN") + version = "N/A" + versioncolor = None + upgradetext = "Version check skipped" + if tool in tool_versions: + version = tool_versions[tool] + if version.removeprefix("v") != tinfo.version.removeprefix("v"): + # TODO(sg): what's the best color here? + versioncolor = "yellow" + upgradetext = "Upgrade available!" + else: + upgradetext = "No upgrade available" + click.secho(f"{tool} {tinfo.version}", bold=True) + click.echo(f"Location: {tinfo.path}") + click.echo(f"Managed: {managed}") + click.secho( + f"Latest version: {version} (" + + click.style(upgradetext, fg=versioncolor) + + ")" + ) + click.echo(f"Updated: {updated}") + + +def latest_version(config: Config, tool: str) -> str: + auth = None + if config.github_token: + auth = github.Auth.Token(config.github_token) + elif config.verbose: + click.secho( + "[WARN] Using unauthenticated GitHub client, strict rate limits apply", + fg="yellow", + ) + gh = github.Github(auth=auth) + try: + gr = gh.get_repo(TOOL_REPOS[tool]) + except github.UnknownObjectException: + raise click.ClickException(f"GitHub repo for tool {tool} not found") + latest_release = gr.get_latest_release() + return latest_release.tag_name.removeprefix(f"{tool}/") + + +def install_jb(config: Config, jb_version: str): + machine = platform.machine() + match machine: + case "x86_64": + arch = "amd64" + case "aarch64": + arch = "arm64" + case a: + arch = a + system = platform.system().lower() + click.echo(f" > Downloading jb {jb_version}") + base_url = ( + f"https://github.com/projectsyn/jsonnet-bundler/releases/download/{jb_version}" + ) + jb_file = f"jb_{system}_{arch}" + jb_url = f"{base_url}/{jb_file}" + jb_checksums_url = f"{base_url}/checksums.txt" + jb_path = MANAGED_TOOLS_PATH / "jb" + try: + jb_chksums = requests.get(jb_checksums_url, timeout=config.request_timeout) + jb_chksums.raise_for_status() + jb_data = requests.get(jb_url, timeout=config.request_timeout) + jb_data.raise_for_status() + except (ConnectionError, HTTPError) as e: + raise click.ClickException(f"Failed to download jb: {e}") + click.echo(" > Validating checksum for jb") + jb_content = jb_data.content + jb_sha256 = hashlib.sha256(jb_content).hexdigest() + checksums = [line.split(" ") for line in jb_chksums.text.strip().splitlines()] + for sum, name in checksums: + if name == jb_file: + if sum != jb_sha256: + raise click.ClickException(f"Failed to validate checksum for {jb_file}") + else: + break + else: + raise click.ClickException(f"No checksum available for {jb_file}") + + with open(jb_path, "wb") as jbf: + jbf.write(jb_data.content) + jb_path.chmod(0o755) + + +def install_script(config: Config, tool: str, version: Optional[str]): + if version and version.startswith("v"): + # this command expects that an optional v prefix for the version has been + # stripped. + raise ValueError( + "Function install_script() expects parameter `version` to not be prefixed with 'v'." + ) + install_args = [] + if tool == "helm": + if version: + install_args = ["--version", f"v{version}"] + install_args = install_args + ["--no-sudo"] + elif tool == "kustomize": + if version: + install_args = [version] + install_args = install_args + [MANAGED_TOOLS_PATH.as_posix()] + install_script = TOOL_INSTALL_SCRIPT_URL[tool] + try: + script_data = requests.get(install_script, timeout=config.request_timeout) + script_data.raise_for_status() + except (ConnectionError, HTTPError) as e: + raise click.ClickException( + f"Failed to download install script for tool {tool}: {e}" + ) + script = MANAGED_TOOLS_PATH / f"{tool}-install.sh" + with open(script, "w", encoding="utf-8") as scriptf: + scriptf.write(script_data.text) + script.chmod(0o755) + # create a copy of os.environ so we don't pollute our own env. + env = deepcopy(os.environ) + env["HELM_INSTALL_DIR"] = MANAGED_TOOLS_PATH.as_posix() + if config.github_token: + env["GITHUB_TOKEN"] = config.github_token + try: + result = subprocess.run([script.as_posix()] + install_args, env=env) + result.check_returncode() + except (PermissionError, subprocess.CalledProcessError) as e: + raise click.ClickException(f"Failed to run install script for tool {tool}: {e}") + script.unlink() + + +def do_install(config: Config, tool: str, version: Optional[str]): + if version: + version = version.removeprefix("v") + if tool == "jb": + if version: + jb_version = f"v{version}" + else: + jb_version = latest_version(config, "jb") + install_jb(config, jb_version) + else: + install_script(config, tool, version) + + state = load_state() + now = datetime.now() + state[tool] = now.isoformat(timespec="seconds") + with open(MANAGED_TOOLS_STATE, "w", encoding="utf-8") as statef: + json.dump(state, statef) + + +def check_known(tool: str): + if tool not in REQUIRED_TOOLS: + raise click.ClickException( + f"Unknown tool {tool}. " + + "Commodore currently supports managing the following tools: " + + ", ".join(REQUIRED_TOOLS) + ) + + +def install_tool(config: Config, tool: str, version: Optional[str]): + check_known(tool) + if tool in config.managed_tools: + click.echo( + f"Tool {tool} already installed. " + + f"Use `commodore tool upgrade {tool}` to upgrade installed tools." + ) + return + + click.secho(f"Installing tool {tool}", bold=True) + MANAGED_TOOLS_PATH.mkdir(parents=True, exist_ok=True) + do_install(config, tool, version) + + +def install_missing_tools(config: Config): + MANAGED_TOOLS_PATH.mkdir(parents=True, exist_ok=True) + missing_tools = set(REQUIRED_TOOLS) - set(config.managed_tools.keys()) + if len(missing_tools) == 0: + click.echo( + "All required tools are already managed by Commodore.\n\n" + + "Use `commodore tool upgrade --all` to upgrade all tools to their latest versions." + ) + return + + for tool in sorted(REQUIRED_TOOLS): + if tool in config.managed_tools: + click.secho(f"Tool {tool} already managed, skipping...", fg="yellow") + continue + click.secho(f"Installing tool {tool}", bold=True) + do_install(config, tool, None) + + +def do_upgrade(config: Config, tool: str, version: Optional[str]): + # The kustomize install script is unhappy if the kustomize binary is already + # present in the install directory. To keep it simple, we unlink the old + # tool binary for all tools when doing an upgrade (note that this generates + # some extra work for the Helm install script when calling tool upgrade when + # no upgrade is available). Notably we only unlink the existing tool when + # it's in our MANAGED_TOOLS_PATH, so we never unlink a manually installed + # copy of a tool (e.g. in `~/.local/bin`) + tool_path_str = shutil.which(tool) + if tool_path_str: + tool_path = Path(tool_path_str) + if tool_path.parent == MANAGED_TOOLS_PATH: + tool_path.unlink() + do_install(config, tool, version) + + +def upgrade_tool(config: Config, tool: str, version: Optional[str]): + check_known(tool) + if tool not in config.managed_tools: + click.echo( + f"Tool {tool} not installed yet. " + + f"Use `commodore tool install {tool}` to install tools." + ) + return + + do_upgrade(config, tool, version) + + +def upgrade_all_tools(config: Config): + if len(config.managed_tools) == 0: + click.echo( + "No tools managed by Commodore yet.\n\n" + + "Use `commodore tool install --missing` to install the latest version for all required tools." + ) + return + + for tool in sorted(REQUIRED_TOOLS): + if tool not in config.managed_tools: + click.secho(f"Tool {tool} not managed, skipping...", fg="yellow") + continue + click.secho(f"Upgrading tool {tool}", bold=True) + do_upgrade(config, tool, None) diff --git a/commodore/version.py b/commodore/version.py index 3b1752826..4326dd63f 100644 --- a/commodore/version.py +++ b/commodore/version.py @@ -1,8 +1,6 @@ """Extended Commodore version information""" import os -import subprocess # nosec -import shutil import sys from importlib import metadata @@ -10,6 +8,7 @@ import click import reclass_rs +from commodore import tools from commodore.config import Config from pygobuildinfo import get_go_build_info @@ -51,28 +50,6 @@ def _reclass_rs_buildinfo(): } -def _get_tool_info(tool) -> tuple[str, bool]: - tool_path = shutil.which(tool) - if not tool_path: - return "NOT FOUND IN PATH", False - - version_arg = { - "jb": ["--version"], - "helm": ["version", "--template", "{{.Version}}"], - "kustomize": ["version"], - } - tool_version = ( - subprocess.run( - [tool_path] + version_arg[tool], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - .stdout.decode("utf-8") - .strip() - ) - return f"{tool_path}, version: {tool_version}", True - - def version_info(config: Config, version: str): exit_code = 0 click.secho(f"Commodore {version}", bold=True) @@ -86,13 +63,13 @@ def version_info(config: Config, version: str): click.echo(f"{dep}: {dep_ver}{dep_buildinfo}") click.echo("") click.secho("External tool versions", bold=True) - for tool in ["helm", "jb", "kustomize"]: - tool_info, found = _get_tool_info(tool) + for tool in tools.REQUIRED_TOOLS: + tool_info = tools.ToolInfo(tool) fgcolor = None bold = False - if not found: + if not tool_info.available: fgcolor = "red" bold = True exit_code = 127 - click.secho(f"{tool}: {tool_info}", fg=fgcolor, bold=bold) + click.secho(f"{tool}: {tool_info.info()}", fg=fgcolor, bold=bold) sys.exit(exit_code) diff --git a/docs/modules/ROOT/pages/explanation/running-commodore.adoc b/docs/modules/ROOT/pages/explanation/running-commodore.adoc index 7df7a887f..b50b8a3f2 100644 --- a/docs/modules/ROOT/pages/explanation/running-commodore.adoc +++ b/docs/modules/ROOT/pages/explanation/running-commodore.adoc @@ -1,5 +1,7 @@ = Running Commodore +TIP: See xref:how-to/installing-commodore.adoc[] for the recommended installation with https://docs.astral.sh/uv[`uv`]. + Commodore is written in Python and it requires external dependencies. We provide Commodore as a container image and a Python package on PyPI. @@ -17,6 +19,7 @@ We recommend that you use the Commodore Python package provided on PyPI to make === Prerequisites +* `git` * A Python version between 3.10 and 3.12 as `python3` and the Python `venv` module. We recommend that you install Python and the `venv` module with your preferred package manager. * Additionally, a few of the Commodore Python package dependencies require a working C compiler, the Python 3 development package, and the FFI development package. @@ -32,10 +35,11 @@ Please check your operating system's documentation for instructions to setup a w Versions >= 5 are recommended. https://kubectl.docs.kubernetes.io/installation/kustomize/[Installation instructions] -[IMPORTANT] +[NOTE] ==== -Other documentation assumes that Helm 3 is available as `helm` and `helm3`, and Helm 2 is available as `helm2` in `$PATH`. -Please make sure you setup the Helm binaries accordingly on your local system. +Some older documentation assumes that Helm 3 is available as `helm` and `helm3`, and Helm 2 is available as `helm2` in `$PATH`. + +If you still need `helm2` for some reason, we recommend this approach. ==== === Installation @@ -56,6 +60,13 @@ This command should report something like ---- Python 3.12.7 ---- ++ +[IMPORTANT] +==== +Make sure that you use a Python version that's supported by Commodore for the following steps. + +Check your system's documentation on how to install additional Python versions. +==== . Create a virtualenv in `~/.local/commodore-venv` + diff --git a/docs/modules/ROOT/pages/how-to/installing-commodore.adoc b/docs/modules/ROOT/pages/how-to/installing-commodore.adoc new file mode 100644 index 000000000..cd0659c66 --- /dev/null +++ b/docs/modules/ROOT/pages/how-to/installing-commodore.adoc @@ -0,0 +1,83 @@ += Installing Commodore + +Commodore is written in Python and requires external dependencies. +We provide Commodore as a https://pypi.org/project/syn-commodore[Python package on PyPI] and as a https://hub.docker.com/r/projectsyn/commodore[container image]. + +Commodore interacts with Git repositories that might require authorization. +For this to work, Commodore needs to have access to an authorized SSH key. + +We recommend using https://docs.astral.sh/uv/[`uv`] to install the Commodore python package from PyPI. +`uv tool` makes installing and updating Python tools very simple and transparently manages Python versions and virtualenvs for each tool. +See the https://docs.astral.sh/uv/concepts/tools/[upstream documentation] for more details. + +TIP: See the extended xref:explanation/running-commodore.adoc[Running Commodore] explanation for a generic PyPI installation in a user-managed virtualenv and for instructions on how to run the container image locally. + +== Prerequisites + +* `git` +* `uv`. +Please check the https://docs.astral.sh/uv/getting-started/installation/[uv installation instructions] for installing `uv` on your system. +This installation guide uses `uv` to install a `python3` version that's supported by Commodore if your system's default Python version isn't compatible with Commodore. +* A few of the Commodore Python package dependencies require a working C compiler, the Python 3 development package, and the FFI development package. +On Linux distributions you'll want packages `python3-dev` or `python3-devel` and `libffi-dev` or `libffi-devel` respectively. +Please refer to your operating system's documentation for instructions to setup a working C compiler. +* Installing the `gojsonnet` Python package may require a working Go compiler on some operating systems. +gojsonnet 0.21 and newer (Commodore v1.27.6 and newer) are available as prebuilt wheels for Linux and macOS. +Please check your operating system's documentation for instructions to setup a working Go compiler. +* On some Linux distributions, you may need to install the Python `wheel` package manually. + +== Installation with `uv` + +. Install Commodore as a tool with `uv tool` ++ +[source,bash] +---- +uv tool install --python=python3.12 --python-preference=system syn-commodore +---- ++ +[TIP] +==== +Commodore currently only supports Python 3.10 - Python 3.12. + +This command will prefer using your system's version of Python 3.12. +However, `uv` will download a copy of Python 3.12 if `python3.12` isn't available on your system. + +If you'd prefer to use your system's `python3.10` or `python3.11` you can adjust the command accordingly. +==== ++ +[TIP] +==== +`uv` creates symlinks for installed tools in `~/.local/bin`. +We recommend that you add that directory to your `$PATH` variable if your system doesn't do so out of the box. +==== + +. Verify that `commodore` is available in your `$PATH` ++ +[source,bash] +---- +commodore version +---- + +. Install all the required external tools (`helm`, `jb`, and `kustomize`) ++ +[source,bash] +---- +commodore tool install --missing +---- ++ +[TIP] +==== +This command installs the required external tools in `$XDG_CACHE_HOME/commodore/tools`. +This defaults to `$HOME/.cache/commodore/tools` if you've not customized the `$XDG_CACHE_HOME` environment variable. + +If you want, you can add that directory to your `$PATH` so that you can always use the Commodore-managed copies of `helm`, `jb` and `kustomize`. +==== + +== Upgrade with `uv` + +. Upgrade your Commodore installation to the latest published version ++ +[source,bash] +---- +uv tool upgrade syn-commodore +---- diff --git a/docs/modules/ROOT/pages/reference/cli.adoc b/docs/modules/ROOT/pages/reference/cli.adoc index 547c57e70..e82688b3f 100644 --- a/docs/modules/ROOT/pages/reference/cli.adoc +++ b/docs/modules/ROOT/pages/reference/cli.adoc @@ -655,6 +655,44 @@ However, labels added by previous runs can't be removed since we've got no easy The component template version (Git tree-ish) to use. If not provided, the currently active template version will be used. +== Tool List + +*--github-token* TEXT:: + The GitHub access token to use when interacting with the GitHub API. + We recommend passing the token in environment variable `COMMODORE_GITHUB_TOKEN`. + + +*--version-check / -V, --skip-version-check*:: + Whether to query the GitHub API to get latest versions. + +== Tool Install + +*--github-token* TEXT:: + The GitHub access token to use when interacting with the GitHub API. + We recommend passing the token in environment variable `COMMODORE_GITHUB_TOKEN`. + +*--version VERSION*:: + Specify a version to install for the requested tool. + By default, the latest version is installed. + +*--missing*:: + Install the latest version for all currently unmanaged tools. + This flag and providing a tool name on the command line are mutually exclusive. + +== Tool Upgrade + +*--github-token* TEXT:: + The GitHub access token to use when interacting with the GitHub API. + We recommend passing the token in environment variable `COMMODORE_GITHUB_TOKEN`. + +*--version VERSION*:: + Specify a custom version to upgrade (or downgrade) to for the requested tool. + By default, tools are upgraded to the latest version. + +*--all*:: + Upgrade all currently managed tools to their latest versions. + This flag and providing a tool name on the command line are mutually exclusive. + == Version Show extended version information for Commodore. diff --git a/docs/modules/ROOT/pages/reference/commands.adoc b/docs/modules/ROOT/pages/reference/commands.adoc index a731e3d4f..f0fd98392 100644 --- a/docs/modules/ROOT/pages/reference/commands.adoc +++ b/docs/modules/ROOT/pages/reference/commands.adoc @@ -278,6 +278,56 @@ The command bases each PR on the default branch of the corresponding package rep The command requires a GitHub Access token with the 'public_repo' permission, which is required to create PRs on public repositories. If you want to manage private repos, the access token may require additional permissions. +== Tool List + + commodore tool list + +This command lists the version, location and management state of the required external tools. + +Currently, `helm`, jsonnet-bundler/`jb`, and `kustomize` are required external tools. +By default, the command also queries the GitHub API to determine the latest available version of each tool and indicates whether an update is available. + +Optionally, the command accepts a GitHub personal access token (PAT) to avoid running into the fairly strict unauthenticated GitHub rate limits. + +== Tool Install + + commodore tool install TOOL + +Install one of the required tools in `$XDG_CACHE_DIR/commodore/tools`. + +The command will fail for tools which are already managed by Commodore. + +By default, the command will install the latest available tool version. +For `helm` and `kustomize`, the command downloads the official installation scripts and executes them with appropriate arguments. +For `jb`, the command directly downloads the requested version from the GitHub release page. + +Optionally, the command accepts a tool version to install. +The command accepts versions prefixed with "v" and unprefixed versions. + + commodore tool install --missing + +Install the latest version of each required tool which isn't managed by Commodore yet. +This variant of the command doesn't accept a tool name or the `--version` flag. + +== Tool Upgrade + + commodore tool upgrade TOOL + +Upgrade (or downgrade) one of the required tools in `$XDG_CACHE_DIR/commodore/tools`. +The command will fail for tools which aren't managed by Commodore yet. + +By default, the command will upgrade the tool to the latest available version. +For `helm` and `kustomize`, the command downloads the official installation scripts and executes them with appropriate arguments. +For `jb`, the command directly downloads the requested version from the GitHub release page. + +Optionally, the command accepts a tool version to upgrade (or downgrade) to. +The command accepts versions prefixed with "v" and unprefixed versions. + + commodore tool upgrade --all + +Upgrade all tools which are managed by Commodore to their latest versions. +This variant of the command doesn't accept a tool name or the `--version` flag. + == Version commodore version diff --git a/docs/modules/ROOT/partials/nav-howtos.adoc b/docs/modules/ROOT/partials/nav-howtos.adoc index 220dbf239..a948e9f07 100644 --- a/docs/modules/ROOT/partials/nav-howtos.adoc +++ b/docs/modules/ROOT/partials/nav-howtos.adoc @@ -1,2 +1,3 @@ +* xref:commodore:ROOT:how-to/installing-commodore.adoc[] * xref:commodore:ROOT:how-to/local-mode-component.adoc[] * xref:commodore:ROOT:how-to/shell-completion.adoc[] diff --git a/renovate.json b/renovate.json index f40292158..9fbb7f13c 100644 --- a/renovate.json +++ b/renovate.json @@ -47,6 +47,12 @@ "matchStrings": ["ARG JSONNET_BUNDLER_VERSION=(?.*?)\\n"], "datasourceTemplate": "github-releases", "depNameTemplate": "projectsyn/jsonnet-bundler" + }, + { + "fileMatch": ["^Dockerfile$"], + "matchStrings": ["ARG HELM_VERSION=(?.*?)\\n"], + "datasourceTemplate": "github-releases", + "depNameTemplate": "helm/helm" } ], "packageRules": [ diff --git a/tests/test_cli.py b/tests/test_cli.py index cf6a49bd4..59de89eb0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -107,3 +107,18 @@ def test_package_sync_command(): def test_version_command(): exit_status = call("commodore version --help", shell=True) assert exit_status == 0 + + +def test_tool_list_command(): + exit_status = call("commodore tool list --help", shell=True) + assert exit_status == 0 + + +def test_tool_install_command(): + exit_status = call("commodore tool install --help", shell=True) + assert exit_status == 0 + + +def test_tool_upgrade_command(): + exit_status = call("commodore tool upgrade --help", shell=True) + assert exit_status == 0 diff --git a/tests/test_cli_tool.py b/tests/test_cli_tool.py new file mode 100644 index 000000000..6ecb89a7c --- /dev/null +++ b/tests/test_cli_tool.py @@ -0,0 +1,164 @@ +from unittest.mock import patch +from typing import Optional + +import pytest + +from conftest import RunnerFunc + +from commodore.config import Config + + +@patch("commodore.tools.list_tools") +@patch("commodore.tools.load_state") +@pytest.mark.parametrize( + "args,vcheck", + [ + ([], True), + (["--version-check"], True), + (["--skip-version-check"], False), + (["-V"], False), + ], +) +def test_tool_list( + mock_load_state, + mock_list_tools, + cli_runner: RunnerFunc, + args: list[str], + vcheck: bool, +): + def mock_list(_config: Config, version_check: bool): + assert version_check == vcheck + + mock_list_tools.side_effect = mock_list + + result = cli_runner(["tool", "list"] + args) + assert result.exit_code == 0 + mock_load_state.assert_called_once() + + +@patch("commodore.tools.install_tool") +@patch("commodore.tools.load_state") +@pytest.mark.parametrize( + "tool,args,expected_version", + [ + ("jb", [], None), + ("jb", ["--version", "v0.6.3"], "v0.6.3"), + ], +) +def test_tool_install( + mock_load_state, + mock_install_tool, + cli_runner: RunnerFunc, + tool: str, + args: list[str], + expected_version, +): + def mock_install(_config: Config, mtool: str, mversion: Optional[str]): + assert mtool == tool + assert mversion == expected_version + + mock_install_tool.side_effect = mock_install + + result = cli_runner(["tool", "install", tool] + args) + assert result.exit_code == 0 + mock_load_state.assert_called_once() + + +@patch("commodore.tools.install_missing_tools") +@patch("commodore.tools.load_state") +@pytest.mark.parametrize( + "args,exit_code,output", + [ + ([], 0, ""), + ( + ["--version", "1.2.3"], + 0, + "Flag `--version` has no effect when calling the command with `--missing`", + ), + ( + ["jb"], + 1, + "`commodore tool install` expects to be called with either a tool name or the `--missing` flag.", + ), + ], +) +def test_tool_install_missing( + mock_load_state, + mock_install_missing_tools, + cli_runner: RunnerFunc, + args: list[str], + exit_code: int, + output: str, +): + result = cli_runner(["tool", "install", "--missing"] + args) + assert result.exit_code == exit_code + assert output in result.output + if exit_code == 0: + mock_install_missing_tools.assert_called_once() + else: + mock_install_missing_tools.assert_not_called() + mock_load_state.assert_called_once() + + +@patch("commodore.tools.upgrade_tool") +@patch("commodore.tools.load_state") +@pytest.mark.parametrize( + "tool,args,expected_version", + [ + ("jb", [], None), + ("jb", ["--version", "v0.6.3"], "v0.6.3"), + ], +) +def test_tool_upgrade( + mock_load_state, + mock_upgrade_tool, + cli_runner: RunnerFunc, + tool: str, + args: list[str], + expected_version, +): + def mock_upgrade(_config: Config, mtool: str, mversion: Optional[str]): + assert mtool == tool + assert mversion == expected_version + + mock_upgrade_tool.side_effect = mock_upgrade + + result = cli_runner(["tool", "upgrade", tool] + args) + assert result.exit_code == 0 + mock_load_state.assert_called_once() + + +@patch("commodore.tools.upgrade_all_tools") +@patch("commodore.tools.load_state") +@pytest.mark.parametrize( + "args,exit_code,output", + [ + ([], 0, ""), + ( + ["--version", "1.2.3"], + 0, + "Flag `--version` has no effect when calling the command with `--all`", + ), + ( + ["jb"], + 1, + "`commodore tool upgrade` expects to be called with either a tool name or the `--all` flag.", + ), + ], +) +def test_tool_upgrade_all( + mock_load_state, + mock_upgrade_all_tools, + cli_runner: RunnerFunc, + args: list[str], + exit_code: int, + output: str, +): + result = cli_runner(["tool", "upgrade", "--all"] + args) + assert result.exit_code == exit_code + assert output in result.output + if exit_code == 0: + mock_upgrade_all_tools.assert_called_once() + else: + mock_upgrade_all_tools.assert_not_called() + mock_load_state.assert_called_once() diff --git a/tests/test_tools.py b/tests/test_tools.py new file mode 100644 index 000000000..abe5ee783 --- /dev/null +++ b/tests/test_tools.py @@ -0,0 +1,595 @@ +import hashlib +import json +import os +import textwrap +import stat +import sys + +from datetime import datetime, timedelta +from pathlib import Path +from typing import Optional +from unittest.mock import patch, MagicMock + +import click +import pytest +import responses + +from commodore.config import Config + +from commodore import tools + +from test_dependency_sync import API_TOKEN_MATCHER + +DATA_DIR = Path(__file__).parent.absolute() / "testdata" / "github" + +TOOL_VERSIONS = { + "helm": "v3.18.3", + "jb": "0.6.3", + "kustomize": "v5.7.0", +} + + +class MockToolInfo: + tool: str + path: Optional[str] + version: Optional[str] + + def __init__(self, tool: str): + self.tool = tool + self.path = f"/path/to/{tool}" + self.version = TOOL_VERSIONS[tool] + + +def _parse_list_tools_output(out: str) -> dict[str, list[str]]: + tool = None + tool_lines = {} + for line in out.splitlines(): + trimmed_line = " ".join(line.strip().split()) + if trimmed_line.startswith(tuple(TOOL_VERSIONS.keys())): + tool = trimmed_line.split(" ")[0] + tool_lines.setdefault(tool, []).append(trimmed_line) + return tool_lines + + +def _setup_tool_github_responses( + auth=False, bad_jb_checksums=False, missing_jb_checksums=False +) -> dict[str, str]: + latest_versions = {} + matchers = [] + if auth: + matchers = [API_TOKEN_MATCHER] + for repo, tool in { + "helm/helm": "helm", + "projectsyn/jsonnet-bundler": "jb", + "kubernetes-sigs/kustomize": "kustomize", + }.items(): + repo_key = repo.replace("/", "-") + with open(DATA_DIR / f"{repo_key}.json", "r", encoding="utf-8") as respf: + resp = json.load(respf) + responses.add( + responses.GET, + f"https://api.github.com:443/repos/{repo}", + json=resp, + status=200, + match=matchers, + ) + with open( + DATA_DIR / f"{repo_key}-releases-latest.json", "r", encoding="utf-8" + ) as latestf: + latest = json.load(latestf) + responses.add( + responses.GET, + f"https://api.github.com:443/repos/{repo}/releases/latest", + json=latest, + status=200, + match=matchers, + ) + latest_versions[tool] = latest["tag_name"].removeprefix(f"{tool}/") + + jb_variants = [ + "jb_darwin_amd64", + "jb_darwin_arm64", + "jb_linux_amd64", + "jb_linux_arm64", + ] + jb_data = [f"#!/bin/sh\necho 'FAKE JB: {variant}'\n" for variant in jb_variants] + if missing_jb_checksums: + jb_checksums = "\n" + else: + if bad_jb_checksums: + fake_chksums = [ + hashlib.sha256(variant.replace("FAKE ", "").encode("utf-8")).hexdigest() + for variant in jb_data + ] + else: + fake_chksums = [ + hashlib.sha256(variant.encode("utf-8")).hexdigest() + for variant in jb_data + ] + jb_checksums = "\n".join( + [ + f"{chksum} {variant}" + for (variant, chksum) in zip(jb_variants, fake_chksums) + ] + ) + responses.add( + responses.GET, + "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/checksums.txt", + body=jb_checksums, + status=200, + ) + for variant, data in zip(jb_variants, jb_data): + responses.add( + responses.GET, + f"https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/{variant}", + body=data, + status=200, + ) + + return latest_versions + + +def test_toolinfo_unknown(): + with pytest.raises(ValueError) as e: + tools.ToolInfo("foo") + assert "Unknown tool foo" in str(e) + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +def test_load_state(fs): + state = { + "helm": "2025-07-09T15:20:00", + "jb": "2025-07-08T19:20:00", + "kustomize": "2025-07-09T15:22:00", + } + fs.create_file(tools.MANAGED_TOOLS_STATE) + fs.create_file(tools.MANAGED_TOOLS_PATH / "helm") + fs.create_file(tools.MANAGED_TOOLS_PATH / "jb") + kustomize = Path("/usr/local/bin/kustomize") + fs.create_file(kustomize) + kustomize.chmod(0o755) + + with open(tools.MANAGED_TOOLS_STATE, "w", encoding="utf-8") as statef: + json.dump(state, statef) + + loaded_state = tools.load_state() + del state["kustomize"] + assert loaded_state == state + + +@patch.object(tools, "ToolInfo") +def test_list_tools_no_version_check(mock_tinfo, config: Config, capsys): + mock_tinfo.side_effect = MockToolInfo + tools.list_tools(config, False) + + out, _ = capsys.readouterr() + tool_lines = _parse_list_tools_output(out) + + for tool, version in TOOL_VERSIONS.items(): + assert tool_lines[tool][0] == f"{tool} {version}" + assert tool_lines[tool][1] == f"Location: /path/to/{tool}" + assert tool_lines[tool][2] == f"Managed: {False}" + assert tool_lines[tool][3] == "Latest version: N/A (Version check skipped)" + assert tool_lines[tool][4] == "Updated: UNKNOWN" + + +@patch.object(tools, "ToolInfo") +@responses.activate +def test_list_tool_version_check_verbose(mock_tinfo, config: Config, capsys): + config.update_verbosity(1) + mock_tinfo.side_effect = MockToolInfo + latest_versions = _setup_tool_github_responses() + + tools.list_tools(config, True) + + out, _ = capsys.readouterr() + tool_lines = _parse_list_tools_output(out) + + for tool, version in TOOL_VERSIONS.items(): + assert tool_lines[tool][0] == f"{tool} {version}" + assert tool_lines[tool][1] == f"Location: /path/to/{tool}" + assert tool_lines[tool][2] == f"Managed: {False}" + if latest_versions[tool].removeprefix("v") == TOOL_VERSIONS[tool].removeprefix( + "v" + ): + # Latest version is always GH tag name even for tools that report + # their own version without a v prefix. + assert ( + tool_lines[tool][3] + == f"Latest version: v{TOOL_VERSIONS[tool].removeprefix('v')} (No upgrade available)" + ) + else: + assert ( + tool_lines[tool][3] + == f"Latest version: {latest_versions[tool]} (Upgrade available!)" + ) + assert tool_lines[tool][4] == "Updated: UNKNOWN" + + +@patch.object(tools, "ToolInfo") +def test_list_tool_missing(mock_tinfo, config: Config, capsys): + class MockToolInfo2(MockToolInfo): + def __init__(self, tool): + if tool != "jb": + super().__init__(tool) + else: + self.tool = tool + self.path = None + self.version = None + + mock_tinfo.side_effect = MockToolInfo2 + + tools.list_tools(config, False) + + out, _ = capsys.readouterr() + tool_lines = _parse_list_tools_output(out) + for tool, version in TOOL_VERSIONS.items(): + if tool == "jb": + assert len(tool_lines[tool]) == 1 + assert tool_lines[tool][0] == f"{tool} missing!" + else: + assert len(tool_lines[tool]) == 5 + assert tool_lines[tool][0] == f"{tool} {version}" + + +@responses.activate +def test_latest_version_authenticated(config: Config): + config.github_token = "ghp_fake-token" + _setup_tool_github_responses(auth=True) + + jb_latest = tools.latest_version(config, "jb") + assert jb_latest == "v0.6.3" + + +def test_check_known_unknown(): + with pytest.raises(click.ClickException) as e: + tools.check_known("foo") + assert e.value.message == ( + "Unknown tool foo. " + + "Commodore currently supports managing the following tools: " + + ", ".join(tools.REQUIRED_TOOLS) + ) + + +def test_install_tool_already_installed(config: Config, capsys): + config.managed_tools = {"jb": "2025-07-09T15:22:00"} + tools.install_tool(config, "jb", None) + out, _ = capsys.readouterr() + assert ( + out + == "Tool jb already installed. Use `commodore tool upgrade jb` to upgrade installed tools.\n" + ) + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +@responses.activate +def test_install_jb(config: Config, fs, capsys): + fs.add_real_directory(os.curdir) + fs.add_real_directory(DATA_DIR) + + config.managed_tools = {} + _setup_tool_github_responses() + assert not tools.MANAGED_TOOLS_PATH.exists() + + tools.install_tool(config, "jb", None) + + out, _ = capsys.readouterr() + outlines = [line.strip() for line in out.splitlines()] + + assert len(outlines) == 3 + assert outlines[0] == "Installing tool jb" + assert outlines[1] == "> Downloading jb v0.6.3" + assert outlines[2] == "> Validating checksum for jb" + + jb_path = tools.MANAGED_TOOLS_PATH / "jb" + assert jb_path.is_file() + + jb_mode = jb_path.stat().st_mode + assert stat.S_ISREG(jb_mode) + assert stat.S_IMODE(jb_mode) == 0o755 + + with open(tools.MANAGED_TOOLS_STATE, "r", encoding="utf-8") as statef: + state = json.load(statef) + assert len(state) == 1 + assert "jb" in state + updated = datetime.fromisoformat(state["jb"]) + assert datetime.now() - updated < timedelta(seconds=1) + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +@responses.activate +@patch.object(tools.platform, "machine") +@patch.object(tools.platform, "system") +@pytest.mark.parametrize( + "machine,system", + [ + ("x86_64", "Linux"), + ("amd64", "Linux"), + ("aarch64", "Linux"), + ("x86_64", "Darwin"), + ("arm64", "Darwin"), + ], +) +def test_install_jb_arch( + mock_system: MagicMock, + mock_machine: MagicMock, + config: Config, + fs, + capsys, + machine: str, + system: str, +): + mock_machine.return_value = machine + mock_system.return_value = system + fs.add_real_directory(os.curdir) + fs.add_real_directory(DATA_DIR) + + config.managed_tools = {} + _setup_tool_github_responses() + assert not tools.MANAGED_TOOLS_PATH.exists() + + tools.install_tool(config, "jb", None) + + osname = system.lower() + match machine: + case "aarch64": + arch = "arm64" + case "x86_64": + arch = "amd64" + case m: + arch = m + jb_binary = f"jb_{osname}_{arch}" + + with open(tools.MANAGED_TOOLS_PATH / "jb", "r", encoding="utf-8") as jbf: + jb_text = jbf.read() + assert f"FAKE JB: {jb_binary}" in jb_text + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +@responses.activate +def test_install_jb_bad_checksum(config: Config, capsys, fs): + fs.add_real_directory(os.curdir) + fs.add_real_directory(DATA_DIR) + + config.managed_tools = {} + _setup_tool_github_responses(bad_jb_checksums=True) + assert not tools.MANAGED_TOOLS_PATH.exists() + with pytest.raises(click.ClickException) as exc: + tools.install_tool(config, "jb", "v0.6.3") + + assert str(exc.value).startswith("Failed to validate checksum for jb_") + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +@responses.activate +def test_install_jb_missing_checksum(config: Config, capsys, fs): + fs.add_real_directory(os.curdir) + fs.add_real_directory(DATA_DIR) + + config.managed_tools = {} + _setup_tool_github_responses(missing_jb_checksums=True) + assert not tools.MANAGED_TOOLS_PATH.exists() + with pytest.raises(click.ClickException) as exc: + tools.install_tool(config, "jb", "v0.6.3") + + assert str(exc.value).startswith("No checksum available for jb_") + + +@responses.activate +@pytest.mark.parametrize("github_token", ["", "ghp_fake-token"]) +def test_install_helm(config: Config, capfd, tmp_path, github_token): + # NOTE(sg): We use `capfd` for this test so we capture writes to + # stdout/stderr (fd 1/2) from subprocesses. + config.github_token = github_token + + responses.add( + responses.GET, + "https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3", + body=textwrap.dedent( + """#!/bin/sh + echo 'Helm installer' + echo "command line=$@" + echo "HELM_INSTALL_DIR=${HELM_INSTALL_DIR}" + echo "GITHUB_TOKEN=${GITHUB_TOKEN}" + """ + ), + status=200, + ) + + with patch.object(tools, "MANAGED_TOOLS_PATH", new=tmp_path) as _: + with patch.object( + tools, "MANAGED_TOOLS_STATE", new=tmp_path / "state.json" + ) as _: + tools.install_tool(config, "helm", TOOL_VERSIONS["helm"]) + + out, _ = capfd.readouterr() + outlines = list(map(str.strip, out.splitlines())) + assert len(outlines) == 5 + assert outlines[1] == "Helm installer" + assert outlines[2] == f"command line=--version {TOOL_VERSIONS['helm']} --no-sudo" + assert outlines[3] == f"HELM_INSTALL_DIR={tmp_path}" + assert outlines[4] == f"GITHUB_TOKEN={github_token}" + + +@responses.activate +@pytest.mark.parametrize("github_token", ["", "ghp_fake-token"]) +def test_install_kustomize(config: Config, capfd, tmp_path, github_token): + # NOTE(sg): We use `capfd` for this test so we capture writes to + # stdout/stderr (fd 1/2) from subprocesses. + config.github_token = github_token + + responses.add( + responses.GET, + "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh", + body=textwrap.dedent( + """#!/bin/sh + echo 'Kustomize installer' + echo "command line=$@" + echo "HELM_INSTALL_DIR=${HELM_INSTALL_DIR}" + echo "GITHUB_TOKEN=${GITHUB_TOKEN}" + """ + ), + status=200, + ) + + with patch.object(tools, "MANAGED_TOOLS_PATH", new=tmp_path) as _: + with patch.object( + tools, "MANAGED_TOOLS_STATE", new=tmp_path / "state.json" + ) as _: + tools.install_tool(config, "kustomize", TOOL_VERSIONS["kustomize"]) + + out, _ = capfd.readouterr() + outlines = list(map(str.strip, out.splitlines())) + assert len(outlines) == 5 + assert outlines[1] == "Kustomize installer" + assert ( + outlines[2] + == f"command line={TOOL_VERSIONS['kustomize'].removeprefix('v')} {tmp_path}" + ) + # we inject the HELM_INSTALL_DIR and GITHUB_TOKEN env vars regardless of + # which tool we install. + assert outlines[3] == f"HELM_INSTALL_DIR={tmp_path}" + assert outlines[4] == f"GITHUB_TOKEN={github_token}" + + +@patch.object(tools, "do_install") +@pytest.mark.parametrize( + "managed,output", + [ + ( + { + "helm": "2025-07-11T11:04:40", + "jb": "2025-07-11T10:58:11", + "kustomize": "2025-07-11T11:05:05", + }, + "All required tools are already managed by Commodore.\n\n" + + "Use `commodore tool upgrade --all` to upgrade all tools " + + "to their latest versions.\n", + ), + ( + {"jb": "2025-07-11T10:58:11"}, + "Installing tool helm\n" + + "Tool jb already managed, skipping...\n" + + "Installing tool kustomize\n", + ), + ], +) +def test_install_missing_tools( + mock_do_install: MagicMock, + config: Config, + capsys, + managed: dict[str, str], + output: str, +): + config.managed_tools = managed + + tools.install_missing_tools(config) + + assert mock_do_install.call_count == len(tools.REQUIRED_TOOLS) - len(managed) + + out, _ = capsys.readouterr() + assert out == output + + +def test_install_script_invalid_version(config: Config): + with pytest.raises(ValueError) as exc: + tools.install_script(config, "jb", "v0.6.3") + + assert ( + str(exc.value) + == "Function install_script() expects parameter `version` to not be prefixed with 'v'." + ) + + +def test_upgrade_tool_not_installed(config: Config, capsys): + config.managed_tools = {} + tools.upgrade_tool(config, "jb", None) + out, _ = capsys.readouterr() + assert ( + out + == "Tool jb not installed yet. Use `commodore tool install jb` to install tools.\n" + ) + + +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="pyfakefs doesn't work nicely with existing pathlib.Path objects on Python < 3.11", +) +@patch.object(tools, "do_install") +@pytest.mark.parametrize("managed_jb", [True, False]) +def test_upgrade_tool(mock_do_install, config: Config, tmp_path, managed_jb): + config.managed_tools["jb"] = "2025-07-10T12:00:00" + if managed_jb: + jb_file = tmp_path / "tools" / "jb" + else: + jb_file = tmp_path / "jb" + jb_file.parent.mkdir(exist_ok=True) + jb_file.touch() + jb_file.chmod(0o755) + + def do_inst(_config: Config, tool: str, version: Optional[str]): + assert tool == "jb" + assert version is None + + mock_do_install.side_effect = do_inst + + # patching MANAGED_TOOLS_PATH for this test because comparing a pyfakefs + # Path with a non-fake Path (the check whether we need to unlink an existing + # managed tool) returns False for the same absolute path. + with patch.object(tools, "MANAGED_TOOLS_PATH", new=tmp_path / "tools"): + with patch.dict( + os.environ, {"PATH": f"{tmp_path/'tools'}{os.pathsep}{tmp_path}"} + ): + tools.upgrade_tool(config, "jb", None) + + assert jb_file.exists() != managed_jb + + +@patch.object(tools, "do_upgrade") +@pytest.mark.parametrize( + "managed,output", + [ + ( + {}, + "No tools managed by Commodore yet.\n\n" + + "Use `commodore tool install --missing` to install the latest " + + "version for all required tools.\n", + ), + ( + {"jb": "2025-07-11T10:58:11"}, + "Tool helm not managed, skipping...\n" + + "Upgrading tool jb\n" + + "Tool kustomize not managed, skipping...\n", + ), + ], +) +def test_upgrade_all_tools( + mock_do_upgrade: MagicMock, + config: Config, + capsys, + managed: dict[str, str], + output: str, +): + config.managed_tools = managed + + tools.upgrade_all_tools(config) + + assert mock_do_upgrade.call_count == len(managed) + + out, _ = capsys.readouterr() + assert out == output diff --git a/tests/testdata/github/helm-helm-releases-latest.json b/tests/testdata/github/helm-helm-releases-latest.json new file mode 100644 index 000000000..8e0566268 --- /dev/null +++ b/tests/testdata/github/helm-helm-releases-latest.json @@ -0,0 +1,1242 @@ +{ + "url": "https://api.github.com/repos/helm/helm/releases/230962935", + "assets_url": "https://api.github.com/repos/helm/helm/releases/230962935/assets", + "upload_url": "https://uploads.github.com/repos/helm/helm/releases/230962935/assets{?name,label}", + "html_url": "https://github.com/helm/helm/releases/tag/v3.18.4", + "id": 230962935, + "author": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "node_id": "RE_kwDOApspmc4NxDb3", + "tag_name": "v3.18.4", + "target_commitish": "main", + "name": "Helm v3.18.4", + "draft": false, + "immutable": false, + "prerelease": false, + "created_at": "2025-07-08T20:31:02Z", + "published_at": "2025-07-08T20:49:25Z", + "assets": [ + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136719", + "id": 271136719, + "node_id": "RA_kwDOApspmc4QKTfP", + "name": "helm-v3.18.4-darwin-amd64.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:68db5507c9dc874421aac5ac66630c8ea73bcf951018805cb87ba4342938781f", + "download_count": 17, + "created_at": "2025-07-08T20:49:14Z", + "updated_at": "2025-07-08T20:49:14Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-amd64.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136718", + "id": 271136718, + "node_id": "RA_kwDOApspmc4QKTfO", + "name": "helm-v3.18.4-darwin-amd64.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:b9e7539068dd14362cdfd689be53b39415780fc87c7c7204c00768ae3fa2cbf1", + "download_count": 14, + "created_at": "2025-07-08T20:49:13Z", + "updated_at": "2025-07-08T20:49:14Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-amd64.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136717", + "id": 271136717, + "node_id": "RA_kwDOApspmc4QKTfN", + "name": "helm-v3.18.4-darwin-amd64.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:9e60eb097c7057d1f62c9177dc504ad4db2938365d352a295b02ecaa93264292", + "download_count": 14, + "created_at": "2025-07-08T20:49:13Z", + "updated_at": "2025-07-08T20:49:13Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-amd64.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136715", + "id": 271136715, + "node_id": "RA_kwDOApspmc4QKTfL", + "name": "helm-v3.18.4-darwin-arm64.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:01c6490403fb5d3bb6a4ee2e8b21347e15c95239de237886d1cfdd89ad6a97f7", + "download_count": 12, + "created_at": "2025-07-08T20:49:13Z", + "updated_at": "2025-07-08T20:49:13Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-arm64.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136714", + "id": 271136714, + "node_id": "RA_kwDOApspmc4QKTfK", + "name": "helm-v3.18.4-darwin-arm64.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:072b9b0144932ea575370702b48bd943d8e3ce2c15bc17db717e74d0560373fd", + "download_count": 11, + "created_at": "2025-07-08T20:49:13Z", + "updated_at": "2025-07-08T20:49:13Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-arm64.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136713", + "id": 271136713, + "node_id": "RA_kwDOApspmc4QKTfJ", + "name": "helm-v3.18.4-darwin-arm64.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:9413d08e069195014815b5b5908f47d1da3bf5dfba2384916134dbe6dafc5f20", + "download_count": 11, + "created_at": "2025-07-08T20:49:13Z", + "updated_at": "2025-07-08T20:49:13Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-darwin-arm64.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136711", + "id": 271136711, + "node_id": "RA_kwDOApspmc4QKTfH", + "name": "helm-v3.18.4-linux-386.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:8d57cdfc97b9349430fc5dec6ede8ab21d41c8303a3cabced3cd5a0fc8e2aed2", + "download_count": 14, + "created_at": "2025-07-08T20:49:12Z", + "updated_at": "2025-07-08T20:49:13Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-386.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136710", + "id": 271136710, + "node_id": "RA_kwDOApspmc4QKTfG", + "name": "helm-v3.18.4-linux-386.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:1eb5cbccbf59801596ac21ae4b77b8fbe961b344aa2b0b3acf6a10c35f790356", + "download_count": 13, + "created_at": "2025-07-08T20:49:12Z", + "updated_at": "2025-07-08T20:49:12Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-386.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136709", + "id": 271136709, + "node_id": "RA_kwDOApspmc4QKTfF", + "name": "helm-v3.18.4-linux-386.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:8d0a5afc908b3c58d577f86626203aefa11eef05fb3e30ae15c23fc780d49b90", + "download_count": 15, + "created_at": "2025-07-08T20:49:12Z", + "updated_at": "2025-07-08T20:49:12Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-386.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136708", + "id": 271136708, + "node_id": "RA_kwDOApspmc4QKTfE", + "name": "helm-v3.18.4-linux-amd64.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:d6d3afd6ade68b32faa19f5e5b0bd0b32cddb21d5cd624d565f9323d5dca0813", + "download_count": 332, + "created_at": "2025-07-08T20:49:12Z", + "updated_at": "2025-07-08T20:49:12Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-amd64.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136707", + "id": 271136707, + "node_id": "RA_kwDOApspmc4QKTfD", + "name": "helm-v3.18.4-linux-amd64.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:fea9343bbfb29da961df26a7c4ac01229ef9be622cd17ee819d0a46fdf1770c9", + "download_count": 296, + "created_at": "2025-07-08T20:49:12Z", + "updated_at": "2025-07-08T20:49:12Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-amd64.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136706", + "id": 271136706, + "node_id": "RA_kwDOApspmc4QKTfC", + "name": "helm-v3.18.4-linux-amd64.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:efe63becef19d119d11185121a24763dcc5430ddaf0e3d87f356c01dd17c3d62", + "download_count": 22, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:12Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-amd64.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136704", + "id": 271136704, + "node_id": "RA_kwDOApspmc4QKTfA", + "name": "helm-v3.18.4-linux-arm.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:222d0402407456cc47dc824bf5b8b82ac0eadc3cfd80b86a418e846767656461", + "download_count": 12, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136703", + "id": 271136703, + "node_id": "RA_kwDOApspmc4QKTe_", + "name": "helm-v3.18.4-linux-arm.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:0c9c9cf70034931c8a387deb9edc278255692f86b867ad9e84690a7c8bc1192c", + "download_count": 13, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136702", + "id": 271136702, + "node_id": "RA_kwDOApspmc4QKTe-", + "name": "helm-v3.18.4-linux-arm.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:d70343912144675c86173f339dc973a2415fba3a84c5af47b742225cbd5af03f", + "download_count": 13, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136698", + "id": 271136698, + "node_id": "RA_kwDOApspmc4QKTe6", + "name": "helm-v3.18.4-linux-arm64.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:71de71d7ab1b00dc7ba0faae8c04d265e010b04de8ed87d5231a02bb887faaf9", + "download_count": 58, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm64.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136697", + "id": 271136697, + "node_id": "RA_kwDOApspmc4QKTe5", + "name": "helm-v3.18.4-linux-arm64.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:2996e4e58c31571f4d52ae330b51fead2541f506144f26241a8bfbe031bfdef0", + "download_count": 62, + "created_at": "2025-07-08T20:49:11Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm64.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136695", + "id": 271136695, + "node_id": "RA_kwDOApspmc4QKTe3", + "name": "helm-v3.18.4-linux-arm64.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:5b76317432f33b2bb41bc9478d7c9779ec101110541758e3848b99b03fa0e38b", + "download_count": 11, + "created_at": "2025-07-08T20:49:10Z", + "updated_at": "2025-07-08T20:49:11Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-arm64.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136694", + "id": 271136694, + "node_id": "RA_kwDOApspmc4QKTe2", + "name": "helm-v3.18.4-linux-ppc64le.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:206b569171cfdd5c9ff88424510e6b736fd8c5b0ab338bbb4755ca80512bc1b5", + "download_count": 9, + "created_at": "2025-07-08T20:49:10Z", + "updated_at": "2025-07-08T20:49:10Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-ppc64le.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136692", + "id": 271136692, + "node_id": "RA_kwDOApspmc4QKTe0", + "name": "helm-v3.18.4-linux-ppc64le.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:3f1dc62b0aea154e8d4b68a97e6fc15226185e3e904d1f474982872c0ec782f4", + "download_count": 10, + "created_at": "2025-07-08T20:49:10Z", + "updated_at": "2025-07-08T20:49:10Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-ppc64le.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136690", + "id": 271136690, + "node_id": "RA_kwDOApspmc4QKTey", + "name": "helm-v3.18.4-linux-ppc64le.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:843a264fd8c27407a8df4c10eb41ed2e624e62b5e2a9cdbeff9ee2f94fb1356f", + "download_count": 10, + "created_at": "2025-07-08T20:49:10Z", + "updated_at": "2025-07-08T20:49:10Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-ppc64le.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136689", + "id": 271136689, + "node_id": "RA_kwDOApspmc4QKTex", + "name": "helm-v3.18.4-linux-riscv64.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:fc2dc28dc5e99fea1699cd44502fbd0660c78d39da1e0615d59aaa018760855d", + "download_count": 10, + "created_at": "2025-07-08T20:49:10Z", + "updated_at": "2025-07-08T20:49:10Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-riscv64.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136687", + "id": 271136687, + "node_id": "RA_kwDOApspmc4QKTev", + "name": "helm-v3.18.4-linux-riscv64.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:6688ece2e017e56d04dadab1f8f168c57c191e65c84be0bb9a9846d35c24c1b1", + "download_count": 11, + "created_at": "2025-07-08T20:49:09Z", + "updated_at": "2025-07-08T20:49:10Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-riscv64.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136685", + "id": 271136685, + "node_id": "RA_kwDOApspmc4QKTet", + "name": "helm-v3.18.4-linux-riscv64.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:41918631e498b4206f81cdaed069a5d5d119a90bdc60f8530b5fd8d171c0f593", + "download_count": 11, + "created_at": "2025-07-08T20:49:09Z", + "updated_at": "2025-07-08T20:49:09Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-riscv64.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136678", + "id": 271136678, + "node_id": "RA_kwDOApspmc4QKTem", + "name": "helm-v3.18.4-linux-s390x.tar.gz.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:180574cb4e2b59d1f8a2fc4c481d86d0bb0b24aa9f21e23c67d15f5da2e2bddd", + "download_count": 10, + "created_at": "2025-07-08T20:49:09Z", + "updated_at": "2025-07-08T20:49:09Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-s390x.tar.gz.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136677", + "id": 271136677, + "node_id": "RA_kwDOApspmc4QKTel", + "name": "helm-v3.18.4-linux-s390x.tar.gz.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:71394c253fc3594e506bf13cb3892a96c11bc99a76137d8b846a30a3fc63290e", + "download_count": 10, + "created_at": "2025-07-08T20:49:09Z", + "updated_at": "2025-07-08T20:49:09Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-s390x.tar.gz.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136676", + "id": 271136676, + "node_id": "RA_kwDOApspmc4QKTek", + "name": "helm-v3.18.4-linux-s390x.tar.gz.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:30c256ebc2a7af19d06d43149ab8d3aceff92ee8597930436f2d9a59822cf6ed", + "download_count": 10, + "created_at": "2025-07-08T20:49:09Z", + "updated_at": "2025-07-08T20:49:09Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-linux-s390x.tar.gz.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136673", + "id": 271136673, + "node_id": "RA_kwDOApspmc4QKTeh", + "name": "helm-v3.18.4-windows-amd64.zip.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:1ee979a8620fe5b169805940707d0a9201d280acea104e82176f039e056f63b0", + "download_count": 31, + "created_at": "2025-07-08T20:49:08Z", + "updated_at": "2025-07-08T20:49:09Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-amd64.zip.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136672", + "id": 271136672, + "node_id": "RA_kwDOApspmc4QKTeg", + "name": "helm-v3.18.4-windows-amd64.zip.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:37552366065d160c8afe7e8957c9fa8a4227e3126963966777c4f28eee2cf2b7", + "download_count": 14, + "created_at": "2025-07-08T20:49:08Z", + "updated_at": "2025-07-08T20:49:08Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-amd64.zip.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136671", + "id": 271136671, + "node_id": "RA_kwDOApspmc4QKTef", + "name": "helm-v3.18.4-windows-amd64.zip.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:f37068d1e2e48fcbe853c005710996723dfef543a6f042ff84401a29984f4617", + "download_count": 13, + "created_at": "2025-07-08T20:49:08Z", + "updated_at": "2025-07-08T20:49:08Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-amd64.zip.sha256sum.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136670", + "id": 271136670, + "node_id": "RA_kwDOApspmc4QKTee", + "name": "helm-v3.18.4-windows-arm64.zip.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:5e985acf5f855a982a5df19227877e90d49b422be296956551a463e99f563145", + "download_count": 13, + "created_at": "2025-07-08T20:49:08Z", + "updated_at": "2025-07-08T20:49:08Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-arm64.zip.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136668", + "id": 271136668, + "node_id": "RA_kwDOApspmc4QKTec", + "name": "helm-v3.18.4-windows-arm64.zip.sha256.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:3f0b0d89992cdcb2fc4fa594bbabf816b7f16d448a61915fd7cefb65544fd4f1", + "download_count": 11, + "created_at": "2025-07-08T20:49:08Z", + "updated_at": "2025-07-08T20:49:08Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-arm64.zip.sha256.asc" + }, + { + "url": "https://api.github.com/repos/helm/helm/releases/assets/271136667", + "id": 271136667, + "node_id": "RA_kwDOApspmc4QKTeb", + "name": "helm-v3.18.4-windows-arm64.zip.sha256sum.asc", + "label": null, + "uploader": { + "login": "robertsirc", + "id": 13884882, + "node_id": "MDQ6VXNlcjEzODg0ODgy", + "avatar_url": "https://avatars.githubusercontent.com/u/13884882?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/robertsirc", + "html_url": "https://github.com/robertsirc", + "followers_url": "https://api.github.com/users/robertsirc/followers", + "following_url": "https://api.github.com/users/robertsirc/following{/other_user}", + "gists_url": "https://api.github.com/users/robertsirc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/robertsirc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/robertsirc/subscriptions", + "organizations_url": "https://api.github.com/users/robertsirc/orgs", + "repos_url": "https://api.github.com/users/robertsirc/repos", + "events_url": "https://api.github.com/users/robertsirc/events{/privacy}", + "received_events_url": "https://api.github.com/users/robertsirc/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 228, + "digest": "sha256:05749d19acfcfcf4b80f125a58d045403f9bb8e8156172d3aa37e2299d3faca6", + "download_count": 11, + "created_at": "2025-07-08T20:49:07Z", + "updated_at": "2025-07-08T20:49:08Z", + "browser_download_url": "https://github.com/helm/helm/releases/download/v3.18.4/helm-v3.18.4-windows-arm64.zip.sha256sum.asc" + } + ], + "tarball_url": "https://api.github.com/repos/helm/helm/tarball/v3.18.4", + "zipball_url": "https://api.github.com/repos/helm/helm/zipball/v3.18.4", + "body": "Helm v3.18.4 is a security release. Users are encouraged to upgrade for the best experience.\r\n\r\nThe community keeps growing, and we'd love to see you there!\r\n\r\n- Join the discussion in [Kubernetes Slack](https://kubernetes.slack.com):\r\n - for questions and just to hang out\r\n - for discussing PRs, code, and bugs\r\n- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/696660622)\r\n- Test, debug, and contribute charts: [ArtifactHub/packages](https://artifacthub.io/packages/search?kind=0)\r\n\r\n## Installation and Upgrading\r\n\r\nDownload Helm v3.18.4. The common platform binaries are here:\r\n\r\n- [MacOS amd64](https://get.helm.sh/helm-v3.18.4-darwin-amd64.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-darwin-amd64.tar.gz.sha256sum) / 860a7238285b44b5dc7b3c4dad6194316885d7015d77c34e23177e0e9554af8f)\r\n- [MacOS arm64](https://get.helm.sh/helm-v3.18.4-darwin-arm64.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-darwin-arm64.tar.gz.sha256sum) / 041849741550b20710d7ad0956e805ebd960b483fe978864f8e7fdd03ca84ec8)\r\n- [Linux amd64](https://get.helm.sh/helm-v3.18.4-linux-amd64.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-amd64.tar.gz.sha256sum) / f8180838c23d7c7d797b208861fecb591d9ce1690d8704ed1e4cb8e2add966c1)\r\n- [Linux arm](https://get.helm.sh/helm-v3.18.4-linux-arm.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-arm.tar.gz.sha256sum) / 34ea88aef15fd822e839da262176a36e865bb9cfdb89b1f723811c0cc527f981)\r\n- [Linux arm64](https://get.helm.sh/helm-v3.18.4-linux-arm64.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-arm64.tar.gz.sha256sum) / c0a45e67eef0c7416a8a8c9e9d5d2d30d70e4f4d3f7bea5de28241fffa8f3b89)\r\n- [Linux i386](https://get.helm.sh/helm-v3.18.4-linux-386.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-386.tar.gz.sha256sum) / 75c2d9858725a5907faf8f19d9fb21c0263e4cb864d27d6df8809f96f147d3c0)\r\n- [Linux ppc64le](https://get.helm.sh/helm-v3.18.4-linux-ppc64le.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-ppc64le.tar.gz.sha256sum) / dbd74c59e7710f26e058596723abbf73662b553e01f40dfb08508ffffaeb7b81)\r\n- [Linux s390x](https://get.helm.sh/helm-v3.18.4-linux-s390x.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-s390x.tar.gz.sha256sum) / c8bafb34bcebd53494f0223239977e1ff7b487e714598a5843a0cb1788e20075)\r\n- [Linux riscv64](https://get.helm.sh/helm-v3.18.4-linux-riscv64.tar.gz) ([checksum](https://get.helm.sh/helm-v3.18.4-linux-riscv64.tar.gz.sha256sum) / f67f39104c7e695cbba04dc3b4507a80a034ce9e5ccbe55c84e91b1553b787bd)\r\n- [Windows amd64](https://get.helm.sh/helm-v3.18.4-windows-amd64.zip) ([checksum](https://get.helm.sh/helm-v3.18.4-windows-amd64.zip.sha256sum) / 0af12a2233d71ef4207db1eabbf103b554631206ed5b2b34fc56b73a52596888)\r\n- [Windows arm64](https://get.helm.sh/helm-v3.18.4-windows-arm64.zip) ([checksum](https://get.helm.sh/helm-v3.18.4-windows-arm64.zip.sha256sum) / de6bc8fcffeb041f524a92c6026ea22ef6f939118a30e6bb8b996b77a38486b1)\r\n\r\nThe [Quickstart Guide](https://helm.sh/docs/intro/quickstart/) will get you going from there. For **upgrade instructions** or detailed installation notes, check the [install guide](https://helm.sh/docs/intro/install/). You can also use a [script to install](https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3) on any system with `bash`.\r\n\r\n## What's Next\r\n\r\n - 3.18.5 is the next patch release and will be on August 13, 2025\r\n - 3.19.0 is the next minor release and will be on September 11, 2025\r\n\r\n\r\n## Changelog\r\n\r\n- Disabling linter due to unknown issue f20a4ad1d5c953ca0fb3d3b30aa9aa796d472ef1 (Matt Farina)\r\n- build(deps): bump the k8s-io group with 7 updates 563b0947b995c48354319aa054830db61f793a08 (dependabot[bot])\r\n- Updating link handling 00de613324df4dd930e6d231d9aae7f9dee29c76 (Matt Farina)\r\n", + "reactions": { + "url": "https://api.github.com/repos/helm/helm/releases/230962935/reactions", + "total_count": 1, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 1, + "eyes": 0 + } +} diff --git a/tests/testdata/github/helm-helm.json b/tests/testdata/github/helm-helm.json new file mode 100644 index 000000000..d9fecc45d --- /dev/null +++ b/tests/testdata/github/helm-helm.json @@ -0,0 +1,140 @@ +{ + "id": 43723161, + "node_id": "MDEwOlJlcG9zaXRvcnk0MzcyMzE2MQ==", + "name": "helm", + "full_name": "helm/helm", + "private": false, + "owner": { + "login": "helm", + "id": 15859888, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE1ODU5ODg4", + "avatar_url": "https://avatars.githubusercontent.com/u/15859888?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/helm", + "html_url": "https://github.com/helm", + "followers_url": "https://api.github.com/users/helm/followers", + "following_url": "https://api.github.com/users/helm/following{/other_user}", + "gists_url": "https://api.github.com/users/helm/gists{/gist_id}", + "starred_url": "https://api.github.com/users/helm/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/helm/subscriptions", + "organizations_url": "https://api.github.com/users/helm/orgs", + "repos_url": "https://api.github.com/users/helm/repos", + "events_url": "https://api.github.com/users/helm/events{/privacy}", + "received_events_url": "https://api.github.com/users/helm/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/helm/helm", + "description": "The Kubernetes Package Manager", + "fork": false, + "url": "https://api.github.com/repos/helm/helm", + "forks_url": "https://api.github.com/repos/helm/helm/forks", + "keys_url": "https://api.github.com/repos/helm/helm/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/helm/helm/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/helm/helm/teams", + "hooks_url": "https://api.github.com/repos/helm/helm/hooks", + "issue_events_url": "https://api.github.com/repos/helm/helm/issues/events{/number}", + "events_url": "https://api.github.com/repos/helm/helm/events", + "assignees_url": "https://api.github.com/repos/helm/helm/assignees{/user}", + "branches_url": "https://api.github.com/repos/helm/helm/branches{/branch}", + "tags_url": "https://api.github.com/repos/helm/helm/tags", + "blobs_url": "https://api.github.com/repos/helm/helm/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/helm/helm/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/helm/helm/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/helm/helm/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/helm/helm/statuses/{sha}", + "languages_url": "https://api.github.com/repos/helm/helm/languages", + "stargazers_url": "https://api.github.com/repos/helm/helm/stargazers", + "contributors_url": "https://api.github.com/repos/helm/helm/contributors", + "subscribers_url": "https://api.github.com/repos/helm/helm/subscribers", + "subscription_url": "https://api.github.com/repos/helm/helm/subscription", + "commits_url": "https://api.github.com/repos/helm/helm/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/helm/helm/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/helm/helm/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/helm/helm/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/helm/helm/contents/{+path}", + "compare_url": "https://api.github.com/repos/helm/helm/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/helm/helm/merges", + "archive_url": "https://api.github.com/repos/helm/helm/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/helm/helm/downloads", + "issues_url": "https://api.github.com/repos/helm/helm/issues{/number}", + "pulls_url": "https://api.github.com/repos/helm/helm/pulls{/number}", + "milestones_url": "https://api.github.com/repos/helm/helm/milestones{/number}", + "notifications_url": "https://api.github.com/repos/helm/helm/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/helm/helm/labels{/name}", + "releases_url": "https://api.github.com/repos/helm/helm/releases{/id}", + "deployments_url": "https://api.github.com/repos/helm/helm/deployments", + "created_at": "2015-10-06T01:07:32Z", + "updated_at": "2025-07-09T11:28:58Z", + "pushed_at": "2025-07-08T20:32:25Z", + "git_url": "git://github.com/helm/helm.git", + "ssh_url": "git@github.com:helm/helm.git", + "clone_url": "https://github.com/helm/helm.git", + "svn_url": "https://github.com/helm/helm", + "homepage": "https://helm.sh", + "size": 24167, + "stargazers_count": 28117, + "watchers_count": 28117, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 7272, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 836, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": true, + "topics": [ + "chart", + "charts", + "cncf", + "helm", + "kubernetes" + ], + "visibility": "public", + "forks": 7272, + "open_issues": 836, + "watchers": 28117, + "default_branch": "main", + "temp_clone_token": null, + "custom_properties": { + + }, + "organization": { + "login": "helm", + "id": 15859888, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE1ODU5ODg4", + "avatar_url": "https://avatars.githubusercontent.com/u/15859888?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/helm", + "html_url": "https://github.com/helm", + "followers_url": "https://api.github.com/users/helm/followers", + "following_url": "https://api.github.com/users/helm/following{/other_user}", + "gists_url": "https://api.github.com/users/helm/gists{/gist_id}", + "starred_url": "https://api.github.com/users/helm/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/helm/subscriptions", + "organizations_url": "https://api.github.com/users/helm/orgs", + "repos_url": "https://api.github.com/users/helm/repos", + "events_url": "https://api.github.com/users/helm/events{/privacy}", + "received_events_url": "https://api.github.com/users/helm/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "network_count": 7272, + "subscribers_count": 509 +} diff --git a/tests/testdata/github/kubernetes-sigs-kustomize-releases-latest.json b/tests/testdata/github/kubernetes-sigs-kustomize-releases-latest.json new file mode 100644 index 000000000..fe17c154f --- /dev/null +++ b/tests/testdata/github/kubernetes-sigs-kustomize-releases-latest.json @@ -0,0 +1,366 @@ +{ + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/228518128", + "assets_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/228518128/assets", + "upload_url": "https://uploads.github.com/repos/kubernetes-sigs/kustomize/releases/228518128/assets{?name,label}", + "html_url": "https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize/v5.7.0", + "id": 228518128, + "author": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "node_id": "RE_kwDOB-5y6s4Nnujw", + "tag_name": "kustomize/v5.7.0", + "target_commitish": "master", + "name": "kustomize/v5.7.0", + "draft": false, + "immutable": false, + "prerelease": false, + "created_at": "2025-06-28T06:59:47Z", + "published_at": "2025-06-28T07:09:54Z", + "assets": [ + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091691", + "id": 268091691, + "node_id": "RA_kwDOB-5y6s4P-sEr", + "name": "checksums.txt", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "text/plain; charset=utf-8", + "state": "uploaded", + "size": 818, + "digest": "sha256:ae74bd7d4a104bc9f2cbc26c66b704aa78394ffb517922962c28f17374caaba0", + "download_count": 3357, + "created_at": "2025-06-28T07:02:23Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/checksums.txt" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091688", + "id": 268091688, + "node_id": "RA_kwDOB-5y6s4P-sEo", + "name": "kustomize_v5.7.0_darwin_amd64.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5908188, + "digest": "sha256:277a7401f969ce3945e8f0ff8b0cce6f4353854db1ff89ba070001e3246e7f22", + "download_count": 208, + "created_at": "2025-06-28T07:02:23Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_darwin_amd64.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091687", + "id": 268091687, + "node_id": "RA_kwDOB-5y6s4P-sEn", + "name": "kustomize_v5.7.0_darwin_arm64.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5523988, + "digest": "sha256:c0dac68dc7870e1f673ae4d8fb554df971e0b9b9f0affc4be4c0852f62d0796e", + "download_count": 863, + "created_at": "2025-06-28T07:02:23Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_darwin_arm64.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091690", + "id": 268091690, + "node_id": "RA_kwDOB-5y6s4P-sEq", + "name": "kustomize_v5.7.0_linux_amd64.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5813395, + "digest": "sha256:0d98f06d6d2c2c0ff8923cc136a517af74aaa187f1b9f3e17ff370d0625ede84", + "download_count": 148413, + "created_at": "2025-06-28T07:02:23Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_linux_amd64.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091689", + "id": 268091689, + "node_id": "RA_kwDOB-5y6s4P-sEp", + "name": "kustomize_v5.7.0_linux_arm64.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5311510, + "digest": "sha256:744bb1bc1854b6634dea9eaf6db2f401a734ed25d6837baa6f91157d79c27d5e", + "download_count": 4627, + "created_at": "2025-06-28T07:02:23Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_linux_arm64.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091692", + "id": 268091692, + "node_id": "RA_kwDOB-5y6s4P-sEs", + "name": "kustomize_v5.7.0_linux_ppc64le.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5288000, + "digest": "sha256:752e750d5f349156ea228ae01cf57be22e6cc29f0f05748a1bca7fa870393561", + "download_count": 105, + "created_at": "2025-06-28T07:02:24Z", + "updated_at": "2025-06-28T07:02:24Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_linux_ppc64le.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091693", + "id": 268091693, + "node_id": "RA_kwDOB-5y6s4P-sEt", + "name": "kustomize_v5.7.0_linux_s390x.tar.gz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/x-gtar", + "state": "uploaded", + "size": 5682574, + "digest": "sha256:64898beb154a111c1a98f8cff066fdfa866c4c73505e9a9b5fa6ec39f0292558", + "download_count": 112, + "created_at": "2025-06-28T07:02:24Z", + "updated_at": "2025-06-28T07:02:25Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_linux_s390x.tar.gz" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091694", + "id": 268091694, + "node_id": "RA_kwDOB-5y6s4P-sEu", + "name": "kustomize_v5.7.0_windows_amd64.zip", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/zip", + "state": "uploaded", + "size": 5967161, + "digest": "sha256:eacee576f22e8c0cb1ff2840ec6496aa42346d5a23936fed9899f7019ed2af62", + "download_count": 920, + "created_at": "2025-06-28T07:02:24Z", + "updated_at": "2025-06-28T07:02:25Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_windows_amd64.zip" + }, + { + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases/assets/268091695", + "id": 268091695, + "node_id": "RA_kwDOB-5y6s4P-sEv", + "name": "kustomize_v5.7.0_windows_arm64.zip", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/zip", + "state": "uploaded", + "size": 5386274, + "digest": "sha256:acb94b010781663abe4ffce7d674da31a644c6df9839f73fa6711d5fe13574c0", + "download_count": 147, + "created_at": "2025-06-28T07:02:24Z", + "updated_at": "2025-06-28T07:02:25Z", + "browser_download_url": "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.7.0/kustomize_v5.7.0_windows_arm64.zip" + } + ], + "tarball_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/tarball/kustomize/v5.7.0", + "zipball_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/zipball/kustomize/v5.7.0", + "body": "## Feature\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5630: Add static value source for replacement\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5921: feat: Add images suport for Image Volumes\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5771: fix: Allow patches with empty files with multiple newlines or comments\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5865: feat(helm): allow the use of devel alias for helmcharts\r\n\r\n## fix\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5846: fix: Get version from the BuildInfo.Main.Version if not found in deps and build flag\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5859: fix: Don't panic on multiple $patch: delete strategic merge patches in a single patch file\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5877: fix: make private one field in replacements transformer struct that had a missing JSON tag\r\n\r\n## Dependencies\r\n#5847: replace deplecated package github.com/google/shlex with github.com/carapace-sh/carapace-shlex\r\n#5873: Bump to github.com/spf13/viper v1.20.0\r\n#5931: Drop usage of forked copies of goyaml.v2 and goyaml.v3\r\n\r\n## chore\r\nhttps://github.com/kubernetes-sigs/kustomize/pull/5882: Set Git messages to English for TestRemoteLoad_LocalProtocol\r\n#5934: Update kyaml to v0.20.0\r\n#5935: Update cmd/config to v0.20.0\r\n#5936: Update api to v0.20.0\r\n" +} diff --git a/tests/testdata/github/kubernetes-sigs-kustomize.json b/tests/testdata/github/kubernetes-sigs-kustomize.json new file mode 100644 index 000000000..caea29624 --- /dev/null +++ b/tests/testdata/github/kubernetes-sigs-kustomize.json @@ -0,0 +1,137 @@ +{ + "id": 133067498, + "node_id": "MDEwOlJlcG9zaXRvcnkxMzMwNjc0OTg=", + "name": "kustomize", + "full_name": "kubernetes-sigs/kustomize", + "private": false, + "owner": { + "login": "kubernetes-sigs", + "id": 36015203, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjM2MDE1MjAz", + "avatar_url": "https://avatars.githubusercontent.com/u/36015203?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/kubernetes-sigs", + "html_url": "https://github.com/kubernetes-sigs", + "followers_url": "https://api.github.com/users/kubernetes-sigs/followers", + "following_url": "https://api.github.com/users/kubernetes-sigs/following{/other_user}", + "gists_url": "https://api.github.com/users/kubernetes-sigs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/kubernetes-sigs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/kubernetes-sigs/subscriptions", + "organizations_url": "https://api.github.com/users/kubernetes-sigs/orgs", + "repos_url": "https://api.github.com/users/kubernetes-sigs/repos", + "events_url": "https://api.github.com/users/kubernetes-sigs/events{/privacy}", + "received_events_url": "https://api.github.com/users/kubernetes-sigs/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/kubernetes-sigs/kustomize", + "description": "Customization of kubernetes YAML configurations", + "fork": false, + "url": "https://api.github.com/repos/kubernetes-sigs/kustomize", + "forks_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/forks", + "keys_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/teams", + "hooks_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/hooks", + "issue_events_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/issues/events{/number}", + "events_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/events", + "assignees_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/assignees{/user}", + "branches_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/branches{/branch}", + "tags_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/tags", + "blobs_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/statuses/{sha}", + "languages_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/languages", + "stargazers_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/stargazers", + "contributors_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/contributors", + "subscribers_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/subscribers", + "subscription_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/subscription", + "commits_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/contents/{+path}", + "compare_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/merges", + "archive_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/downloads", + "issues_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/issues{/number}", + "pulls_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/pulls{/number}", + "milestones_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/milestones{/number}", + "notifications_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/labels{/name}", + "releases_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/releases{/id}", + "deployments_url": "https://api.github.com/repos/kubernetes-sigs/kustomize/deployments", + "created_at": "2018-05-11T17:09:33Z", + "updated_at": "2025-07-09T10:27:15Z", + "pushed_at": "2025-06-28T07:24:29Z", + "git_url": "git://github.com/kubernetes-sigs/kustomize.git", + "ssh_url": "git@github.com:kubernetes-sigs/kustomize.git", + "clone_url": "https://github.com/kubernetes-sigs/kustomize.git", + "svn_url": "https://github.com/kubernetes-sigs/kustomize", + "homepage": "", + "size": 96516, + "stargazers_count": 11554, + "watchers_count": 11554, + "language": "Go", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": true, + "forks_count": 2317, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 181, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "hacktoberfest", + "k8s-sig-cli" + ], + "visibility": "public", + "forks": 2317, + "open_issues": 181, + "watchers": 11554, + "default_branch": "master", + "temp_clone_token": null, + "custom_properties": { + + }, + "organization": { + "login": "kubernetes-sigs", + "id": 36015203, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjM2MDE1MjAz", + "avatar_url": "https://avatars.githubusercontent.com/u/36015203?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/kubernetes-sigs", + "html_url": "https://github.com/kubernetes-sigs", + "followers_url": "https://api.github.com/users/kubernetes-sigs/followers", + "following_url": "https://api.github.com/users/kubernetes-sigs/following{/other_user}", + "gists_url": "https://api.github.com/users/kubernetes-sigs/gists{/gist_id}", + "starred_url": "https://api.github.com/users/kubernetes-sigs/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/kubernetes-sigs/subscriptions", + "organizations_url": "https://api.github.com/users/kubernetes-sigs/orgs", + "repos_url": "https://api.github.com/users/kubernetes-sigs/repos", + "events_url": "https://api.github.com/users/kubernetes-sigs/events{/privacy}", + "received_events_url": "https://api.github.com/users/kubernetes-sigs/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "network_count": 2317, + "subscribers_count": 113 +} diff --git a/tests/testdata/github/projectsyn-jsonnet-bundler-releases-latest.json b/tests/testdata/github/projectsyn-jsonnet-bundler-releases-latest.json new file mode 100644 index 000000000..3f41df152 --- /dev/null +++ b/tests/testdata/github/projectsyn-jsonnet-bundler-releases-latest.json @@ -0,0 +1,222 @@ +{ + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/195798443", + "assets_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/195798443/assets", + "upload_url": "https://uploads.github.com/repos/projectsyn/jsonnet-bundler/releases/195798443/assets{?name,label}", + "html_url": "https://github.com/projectsyn/jsonnet-bundler/releases/tag/v0.6.3", + "id": 195798443, + "author": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "node_id": "RE_kwDOHnZ9tM4Lq6Wr", + "tag_name": "v0.6.3", + "target_commitish": "master", + "name": "v0.6.3", + "draft": false, + "immutable": false, + "prerelease": false, + "created_at": "2025-01-21T09:21:56Z", + "published_at": "2025-01-21T09:23:25Z", + "assets": [ + { + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/assets/222058904", + "id": 222058904, + "node_id": "RA_kwDOHnZ9tM4NPFmY", + "name": "checksums.txt", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "text/plain; charset=utf-8", + "state": "uploaded", + "size": 326, + "digest": null, + "download_count": 10, + "created_at": "2025-01-21T09:23:24Z", + "updated_at": "2025-01-21T09:23:24Z", + "browser_download_url": "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/checksums.txt" + }, + { + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/assets/222058893", + "id": 222058893, + "node_id": "RA_kwDOHnZ9tM4NPFmN", + "name": "jb_darwin_amd64", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 7783872, + "digest": null, + "download_count": 3, + "created_at": "2025-01-21T09:23:23Z", + "updated_at": "2025-01-21T09:23:24Z", + "browser_download_url": "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/jb_darwin_amd64" + }, + { + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/assets/222058892", + "id": 222058892, + "node_id": "RA_kwDOHnZ9tM4NPFmM", + "name": "jb_darwin_arm64", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 7659106, + "digest": null, + "download_count": 5, + "created_at": "2025-01-21T09:23:23Z", + "updated_at": "2025-01-21T09:23:24Z", + "browser_download_url": "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/jb_darwin_arm64" + }, + { + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/assets/222058890", + "id": 222058890, + "node_id": "RA_kwDOHnZ9tM4NPFmK", + "name": "jb_linux_amd64", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 7176192, + "digest": null, + "download_count": 387, + "created_at": "2025-01-21T09:23:23Z", + "updated_at": "2025-01-21T09:23:24Z", + "browser_download_url": "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/jb_linux_amd64" + }, + { + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases/assets/222058891", + "id": 222058891, + "node_id": "RA_kwDOHnZ9tM4NPFmL", + "name": "jb_linux_arm64", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 6881280, + "digest": null, + "download_count": 5, + "created_at": "2025-01-21T09:23:23Z", + "updated_at": "2025-01-21T09:23:24Z", + "browser_download_url": "https://github.com/projectsyn/jsonnet-bundler/releases/download/v0.6.3/jb_linux_arm64" + } + ], + "tarball_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/tarball/v0.6.3", + "zipball_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/zipball/v0.6.3", + "body": "2 changes since v0.6.2\n\n## 🐛 Fixes\n\n- Retry Git ref resolution with `main` if `master` resolves to empty string (#7)\n- Fix `--version` flag for released binaries (#8)\n\n\n" +} diff --git a/tests/testdata/github/projectsyn-jsonnet-bundler.json b/tests/testdata/github/projectsyn-jsonnet-bundler.json new file mode 100644 index 000000000..248d214cf --- /dev/null +++ b/tests/testdata/github/projectsyn-jsonnet-bundler.json @@ -0,0 +1,354 @@ +{ + "id": 511081908, + "node_id": "R_kgDOHnZ9tA", + "name": "jsonnet-bundler", + "full_name": "projectsyn/jsonnet-bundler", + "private": false, + "owner": { + "login": "projectsyn", + "id": 58460880, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4NDYwODgw", + "avatar_url": "https://avatars.githubusercontent.com/u/58460880?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/projectsyn", + "html_url": "https://github.com/projectsyn", + "followers_url": "https://api.github.com/users/projectsyn/followers", + "following_url": "https://api.github.com/users/projectsyn/following{/other_user}", + "gists_url": "https://api.github.com/users/projectsyn/gists{/gist_id}", + "starred_url": "https://api.github.com/users/projectsyn/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/projectsyn/subscriptions", + "organizations_url": "https://api.github.com/users/projectsyn/orgs", + "repos_url": "https://api.github.com/users/projectsyn/repos", + "events_url": "https://api.github.com/users/projectsyn/events{/privacy}", + "received_events_url": "https://api.github.com/users/projectsyn/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/projectsyn/jsonnet-bundler", + "description": "A jsonnet package manager.", + "fork": true, + "url": "https://api.github.com/repos/projectsyn/jsonnet-bundler", + "forks_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/forks", + "keys_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/teams", + "hooks_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/hooks", + "issue_events_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/issues/events{/number}", + "events_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/events", + "assignees_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/assignees{/user}", + "branches_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/branches{/branch}", + "tags_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/tags", + "blobs_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/statuses/{sha}", + "languages_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/languages", + "stargazers_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/stargazers", + "contributors_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/contributors", + "subscribers_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/subscribers", + "subscription_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/subscription", + "commits_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/contents/{+path}", + "compare_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/merges", + "archive_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/downloads", + "issues_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/issues{/number}", + "pulls_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/pulls{/number}", + "milestones_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/milestones{/number}", + "notifications_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/labels{/name}", + "releases_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/releases{/id}", + "deployments_url": "https://api.github.com/repos/projectsyn/jsonnet-bundler/deployments", + "created_at": "2022-07-06T09:58:15Z", + "updated_at": "2025-01-21T09:21:41Z", + "pushed_at": "2025-01-21T09:22:05Z", + "git_url": "git://github.com/projectsyn/jsonnet-bundler.git", + "ssh_url": "git@github.com:projectsyn/jsonnet-bundler.git", + "clone_url": "https://github.com/projectsyn/jsonnet-bundler.git", + "svn_url": "https://github.com/projectsyn/jsonnet-bundler", + "homepage": "", + "size": 1703, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Go", + "has_issues": false, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "temp_clone_token": null, + "custom_properties": { + + }, + "organization": { + "login": "projectsyn", + "id": 58460880, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4NDYwODgw", + "avatar_url": "https://avatars.githubusercontent.com/u/58460880?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/projectsyn", + "html_url": "https://github.com/projectsyn", + "followers_url": "https://api.github.com/users/projectsyn/followers", + "following_url": "https://api.github.com/users/projectsyn/following{/other_user}", + "gists_url": "https://api.github.com/users/projectsyn/gists{/gist_id}", + "starred_url": "https://api.github.com/users/projectsyn/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/projectsyn/subscriptions", + "organizations_url": "https://api.github.com/users/projectsyn/orgs", + "repos_url": "https://api.github.com/users/projectsyn/repos", + "events_url": "https://api.github.com/users/projectsyn/events{/privacy}", + "received_events_url": "https://api.github.com/users/projectsyn/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "parent": { + "id": 130865762, + "node_id": "MDEwOlJlcG9zaXRvcnkxMzA4NjU3NjI=", + "name": "jsonnet-bundler", + "full_name": "jsonnet-bundler/jsonnet-bundler", + "private": false, + "owner": { + "login": "jsonnet-bundler", + "id": 38695592, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjM4Njk1NTky", + "avatar_url": "https://avatars.githubusercontent.com/u/38695592?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jsonnet-bundler", + "html_url": "https://github.com/jsonnet-bundler", + "followers_url": "https://api.github.com/users/jsonnet-bundler/followers", + "following_url": "https://api.github.com/users/jsonnet-bundler/following{/other_user}", + "gists_url": "https://api.github.com/users/jsonnet-bundler/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jsonnet-bundler/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jsonnet-bundler/subscriptions", + "organizations_url": "https://api.github.com/users/jsonnet-bundler/orgs", + "repos_url": "https://api.github.com/users/jsonnet-bundler/repos", + "events_url": "https://api.github.com/users/jsonnet-bundler/events{/privacy}", + "received_events_url": "https://api.github.com/users/jsonnet-bundler/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/jsonnet-bundler/jsonnet-bundler", + "description": "A jsonnet package manager.", + "fork": false, + "url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler", + "forks_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/forks", + "keys_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/teams", + "hooks_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/hooks", + "issue_events_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues/events{/number}", + "events_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/events", + "assignees_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/assignees{/user}", + "branches_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/branches{/branch}", + "tags_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/tags", + "blobs_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/statuses/{sha}", + "languages_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/languages", + "stargazers_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/stargazers", + "contributors_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/contributors", + "subscribers_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/subscribers", + "subscription_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/subscription", + "commits_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/contents/{+path}", + "compare_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/merges", + "archive_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/downloads", + "issues_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues{/number}", + "pulls_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/pulls{/number}", + "milestones_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/milestones{/number}", + "notifications_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/labels{/name}", + "releases_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/releases{/id}", + "deployments_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/deployments", + "created_at": "2018-04-24T14:19:06Z", + "updated_at": "2025-07-08T07:22:22Z", + "pushed_at": "2024-08-23T10:25:14Z", + "git_url": "git://github.com/jsonnet-bundler/jsonnet-bundler.git", + "ssh_url": "git@github.com:jsonnet-bundler/jsonnet-bundler.git", + "clone_url": "https://github.com/jsonnet-bundler/jsonnet-bundler.git", + "svn_url": "https://github.com/jsonnet-bundler/jsonnet-bundler", + "homepage": "", + "size": 1682, + "stargazers_count": 566, + "watchers_count": 566, + "language": "Go", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 77, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 58, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 77, + "open_issues": 58, + "watchers": 566, + "default_branch": "master" + }, + "source": { + "id": 130865762, + "node_id": "MDEwOlJlcG9zaXRvcnkxMzA4NjU3NjI=", + "name": "jsonnet-bundler", + "full_name": "jsonnet-bundler/jsonnet-bundler", + "private": false, + "owner": { + "login": "jsonnet-bundler", + "id": 38695592, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjM4Njk1NTky", + "avatar_url": "https://avatars.githubusercontent.com/u/38695592?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jsonnet-bundler", + "html_url": "https://github.com/jsonnet-bundler", + "followers_url": "https://api.github.com/users/jsonnet-bundler/followers", + "following_url": "https://api.github.com/users/jsonnet-bundler/following{/other_user}", + "gists_url": "https://api.github.com/users/jsonnet-bundler/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jsonnet-bundler/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jsonnet-bundler/subscriptions", + "organizations_url": "https://api.github.com/users/jsonnet-bundler/orgs", + "repos_url": "https://api.github.com/users/jsonnet-bundler/repos", + "events_url": "https://api.github.com/users/jsonnet-bundler/events{/privacy}", + "received_events_url": "https://api.github.com/users/jsonnet-bundler/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/jsonnet-bundler/jsonnet-bundler", + "description": "A jsonnet package manager.", + "fork": false, + "url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler", + "forks_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/forks", + "keys_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/teams", + "hooks_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/hooks", + "issue_events_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues/events{/number}", + "events_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/events", + "assignees_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/assignees{/user}", + "branches_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/branches{/branch}", + "tags_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/tags", + "blobs_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/statuses/{sha}", + "languages_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/languages", + "stargazers_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/stargazers", + "contributors_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/contributors", + "subscribers_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/subscribers", + "subscription_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/subscription", + "commits_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/contents/{+path}", + "compare_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/merges", + "archive_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/downloads", + "issues_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/issues{/number}", + "pulls_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/pulls{/number}", + "milestones_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/milestones{/number}", + "notifications_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/labels{/name}", + "releases_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/releases{/id}", + "deployments_url": "https://api.github.com/repos/jsonnet-bundler/jsonnet-bundler/deployments", + "created_at": "2018-04-24T14:19:06Z", + "updated_at": "2025-07-08T07:22:22Z", + "pushed_at": "2024-08-23T10:25:14Z", + "git_url": "git://github.com/jsonnet-bundler/jsonnet-bundler.git", + "ssh_url": "git@github.com:jsonnet-bundler/jsonnet-bundler.git", + "clone_url": "https://github.com/jsonnet-bundler/jsonnet-bundler.git", + "svn_url": "https://github.com/jsonnet-bundler/jsonnet-bundler", + "homepage": "", + "size": 1682, + "stargazers_count": 566, + "watchers_count": 566, + "language": "Go", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 77, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 58, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 77, + "open_issues": 58, + "watchers": 566, + "default_branch": "master" + }, + "network_count": 77, + "subscribers_count": 1 +} diff --git a/tools/install-jb.sh b/tools/install-jb.sh deleted file mode 100755 index 0cb36352a..000000000 --- a/tools/install-jb.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -eu - -VERSION=${1:-} - -if [ "x${VERSION}" = "x" ]; then - echo "Usage: $0 VERSION" - exit 3 -fi - -ARCH=$(uname -m) -case $ARCH in - armv7*) ARCH="arm";; - aarch64|arm64) ARCH="arm64";; - x86_64|amd64) ARCH="amd64";; - *) - echo "Unsupported arch: $ARCH" - exit 5 - :: -esac - -curl -fsSLo /usr/local/bin/jb \ - "https://github.com/projectsyn/jsonnet-bundler/releases/download/$VERSION/jb_linux_$ARCH" - -chmod +x /usr/local/bin/jb