Skip to content

Commit

Permalink
Merge pull request #529 from launchableinc/support-link-option
Browse files Browse the repository at this point in the history
Support link option
  • Loading branch information
Konboi authored Jan 23, 2023
2 parents 797588c + e606695 commit aa5bcd2
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 135 deletions.
1 change: 1 addition & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ env:
LAUNCHABLE_ORGANIZATION: "launchableinc"
LAUNCHABLE_WORKSPACE: "cli"
EXPERIMENTAL_GITHUB_OIDC_TOKEN_AUTH: 1
GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }}

permissions:
id-token: write
Expand Down
4 changes: 3 additions & 1 deletion launchable/commands/helper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Optional

import click

Expand All @@ -12,6 +12,7 @@ def find_or_create_session(
build_name: Optional[str],
flavor=[],
is_observation: bool = False,
links: List[str] = [],
) -> Optional[str]:
"""Determine the test session ID to be used.
Expand Down Expand Up @@ -63,6 +64,7 @@ def find_or_create_session(
print_session=False,
flavor=flavor,
is_observation=is_observation,
links=links,
)
return read_session(saved_build_name)

Expand Down
36 changes: 25 additions & 11 deletions launchable/commands/record/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import click
from tabulate import tabulate

from launchable.utils.key_value_type import normalize_key_value_types
from launchable.utils.link import LinkKind, capture_link

from ...utils import subprocess
from ...utils.authentication import get_org_workspace
from ...utils.click import KeyValueType
Expand Down Expand Up @@ -63,9 +66,17 @@
default=[],
cls=KeyValueType,
)
@click.option(
'--link',
'links',
help="Set external link of title and url",
multiple=True,
default=[],
cls=KeyValueType,
)
@click.pass_context
def build(ctx: click.core.Context, build_name: str, source: List[str], max_days: int, no_submodules: bool,
no_commit_collection: bool, scrub_pii: bool, commits: List[str]):
no_commit_collection: bool, scrub_pii: bool, commits: List[str], links: List[str]):

if "/" in build_name or "%2f" in build_name.lower():
sys.exit("--name must not contain a slash and an encoded slash")
Expand Down Expand Up @@ -138,15 +149,8 @@ def build(ctx: click.core.Context, build_name: str, source: List[str], max_days:

if len(commits) != 0:
invalid = False
_commits = []
# TODO: handle extraction of flavor tuple to dict in better way for
# >=click8.0 that returns tuple of tuples as tuple of str
if isinstance(commits[0], str):
for c in commits:
k, v = c.replace("(", "").replace(")", "").replace("'", "").split(",")
_commits.append((k.strip(), v.strip()))
else:
_commits = commits
_commits = normalize_key_value_types(commits)

for repo_name, hash in _commits:
if not re.match("[0-9A-Fa-f]{5,40}$", hash):
click.echo(click.style(
Expand Down Expand Up @@ -174,9 +178,19 @@ def build(ctx: click.core.Context, build_name: str, source: List[str], max_days:

payload = {
"buildNumber": build_name,
"commitHashes": commitHashes
"commitHashes": commitHashes,
}

_links = capture_link(os.environ)
if len(links) != 0:
for link in normalize_key_value_types(links):
_links.append({
"title": link[0],
"url": link[1],
"kind": LinkKind.CUSTOM_LINK.name,
})
payload["links"] = _links

client = LaunchableClient(dry_run=ctx.obj.dry_run)

res = client.request("post", "builds", payload=payload)
Expand Down
56 changes: 24 additions & 32 deletions launchable/commands/record/session.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
import os
import sys
from http import HTTPStatus
from typing import Dict, List, Mapping, Optional
from typing import List

import click

from ...utils.ci_provider import CIProvider
from launchable.utils.key_value_type import normalize_key_value_types
from launchable.utils.link import LinkKind, capture_link

from ...utils.click import KeyValueType
from ...utils.env_keys import REPORT_ERROR_KEY
from ...utils.flavor import normalize_flavors
from ...utils.http_client import LaunchableClient
from ...utils.session import write_session

LAUNCHABLE_SESSION_DIR_KEY = 'LAUNCHABLE_SESSION_DIR'

JENKINS_URL_KEY = 'JENKINS_URL'
JENKINS_BUILD_URL_KEY = 'BUILD_URL'
GITHUB_ACTIONS_KEY = 'GITHUB_ACTIONS'
GITHUB_ACTIONS_SERVER_URL_KEY = 'GITHUB_SERVER_URL'
GITHUB_ACTIONS_REPOSITORY_KEY = 'GITHUB_REPOSITORY'
GITHUB_ACTIONS_RUN_ID_KEY = 'GITHUB_RUN_ID'
CIRCLECI_KEY = 'CIRCLECI'
CIRCLECI_BUILD_URL_KEY = 'CIRCLE_BUILD_URL'


@click.command()
@click.option(
Expand Down Expand Up @@ -54,6 +46,14 @@
help="enable observation mode",
is_flag=True,
)
@click.option(
'--link',
'links',
help="Set external link of title and url",
multiple=True,
default=[],
cls=KeyValueType,
)
@click.pass_context
def session(
ctx: click.core.Context,
Expand All @@ -62,6 +62,7 @@ def session(
print_session: bool = True,
flavor: List[str] = [],
is_observation: bool = False,
links: List[str] = [],
):
"""
print_session is for barckward compatibility.
Expand All @@ -73,16 +74,23 @@ def session(
"""

flavor_dict = {}
for f in normalize_flavors(flavor):
for f in normalize_key_value_types(flavor):
flavor_dict[f[0]] = f[1]

link = _capture_link(os.environ)
payload = {
"flavors": flavor_dict,
"isObservation": is_observation,
}
if link:
payload["link"] = link

_links = capture_link(os.environ)
if len(links) != 0:
for link in normalize_key_value_types(links):
_links.append({
"title": link[0],
"url": link[1],
"kind": LinkKind.CUSTOM_LINK.name,
})
payload["links"] = _links

client = LaunchableClient(dry_run=ctx.obj.dry_run)
try:
Expand Down Expand Up @@ -116,19 +124,3 @@ def session(
raise e
else:
click.echo(e, err=True)


def _capture_link(env: Mapping[str, str]) -> Optional[Dict[str, str]]:
if env.get(JENKINS_URL_KEY):
return {"provider": CIProvider.JENKINS.value, "url": env.get(JENKINS_BUILD_URL_KEY, "")}
elif env.get(GITHUB_ACTIONS_KEY):
return {"provider": CIProvider.GITHUB_ACTIONS.value, "url": "{}/{}/actions/runs/{}".format(
env.get(GITHUB_ACTIONS_SERVER_URL_KEY),
env.get(GITHUB_ACTIONS_REPOSITORY_KEY),
env.get(GITHUB_ACTIONS_RUN_ID_KEY),
),
}
elif env.get(CIRCLECI_KEY):
return {"provider": CIProvider.CIRCLECI.value, "url": env.get(CIRCLECI_BUILD_URL_KEY, "")}
else:
return None
16 changes: 15 additions & 1 deletion launchable/commands/record/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ def _validate_group(ctx, param, value):
is_flag=True,
hidden=True,
)
@click.option(
'--link',
'links',
help="Set external link of title and url",
multiple=True,
default=[],
cls=KeyValueType,
)
@click.pass_context
def tests(
context: click.core.Context,
Expand All @@ -133,6 +141,7 @@ def tests(
report_paths: bool,
group: str,
is_allow_test_before_build: bool,
links: List[str] = [],
):
logger = Logger()

Expand All @@ -150,7 +159,12 @@ def tests(
session_id = result["session"]
record_start_at = result["start_at"]
else:
session_id = find_or_create_session(context, session, build_name, flavor)
session_id = find_or_create_session(
context=context,
session=session,
build_name=build_name,
flavor=flavor,
links=links)
build_name = read_build()
record_start_at = get_record_start_at(session_id, client)

Expand Down
4 changes: 2 additions & 2 deletions launchable/commands/stats/test_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

from ...utils.click import KeyValueType
from ...utils.env_keys import REPORT_ERROR_KEY
from ...utils.flavor import normalize_flavors
from ...utils.http_client import LaunchableClient
from ...utils.key_value_type import normalize_key_value_types


@click.command()
Expand Down Expand Up @@ -37,7 +37,7 @@ def test_sessions(
# and the check will not pass.
params = {'days': days, 'flavor': []}
flavors = []
for f in normalize_flavors(flavor):
for f in normalize_key_value_types(flavor):
flavors.append('%s=%s' % (f[0], f[1]))

if flavors:
Expand Down
10 changes: 10 additions & 0 deletions launchable/commands/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@
help='Ignore flaky tests above the value set by this option.You can confirm flaky scores in WebApp',
type=click.FloatRange(min=0, max=1.0),
)
@click.option(
'--link',
'links',
help="Set external link of title and url",
multiple=True,
default=[],
cls=KeyValueType,
)
@click.pass_context
def subset(
context: click.core.Context,
Expand All @@ -144,6 +152,7 @@ def subset(
is_get_tests_from_previous_sessions: bool,
is_output_exclusion_rules: bool,
ignore_flaky_tests_above: Optional[float],
links: List[str] = [],
):

if is_observation and is_get_tests_from_previous_sessions:
Expand All @@ -161,6 +170,7 @@ def subset(
build_name=build_name,
flavor=flavor,
is_observation=is_observation,
links=links,
)
file_path_normalizer = FilePathNormalizer(base_path, no_base_path_inference=no_base_path_inference)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List, Sequence, Tuple


def normalize_flavors(flavors_raw: List[str]) -> List[Tuple[str, str]]:
def normalize_key_value_types(kv_types_raw: List[str]) -> List[Tuple[str, str]]:
"""Normalize flavor list, because the type of the flavor list specified in the command line flags differs depending
on the version of the click.
Expand All @@ -15,12 +15,12 @@ def normalize_flavors(flavors_raw: List[str]) -> List[Tuple[str, str]]:
`launchable record session --build aaa --flavor os=ubuntu --flavor python=3.8`
is parsed as build=aaa, flavor=("('os', 'ubuntu')", "('python', '3.8')")
"""
flavors = []
for f in flavors_raw:
if isinstance(f, str):
k, v = f.replace("(", "").replace(")", "").replace("'", "").split(",")
flavors.append((k.strip(), v.strip()))
elif isinstance(f, Sequence):
flavors.append((f[0], f[1]))
kvs = []
for kv in kv_types_raw:
if isinstance(kv, str):
k, v = kv.replace("(", "").replace(")", "").replace("'", "").split(",")
kvs.append((k.strip(), v.strip()))
elif isinstance(kv, Sequence):
kvs.append((kv[0], kv[1]))

return flavors
return kvs
53 changes: 53 additions & 0 deletions launchable/utils/link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from enum import Enum
from typing import Dict, List, Mapping

JENKINS_URL_KEY = 'JENKINS_URL'
JENKINS_BUILD_URL_KEY = 'BUILD_URL'
GITHUB_ACTIONS_KEY = 'GITHUB_ACTIONS'
GITHUB_ACTIONS_SERVER_URL_KEY = 'GITHUB_SERVER_URL'
GITHUB_ACTIONS_REPOSITORY_KEY = 'GITHUB_REPOSITORY'
GITHUB_ACTIONS_RUN_ID_KEY = 'GITHUB_RUN_ID'
GITHUB_PULL_REQUEST_URL_KEY = "GITHUB_PULL_REQUEST_URL"
CIRCLECI_KEY = 'CIRCLECI'
CIRCLECI_BUILD_URL_KEY = 'CIRCLE_BUILD_URL'


class LinkKind(Enum):

LINK_KIND_UNSPECIFIED = 0
CUSTOM_LINK = 1
JENKINS = 2
GITHUB_ACTIONS = 3
GITHUB_PULL_REQUEST = 4
CIRCLECI = 5


def capture_link(env: Mapping[str, str]) -> List[Dict[str, str]]:
links = []

if env.get(JENKINS_URL_KEY):
links.append(
{"kind": LinkKind.JENKINS.name, "url": env.get(JENKINS_BUILD_URL_KEY, ""), "title": ""}
)
if env.get(GITHUB_ACTIONS_KEY):
links.append({
"kind": LinkKind.GITHUB_ACTIONS.name,
"url": "{}/{}/actions/runs/{}".format(
env.get(GITHUB_ACTIONS_SERVER_URL_KEY),
env.get(GITHUB_ACTIONS_REPOSITORY_KEY),
env.get(GITHUB_ACTIONS_RUN_ID_KEY),
),
"title": ""
})
if env.get(GITHUB_PULL_REQUEST_URL_KEY):
links.append({
"kind": LinkKind.GITHUB_PULL_REQUEST.name,
"url": env.get(GITHUB_PULL_REQUEST_URL_KEY, ""),
"title": ""
})
if env.get(CIRCLECI_KEY):
links.append(
{"kind": LinkKind.CIRCLECI.name, "url": env.get(CIRCLECI_BUILD_URL_KEY, ""), "title": ""}
)

return links
Loading

0 comments on commit aa5bcd2

Please sign in to comment.