This is an automated email from the ASF dual-hosted git repository.
ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new b3371d7bc1 Add GHA to update chromedriver (#7365)
b3371d7bc1 is described below
commit b3371d7bc112166f07af577d852a11e3693f51e8
Author: Steve Hamrick <[email protected]>
AuthorDate: Fri Mar 3 14:02:05 2023 -0700
Add GHA to update chromedriver (#7365)
* Add GHA to update chromedriver
* Update old reference
* Clean up & feedback
* pylint fixes
---
.github/actions/chromedriver-updater/README.rst | 56 ++++++
.github/actions/chromedriver-updater/action.yml | 24 +++
.../chromedriver_updater/__main__.py | 210 +++++++++++++++++++++
.../chromedriver_updater/constants.py | 36 ++++
.../chromedriver_updater/templates/pr.md | 33 ++++
.github/actions/chromedriver-updater/entrypoint.sh | 55 ++++++
.../actions/chromedriver-updater/requirements.txt | 13 ++
.github/actions/chromedriver-updater/setup.cfg | 36 ++++
.github/actions/chromedriver-updater/setup.py | 20 ++
.github/workflows/chromdriver-update.yml | 51 +++++
10 files changed, 534 insertions(+)
diff --git a/.github/actions/chromedriver-updater/README.rst
b/.github/actions/chromedriver-updater/README.rst
new file mode 100644
index 0000000000..d21046dcf5
--- /dev/null
+++ b/.github/actions/chromedriver-updater/README.rst
@@ -0,0 +1,56 @@
+..
+..
+.. 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.
+..
+
+********************
+chromedriver-updater
+********************
+
+Assigns the GitHub Triage role to non-committers who have fixed 2 Issues in
the past month.
+
+Environment Variables
+=====================
+
++----------------------------+----------------------------------------------------------------------------------+
+| Environment Variable Name | Value
|
++============================+==================================================================================+
+| ``GITHUB_TOKEN`` | Required. ``${{ github.token }}`` or ``${{
secrets.GITHUB_TOKEN }}`` |
++----------------------------+----------------------------------------------------------------------------------+
+| ``PR_GITHUB_TOKEN`` | Required. ``${{ github.token }}`` or another
token |
++----------------------------+----------------------------------------------------------------------------------+
+| ``GIT_AUTHOR_NAME`` | Optional. The username to associate with the
commit that updates the Go version. |
++----------------------------+----------------------------------------------------------------------------------+
+
+Outputs
+=======
+
+``exit-code``
+-------------
+
+Exit code is 0 unless an error was encountered.
+
+Inputs
+======
+Optionally takes a file that contains a line for each project update of the
form: `{project path}:{old version},{new version}`
+
+Example usage
+=============
+
+.. code-block:: yaml
+
+ - name: Update Chromedriver Versions
+ run: python3 -m chromedriver_updater
+ env:
+ GIT_AUTHOR_NAME: asf-ci
+ GITHUB_TOKEN: ${{ github.token }}
diff --git a/.github/actions/chromedriver-updater/action.yml
b/.github/actions/chromedriver-updater/action.yml
new file mode 100644
index 0000000000..2ee47a5100
--- /dev/null
+++ b/.github/actions/chromedriver-updater/action.yml
@@ -0,0 +1,24 @@
+# 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.
+
+name: 'chromedriver-updater'
+description: 'Runs chromedriver updater'
+runs:
+ using: 'composite'
+ steps:
+ - run: "${{ github.action_path }}/entrypoint.sh"
+ shell: bash
diff --git
a/.github/actions/chromedriver-updater/chromedriver_updater/__main__.py
b/.github/actions/chromedriver-updater/chromedriver_updater/__main__.py
new file mode 100644
index 0000000000..61fc65f599
--- /dev/null
+++ b/.github/actions/chromedriver-updater/chromedriver_updater/__main__.py
@@ -0,0 +1,210 @@
+# 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.
+"""
+Utility for automatically updating chromedriver. See README.rst for more
details.
+"""
+import os
+import sys
+from typing import Optional, NamedTuple
+
+from github.MainClass import Github
+from github.Repository import Repository
+from github.GithubException import UnknownObjectException
+from github.GitRef import GitRef
+from github.PullRequest import PullRequest
+from github.InputGitTreeElement import InputGitTreeElement
+
+try:
+ from chromedriver_updater.constants import PR_GITHUB_TOKEN,
GITHUB_REPO, GITHUB_REF_NAME, \
+ BRANCH_NAME, GIT_AUTHOR_NAME, TRAFFIC_PORTAL, TRAFFIC_PORTAL_V2
+except ModuleNotFoundError:
+ from constants import PR_GITHUB_TOKEN, GITHUB_REPO, GITHUB_REF_NAME,
BRANCH_NAME, \
+ GIT_AUTHOR_NAME, TRAFFIC_PORTAL, TRAFFIC_PORTAL_V2
+
+
+class UpdateEntry(NamedTuple):
+ """
+ Named tuple surrounding each line in the updates file
+ """
+ path: str
+ old_version: str
+ new_version: str
+
+ def __str__(self) -> str:
+ return f"{self.path}: {self.old_version} ->
{self.new_version}\n"
+
+
+def parse_update_entry(entry: str) -> UpdateEntry:
+ """
+ Parses string to UpdateEntry
+ :param entry: String to parse
+ :return: Parsed string as UpdateEntry
+ """
+ if ":" not in entry:
+ print(f"Invalid update entry '{entry}', expected format
{{path}}:{{old}},{{new}}",
+ file=sys.stderr)
+ sys.exit(1)
+ parts = entry.split(":")
+ if len(parts) != 2 or "," not in parts[1]:
+ print(f"Invalid update entry '{entry}', expected format
{{path}}:{{old}},{{new}}",
+ file=sys.stderr)
+ sys.exit(1)
+ if parts[0].endswith("/"):
+ project = parts[0][:-1]
+ else:
+ project = parts[0]
+ parts = parts[1].split(",")
+ if len(parts) != 2:
+ print(f"Invalid update entry '{entry}', expected format
{{path}}:{{old}},{{new}}",
+ file=sys.stderr)
+ sys.exit(1)
+
+ return UpdateEntry(path=project, old_version=parts[0],
new_version=parts[1])
+
+
+def path_to_project(path: str) -> Optional[str]:
+ """
+ Converts paths to projects
+ :param path: Path to check
+ :return: The project string, or None
+ """
+ if "traffic_portal" in path:
+ return TRAFFIC_PORTAL
+ if "traffic-portal" in path:
+ return TRAFFIC_PORTAL_V2
+ return None
+
+
+class PRCreator(Github):
+ """
+ Creates the PR to update chromedriver
+ """
+ repo: Repository
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.repo = self.get_repo(GITHUB_REPO)
+
+ def get_pr(self) -> Optional[PullRequest]:
+ """
+ Retrieve the PR opened by this script if available
+ :return:
+ """
+ for issue in self.search_issues("repo:%s is:pr is:open head:%s"
%
+
(self.repo.full_name, BRANCH_NAME)):
+ return issue.as_pull_request()
+ return None
+
+ def get_branch(self) -> Optional[GitRef]:
+ """
+ Retrieve the git reference to this scripts branch if available
+ :return:
+ """
+ try:
+ return self.repo.get_git_ref(f"heads/{BRANCH_NAME}")
+ except UnknownObjectException:
+ return None
+
+ def create_git_tree_from_entry(self, entry: UpdateEntry, file: str) ->
InputGitTreeElement:
+ """
+ Creates a git element for the purposes of committing
+ :param entry:
+ :param file:
+ :return:
+ """
+ file_path = os.path.join(entry.path, file)
+ if not os.path.exists(file_path):
+ print(f"Could not find '{file_path}' to commit",
file=sys.stderr)
+ sys.exit(1)
+ with open(file_path, "r", encoding="utf-8") as changed_file:
+ change_file = changed_file.read()
+ blob = self.repo.create_git_blob(change_file, "utf-8")
+ return InputGitTreeElement(path=file_path, mode='100644',
type='blob', sha=blob.sha)
+
+ def create_pull_request(self, update_entries: [UpdateEntry]) ->
PullRequest:
+ """
+ Create a pull request based on update entries
+ :param update_entries:
+ :return:
+ """
+ with open(os.path.join(os.path.dirname(__file__), "templates",
"pr.md"),
+ encoding="utf-8") as template_file:
+ pr_template = template_file.read()
+ tree_elements = []
+ projects = ""
+ updated = ""
+ for update in update_entries:
+
tree_elements.append(self.create_git_tree_from_entry(update, "package.json"))
+
tree_elements.append(self.create_git_tree_from_entry(update,
"package-lock.json"))
+ updated += str(update)
+ project = path_to_project(update.path)
+ if project is None:
+ print(f"Unknown project from path
{update.path}")
+ elif project not in projects:
+ projects += f"* {project}\n"
+ ref = self.repo.create_git_ref(ref=f"refs/heads/{BRANCH_NAME}",
+
sha=self.repo.get_branch(GITHUB_REF_NAME).commit.sha)
+ branch = self.repo.get_branch(BRANCH_NAME)
+ base_tree = self.repo.get_git_tree(sha=branch.commit.sha)
+ commit = self.repo.create_git_commit("Update chromedriver",
+
self.repo.create_git_tree(tree_elements, base_tree),
+
[self.repo.get_git_commit(sha=branch.commit.sha)])
+ ref.edit(sha=commit.sha)
+
+ pull = self.repo.create_pull(title="Update Chromedriver
Versions", maintainer_can_modify=True,
+
body=pr_template.format(UPDATES=updated, PROJECTS=projects),
+
head=f"{GIT_AUTHOR_NAME}:{BRANCH_NAME}", base=GITHUB_REF_NAME)
+
+ try:
+ labels = [self.repo.get_label("tests"),
self.repo.get_label("dependencies")]
+ if TRAFFIC_PORTAL in projects:
+
labels.append(self.repo.get_label(TRAFFIC_PORTAL))
+ if TRAFFIC_PORTAL_V2 in projects:
+
labels.append(self.repo.get_label(TRAFFIC_PORTAL_V2))
+ pull.add_to_labels(*labels)
+ except UnknownObjectException:
+ print("Could not find labels", file=sys.stderr)
+
+ return pull
+
+
+if __name__ == "__main__":
+ print("Logging into github")
+ gh = PRCreator(login_or_token=PR_GITHUB_TOKEN)
+
+ if len(sys.argv) > 2:
+ print("chromedriver_updater [updates file]", file=sys.stderr)
+ sys.exit(1)
+
+ pull_request = gh.get_pr()
+ if pull_request is not None:
+ print(f"PR already exists; number: {pull_request.number}, url:
{pull_request.html_url}")
+ sys.exit(0)
+
+ if len(sys.argv) == 1:
+ sys.exit(0)
+
+ if not os.path.exists(sys.argv[1]):
+ print(f"File '{sys.argv[1]}' does not exist", file=sys.stderr)
+ sys.exit(1)
+ with open(sys.argv[1], "r", encoding="utf-8") as f:
+ updates = [line.rstrip() for line in f.readlines()]
+ if len(updates) == 0:
+ print("Nothing to update")
+ sys.exit(0)
+ branch_ref = gh.get_branch()
+ if branch_ref is not None:
+ print("Branch already exists (but not a pull request),
recreating")
+ branch_ref.delete()
+
+ updates = [parse_update_entry(update) for update in updates if update
!= ""]
+ gh.create_pull_request(updates)
diff --git
a/.github/actions/chromedriver-updater/chromedriver_updater/constants.py
b/.github/actions/chromedriver-updater/chromedriver_updater/constants.py
new file mode 100644
index 0000000000..d8c4cedb35
--- /dev/null
+++ b/.github/actions/chromedriver-updater/chromedriver_updater/constants.py
@@ -0,0 +1,36 @@
+# 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.
+"""
+Contains and loads constants used by the updater
+"""
+import os
+from typing import Optional
+
+
+def getenv(env_name: str) -> str:
+ """
+ Gets environment variable :param env_name:
+ """
+ env_var: Optional[str] = os.environ.get(env_name)
+ if env_var is None:
+ raise NameError(f"Environment variable {env_name} is not
defined")
+ return env_var
+
+
+GIT_AUTHOR_NAME = getenv("GIT_AUTHOR_NAME")
+GITHUB_REPO = getenv("GITHUB_REPOSITORY")
+GITHUB_REF_NAME = getenv("GITHUB_REF_NAME")
+PR_GITHUB_TOKEN = getenv("PR_GITHUB_TOKEN")
+GITHUB_TOKEN = getenv("GITHUB_TOKEN")
+BRANCH_NAME = "ATC-Chromedriver-Updater"
+TRAFFIC_PORTAL_V2 = "Traffic Portal v2"
+TRAFFIC_PORTAL = "Traffic Portal"
diff --git
a/.github/actions/chromedriver-updater/chromedriver_updater/templates/pr.md
b/.github/actions/chromedriver-updater/chromedriver_updater/templates/pr.md
new file mode 100644
index 0000000000..9a92343051
--- /dev/null
+++ b/.github/actions/chromedriver-updater/chromedriver_updater/templates/pr.md
@@ -0,0 +1,33 @@
+<!--
+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.
+-->
+
+This PR updates chromedriver in:
+{UPDATES}
+
+## Which Traffic Control components are affected by this PR?
+{PROJECTS}
+
+## What is the best way to verify this PR?
+Verify that the affected e2e tests pass.
+
+## PR submission checklist
+- [ ] This PR has tests
+- [ ] This PR has documentation
+- [ ] This PR has a CHANGELOG.md entry
+- [x] This PR **DOES NOT FIX A SERIOUS SECURITY VULNERABILITY** (see [the
Apache Software Foundation's security guidelines](https://apache.org/security)
for details)
diff --git a/.github/actions/chromedriver-updater/entrypoint.sh
b/.github/actions/chromedriver-updater/entrypoint.sh
new file mode 100755
index 0000000000..4f96e429b9
--- /dev/null
+++ b/.github/actions/chromedriver-updater/entrypoint.sh
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+
+trap 'echo "Error on line ${LINENO} of ${0}"; exit 1' ERR;
+set -o errexit -o nounset
+
+if [[ -z ${PROJECTS} ]]; then
+ echo "PROJECTS environment variable not set!"
+ exit 1
+fi
+
+python3 -m chromedriver_updater
+
+projects=($(echo $PROJECTS | tr ',' ' '))
+touch updates.txt
+
+for proj in "${projects[@]}"
+do
+ package="./$proj"package.json
+ if [[ ! -f "$package" ]]; then
+ echo "Unable to find package.json in project directory $proj"
+ continue
+ fi
+
+ pushd "./$proj" > /dev/null
+
+ outdated=$(npm outdated | grep "chromedriver" || echo "" )
+
+ if [ "$outdated" = "" ]; then
+ echo "$proj is up to date"
+ popd > /dev/null
+ continue
+ fi
+
+ latest=$(echo $outdated | cut -d ' ' -f4)
+ wanted=$(echo $outdated | cut -d ' ' -f3)
+
+ npm i --save-dev "chromedriver@$latest" --ignore-scripts > /dev/null
+
+ popd > /dev/null
+ echo -e "$proj:$wanted,$latest\n" >> updates.txt
+done
+
+python3 -m chromedriver_updater updates.txt
diff --git a/.github/actions/chromedriver-updater/requirements.txt
b/.github/actions/chromedriver-updater/requirements.txt
new file mode 100644
index 0000000000..c46ccd487e
--- /dev/null
+++ b/.github/actions/chromedriver-updater/requirements.txt
@@ -0,0 +1,13 @@
+# 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.
+#
+PyGithub
diff --git a/.github/actions/chromedriver-updater/setup.cfg
b/.github/actions/chromedriver-updater/setup.cfg
new file mode 100644
index 0000000000..3c431a7f51
--- /dev/null
+++ b/.github/actions/chromedriver-updater/setup.cfg
@@ -0,0 +1,36 @@
+# 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.
+#
+[metadata]
+name = chromedriver_updater
+version = 1.0.0
+description = Updates chromedriver in package.json to latest version
+long_description = file: README.rst
+long_description_content_type = text/x-rst
+author = Apache Traffic Control
+author_email = [email protected]
+classifiers = OSI Approved :: Apache Software License
+
+[options]
+python_requires = >=3.10
+packages = chromedriver_updater
+install_requires =
+ PyGithub
+
+[options.entry_points]
+console_scripts = chromedriver_updater = chromedriver_updater:main
+
+[options.extras_require]
+test = unittest
+
+[options.package_data]
+chromedriver_updater = templates/pr.md
diff --git a/.github/actions/chromedriver-updater/setup.py
b/.github/actions/chromedriver-updater/setup.py
new file mode 100644
index 0000000000..027c64df17
--- /dev/null
+++ b/.github/actions/chromedriver-updater/setup.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+# 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 setuptools-based install script for the audit-checker GitHub Action
+"""
+from setuptools import setup
+
+setup()
diff --git a/.github/workflows/chromdriver-update.yml
b/.github/workflows/chromdriver-update.yml
new file mode 100644
index 0000000000..965e1624a7
--- /dev/null
+++ b/.github/workflows/chromdriver-update.yml
@@ -0,0 +1,51 @@
+# 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.
+
+name: Chromedriver Updater
+
+on:
+ workflow_dispatch:
+ schedule:
+ # Every day at 00:00
+ - cron: '0 0 * * *'
+
+env:
+ PROJECTS:
+
+jobs:
+ chromedriver-updater:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@master
+ id: checkout
+ - name: Install Python 3.10
+ uses: actions/setup-python@v2
+ with: { python-version: '3.10' } # Must be quoted to include the
trailing 0
+ - name: Install Node 16
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+ - name: Install updater Python module and dependencies
+ run: pip install .github/actions/chromedriver-updater
+ - name: Run chromedriver-updater
+ uses: ./.github/actions/chromedriver-updater
+ env:
+ GIT_AUTHOR_NAME: asf-ci
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_GITHUB_TOKEN: ${{ secrets.ASFCI_TOKEN }}
+ PROJECTS:
"traffic_portal/test/integration/,experimental/traffic-portal/"