Skip to content

Monitor version number for release #400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
26 changes: 8 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,28 @@ name: CI
on: [push]
jobs:
python-tests:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up JS requirements
run: npm install

- name: Set up Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: "3.13"
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- id: cache
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/test_requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Install dependencies
run: pip install -r requirements.txt -r test_requirements.txt
- name: Install Python dependencies with uv
run: uv sync --locked

- name: Lint
run: pylint *.py
run: uv run pylint *.py

- name: Black
run: black --version && black . --check
run: uv run black --version && uv run black . --check

- name: Tests
run: pytest . && coverage xml
run: uv run pytest . && uv run coverage xml

# - name: Upload coverage to CodeCov
# uses: codecov/codecov-action@v1
Expand Down
16 changes: 9 additions & 7 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ async def _web_application_release(
)

async def _wait_for_deploy_with_alerts(
self, *, repo_info, release_pr, hash_url, watch_branch
self, *, repo_info, release_pr, hash_url, watch_branch, expected_version
):
"""
Wait for a deployment, but alert with a a timeout
Expand All @@ -471,6 +471,7 @@ async def _wait_for_deploy_with_alerts(
repo_url=repo_url,
hash_url=hash_url,
watch_branch=watch_branch,
expected_version=expected_version,
timeout_seconds=timeout_seconds,
):
break
Expand All @@ -490,12 +491,15 @@ async def _wait_for_deploy_rc(self, *, repo_info, manager, release_pr):
"""
repo_url = repo_info.repo_url
channel_id = repo_info.channel_id
# Get the expected version from the release PR title
expected_version = release_pr.version

await self._wait_for_deploy_with_alerts(
repo_info=repo_info,
release_pr=release_pr,
hash_url=repo_info.rc_hash_url,
watch_branch="release-candidate",
expected_version=expected_version,
)

