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
106 changes: 106 additions & 0 deletions release/github.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""
Auxiliary functions to interact with the GitHub REST API.

Set the GITHUB_REPO environment variable to override the target repository
(e.g. "myuser/kafka" to test against a personal fork).

Set GITHUB_DRY_RUN=true to print API calls without executing them.
"""

import json
import os
import urllib.request

from runtime import fail

GITHUB_API_URL = "https://api.github.com"
GITHUB_REPO = os.environ.get("GITHUB_REPO", "apache/kafka")
DRY_RUN = os.environ.get("GITHUB_DRY_RUN", "").lower() in ("true", "1", "yes")


def _api_request(token, method, path, body=None):
"""
Make an authenticated request to the GitHub REST API.
In dry-run mode, prints the request details without executing.
"""
url = f"{GITHUB_API_URL}{path}"

if DRY_RUN:
print(f"[DRY RUN] {method} {url}")
if body:
print(f"[DRY RUN] Body: {json.dumps(body, indent=2)}")
return None

data = json.dumps(body).encode("utf-8") if body else None
req = urllib.request.Request(url, data=data, method=method)
req.add_header("Accept", "application/vnd.github.v3+json")
req.add_header("Authorization", f"token {token}")
if data:
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req) as resp:
if resp.status == 204:
return None
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as e:
error_body = e.read().decode("utf-8") if e.fp else ""
fail(f"GitHub API error {e.code} for {method} {path}: {error_body}")


def trigger_workflow(token, workflow_file, ref, inputs):
"""
Trigger a GitHub Actions workflow_dispatch event.
Returns None on success (HTTP 204).
"""
path = f"/repos/{GITHUB_REPO}/actions/workflows/{workflow_file}/dispatches"
body = {"ref": ref, "inputs": inputs}
print(f"Triggering workflow {workflow_file} on {GITHUB_REPO} with inputs: {json.dumps(inputs)}")
_api_request(token, "POST", path, body)
print(f"Successfully triggered {workflow_file}")


def trigger_docker_build_test(token, ref, image_type, kafka_url):
"""
Trigger the Docker Build Test workflow for the given image type.
"""
print(f"\n--- Docker Build Test ({image_type}) ---")
print(f" Image type : {image_type}")
print(f" Branch/ref : {ref}")
print(f" Kafka URL : {kafka_url}")
trigger_workflow(token, "docker_build_and_test.yml", ref, {
"image_type": image_type,
"kafka_url": kafka_url,
})


def trigger_docker_rc_release(token, ref, image_type, rc_docker_image, kafka_url):
"""
Trigger the Docker RC Release workflow for the given image type.
"""
print(f"\n--- Docker RC Release ({image_type}) ---")
print(f" Image type : {image_type}")
print(f" Docker image : {rc_docker_image}")
print(f" Branch/ref : {ref}")
print(f" Kafka URL : {kafka_url}")
trigger_workflow(token, "docker_rc_release.yml", ref, {
"image_type": image_type,
"rc_docker_image": rc_docker_image,
"kafka_url": kafka_url,
})
25 changes: 25 additions & 0 deletions release/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
repo_dir,
)
import git
import github
import gpg
import notes
import preferences
Expand Down Expand Up @@ -372,6 +373,30 @@ def delete_gitrefs():
git.push_ref(rc_tag)
git.push_ref(starting_branch)

# Trigger Docker image build and test workflows via GitHub Actions
print("\n=== Docker Image Workflows ===")
if github.DRY_RUN:
print("NOTE: GITHUB_DRY_RUN is enabled. No actual API calls will be made.")
if github.GITHUB_REPO != "apache/kafka":
print(f"NOTE: Using custom repository: {github.GITHUB_REPO}")
if confirm("Trigger Docker image build workflows via GitHub Actions?"):
github_token = preferences.get('github_token', lambda: prompt("Enter your GitHub personal access token (with 'actions' scope): "))
kafka_url = f"https://dist.apache.org/repos/dist/dev/kafka/{rc_tag}/kafka_2.13-{release_version}.tgz"
print(f"\nStep 1/2: Triggering Docker Build Test workflows for JVM and native images...")
for image_type in ["jvm", "native"]:
github.trigger_docker_build_test(github_token, dev_branch, image_type, kafka_url)
print("\nDocker Build Test workflows triggered successfully for both JVM and native images.")
if confirm("Also trigger Docker RC release workflows to push RC images to DockerHub?"):
print(f"\nStep 2/2: Triggering Docker RC Release workflows for JVM and native images...")
for image_type in ["jvm", "native"]:
docker_image_name = "apache/kafka-native" if image_type == "native" else "apache/kafka"
rc_docker_image = f"{docker_image_name}:{rc_tag}"
github.trigger_docker_rc_release(github_token, dev_branch, image_type, rc_docker_image, kafka_url)
print("\nDocker RC Release workflows triggered successfully for both JVM and native images.")
print(f"\nAll Docker workflow runs can be monitored at: https://github.com/{github.GITHUB_REPO}/actions")
else:
print("Skipping Docker image workflows.")

# Move back to starting branch and clean out the temporary release branch (e.g. 1.0.0) we used to generate everything
git.reset_hard_head()
git.switch_branch(starting_branch)
Expand Down
5 changes: 3 additions & 2 deletions release/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,9 @@ def deploy_instructions():
There will be more than one repository entries created, please close all of them.
In some cases, you may get errors on some repositories while closing them, see KAFKA-15033.
If this is not the first RC, you need to 'Drop' the previous artifacts.
Confirm the correct artifacts are visible at https://repository.apache.org/content/groups/staging/org/apache/kafka/ and build the
jvm and native Docker images following these instructions: https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=34840886#ReleaseProcess-CreateJVMApacheKafkaDockerArtifacts(Forversions>=3.7.0)
Confirm the correct artifacts are visible at https://repository.apache.org/content/groups/staging/org/apache/kafka/
Note: Docker image builds are triggered automatically by this script after the RC tag is pushed.
Monitor the workflow runs at https://github.com/apache/kafka/actions
"""

def sanity_check_instructions(release_version, rc_tag):
Expand Down
Loading
Loading