Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions codecov-cli/codecov_cli/helpers/ci_adapters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from codecov_cli.helpers.ci_adapters.droneci import DroneCIAdapter
from codecov_cli.helpers.ci_adapters.github_actions import GithubActionsCIAdapter
from codecov_cli.helpers.ci_adapters.gitlab_ci import GitlabCIAdapter
from codecov_cli.helpers.ci_adapters.harness import HarnessAdapter
from codecov_cli.helpers.ci_adapters.heroku import HerokuCIAdapter
from codecov_cli.helpers.ci_adapters.jenkins import JenkinsAdapter
from codecov_cli.helpers.ci_adapters.local import LocalAdapter
Expand Down Expand Up @@ -48,6 +49,7 @@ def get_ci_providers_list():
BitriseCIAdapter(),
AppveyorCIAdapter(),
WoodpeckerCIAdapter(),
HarnessAdapter(),
HerokuCIAdapter(),
DroneCIAdapter(),
BuildkiteAdapter(),
Expand Down
52 changes: 52 additions & 0 deletions codecov-cli/codecov_cli/helpers/ci_adapters/harness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os

from codecov_cli.helpers.ci_adapters.base import CIAdapterBase
from codecov_cli.helpers.git import parse_slug

# https://developer.harness.io/docs/continuous-integration/troubleshoot-ci/ci-env-var/

# Uses CI_ prefixed environment variables variant if available and DRONE_ prefixed environment variables variant if not
# The DRONE variables overlap with the Drone CI Adapter as Harness CI is built on top
class HarnessAdapter(CIAdapterBase):
def detect(self) -> bool:
return bool(os.getenv("HARNESS_BUILD_ID"))

def _get_branch(self):
return os.getenv("DRONE_COMMIT_BRANCH")

def _get_commit_sha(self):
return os.getenv("DRONE_COMMIT_SHA")

def _get_pull_request_number(self):
return os.getenv("DRONE_PULL_REQUEST")

def _get_job_code(self):
return None

def _get_build_code(self):
return os.getenv("CI_BUILD_NUMBER")

def _get_build_url(self):
return os.getenv("CI_BUILD_LINK")

def _get_slug(self):
ci_repo = os.getenv("CI_REPO")
if ci_repo and "/" in ci_repo:
return ci_repo
for env_var in (
"CI_REPO_REMOTE",
"CI_REMOTE_URL",
"CI_REPO_LINK",
"DRONE_GIT_HTTP_URL",
"DRONE_REMOTE_URL",
):
if url := os.getenv(env_var):
if slug := parse_slug(url):
return slug
return None

def _get_service(self):
return "harness"

def get_service_name(self):
return "Harness"
2 changes: 1 addition & 1 deletion codecov-cli/codecovcli_commands
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Usage: codecovcli [OPTIONS] COMMAND [ARGS]...

Options:
--auto-load-params-from [CircleCI|GithubActions|GitlabCI|Bitbucket|Bitrise|AppVeyor|Woodpecker|Heroku|DroneCI|BuildKite|AzurePipelines|Jenkins|CirrusCI|Teamcity|Travis|AWSCodeBuild|GoogleCloudBuild|Local]
--auto-load-params-from [CircleCI|GithubActions|GitlabCI|Bitbucket|Bitrise|AppVeyor|Woodpecker|Harness|Heroku|DroneCI|BuildKite|AzurePipelines|Jenkins|CirrusCI|Teamcity|Travis|AWSCodeBuild|GoogleCloudBuild|Local]
--codecov-yml-path PATH
-u, --enterprise-url, --url TEXT
Change the upload host (Enterprise use)
Expand Down
4 changes: 2 additions & 2 deletions codecov-cli/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ Homepage = "https://about.codecov.io"
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
packages = ["codecov_cli"]
[tool.setuptools.packages.find]
include = ["codecov_cli*"]

[tool.pytest.ini_options]
env = ["CODECOV_ENV=test"]
Expand Down
150 changes: 150 additions & 0 deletions codecov-cli/tests/ci_adapters/test_harnessci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import os
from enum import Enum

import pytest

from codecov_cli.fallbacks import FallbackFieldEnum
from codecov_cli.helpers.ci_adapters import HarnessAdapter


class HarnessEnvEnum(str, Enum):
HARNESS_BUILD_ID = "HARNESS_BUILD_ID"
CI_BUILD_LINK = "CI_BUILD_LINK"
CI_BUILD_NUMBER = "CI_BUILD_NUMBER"
CI_REMOTE_URL = "CI_REMOTE_URL"
CI_REPO = "CI_REPO"
CI_REPO_LINK = "CI_REPO_LINK"
CI_REPO_REMOTE = "CI_REPO_REMOTE"
DRONE_COMMIT_BRANCH = "DRONE_COMMIT_BRANCH"
DRONE_COMMIT_SHA = "DRONE_COMMIT_SHA"
DRONE_PULL_REQUEST = "DRONE_PULL_REQUEST"
DRONE_GIT_HTTP_URL = "DRONE_GIT_HTTP_URL"
DRONE_REMOTE_URL = "DRONE_REMOTE_URL"

