suite-py 1.41.10__tar.gz → 1.42.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {suite_py-1.41.10 → suite_py-1.42.1}/PKG-INFO +4 -4
  2. {suite_py-1.41.10 → suite_py-1.42.1}/pyproject.toml +4 -4
  3. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/__version__.py +1 -1
  4. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/cli.py +6 -194
  5. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/check.py +0 -18
  6. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/merge_pr.py +1 -12
  7. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/open_pr.py +1 -6
  8. suite_py-1.41.10/suite_py/commands/deploy.py → suite_py-1.42.1/suite_py/commands/release.py +46 -48
  9. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/config.py +0 -1
  10. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/captainhook_handler.py +0 -7
  11. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/okta_handler.py +8 -4
  12. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/metrics.py +1 -1
  13. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/oauth.py +7 -3
  14. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/tokens.py +3 -7
  15. suite_py-1.41.10/suite_py/commands/aggregator.py +0 -159
  16. suite_py-1.41.10/suite_py/commands/batch_job.py +0 -215
  17. suite_py-1.41.10/suite_py/commands/docker.py +0 -91
  18. suite_py-1.41.10/suite_py/commands/generator.py +0 -238
  19. suite_py-1.41.10/suite_py/commands/id.py +0 -60
  20. suite_py-1.41.10/suite_py/commands/ip.py +0 -68
  21. suite_py-1.41.10/suite_py/commands/release.py +0 -449
  22. suite_py-1.41.10/suite_py/commands/secret.py +0 -204
  23. suite_py-1.41.10/suite_py/lib/handler/drone_handler.py +0 -252
  24. suite_py-1.41.10/suite_py/lib/handler/vault_handler.py +0 -28
  25. {suite_py-1.41.10 → suite_py-1.42.1}/LICENSE-APACHE +0 -0
  26. {suite_py-1.41.10 → suite_py-1.42.1}/LICENSE-MIT +0 -0
  27. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/__init__.py +0 -0
  28. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/__init__.py +0 -0
  29. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/ask_review.py +0 -0
  30. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/bump.py +0 -0
  31. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/common.py +0 -0
  32. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/context.py +0 -0
  33. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/create_branch.py +0 -0
  34. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/login.py +0 -0
  35. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/project_lock.py +0 -0
  36. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/set_token.py +0 -0
  37. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/commands/status.py +0 -0
  38. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/__init__.py +0 -0
  39. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/__init__.py +0 -0
  40. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/aws_handler.py +0 -0
  41. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/changelog_handler.py +0 -0
  42. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/frequent_reviewers_handler.py +0 -0
  43. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/git_handler.py +0 -0
  44. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/github_handler.py +0 -0
  45. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/metrics_handler.py +0 -0
  46. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/prompt_utils.py +0 -0
  47. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/version_handler.py +0 -0
  48. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/handler/youtrack_handler.py +0 -0
  49. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/logger.py +0 -0
  50. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/requests/__init__.py +0 -0
  51. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/requests/auth.py +0 -0
  52. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/requests/session.py +0 -0
  53. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/lib/symbol.py +0 -0
  54. {suite_py-1.41.10 → suite_py-1.42.1}/suite_py/templates/login.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: suite-py
3
- Version: 1.41.10
3
+ Version: 1.42.1
4
4
  Summary:
5
5
  Author: larrywax, EugenioLaghi, michelangelomo
6
6
  Author-email: devops@prima.it
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Dist: Click (>=7.0)
15
15
  Requires-Dist: InquirerPy (>=0.2.0)
16
- Requires-Dist: Jinja2 (>=2.11,<3.0.0)
16
+ Requires-Dist: Jinja2 (>=3.1.4,<4.0.0)
17
17
  Requires-Dist: PyGithub (>=1.57)
18
18
  Requires-Dist: PyYaml (>=5.4)
19
19
  Requires-Dist: autoupgrade-prima (>=0.6)
