Skip to content

Commit 0b25806

Browse files
Automate PR creation to release helm chart using gh helm repo
1 parent 41049c8 commit 0b25806

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed

.evergreen-functions.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,25 @@ functions:
838838
unzip -u macos-notary.zip
839839
chmod 755 ./linux_amd64/macnotary
840840
841+
create_chart_release_pr:
842+
- command: github.generate_token
843+
params:
844+
repo: helm-charts
845+
expansion_name: GH_TOKEN
846+
- command: subprocess.exec
847+
type: setup
848+
params:
849+
working_dir: src/github.com/mongodb/mongodb-kubernetes
850+
include_expansions_in_env:
851+
- GH_TOKEN
852+
- workdir
853+
- RELEASE_OPERATOR_VERSION
854+
env:
855+
GH_TOKEN: ${GH_TOKEN}
856+
MCK_DIR: ${workdir}/src/github.com/mongodb/mongodb-kubernetes
857+
# binary: scripts/dev/run_python.sh scripts/create_chart_release_pr.py --chart_version ${RELEASE_OPERATOR_VERSION|*triggered_by_git_tag}
858+
binary: scripts/dev/run_python.sh scripts/create_chart_release_pr.py --chart_version x.y.z
859+
841860
release_kubectl_mongodb_plugin:
842861
- command: github.generate_token
843862
params:

.evergreen-release.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ tasks:
105105
- func: install_goreleaser
106106
- func: install_macos_notarization_service
107107
- func: release_kubectl_mongodb_plugin
108+
109+
- name: create_chart_release_pr
110+
tags: [ "helm_chart_release_pr" ]
111+
commands:
112+
- func: clone
113+
- func: python_venv
114+
- func: create_chart_release_pr
108115

109116
### Release build variants
110117
buildvariants:
@@ -220,3 +227,12 @@ buildvariants:
220227
allowed_requesters: [ "patch", "github_tag" ]
221228
tasks:
222229
- name: release_kubectl_mongodb_plugin
230+
231+
- name: create_chart_release_pr
232+
display_name: create_chart_release_pr
233+
tags: [ "release" ]
234+
run_on:
235+
- release-ubuntu2404-small # This is required for CISA attestation https://jira.mongodb.org/browse/DEVPROD-17780
236+
allowed_requesters: [ "patch", "github_tag" ]
237+
tasks:
238+
- name: create_chart_release_pr

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ python-frontmatter==1.1.0
3737
python-on-whales==0.78.0
3838
yamale==6.0.0
3939
yamllint==1.37.1
40+
PyGithub==2.7.0
4041

4142
# from kubeobject
4243
freezegun==1.5.5

