Skip to content
Closed
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
18 changes: 8 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ on:
description: "Should the Gradle cache be write-only?"
default: "false"
type: string
github-actions-opt-in:
description: "Should we run the opt-in steps?"
default: "false"
type: string
is-public-fork:
description: "Is this CI run from a public fork?"
default: "true"
Expand Down Expand Up @@ -66,8 +62,12 @@ jobs:
# Gradle flags
# --build-cache: Let Gradle restore the build cache
# --info: For now, we'll generate lots of logs while setting up the GH Actions
# --scan: Attempt to publish build scans in PRs. This will only work on PRs from apache/kafka, not public forks.
run: ./gradlew --build-cache --info --scan check -x test
# --scan: Publish the build scan. This will only work on PRs from apache/kafka and trunk
# --no-scan: For public fork PRs, we won't attempt to publish the scan
run: |
./gradlew --build-cache --info \
${{ inputs.is-public-fork == 'true' && '--no-scan' || '--scan' }} \
check -x test
- name: Archive check reports
if: always()
uses: actions/upload-artifact@v4
Expand All @@ -78,8 +78,7 @@ jobs:
if-no-files-found: ignore
- name: Annotate checkstyle errors
# Avoid duplicate annotations, only run on java 21
# For now, limit to "gh-" PRs
if: ${{ inputs.github-actions-opt-in && failure() && matrix.java == '21' }}
if: ${{ failure() && matrix.java == '21' }}
run: python .github/scripts/checkstyle.py
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
Expand All @@ -90,8 +89,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java: [ 17, 11 ]
if: ${{ inputs.github-actions-opt-in == 'true' }}
java: [ 17, 11 ] # If we change these, make sure to adjust ci-complete.yml
name: JUnit tests Java ${{ matrix.java }}
steps:
- name: Checkout code
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci-complete.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ jobs:
run: |
./gradlew --info buildScanPublishPrevious > gradle.out
SCAN_URL=$(grep '^https://.*$' gradle.out)
echo "Published build scan to $SCAN_URL"
cat gradle.out
echo "Published build scan to $SCAN_URL" >> $GITHUB_STEP_SUMMARY
echo "build-scan-url=$SCAN_URL" >> $GITHUB_OUTPUT
- name: Handle failed publish
if: ${{ steps.publish-build-scan.outcome == 'failure' }}
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ jobs:
with:
gradle-cache-read-only: ${{ github.ref != 'refs/heads/trunk' }}
gradle-cache-write-only: ${{ github.ref == 'refs/heads/trunk' }}
github-actions-opt-in: ${{ github.ref == 'refs/heads/trunk' || contains(github.head_ref, 'gh-') }}
is-public-fork: ${{ github.event.pull_request.head.repo.full_name != 'apache/kafka' }}
secrets:
inherit
116 changes: 116 additions & 0 deletions approve-workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# 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.

import json
import subprocess
import shlex
import webbrowser


def prompt_user() -> str:
choices = "ynw?"
while True:
try:
user_input = input(f"Make a selection [{','.join(choices)}]: ")
except (KeyboardInterrupt, EOFError):
exit(0)
clean_input = user_input.strip().lower()
if clean_input == "?":
print("\ny: approve the run\nn: do nothing\nw: open the URL for this run")
continue
if clean_input not in choices:
print(f"\nInvalid selection '{clean_input}'. Valid choices are:")
print("y: approve the run\nn: do nothing\nw: open the URL for this run")
continue
else:
return clean_input


def run_gh_command(cmd: str) -> str:
"Run a gh CLI command and return the stdout"
p = subprocess.run(
shlex.split(cmd),
capture_output=True
)
if p.returncode == 4:
# Not auth'd
print(p.stderr.decode())
exit(1)
elif p.returncode == 0:
return p.stdout.decode()
else:
print(f"Had an error running '{cmd}'.\nSTDOUT: {p.stdout.decode()}\nSTDERR: {p.stderr.decode()}")


def list_pending_workflow_runs():
command = r"gh run list --limit 20 --repo apache/kafka --workflow CI --status action_required --json 'databaseId,headBranch'"
out = run_gh_command(command)
pending_workflows = json.loads(out)
runs_by_branch = dict()
for workflow in pending_workflows:
run_id = workflow.get("databaseId")
branch = workflow.get("headBranch")
if branch in runs_by_branch:
print(f"Ignoring run {run_id} since there is a newer one: {runs_by_branch[branch]}")
continue
runs_by_branch[branch] = run_id
return runs_by_branch.values()

def load_workflow_run(run_id: str):
command = rf"gh api --method GET -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/apache/kafka/actions/runs/{run_id}"
out = run_gh_command(command)
workflow_run = json.loads(out)
return workflow_run


def approve_workflow_run(run_id: str):
command = rf"gh api --method POST -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/apache/kafka/actions/runs/{run_id}/approve"
out = run_gh_command(command)
workflow_run = json.loads(out)
return workflow_run


if __name__ == "__main__":
"""
Interactive script to approve pending CI workflow runs. This script can only be used by committers.

Requires the GitHub CLI. See https://cli.github.com/ for installation instructions.

Once installed authenticate with: gh auth login
"""
pending_runs = list_pending_workflow_runs()
for run_id in pending_runs:
run = load_workflow_run(run_id)
branch = run.get("head_branch")
run_id = run.get("id")
title = run.get("display_title")
repo = run.get("head_repository", {}).get("full_name")
actor = run.get("actor", {}).get("login")
url = run.get("html_url")
updated = run.get("updated_at")
print("-"*80)
print(f"PR: {title}")
print(f"Actor: {actor}")
print(f"Branch: {repo} {branch}")
print(f"Updated: {updated}")
print(f"URL: {url}")
print("")
selection = prompt_user()
if selection == "y":
approve_workflow_run(run_id)
elif selection == "n":
continue
elif selection == "w":
webbrowser.open(url)
Loading