@@ -21,12 +21,12 @@ Requires-Dist: black (>=22.6,<25.0)
21
21
  Requires-Dist: boto3 (>=1.17.84)
22
22
  Requires-Dist: cement (>=3.0)
23
23
  Requires-Dist: colorama (>=0.4.3)
24
- Requires-Dist: cryptography (==42.0.7)
24
+ Requires-Dist: cryptography (==43.0.0)
25
25
  Requires-Dist: halo (>=0.0.28)
26
26
  Requires-Dist: inquirer (==3.1.4)
27
27
  Requires-Dist: itsdangerous (==2.2.0)
28
28
  Requires-Dist: keyring (>=23.9.1,<26.0.0)
29
- Requires-Dist: kubernetes (==29.0.0)
29
+ Requires-Dist: kubernetes (==30.1.0)
30
30
  Requires-Dist: logzero (==1.7.0)
31
31
  Requires-Dist: markupsafe (==2.0.1)
32
32
  Requires-Dist: pptree (==3.1)
@@ -2,12 +2,12 @@
2
2
  authors = ["larrywax, EugenioLaghi, michelangelomo <devops@prima.it>"]
3
3
  description = ""
4
4
  name = "suite-py"
5
- version = "1.41.10"
5
+ version = "1.42.1"
6
6
 
7
7
  [tool.poetry.dependencies]
8
8
  Click = ">=7.0"
9
9
  InquirerPy = ">=0.2.0"
10
- Jinja2 = ">=2.11,<3.0.0"
10
+ Jinja2 = ">=3.1.4,<4.0.0"
11
11
  PyGithub = ">=1.57"
12
12
  PyYaml = ">=5.4"
13
13
  autoupgrade-prima = ">=0.6"
@@ -19,7 +19,7 @@ halo = ">=0.0.28"
19
19
  inquirer = "==3.1.4"
20
20
  itsdangerous = "==2.2.0"
21
21
  keyring = ">=23.9.1,<26.0.0"
22
- kubernetes = "==29.0.0"
22
+ kubernetes = "==30.1.0"
23
23
  logzero = "==1.7.0"
24
24
  markupsafe = "==2.0.1"
25
25
  pptree = "==3.1"
@@ -34,7 +34,7 @@ rich = "==13.7.1"
34
34
  semver = "^2.13.0"
35
35
  termcolor = ">=1.1.0"
36
36
  truststore = {version = ">=0.7,<0.10", python = ">=3.10"}
37
- cryptography = "42.0.7"
37
+ cryptography = "43.0.0"
38
38
 
39
39
  [tool.poetry.dev-dependencies]
40
40
 
@@ -1,2 +1,2 @@
1
1
  # -*- encoding: utf-8 -*-
2
- __version__ = "1.41.10"
2
+ __version__ = "1.42.1"
@@ -53,8 +53,8 @@ from suite_py.lib.tokens import Tokens
53
53
 
54
54
  # pylint: enable=wrong-import-position
55
55
 
56
- ALLOW_NO_GIT_SUBCOMMAND = ["login", "aggregator"]
57
- ALLOW_NO_HOME_SUBCOMMAND = ["login", "aggregator"]
56
+ ALLOW_NO_GIT_SUBCOMMAND = ["check", "set-token", "login"]
57
+ ALLOW_NO_HOME_SUBCOMMAND = ["check", "set-token", "login"]
58
58
 
59
59
 
60
60
  def fetch_latest_version() -> Optional[str]:
@@ -146,12 +146,12 @@ def main(ctx, project, timeout, verbose):
146
146
  if ctx.invoked_subcommand not in ALLOW_NO_GIT_SUBCOMMAND and not git.is_repo(
147
147
  project
148
148
  ):
149
- raise Exception(f"the folder {project} is not a git repo")
149
+ raise ClickException(f"the folder {project} is not a git repo")
150
150
 
