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
1 change: 1 addition & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ It does not support:

It accepts the following parameters:

* `--stage` - [optional] flag to choose staging splunkbase to publish the app.
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we planning to expose this for all UCC users, or is this for a specific use case?

* `--app-id` - [required] Splunkbase numerical app id listed in the URL of the app details page.
* `--package-path` - [required] path to the package file (.tar.gz) to be published (must be a valid UCC package).
* `--splunk-versions` - [required] comma-separated list of supported Splunk versions (e.g. "9.1,9.2").
Expand Down
22 changes: 17 additions & 5 deletions splunk_add_on_ucc_framework/commands/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def encode_multipart_formdata(


def upload_package(
base_url: str,
app_id: int,
package_path: str,
splunk_versions: str,
Expand All @@ -70,7 +71,7 @@ def upload_package(
username: str,
password: str,
) -> str:
upload_url = f"https://splunkbase.splunk.com/api/v1/app/{app_id}/new_release/"
upload_url = f"{base_url}/app/{app_id}/new_release/"

fields = {
"filename": os.path.basename(package_path),
Expand Down Expand Up @@ -109,9 +110,9 @@ def upload_package(


def check_package_validation(
package_upload_id: str, username: str, password: str
base_url: str, package_upload_id: str, username: str, password: str
) -> None:
url = f"https://splunkbase.splunk.com/api/v1/package/{package_upload_id}/"
url = f"{base_url}/package/{package_upload_id}/"
auth_header = base64.b64encode(f"{username}:{password}".encode()).decode("utf-8")
context = ssl.create_default_context(cafile=certifi.where())

Expand All @@ -121,14 +122,20 @@ def check_package_validation(
try:
with urllib.request.urlopen(request, context=context) as response:
response_data = json.loads(response.read().decode("utf-8"))
logger.info("Validation status: {}".format(response_data.get("message")))
if response_data.get("result") == "pass":
logger.info(
"Validation status: {}".format(response_data.get("message"))
)
else:
raise Exception(response_data.get("message"))
except urllib.error.HTTPError as e:
error_msg = e.read().decode()
logger.error(f"Failed to retrieve package validation status. {error_msg}")
raise


def publish_package(
use_stage: bool,
app_id: int,
package_path: str,
splunk_versions: str,
Expand All @@ -137,7 +144,12 @@ def publish_package(
username: str,
password: str,
) -> None:
if use_stage:
API_BASEURL = "https://classic.stage.splunkbase.splunk.com/api/v1"
else:
API_BASEURL = "https://splunkbase.splunk.com/api/v1"
package_upload_id = upload_package(
API_BASEURL,
app_id,
package_path,
splunk_versions,
Expand All @@ -147,4 +159,4 @@ def publish_package(
password,
)
if package_upload_id:
check_package_validation(package_upload_id, username, password)
check_package_validation(API_BASEURL, package_upload_id, username, password)
7 changes: 7 additions & 0 deletions splunk_add_on_ucc_framework/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
publish_parser = subparsers.add_parser(
"publish", description="Publish package to the Splunkbase"
)
publish_parser.add_argument(
"--stage",
dest="stage",
help="Whether to release the app on staging or production splunkbase.",
action="store_true",
)
publish_parser.add_argument(
"--app-id",
type=int,
Expand Down Expand Up @@ -334,6 +340,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
)
if args.command == "publish":
publish.publish_package(
use_stage=args.stage,
app_id=args.app_id,
package_path=args.package_path,
splunk_versions=args.splunk_versions,
Expand Down
27 changes: 22 additions & 5 deletions tests/unit/commands/test_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_upload_package_success(self, mock_file, mock_urlopen, mock_logger):
mock_urlopen.return_value.__exit__ = MagicMock(return_value=None)

pkg_id = upload_package(
base_url="https://dummy_url",
app_id=1001,
package_path="tests/test_package.tgz",
splunk_versions="9.5",
Expand All @@ -48,7 +49,14 @@ def test_upload_package_no_id(self, mock_file, mock_urlopen, mock_logger):
mock_urlopen.return_value.__exit__ = MagicMock(return_value=None)

pkg_id = upload_package(
1001, "tests/test_package.tgz", "9.5", "6.x", True, "user", "pass"
"https://dummy_url",
1001,
"tests/test_package.tgz",
"9.5",
"6.x",
True,
"user",
"pass",
)
assert pkg_id == ""
mock_file.assert_called_once_with("tests/test_package.tgz", "rb")
Expand All @@ -75,7 +83,14 @@ def test_upload_package_http_error(self, mock_file, mock_urlopen, mock_logger):

with pytest.raises(urllib.error.HTTPError):
upload_package(
1001, "tests/test_package.tgz", "9.5", "6.x", True, "user", "pass"
"https://dummy_url",
1001,
"tests/test_package.tgz",
"9.5",
"6.x",
True,
"user",
"pass",
)
mock_file.assert_called_once_with("tests/test_package.tgz", "rb")
mock_logger.error.assert_called_with(
Expand All @@ -89,13 +104,15 @@ class TestPackageValidation:
def test_check_package_validation_success(self, mock_urlopen, mock_logger):
mock_response = MagicMock()
mock_response.read.return_value = json.dumps(
{"message": "Validation passed"}
{"message": "Validation passed", "result": "pass"}
).encode("utf-8")
mock_urlopen.return_value = mock_response
mock_urlopen.return_value.__enter__ = MagicMock(return_value=mock_response)
mock_urlopen.return_value.__exit__ = MagicMock(return_value=None)

check_package_validation("pkg123", "user", "pass") # should not raise
check_package_validation(
"https://dummy_url", "pkg123", "user", "pass"
) # should not raise
mock_logger.info.assert_called_with("Validation status: Validation passed")

@patch("splunk_add_on_ucc_framework.commands.publish.logger")
Expand All @@ -115,7 +132,7 @@ def test_check_package_validation_http_error(self, mock_urlopen, mock_logger):
mock_urlopen.return_value.__exit__ = MagicMock(return_value=None)

with pytest.raises(urllib.error.HTTPError):
check_package_validation("pkg123", "user", "pass")
check_package_validation("https://dummy_url", "pkg123", "user", "pass")
mock_logger.error.assert_called_with(
f"Failed to retrieve package validation status. {mock_error.read().decode()}"
)
3 changes: 3 additions & 0 deletions tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ def test_package_command(mock_package, args, expected_parameters):
(
[
"publish",
"--stage",
"--app-id",
"123",
"--package-path",
Expand All @@ -539,6 +540,7 @@ def test_package_command(mock_package, args, expected_parameters):
"pass",
],
{
"use_stage": True,
"app_id": 123,
"package_path": "dist/app.tar.gz",
"splunk_versions": "9.5",
Expand Down Expand Up @@ -566,6 +568,7 @@ def test_package_command(mock_package, args, expected_parameters):
"--make-visible",
],
{
"use_stage": False,
"app_id": 456,
"package_path": "/tmp/app.tar.gz",
"splunk_versions": "9.1,9.2",
Expand Down
Loading