rc_server = remove_path_from_url(repo_info.rc_hash_url)
Expand Down Expand Up @@ -525,17 +529,15 @@ async def _wait_for_deploy_prod(self, *, repo_info, manager, release_pr):
"""
repo_url = repo_info.repo_url
channel_id = repo_info.channel_id
version = await get_version_tag(
github_access_token=self.github_access_token,
repo_url=repo_url,
commit_hash="origin/release",
)
# Get the expected version from the release PR title (which should match the tag)
expected_version = release_pr.version

await self._wait_for_deploy_with_alerts(
repo_info=repo_info,
release_pr=release_pr,
hash_url=repo_info.prod_hash_url,
watch_branch="release",
expected_version=expected_version,
)

await set_release_label(
Expand All @@ -550,7 +552,7 @@ async def _wait_for_deploy_prod(self, *, repo_info, manager, release_pr):
await self.say(
channel_id=channel_id,
text=(
f"My evil scheme {version} for {repo_info.name} has been released to production at {prod_server}. "
f"My evil scheme {expected_version} for {repo_info.name} has been released to production at {prod_server}. "
"And by 'released', I mean completely...um...leased."
),
)
Expand Down
17 changes: 6 additions & 11 deletions bot_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ async def test_release(
repo_url=test_repo.repo_url,
hash_url=test_repo.rc_hash_url,
watch_branch="release-candidate",
expected_version=pr.version,
timeout_seconds=3600,
)
assert doof.said("Now deploying to RC...")
Expand Down Expand Up @@ -519,6 +520,7 @@ async def test_hotfix_release(
repo_url=test_repo.repo_url,
hash_url=test_repo.rc_hash_url,
watch_branch="release-candidate",
expected_version=pr.version,
timeout_seconds=3600,
)
assert doof.said("Now deploying to RC...")
Expand Down Expand Up @@ -1219,6 +1221,7 @@ async def test_wait_for_deploy_rc(
repo_url=test_repo.repo_url,
hash_url=test_repo.rc_hash_url,
watch_branch="release-candidate",
expected_version=release_pr.version,
timeout_seconds=3600,
)
get_unchecked.assert_called_once_with(
Expand All @@ -1239,26 +1242,17 @@ async def test_wait_for_deploy_prod(
): # pylint: disable=unused-argument
"""Bot._wait_for_deploy_prod should wait until repo has been deployed to production"""
wait_for_deploy_mock = mocker.async_patch("bot.wait_for_deploy")
version = "1.2.345"
get_version_tag_mock = mocker.async_patch(
"bot.get_version_tag", return_value=f"v{version}"
)
channel_id = test_repo.channel_id
release_pr = ReleasePR(
"version", "https://github.com/org/repo/pulls/123456", "body", 123456, False
"1.2.345", "https://github.com/org/repo/pulls/123456", "body", 123456, False
)

await doof._wait_for_deploy_prod( # pylint: disable=protected-access
repo_info=test_repo, manager="me", release_pr=release_pr
)

get_version_tag_mock.assert_called_once_with(
github_access_token=GITHUB_ACCESS,
repo_url=test_repo.repo_url,
commit_hash="origin/release",
)
assert doof.said(
f"My evil scheme v{version} for {test_repo.name} has been released "
f"My evil scheme {release_pr.version} for {test_repo.name} has been released " # Use release_pr.version
f"to production at {remove_path_from_url(test_repo.prod_hash_url)}. "
"And by 'released', I mean completely...um...leased.",
channel_id=channel_id,
Expand All @@ -1268,6 +1262,7 @@ async def test_wait_for_deploy_prod(
repo_url=test_repo.repo_url,
hash_url=test_repo.prod_hash_url,
watch_branch="release",
expected_version=release_pr.version, # Pass expected_version from PR
timeout_seconds=3600,
)

Expand Down
24 changes: 9 additions & 15 deletions publish.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
"""Functions for publishing"""

import os
from pathlib import Path

from async_subprocess import (
call,
check_call,
)
from constants import (
Expand All @@ -28,13 +26,6 @@ async def upload_to_pypi(project_dir):
# Heroku has both Python 2 and 3 installed but the system libraries aren't configured for our use,
# so make a virtualenv.
async with virtualenv("python3", outer_environ) as (virtualenv_dir, environ):
# Use the virtualenv binaries to act within that environment
pip_path = os.path.join(virtualenv_dir, "bin", "pip")

# Install dependencies. wheel is needed for Python 2. twine uploads the package.
await check_call(
[pip_path, "install", "twine"], env=environ, cwd=project_dir
)
await upload_with_twine(
project_dir=project_dir, virtualenv_dir=virtualenv_dir, environ=environ
)
Expand All @@ -56,15 +47,18 @@ async def upload_with_twine(
"TWINE_USERNAME": os.environ["PYPI_USERNAME"],
"TWINE_PASSWORD": os.environ["PYPI_PASSWORD"],
}

python_path = os.path.join(virtualenv_dir, "bin", "python")
# Use the virtualenv binaries to act within that environment
pip_path = os.path.join(virtualenv_dir, "bin", "pip")
python_path = os.path.join(virtualenv_dir, "bin", "python")
# Install dependencies. wheel is needed for Python 2. twine uploads the package.
await check_call([pip_path, "install", "setuptools"], env=environ, cwd=project_dir)
await check_call([pip_path, "install", "build"], env=environ, cwd=project_dir)
await check_call([pip_path, "install", "twine"], env=environ, cwd=project_dir)
twine_path = os.path.join(virtualenv_dir, "bin", "twine")

# Create source distribution and wheel.
await call([pip_path, "install", "setuptools"], env=environ, cwd=project_dir)
await call([python_path, "setup.py", "sdist"], env=environ, cwd=project_dir)
await call([python_path, "setup.py", "bdist_wheel"], env=environ, cwd=project_dir)
# Create source distribution and wheel using the virtualenv's python executable
# and explicitly passing the virtualenv's environment.
await check_call([python_path, "-m", "build", "."], env=environ, cwd=project_dir)
dist_files = os.listdir(os.path.join(project_dir, "dist"))
if len(dist_files) != 2:
raise Exception("Expected to find one tarball and one wheel in directory")
Expand Down
2 changes: 1 addition & 1 deletion publish_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _call(command, *args, **kwargs):
virtualenv_dir=virtualenv_dir,
environ=environ,
)
assert call_mock.call_count == 1
assert call_mock.call_count == 5


async def test_upload_to_npm(mocker, test_repo_directory, library_test_repo):
Expand Down
28 changes: 28 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[project]
name = "doof"
requires-python = "~=3.13"
version = "0.0.1"
dependencies = [
"python-dateutil",
"pytz",
"requests",
"sentry-sdk",
"setuptools>=78.1.0",
"tornado",
"virtualenv",
]

[dependency-groups]
dev = [
"black==22.3.0",
"codecov",
"pdbpp",
"pylint",
"pytest",
"pytest-asyncio",
"pytest-cov",
"pytest-mock",
]

[tool.uv]
package = false
15 changes: 0 additions & 15 deletions release_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
verify_new_commits,
)
from test_util import async_context_manager_yielder, sync_check_call as check_call
from wait_for_deploy import fetch_release_hash


pytestmark = pytest.mark.asyncio
Expand Down Expand Up @@ -368,20 +367,6 @@ async def test_generate_release_pr(mocker):
)


async def test_fetch_release_hash(mocker):
"""
fetch_release_hash should download the release hash at the URL
"""
sha1_hash = b"X" * 40
url = "a_url"
get_mock = mocker.async_patch(
"client_wrapper.ClientWrapper.get", return_value=mocker.Mock(content=sha1_hash)
)
assert await fetch_release_hash(url) == sha1_hash.decode()
get_mock.assert_called_once_with(mocker.ANY, url)
get_mock.return_value.raise_for_status.assert_called_once_with()


@pytest.mark.parametrize("hotfix_hash", ["", "abcdef"])
async def test_release(mocker, hotfix_hash, test_repo_directory, test_repo):
"""release should perform a release"""
Expand Down
7 changes: 0 additions & 7 deletions requirements.txt

This file was deleted.

1 change: 0 additions & 1 deletion runtime.txt

This file was deleted.

8 changes: 0 additions & 8 deletions test_requirements.txt

This file was deleted.

Loading