From 27e991d11eae93ee4e35d3072bef448bd8520124 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 31 Aug 2023 10:15:17 -0700 Subject: [PATCH] ci: Talk to Shaka Bot (#5565) Now maintainers can send commands to Shaka Bot via PR comments. Initially, Shaka Bot understands the following commands from anyone: - `@shaka-bot help`: Show this help message And the following commands from maintainers only: - `@shaka-bot test`: Start lab tests on all devices - `@shaka-bot test ce`: Start lab tests on CE devices only (no desktop browsers) --- .../shaka-bot-commands/command-help.sh | 27 ++++++ .../shaka-bot-commands/command-test.sh | 56 +++++++++++++ .github/workflows/shaka-bot-commands/lib.sh | 83 +++++++++++++++++++ .github/workflows/shaka-bot-commands/main.sh | 51 ++++++++++++ .github/workflows/talk-to-shaka-bot.yaml | 29 +++++++ 5 files changed, 246 insertions(+) create mode 100644 .github/workflows/shaka-bot-commands/command-help.sh create mode 100644 .github/workflows/shaka-bot-commands/command-test.sh create mode 100644 .github/workflows/shaka-bot-commands/lib.sh create mode 100755 .github/workflows/shaka-bot-commands/main.sh create mode 100644 .github/workflows/talk-to-shaka-bot.yaml diff --git a/.github/workflows/shaka-bot-commands/command-help.sh b/.github/workflows/shaka-bot-commands/command-help.sh new file mode 100644 index 000000000..0a6e42342 --- /dev/null +++ b/.github/workflows/shaka-bot-commands/command-help.sh @@ -0,0 +1,27 @@ +# Copyright 2022 Google LLC +# +# Licensed 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. + +# The help command implementation. +# Assumes that lib.sh has been loaded and all required variables are set. + +# Using single quotes to avoid executing the things in backticks, which are +# really markdown. +( + echo 'I honor the following commands from anyone:' + echo ' - `@shaka-bot help`: Show this help message' + echo '' + echo 'I honor the following commands from maintainers only:' + echo ' - `@shaka-bot test`: Start lab tests on all devices' + echo ' - `@shaka-bot test ce`: Start lab tests on CE devices only (no desktop browsers)' +) | reply_from_pipe diff --git a/.github/workflows/shaka-bot-commands/command-test.sh b/.github/workflows/shaka-bot-commands/command-test.sh new file mode 100644 index 000000000..abac8a92e --- /dev/null +++ b/.github/workflows/shaka-bot-commands/command-test.sh @@ -0,0 +1,56 @@ +# Copyright 2022 Google LLC +# +# Licensed 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. + +# The test command implementation. +# Assumes that lib.sh has been loaded and all required variables are set. + +if ! check_permissions; then + reply "Only maintainers may start lab tests." + exit 0 +fi + +# These are passed to the lab testing workflow. +WORKFLOW_ARGS=( "pr=$PR_NUMBER" ) + +case "${SHAKA_BOT_ARGUMENTS[0]}" in + # CE devices only. + ce) WORKFLOW_ARGS+=( "browser_filter=Tizen Chromecast ChromeAndroid" ) ;; + + # No command argument, no extra workflow arguments. + "") ;; + + *) + reply "Unrecognized test argument: ${SHAKA_BOT_ARGUMENTS[0]}" + exit 1 + ;; +esac + +if start_workflow selenium-lab-tests.yaml "${WORKFLOW_ARGS[@]}"; then + ( + echo "Lab tests started with arguments:" + for arg in "${WORKFLOW_ARGS[@]}"; do + echo " - \`$arg\`" + done + ) | reply_from_pipe +else + ( + echo "I failed to start the lab test workflow." + echo "" + echo "Please check GitHub Actions logs for details." + ) | reply_from_pipe + + # Fail this workflow to make it easier to find the right run + # and its logs. + exit 1 +fi diff --git a/.github/workflows/shaka-bot-commands/lib.sh b/.github/workflows/shaka-bot-commands/lib.sh new file mode 100644 index 000000000..e8f018300 --- /dev/null +++ b/.github/workflows/shaka-bot-commands/lib.sh @@ -0,0 +1,83 @@ +# Copyright 2022 Google LLC +# +# Licensed 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. + +# Utilities for handling @shaka-bot commands. + +# Ignore case in all string comparisons. +shopt -s nocasematch + +function check_required_variable() { + local VAR_NAME="$1" + + # The ! syntax here is Bash variable indirection. + if [[ -z "${!VAR_NAME}" ]]; then + echo "Missing environment variable: $VAR_NAME" + exit 1 + fi +} + +# Leaving a comment requires a token with "repo" scope. +function reply() { + echo "@$COMMENTER: $@" | \ + gh issue comment "$PR_NUMBER" -R "$THIS_REPO" -F - +} + +# Leaving a comment requires a token with "repo" scope. +function reply_from_pipe() { + (echo -n "@$COMMENTER: "; cat /dev/stdin) | \ + gh issue comment "$PR_NUMBER" -R "$THIS_REPO" -F - +} + +# Checking permissions requires a token with "repo" and "org:read" scopes, and +# write access. +function check_permissions() { + # Check permissions: this API call fails if the commenter has no special + # permissions on the repo. + gh api "/repos/$THIS_REPO/collaborators/$COMMENTER" +} + +# Starting a workflow requires a token with "repo" scope and write access. +# $1 is the workflow filename. Subsequent arguments are key=value pairs to be +# passed as input to the workflow_dispatch event. +function start_workflow() { + local WORKFLOW="$1" + shift + + # The gh command wants -f before each key-value pair. The caller shouldn't + # have to know that, so we rebuild the argument array with -f here. + local GH_ARGS=() + for arg in "$@"; do + GH_ARGS+=( "-f" "$arg" ) + done + + gh workflow run "$WORKFLOW" -R "$THIS_REPO" "${GH_ARGS[@]}" +} + +# Outputs to global variables SHAKA_BOT_COMMAND and SHAKA_BOT_ARGUMENTS (array). +function parse_command() { + # Tokenize the comment by whitespace. + local TOKENS=( $COMMENT_BODY ) + + local INDEX + for (( INDEX=0; INDEX < ${#TOKENS[@]}; INDEX++ )); do + if [[ "${TOKENS[i]}" == "@shaka-bot" ]]; then + SHAKA_BOT_COMMAND="${TOKENS[i+1]}" + # A slice of all tokens starting with index i+2. + SHAKA_BOT_ARGUMENTS=( "${TOKENS[@]:i+2}" ) + return 0 + fi + done + + return 1 +} diff --git a/.github/workflows/shaka-bot-commands/main.sh b/.github/workflows/shaka-bot-commands/main.sh new file mode 100755 index 000000000..52a1e1956 --- /dev/null +++ b/.github/workflows/shaka-bot-commands/main.sh @@ -0,0 +1,51 @@ +# Copyright 2022 Google LLC +# +# Licensed 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. + +# Handle @shaka-bot commands commented on PRs. + +# Run everything from the folder in which this script lives. +cd "$(dirname "$0")" + +# Load utils. +. lib.sh + +# Check required environment variables passed from the workflow. +# If running this manually while testing changes, supply these. +check_required_variable GH_TOKEN # With repo & org:read scope, write access +check_required_variable THIS_REPO # like shaka-project/shaka-player +check_required_variable COMMENTER # like joeyparrish +check_required_variable PR_NUMBER # like 1234 +check_required_variable COMMENT_BODY # like "@shaka-bot howdy" + +if [[ "$COMMENTER" == "shaka-bot" ]]; then + # Exclude comments by shaka-bot, who will sometimes use its own name. + exit 0 +fi + +# Parse the command. Outputs to globals SHAKA_BOT_COMMAND and +# SHAKA_BOT_ARGUMENTS (array). +parse_command + +if [[ "$SHAKA_BOT_COMMAND" == "" ]]; then + # No command found. + exit 0 +fi + +echo "PR $PR_NUMBER, detected command $SHAKA_BOT_COMMAND" + +case "$SHAKA_BOT_COMMAND" in + help) . command-help.sh ;; + test) . command-test.sh ;; + *) echo "Unknown command!" ;; +esac diff --git a/.github/workflows/talk-to-shaka-bot.yaml b/.github/workflows/talk-to-shaka-bot.yaml new file mode 100644 index 000000000..b0f1f5da1 --- /dev/null +++ b/.github/workflows/talk-to-shaka-bot.yaml @@ -0,0 +1,29 @@ +name: Talk to Shaka Bot (PRs) + +# Runs when comments are created or edited. Jobs below will be filtered to +# only run on PRs, not regular issues. +on: + issue_comment: + types: [created, edited] + +jobs: + handle_command: + # Only runs on PRs that contain '@shaka-bot' comments, but not comments + # made by shaka-bot itself, who will sometimes use its own name. + # Note that contains() is not case sensitive. + if: github.event.issue.pull_request && contains(github.event.comment.body, '@shaka-bot') && github.event.comment.user.login != 'shaka-bot' + runs-on: [ubuntu-latest] + env: + # This token must have "repo" scope, "org:read" scope, and write access. + GH_TOKEN: ${{ secrets.SHAKA_BOT_TOKEN }} + THIS_REPO: ${{ github.repository }} + COMMENTER: ${{ github.event.comment.user.login }} + PR_NUMBER: ${{ github.event.issue.number }} + COMMENT_BODY: ${{ github.event.comment.body }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Handle command + shell: bash + run: .github/workflows/shaka-bot-commands/main.sh