Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ATS_VERSION=9.1.2
GO_VERSION=1.18
Comment thread
zrhoffman marked this conversation as resolved.
6 changes: 6 additions & 0 deletions .github/actions/pr-to-update-go/pr_to_update_go/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
version (e.g. GO_VERSION=3.2.1).
"""

GO_VERSION_KEY: Final = 'GO_VERSION'
"""
The key in the env file whose value corresponds to the Go version to be used by any project
using the env file
"""

GIT_AUTHOR_EMAIL_TEMPLATE: Final = '{git_author_name}@users.noreply.github.com'
"""Template used to construct the Git Author's email address."""
Expand All @@ -94,4 +99,5 @@
"GO_REPO_NAME",
"GO_VERSION_URL",
"RELEASE_PAGE_URL",
"GO_VERSION_KEY",
]
143 changes: 66 additions & 77 deletions .github/actions/pr-to-update-go/pr_to_update_go/go_pr_maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
import re
import subprocess
import sys
from typing import Optional, TypedDict, Any
from pathlib import PurePath
from typing import Optional, TypedDict, Any, Union

import requests
from dotenv import set_key

from github.Commit import Commit
from github.ContentFile import ContentFile
Expand All @@ -48,9 +50,11 @@
RELEASE_PAGE_URL,
ENV_GO_VERSION_FILE,
ENV_GIT_AUTHOR_NAME,
GIT_AUTHOR_EMAIL_TEMPLATE
GIT_AUTHOR_EMAIL_TEMPLATE,
GO_VERSION_KEY,
)


class GoVersion(TypedDict):
"""
A single entry in the list returned by the Go website's version listing API.
Expand All @@ -60,6 +64,7 @@ class GoVersion(TypedDict):
stable: bool
version: str


def _get_pr_body(go_version: str, milestone_url: str) -> str:
"""
Generates the body of a Pull Request given a Go release version and a
Expand All @@ -75,6 +80,7 @@ def _get_pr_body(go_version: str, milestone_url: str) -> str:
print('Templated PR body')
return pr_body


def get_major_version(from_go_version: str) -> str:
"""
Extracts the "major" version part of a full Go release version. ("major" to
Expand All @@ -93,6 +99,7 @@ def get_major_version(from_go_version: str) -> str:
return match.group(0)
return ""


def getenv(var: str) -> str:
"""
Returns the value of the environment variable with the given name.
Expand All @@ -105,6 +112,7 @@ def getenv(var: str) -> str:
"""
return os.environ[var]


def parse_release_notes(version: str, content: str) -> str:
"""
Parses Go version release notes.
Expand Down Expand Up @@ -137,21 +145,23 @@ def parse_release_notes(version: str, content: str) -> str:
"""
go_version_pattern = version.replace('.', r"\.")
release_notes_pattern = re.compile(
r"<p>\s*\n\s*go"+go_version_pattern+r".*?</p>",
r"<p>\s*\n\s*go" + go_version_pattern + r".*?</p>",
re.MULTILINE | re.DOTALL
)
matches = release_notes_pattern.search(content)
if not matches:
raise Exception(f'could not find release notes for Go {version}')
return " ".join(matches.group(0).split())


def _get_release_notes(go_version: str) -> str:
"""
Gets the release notes for the given Go version.
"""
release_history_response = requests.get(RELEASE_PAGE_URL)
release_history_response.raise_for_status()
return parse_release_notes(go_version, release_history_response .content.decode())
return parse_release_notes(go_version, release_history_response.content.decode())


def find_latest_major_upgrade(major_version: str, versions: list[GoVersion]) -> str:
"""
Expand Down Expand Up @@ -200,6 +210,7 @@ def find_latest_major_upgrade(major_version: str, versions: list[GoVersion]) ->

raise Exception(f'no supported {major_version} Go versions exist')


def _get_latest_major_upgrade(from_go_version: str) -> str:
"""
Gets the version of the latest Go release that is the same "major"
Expand All @@ -216,6 +227,7 @@ def _get_latest_major_upgrade(from_go_version: str) -> str:
print(f'Latest version of Go {major_version} is {fetched_go_version}')
return fetched_go_version


class GoPRMaker:
"""
A class to generate pull requests for the purpose of updating the Go version
Expand Down Expand Up @@ -279,22 +291,20 @@ def run(self, update_version_only: bool = False) -> None:
print(f'Go version is up-to-date on {target_branch}, nothing to do.')
return