class TestHarnessCI(object):
@pytest.mark.parametrize(
"env_dict,expected",
[
({}, False),
({HarnessEnvEnum.HARNESS_BUILD_ID: "123"}, True),
],
)
def test_detect(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().detect()
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.DRONE_COMMIT_BRANCH: "branch"}, "branch"),
],
)
def test_branch(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.branch)
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.DRONE_COMMIT_SHA: "sha"}, "sha"),
],
)
def test_commit_sha(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.commit_sha)
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.DRONE_PULL_REQUEST: "123"}, "123"),
],
)
def test_pull_request_number(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.pull_request_number)
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.CI_BUILD_NUMBER: "123"}, "123"),
],
)
def test_build_code(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.build_code)
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.CI_BUILD_LINK: "https://example.com"}, "https://example.com"),
],
)
def test_build_url(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.build_url)
assert actual == expected

@pytest.mark.parametrize(
"env_dict,expected",
[
({}, None),
({HarnessEnvEnum.CI_REPO: "owner/repo"}, "owner/repo"),
({HarnessEnvEnum.CI_REPO: "repo"}, None),
(
{
HarnessEnvEnum.CI_REPO_REMOTE: "https://gitlab.com/mygroup/myrepo.git",
},
"mygroup/myrepo",
),
(
{
HarnessEnvEnum.CI_REMOTE_URL: "https://github.com/from-remote-url/from-remote-url",
},
"from-remote-url/from-remote-url",
),
(
{
HarnessEnvEnum.CI_REPO_LINK: "https://github.com/from-repo-link/from-repo-link",
},
"from-repo-link/from-repo-link",
),
(
{
HarnessEnvEnum.DRONE_GIT_HTTP_URL: "https://github.com/myorg/myrepo.git",
},
"myorg/myrepo",
),
(
{
HarnessEnvEnum.DRONE_REMOTE_URL: "git@github.com:acme/coverage.git",
},
"acme/coverage",
),
(
{
HarnessEnvEnum.CI_REPO_REMOTE: "https://github.com/first/first.git",
HarnessEnvEnum.DRONE_GIT_HTTP_URL: "https://github.com/second/second.git",
},
"first/first",
),
],
)
def test_slug(self, env_dict, expected, mocker):
mocker.patch.dict(os.environ, env_dict)
actual = HarnessAdapter().get_fallback_value(FallbackFieldEnum.slug)
assert actual == expected

def test_service(self):
assert (
HarnessAdapter().get_fallback_value(FallbackFieldEnum.service) == "harness"
)
4 changes: 4 additions & 0 deletions codecov-cli/tests/helpers/test_ci_adapter_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
DroneCIAdapter,
GithubActionsCIAdapter,
GitlabCIAdapter,
HarnessAdapter,
HerokuCIAdapter,
JenkinsAdapter,
LocalAdapter,
Expand Down Expand Up @@ -53,6 +54,9 @@ def test_returns_woodpecker(self):
def test_returns_teamcity(self):
assert isinstance(get_ci_adapter("teamcity"), TeamcityAdapter)

def test_returns_harness(self):
assert isinstance(get_ci_adapter("harness"), HarnessAdapter)

def test_returns_herokuci(self):
assert isinstance(get_ci_adapter("heroku"), HerokuCIAdapter)

Expand Down
2 changes: 1 addition & 1 deletion prevent-cli/preventcli_commands
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Usage: sentry-prevent-cli [OPTIONS] COMMAND [ARGS]...

Options:
--auto-load-params-from [CircleCI|GithubActions|GitlabCI|Bitbucket|Bitrise|AppVeyor|Woodpecker|Heroku|DroneCI|BuildKite|AzurePipelines|Jenkins|CirrusCI|Teamcity|Travis|AWSCodeBuild|GoogleCloudBuild|Local]
--auto-load-params-from [CircleCI|GithubActions|GitlabCI|Bitbucket|Bitrise|AppVeyor|Woodpecker|Harness|Heroku|DroneCI|BuildKite|AzurePipelines|Jenkins|CirrusCI|Teamcity|Travis|AWSCodeBuild|GoogleCloudBuild|Local]
--yml-path PATH
-u, --enterprise-url, --url TEXT
Change the upload host (Enterprise use)
Expand Down
Loading