scripts/create_chart_release_pr.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import argparse
2+
import os
3+
import shutil
4+
import subprocess
5+
import sys
6+
import tempfile
7+
8+
from github import Github, GithubException
9+
10+
from lib.base_logger import logger
11+
12+
REPO_URL = "https://github.com/mongodb/helm-charts.git"
13+
REPO_NAME = "mongodb/helm-charts"
14+
TARGET_CHART_SUBDIR = "charts/mongodb-kubernetes"
15+
BASE_BRANCH = "main"
16+
17+
18+
# run_command runs the command `command` from dir cwd
19+
def run_command(command, cwd=None):
20+
logger.info(f"Running command: {' '.join(command)} in directory {cwd}")
21+
result = subprocess.run(command, capture_output=True, text=True, cwd=cwd)
22+
if result.returncode != 0:
23+
logger.error("ERROR:")
24+
logger.error(result.stdout)
25+
logger.error(result.stderr)
26+
raise RuntimeError(f"Command failed: {' '.join(command)}")
27+
logger.info("Command succeeded")
28+
return result.stdout
29+
30+
31+
def create_pull_request(branch_name, chart_version):
32+
logger.info("Creating the pull request in the helm-charts repo.")
33+
github_token = os.environ.get("GH_TOKEN")
34+
35+
if not github_token:
36+
logger.info("Warning: GH_TOKEN environment variable not set.")
37+
pr_url = f"https://github.com/{REPO_NAME}/pull/new/{branch_name}"
38+
logger.info(f"Please create the Pull Request manually by following the link:\n{pr_url}")
39+
40+
try:
41+
g = Github(github_token)
42+
repo = g.get_repo(REPO_NAME)
43+
pr_title = f"Release MCK {chart_version}"
44+
body = f"This PR publishes the MCK chart version {chart_version}."
45+
46+
pr = repo.create_pull(
47+
title=pr_title,
48+
body=body,
49+
head=branch_name,
50+
base=BASE_BRANCH,
51+
)
52+
logger.info(f"Successfully created Pull Request {pr.html_url}")
53+
except GithubException as e:
54+
logger.error(f"ERROR: Could not create Pull Request. GitHub API returned an error: {e.status}")
55+
logger.error(f"Details: {e.data}")
56+
logger.error("Please check your github token permissions and repository details.")
57+
return 1
58+
except Exception as e:
59+
logger.error(f"An unexpected error occurred while creating the PR: {e}")
60+
return 1
61+
62+
63+
def main():
64+
parser = argparse.ArgumentParser(
65+
description="Automate PR creation to release MCK helm chart to github helm chart repo."
66+
)
67+
parser.add_argument(
68+
"--chart_version", help="The version of the chart to be released (e.g., '1.3.0').", required=True
69+
)
70+
args = parser.parse_args()
71+
72+
chart_version = args.chart_version
73+
branch_name = f"mck-release-{chart_version}"
74+
75+
workdir = os.environ.get("MCK_DIR")
76+
if not workdir:
77+
logger.info("The workdir environment variable is not set this should be set to the root of MCK code.")
78+
return 1
79+
# source_chart_path is local helm chart in MCK repo
80+
source_chart_path = os.path.join(workdir, "helm_chart")
81+
82+
if not os.path.isdir(source_chart_path):
83+
logger.info(f"The source chart path '{source_chart_path}' is not a valid directory.")
84+
return 1
85+
86+
github_token = os.environ.get("GH_TOKEN")
87+
88+
with tempfile.TemporaryDirectory() as temp_dir:
89+
helm_repo_path = os.path.join(temp_dir, "helm-charts")
90+
logger.info(f"Working in a temporary directory: {temp_dir}")
91+
92+
try:
93+
run_command(["git", "clone", REPO_URL, helm_repo_path])
94+
run_command(["git", "checkout", "-b", branch_name], cwd=helm_repo_path)
95+
96+
target_dir = os.path.join(helm_repo_path, TARGET_CHART_SUBDIR)
97+
logger.info(f"Clearing content from dir '{target_dir}'")
98+
if os.path.exists(target_dir):
99+
for item in os.listdir(target_dir):
100+
item_path = os.path.join(target_dir, item)
101+
if os.path.isdir(item_path):
102+
shutil.rmtree(item_path)
103+
else:
104+
os.remove(item_path)
105+
106+
logger.info(f"Copying local MCK chart from '{source_chart_path}' to helm repo chart path {target_dir}")
107+
shutil.copytree(source_chart_path, target_dir, dirs_exist_ok=True)
108+
109+
commit_message = f"Release MCK {chart_version}"
110+
run_command(["git", "add", "."], cwd=helm_repo_path)
111+
run_command(["git", "commit", "-m", commit_message], cwd=helm_repo_path)
112+
113+
if github_token:
114+
logger.info("Configuring remote URL for authenticated push...")
115+
# Constructs a URL like https://x-access-token:[email protected]/owner/repo.git
116+
authenticated_url = f"https://x-access-token:{github_token}@{REPO_URL.split('//')[1]}"
117+
run_command(["git", "remote", "set-url", "origin", authenticated_url], cwd=helm_repo_path)
118+
else:
119+
logger.error("github token not found. Push may fail if credentials are not cached.")
120+
return 1
121+
122+
run_command(["git", "push", "-u", "origin", branch_name], cwd=helm_repo_path)
123+
124+
create_pull_request(branch_name, chart_version)
125+
126+
except (RuntimeError, FileNotFoundError, PermissionError) as e:
127+
logger.error(f"\nAn error occurred during local git operations: {e}")
128+
return 1
129+
130+
131+
if __name__ == "__main__":
132+
sys.exit(main())

0 commit comments

Comments
 (0)