commit: Optional[Commit] = None
commit: Optional[GitCommit] = None
if not self.branch_exists(source_branch_name):
commit = self.set_go_version(self.latest_go_version, commit_message,
source_branch_name)
if commit is None:
source_branch_ref: GitRef = self.repo.get_git_ref(f'heads/{source_branch_name}')
commit = self.repo.get_commit(source_branch_ref.object.sha)
commit = self.repo.get_git_commit(source_branch_ref.object.sha)
subprocess.run(['git', 'fetch', 'origin'], check=True)
subprocess.run(['git', 'checkout', commit.sha], check=True)
if update_version_only:
print(f'Branch {source_branch_name} has been created, exiting...')
return

update_golang_org_x_commit = self.update_golang_org_x(commit)
if update_golang_org_x_commit:
self.update_branch(source_branch_name, update_golang_org_x_commit.sha)
self.update_golang_org_x(commit, source_branch_name)

self.create_pr(
self.latest_go_version,
Expand Down Expand Up @@ -355,70 +365,40 @@ def get_repo_go_version(self, branch: str = 'master') -> str:
Gets the current Go version used at the head of the given branch (or not
given to use "master" by default) for the repository.
"""
return self.file_contents(getenv(ENV_GO_VERSION_FILE), branch).decoded_content.decode().strip()
return self.file_contents(getenv(ENV_GO_VERSION_FILE),
branch).decoded_content.decode().strip()

def set_go_version(self, go_version: str, commit_message: str,
source_branch_name: str) -> Commit:
source_branch_name: str) -> Optional[GitCommit]:
"""
Makes the commits necessary to change the Go version used by the
repository.

This includes updating the GO_VERSION and .env files at the repository's
root.
"""
master = self.repo.get_branch('master')
sha = master.commit.sha
master_tip = self.repo.get_branch('master').commit
sha = master_tip.sha
ref = f'refs/heads/{source_branch_name}'
self.repo.create_git_ref(ref, sha)

print(f'Created branch {source_branch_name}')

go_version_file = getenv(ENV_GO_VERSION_FILE)
content = f"{go_version}\n"
sha = self.file_contents(go_version_file, source_branch_name).sha
if self.author:
self.repo.update_file(
author=self.author,
branch=source_branch_name,
content=content,
path=go_version_file,
message=commit_message,
sha=sha
)
else:
print('Committing using the default author')
self.repo.update_file(
branch=source_branch_name,
content=content,
path=go_version_file,
message=commit_message,
sha=sha
)

print(f'Updated {go_version_file} on {self.repo.name}')
env_path = os.path.join(os.path.dirname(getenv(ENV_ENV_FILE)), ".env")
content = f"GO_VERSION={go_version}\n"
sha = self.file_contents(env_path, source_branch_name).sha
commit = self.repo.update_file(
branch=source_branch_name,
content=content,
path=env_path,
message=commit_message,
sha=sha
)["commit"]
if not isinstance(commit, Commit):
raise TypeError("'commit' property of file update response was not a Commit")
print(f"Updated {env_path} on {self.repo.name}")
return commit

def update_golang_org_x(self, previous_commit: Commit) -> Optional[GitCommit]:
with open(go_version_file, 'w') as go_version_file_stream:
go_version_file_stream.write(f'{go_version}\n')
env_file = getenv(ENV_ENV_FILE)
env_path = PurePath(os.path.dirname(env_file), ".env")
set_key(dotenv_path=env_path, key_to_set=GO_VERSION_KEY, value_to_set=go_version,
quote_mode='never')
return self.update_files_on_tree(head=master_tip, files_to_check=[go_version_file,
env_file], commit_message=commit_message, source_branch_name=source_branch_name)

def update_files_on_tree(self, head: Union[Commit, GitCommit], files_to_check: list[str],
commit_message: str, source_branch_name:
str) -> Optional[GitCommit]:
"""
Updates golang.org/x/ Go dependencies as necessary for the new Go
version.
Commits multiple files in a single Git commit, then reverts those changes locally.
"""
subprocess.run(['git', 'fetch', 'origin'], check=True)
subprocess.run(['git', 'checkout', previous_commit.sha], check=True)
subprocess.run([os.path.join(os.path.dirname(__file__), 'update_golang_org_x.sh')], check=True)
files_to_check = ['go.mod', 'go.sum', os.path.join('vendor', 'modules.txt')]
tree_elements: list[InputGitTreeElement] = []
for file in files_to_check:
diff_process = subprocess.run(['git', 'diff', '--exit-code', '--', file], check=False)
Expand All @@ -429,30 +409,36 @@ def update_golang_org_x(self, previous_commit: Commit) -> Optional[GitCommit]:
tree_element: InputGitTreeElement = InputGitTreeElement(path=file, mode='100644',
type='blob', content=content)
tree_elements.append(tree_element)
subprocess.run(['git', 'checkout', '--', file], check=True)
if len(tree_elements) == 0:
print('No golang.org/x/ dependencies need to be updated.')
print('No files need to be updated.')
return None
tree_hash = subprocess.check_output(
['git', 'log', '-1', '--pretty=%T', previous_commit.sha]).decode().strip()
['git', 'log', '-1', '--pretty=%T', head.sha]).decode().strip()
base_tree = self.repo.get_git_tree(sha=tree_hash)
tree = self.repo.create_git_tree(tree_elements, base_tree)
commit_message: str = f'Update golang.org/x/ dependencies for go{self.latest_go_version}'
previous_git_commit = self.repo.get_git_commit(previous_commit.sha)
git_commit: GitCommit
kwargs = {}
if self.author:
git_commit = self.repo.create_git_commit(
message=commit_message,
tree=tree,
parents=[previous_git_commit],
author=self.author,
committer=self.author
)
else:
git_commit = self.repo.create_git_commit(
message=commit_message,
tree=tree,
parents=[previous_git_commit]
)
kwargs = {'author': self.author, 'committer': self.author}
git_commit = self.repo.create_git_commit(message=commit_message, tree=tree,
parents=[self.repo.get_git_commit(head.sha)], **kwargs)
self.update_branch(source_branch_name, git_commit.sha)
return git_commit

def update_golang_org_x(self, head: GitCommit, source_branch_name: str) -> Optional[GitCommit]:
"""
Updates golang.org/x/ Go dependencies as necessary for the new Go
version.
"""
subprocess.run(['git', 'fetch', 'origin'], check=True)
subprocess.run(['git', 'checkout', head.sha], check=True)
subprocess.run([os.path.join(os.path.dirname(__file__), 'update_golang_org_x.sh')],
check=True)

commit_message: str = f'Update golang.org/x/ dependencies for go{self.latest_go_version}'
git_commit = self.update_files_on_tree(head=head, files_to_check=['go.mod', 'go.sum',
os.path.join('vendor', 'modules.txt')], commit_message=commit_message,
source_branch_name=source_branch_name)
print('Updated golang.org/x/ dependencies')
return git_commit

Expand All @@ -467,7 +453,8 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str,
pull_request = self.repo.get_pull(list_item.number)
if pull_request.head.ref != source_branch_name:
continue
print(f'Pull request for branch {source_branch_name} already exists:\n{pull_request.html_url}')
print(
f'Pull request for branch {source_branch_name} already exists:\n{pull_request.html_url}')
return

milestone_url = self.get_go_milestone(latest_go_version)
Expand All @@ -486,6 +473,8 @@ def create_pr(self, latest_go_version: str, commit_message: str, owner: str,
print('Unable to find a label named "go version"', file=sys.stderr)
print(f'Created pull request {pull_request.html_url}')


if __name__ == "__main__":
import doctest

doctest.testmod()
1 change: 1 addition & 0 deletions .github/actions/pr-to-update-go/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
python-dotenv
PyGithub
requests
1 change: 1 addition & 0 deletions .github/actions/pr-to-update-go/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ classifiers = OSI Approved :: Apache Software License
python_requires = >=3.9
packages = pr_to_update_go
install_requires =
python-dotenv
PyGithub
requests

Expand Down
60 changes: 60 additions & 0 deletions .github/containers/trafficserver-alpine/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 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.

FROM alpine:latest AS build-trafficserver
ARG ATS_VERSION
ADD https://downloads.apache.org/trafficserver/trafficserver-${ATS_VERSION}.tar.bz2 /tmp/
RUN set -o errexit -o nounset; \
cd tmp; \
dirname=trafficserver-${ATS_VERSION}; \
tar xf ${dirname}.tar.bz2; \
rm ${dirname}.tar.bz2; \
apk add --no-cache \
# configure dependencies
g++ \
perl \
openssl-dev \
pcre-dev \
make \
# build dependencies
libexecinfo-dev \
fortify-headers \
linux-headers \
zlib-dev; \
cd $dirname; \
./configure \
--disable-tests \
--enable-experimental-plugins \
--prefix=/ \
--with-user=ats \
--with-group=ats; \
make -j; \
adduser -D ats; \
make install DESTDIR=/tmp/built; \
cd ..; \
rm -r $dirname

FROM alpine:latest
COPY --from=build-trafficserver /tmp/built/ /
RUN apk add --no-cache \
# runtime dependencies
libexecinfo \
libstdc++ \
pcre && \
adduser -D ats
USER ats
CMD /bin/traffic_server
Loading