151
151
  if ctx.invoked_subcommand not in ALLOW_NO_HOME_SUBCOMMAND and not os.path.basename(
152
152
  project
153
153
  ) in os.listdir(config.user["projects_home"]):
154
- raise Exception(
154
+ raise ClickException(
155
155
  f"the folder {project} is not in {config.user['projects_home']}"
156
156
  )
157
157
 
@@ -292,67 +292,12 @@ def release():
292
292
  @release.command(
293
293
  "create", help="Create a github release (and deploy it if GHA are used)"
294
294
  )
295
- @click.option(
296
- "--deploy",
297
- is_flag=True,
298
- help="Trigger deploy with Drone CI after release creation (Github Actions based microservices will be automatically deployed on production)",
299
- )
300
- @click.pass_obj
301
- @catch_exceptions
302
- def cli_release_create(obj, deploy):
303
- from suite_py.commands.release import Release
304
-
305
- obj.call(Release, action="create", flags={"deploy": deploy}).run()
306
-
307
-
308
- @release.command("deploy", help="Deploy a github release with Drone CI")
309
295
  @click.pass_obj
310
296
  @catch_exceptions
311
- def cli_release_deploy(obj):
297
+ def cli_release_create(obj):
312
298
  from suite_py.commands.release import Release
313
299
 
314
- obj.call(Release, action="deploy").run()
315
-
316
-
317
- @release.command("rollback", help="Rollback a deployment")
318
- @click.pass_obj
319
- @catch_exceptions
320
- def cli_release_rollback(obj):
321
- from suite_py.commands.release import Release
322
-
323
- obj.call(Release, "rollback").run()
324
-
325
-
326
- @main.command("deploy", help="Deploy master branch in production")
327
- @click.pass_obj
328
- @catch_exceptions
329
- def cli_deploy(obj):
330
- from suite_py.commands.deploy import Deploy
331
-
332
- obj.call(Deploy).run()
333
-
334
-
335
- @main.group("docker", help="Manage docker images")
336
- def docker():
337
- pass
338
-
339
-
340
- @docker.command("release", help="Release new docker image")
341
- @click.pass_obj
342
- @catch_exceptions
343
- def cli_docker_release(obj):
344
- from suite_py.commands.docker import Docker
345
-
346
- obj.call(Docker, action="release").run()
347
-
348
-
349
- @docker.command("versions", help="List all available versions of specific image")
350
- @click.pass_obj
351
- @catch_exceptions
352
- def cli_docker_versions(obj):
353
- from suite_py.commands.docker import Docker
354
-
355
- obj.call(Docker, action="versions").run()
300
+ obj.call(Release, action="create").run()
356
301
 
357
302
 
358
303
  @main.command("status", help="Current status of a project")
@@ -373,75 +318,6 @@ def cli_check(obj):
373
318
  obj.call(Check).run()
374
319
 
375
320
 
376
- @main.command("id", help="Get the ID of the hosts where the task is running")
377
- @click.argument("environment", type=click.Choice(("staging", "production")))
378
- @click.pass_obj
379
- @catch_exceptions
380
- def cli_id(obj, environment):
381
- from suite_py.commands.id import ID
382
-
383
- obj.call(ID, environment=environment).run()
384
-
385
-
386
- @main.command("ip", help="Get the IP addresses of the hosts where the task is running")
387
- @click.argument("environment", type=click.Choice(("staging", "production")))
388
- @click.pass_obj
389
- @catch_exceptions
390
- def cli_ip(obj, environment):
391
- from suite_py.commands.ip import IP
392
-
393
- obj.call(IP, environment=environment).run()
394
-
395
-
396
- @main.command("generator", help="Generate different files from templates")
397
- @click.pass_obj
398
- @catch_exceptions
399
- def cli_generator(obj):
400
- from suite_py.commands.generator import Generator
401
-
402
- obj.call(Generator).run()
403
-
404
-
405
- @main.group(
406
- "aggregator",
407
- help="Manage CNAMEs of aggregators in QA envs",
408
- invoke_without_command=True,
409
- )
410
- @click.option(
411
- "-l", "--list", "show_list", help="deprecated", required=False, count=True
412
- )
413
- @click.option("-c", "--change", "change", help="deprecated", required=False, count=True)
414
- @click.pass_context
415
- def aggregator(ctx, show_list, change):
416
- if show_list == 1 or change == 1:
417
- logger.error(
418
- "suite-py aggregator [-c|-l] has been hard-deprecated. Use suite-py aggregator [list|change] instead."
419
- )
420
- sys.exit(0)
421
-
422
- if ctx.invoked_subcommand is None:
423
- logger.error("Missing command. Try suite-py aggregator --help for help.")
424
- sys.exit(0)
425
-
426
-
427
- @aggregator.command("list", help="List all aggregators with the current record")
428
- @click.pass_obj
429
- @catch_exceptions
430
- def cli_aggregator_list(obj):
431
- from suite_py.commands.aggregator import Aggregator
432
-
433
- obj.call(Aggregator, action="list").run()
434
-
435
-
436
- @aggregator.command("change", help="Change aggregator record")
437
- @click.pass_obj
438
- @catch_exceptions
439
- def cli_aggregator_change(obj):
440
- from suite_py.commands.aggregator import Aggregator
441
-
442
- obj.call(Aggregator, action="list").run()
443
-
444
-
445
321
  @main.command("login", help="manage login against Auth0")
446
322
  @click.pass_obj
447
323
  @catch_exceptions
@@ -451,70 +327,6 @@ def login(obj):
451
327
  obj.call(Login).run()
452
328
 
453
329
 
454
- @main.group(
455
- "secret", help="Manage secrets grants in multiple countries (aws-vault needed)"
456
- )
457
- def secret():
458
- pass
459
-
460
-
461
- @secret.command("create", help="Create a new secret")
462
- @click.option("-b", "--base-profile", "base_profile", required=False)
463
- @click.option("-f", "--secret-file", "secret_file", required=False)
464
- @click.pass_obj
465
- @catch_exceptions
466
- def cli_secret_create(obj, base_profile, secret_file):
467
- from suite_py.commands.secret import Secret
468
-
469
- obj.call(
470
- Secret, action="create", base_profile=base_profile, secret_file=secret_file
471
- ).run()
472
-
473
-
474
- @secret.command("grant", help="Grant permissions to an existing secret")
475
- @click.option("-b", "--base-profile", "base_profile", required=False)
476
- @click.option("-f", "--secret-file", "secret_file", required=False)
477
- @click.pass_obj
478
- @catch_exceptions
479
- def cli_secret_grant(obj, base_profile, secret_file):
480
- from suite_py.commands.secret import Secret
481
-
482
- obj.call(
483
- Secret, action="grant", base_profile=base_profile, secret_file=secret_file
484
- ).run()
485
-
486
-
487
- @main.command("batch-job", help="Run batch job on kube")
488
- @click.argument("environment", type=click.Choice(("staging", "production")))
489
- @click.option(
490
- "-c",
491
- "--cpu",
492
- "cpu_request",
493
- required=True,
494
- type=str,
495
- help="Millicpu format. E.g: 1000m (=1CPU)",
496
- )
497
- @click.option(
498
- "-m",
499
- "--memory",
500
- "memory_request",
501
- required=True,
502
- type=str,
503
- help="Mebibytes or gibibyte format. E.g: 256Mi or 1Gi",
504
- )
505
- @click.pass_obj
506
- @catch_exceptions
507
- def cli_run_batch_job(obj, environment, cpu_request, memory_request):
508
- from suite_py.commands.batch_job import BatchJob
509
-
510
- obj.call(
511
- BatchJob,
512
- environment=environment,
513
- cpu_request=cpu_request,
514
- memory_request=memory_request,
515
- ).run()
516
-
517
-
518
330
  @main.command("set-token", help="Create or update a service token")
519
331
  @click.pass_obj
520
332
  @catch_exceptions
@@ -2,7 +2,6 @@
2
2
 
3
3
  from suite_py.lib import logger, metrics
4
4
  from suite_py.lib.handler import prompt_utils
5
- from suite_py.lib.handler.drone_handler import DroneHandler
6
5
  from suite_py.lib.handler.github_handler import GithubHandler
7
6
  from suite_py.lib.handler.youtrack_handler import YoutrackHandler
8
7
  from suite_py.lib.symbol import CHECKMARK, CROSSMARK
@@ -16,11 +15,9 @@ class Check:
16
15
  self._youtrack = YoutrackHandler(config, tokens)
17
16
  self._github = GithubHandler(tokens)
18
17
  self._captainhook = captainhook
19
- self._drone = DroneHandler(config, tokens)
20
18
 
21
19
  self._checks = [
22
20
  ("Github", self._check_github),
23
- ("Drone", self._check_drone),
24
21
  ("Youtrack", self._check_youtrack),
25
22
  ("CaptainHook", self._check_captainhook),
26
23
  ("AWS", self._check_aws),
@@ -52,21 +49,6 @@ class Check:
52
49
  self._invalid_or_missing_tokens.append("github")
53
50
  return "missing_token"
54
51
 
55
- def _check_drone(self):
56
- if self._tokens.drone:
57
- try:
58
- drone_user = self._drone.get_user()
59
- if "message" in drone_user and drone_user["message"] == "Unauthorized":
60
- self._invalid_or_missing_tokens.append("drone")
61
- return "invalid_token"
62
- return "ok"
63
- except Exception:
64
- logger.debug("Error connecting to drone", exc_info=True)
65
- return "unreachable"
66
- else:
67
- self._invalid_or_missing_tokens.append("drone")
68
- return "missing_token"
69
-
70
52
  def _check_youtrack(self):
71
53
  if self._tokens.youtrack:
72
54
  try:
@@ -7,7 +7,6 @@ from suite_py.lib import logger, metrics
7
7
  from suite_py.lib.handler import git_handler as git
8
8
  from suite_py.lib.handler import prompt_utils
9
9
  from suite_py.lib.handler.captainhook_handler import CaptainHook
10
- from suite_py.lib.handler.drone_handler import DroneHandler
11
10
  from suite_py.lib.handler.git_handler import GitHandler
12
11
  from suite_py.lib.handler.github_handler import GithubHandler
13
12
  from suite_py.lib.handler.youtrack_handler import YoutrackHandler
@@ -22,7 +21,6 @@ class MergePR:
22
21
  self._captainhook = captainhook
23
22
  self._git = GitHandler(project, config)
24
23
  self._github = GithubHandler(tokens)
25
- self._drone = DroneHandler(config, tokens, repo=project)
26
24
 
27
25
  @metrics.command("merge-pr")
28
26
  def run(self):
@@ -56,13 +54,6 @@ class MergePR:
56
54
 
57
55
  logger.info("Pull request merged on master!")
58
56
 
59
- if self._drone.parse_yaml():
60
- drone_build_number = self._drone.get_pr_build_number(merge_status.sha)
61
- drone_build_url = self._drone.get_build_url(drone_build_number)
62
-
63
- if drone_build_url:
64
- logger.info(f"You can follow the build status at {drone_build_url}")
65
-
66
57
  self._git.fetch()
67
58
  if self._git.remote_branch_exists(branch_name):
68
59
  self._git.delete_remote_branch(branch_name)
@@ -84,9 +75,7 @@ class MergePR:
84
75
  logger.warning(
85
76
  "There is no YouTrack issue in the branch name or the selected issue does not exist."
86
77
  )
87
- logger.warning(
88
- "No card updated on YouTrack and no QA turned off automatically"
89
- )
78
+ logger.warning("No card updated on YouTrack")
90
79
 
91
80
  logger.info("All done!")
92
81
  sys.exit()
@@ -15,7 +15,6 @@ class OpenPR:
15
15
  self._ask_review = ask_review
16
16
  self._project = project
17
17
  self._config = config
18
- self._tokens = tokens
19
18
  self._youtrack = YoutrackHandler(config, tokens)
20
19
  self._git = GitHandler(project, config)
21
20
  self._branch_name = self._git.current_branch_name()
@@ -25,11 +24,7 @@ class OpenPR:
25
24
  def run(self):
26
25
  if not self._git.remote_branch_exists(self._branch_name):
27
26
  logger.warning(f"No branch named {self._branch_name} found on GitHub")
28
- if prompt_utils.ask_confirm(
29
- "Do you want to commit all the files and push them?"
30
- ):
31
- self._git.add()
32
- self._git.commit("Initial commit")
27
+ if prompt_utils.ask_confirm("Do you want to push your commits to github?"):
33
28
  self._git.push(self._branch_name)
34
29
  else:
35
30
  logger.error("Please, run 'git push' manually")
@@ -3,52 +3,59 @@ import re
3
3
  import sys
4
4
 
5
5
  from suite_py.commands import common
6
- from suite_py.commands.release import _parse_available_countries
7
6
  from suite_py.lib import logger, metrics
8
7
  from suite_py.lib.handler import git_handler as git
9
8
  from suite_py.lib.handler import prompt_utils
10
9
  from suite_py.lib.handler.changelog_handler import ChangelogHandler
11
- from suite_py.lib.handler.drone_handler import DroneHandler
12
10
  from suite_py.lib.handler.git_handler import GitHandler
13
11
  from suite_py.lib.handler.github_handler import GithubHandler
14
12
  from suite_py.lib.handler.version_handler import DEFAULT_VERSION, VersionHandler
15
13
  from suite_py.lib.handler.youtrack_handler import YoutrackHandler
16
14
 
17
15
 
18
- class Deploy:
16
+ class Release:
19
17
  # pylint: disable=too-many-instance-attributes
20
- def __init__(self, project, captainhook, config, tokens):
18
+ def __init__(self, action, project, captainhook, config, tokens):
19
+ self._action = action
21
20
  self._project = project
22
21
  self._config = config
22
+ self._tokens = tokens
23
+ self._changelog_handler = ChangelogHandler()
23
24
  self._youtrack = YoutrackHandler(config, tokens)
24
25
  self._captainhook = captainhook
25
- self._changelog_handler = ChangelogHandler()
26
26
  self._github = GithubHandler(tokens)
27
27
  self._repo = self._github.get_repo(project)
28
28
  self._git = GitHandler(project, config)
29
- self._drone = DroneHandler(config, tokens, repo=project)
30
- self._countries = _parse_available_countries(self._drone)
31
29
  self._version = VersionHandler(self._repo, self._git, self._github)
32
30
 
33
- @metrics.command("deploy")
31
+ @metrics.command("release")
34
32
  def run(self):
35
33
  self._stop_if_prod_locked()
36
-
37
34
  self._git.fetch()
38
35
 
39
- if len(self._countries) > 0:
36
+ if self._action == "create":
37
+ self._create()
38
+
39
+ def _stop_if_prod_locked(self):
40
+ request = self._captainhook.status(self._project, "production")
41
+ if request.status_code != 200:
42
+ logger.error("Unable to determine lock status on master.")
43
+ sys.exit(-1)
44
+
45
+ request_object = request.json()
46
+ if request_object["locked"]:
40
47
  logger.error(
41
- "Deploy command cannot be used on this project. Try to run `suite-py release` instead."
48
+ f"The project is locked in production by {request_object['by']}. Unable to continue."
42
49
  )
43
- sys.exit(1)
50
+ sys.exit(-1)
44
51
 
45
- current_version = self._version.get_latest_version()
52
+ def _create(self):
53
+ latest = self._version.get_latest_version()
46
54
 
47
- if current_version != "":
48
- logger.info(f"The current release is {current_version}")
49
- commits = self._github.get_commits_since_release(
50
- self._repo, current_version
51
- )
55
+ commits = []
56
+ if latest != "":
57
+ logger.info(f"The current release is {latest}")
58
+ commits = self._github.get_commits_since_release(self._repo, latest)
52
59
 
53
60
  _check_migrations_deploy(commits)
54
61
 
@@ -65,10 +72,10 @@ class Deploy:
65
72
  logger.info(f"\nCommits list:\n{message}\n")
66
73
 
67
74
  if not prompt_utils.ask_confirm("Do you want to continue?"):
68
- sys.exit()
75
+ return
69
76
 
70
77
  new_version = self._version.select_new_version(
71
- current_version, allow_prerelease=True, allow_custom_version=True
78
+ latest, allow_prerelease=True
72
79
  )
73
80
 
74
81
  else:
@@ -98,43 +105,25 @@ class Deploy:
98
105
  message = f"{latest_entry}\n\n# Commits\n\n{message}"
99
106
 
100
107
  message = common.ask_for_release_description(message)
108
+ sha = commits[0].commit.sha if len(commits) > 0 else ""
109
+ self._create_release(new_version, message, sha)
101
110
 
102
- self._create_release(new_version, message)
103
- self._manage_youtrack_card(commits, new_version)
104
-
105
- def _stop_if_prod_locked(self):
106
- request = self._captainhook.status(self._project, "production")
107
- if request.status_code != 200:
108
- logger.error("Unable to determine lock status on master.")
109
- sys.exit(-1)
110
-
111
- request_object = request.json()
112
- if request_object["locked"]:
113
- logger.error(
114
- f"The project is locked in production by {request_object['by']}. Unable to continue."
115
- )
116
- sys.exit(-1)
117
-
118
- def _create_release(self, new_version, message):
111
+ def _create_release(self, new_version, message, commit):
119
112
  new_release = self._repo.create_git_release(
120
113
  new_version,
121
114
  new_version,
122
115
  self._youtrack.replace_card_names_with_md_links(message),
116
+ target_commitish=commit,
123
117
  )
124
118
  if new_release:
125
119
  logger.info(f"The release has been created! Link: {new_release.html_url}")
126
120
 
127
- build_number = self._drone.get_build_number_from_tag(new_version)
128
- if build_number:
129
- drone_url = self._drone.get_build_url(build_number)
130
- logger.info(
131
- f"You can follow the deployment in production here: {drone_url}"
132
- )
133
-
134
- def _manage_youtrack_card(self, commits, new_version):
121
+ def _manage_youtrack_card(self, version, countries):
135
122
  release_state = self._config.youtrack["release_state"]
136
123
 
137
- issue_ids = self._youtrack.get_issue_ids(commits)
124
+ release_body = self._repo.get_release(version).body
125
+
126
+ issue_ids = self._youtrack.get_ids_from_release_body(release_body)
138
127
 
139
128
  if len(issue_ids) > 0:
140
129
  update_youtrack_state = prompt_utils.ask_confirm(
@@ -146,7 +135,7 @@ class Deploy:
146
135
  try:
147
136
  self._youtrack.comment(
148
137
  issue_id,
149
- f"Deploy in production of {self._project} done with the release {new_version}",
138
+ f"Deploy in production of {self._project} in countries {countries} done with the release {version}",
150
139
  )
151
140
  if update_youtrack_state:
152
141
  self._youtrack.update_state(issue_id, release_state)
@@ -167,7 +156,7 @@ class Deploy:
167
156
 
168
157
  def _get_repos_status_from_issue(self, issue_id):
169
158
  regex_pr = r"^PR .* -> https:\/\/github\.com\/primait\/(.*)\/pull\/([0-9]*)$"
170
- regex_deploy = r"^Deploy in production of (.*) done with the release"
159
+ regex_deploy = r"^Deploy in production of (.*) in countries"
171
160
  comments = self._youtrack.get_comments(issue_id)
172
161
  repos_status = {}
173
162
 
@@ -188,6 +177,15 @@ class Deploy:
188
177
  pass
189
178
  return repos_status
190
179
 
180
+ def _tags_drifted(self, versions):
181
+ for country, version in versions.items():
182
+ for c, v in versions.items():
183
+ if country == c:
184
+ continue
185
+ if version is None or v is None or version.compare(v) != 0:
186
+ return True
187
+ return False
188
+
191
189
 
192
190
  def _check_migrations_deploy(commits):
193
191
  if not commits:
@@ -40,7 +40,6 @@ class Config:
40
40
  conf["user"].setdefault("captainhook_timeout", 30)
41
41
  conf["user"].setdefault("captainhook_url", "https://captainhook.prima.it")
42
42
  conf["user"].setdefault("use_commits_in_pr_body", False)
43
- conf["user"].setdefault("delete_qa_after_merge", True)
44
43
  conf["user"].setdefault("frequent_reviewers_max_number", 5)
45
44
 
46
45
  conf["youtrack"].setdefault("add_reviewers_tags", True)
@@ -52,13 +52,6 @@ class CaptainHook:
52
52
  def get_users_list(self):
53
53
  return self.send_get_request("/users/all")
54
54
 
55
- def aggregators(self):
56
- return self.send_get_request("/cloudflare/aggregators/available")
57
-
58
- def change_aggregator(self, aggregator, qa_address):
59
- data = {"aggregator": aggregator, "qa_address": qa_address}
60
- return self.send_put_request("/cloudflare/aggregators", data)
61
-
62
55
  def send_metrics(self, metrics):
63
56
  self.send_post_request("/suite_py/metrics/", json=metrics).raise_for_status()
64
57
 
@@ -8,6 +8,10 @@ from suite_py.lib.tokens import Tokens
8
8
  _SCOPE = "openid offline_access"
9
9
 
10
10
 
11
+ class OktaError(Exception):
12
+ pass
13
+
14
+
11
15
  class Okta:
12
16
  def __init__(self, config: Config, tokens: Tokens) -> None:
13
17
  self._config = config
@@ -34,8 +38,8 @@ class Okta:
34
38
 
35
39
  refresh_token = self._get_refresh_token()
36
40
  if not isinstance(refresh_token, str):
37
- raise Exception(
38
- "Invalid okta refresh token. Try logging in with `suite_py login`"
41
+ raise OktaError(
42
+ "Invalid okta refresh token. Try logging in with `suite-py login`"
39
43
  )
40
44
  res = oauth.do_refresh_token(
41
45
  self._config.okta["client_id"],
@@ -48,9 +52,9 @@ class Okta:
48
52
 
49
53
  def _update_tokens(self, tokens: oauth.OAuthTokenResponse) -> str:
50
54
  if not tokens.id_token:
51
- raise Exception("Okta didn't return a new id_token. This shouldn't happen.")
55
+ raise OktaError("Okta didn't return a new id_token. This shouldn't happen.")
52
56
  if not tokens.refresh_token:
53
- raise Exception(
57
+ raise OktaError(
54
58
  "Okta didn't return a new refresh_token. This shouldn't happen."
55
59
  )
56
60
 
@@ -12,7 +12,7 @@ def _metrics() -> Metrics:
12
12
  if _metrics_handler:
13
13
  return _metrics_handler
14
14
 
15
- raise Exception(
15
+ raise RuntimeError(
16
16
  "command_executed called before logger.setup(). This is a bug, please report it"
17
17
  )
18
18