Skip to content

Commit

Permalink
Refined release documentation (#14221)
Browse files Browse the repository at this point in the history
  • Loading branch information
john-westcott-iv authored Jul 10, 2023
1 parent cb5a8aa commit 07e30a3
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 12 deletions.
45 changes: 33 additions & 12 deletions docs/release_process.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
# Releasing AWX (and awx-operator)

The release process for AWX is completely automated as of version 19.5.0.
The release process for AWX is mostly automated as of version 19.5.0.

If you need to revert a release, please refer to the [Revert a Release](#revert-a-release) section.
## Get latest release version and list of new work

## Select the next release version

There are two methods you can use to get the next release version. The manual way and the automated way.

### Automated Way

#### Get a github token

Log into your github account, under your user icon go to Settings => Developer Settings => Personal Access Tokens => Tokens (classic).
Select the Generate new token => Generate new token (classic)
Fill in the note, select no scopes select "Generate token".
Copy the token and create a file in your awx repo called `.github_creds`. Enter the token in this file.
Run `./tools/scripts/get_next_release.py`
This will use your token to go query for the PRs in the release and scan their bodies to select X/Y/Z and suggest new versions and spit out notifications.

### Manual Way

#### Get latest release version and list of new work

1. Open the main project page for [AWX](https://github.com/ansible/awx/releases) and [AWX Operator](https://github.com/ansible/awx-operator/releases).

Expand All @@ -20,10 +38,10 @@ The page will now automatically update with a list of PRs that are in `AWX/devel

![PR Compare List](img/pr_compare_list.png)

## Select the next release version

Use this list of PRs to decide if this is a X-stream (major) release, Y-stream (minor) release, or a Z-stream (patch) release. Use [semver](https://semver.org/#summary) to help determine what kind of release is needed.

#### Select the next release version

Indicators of a Z-stream release:

- No significant new features have been merged into devel since the last release.
Expand Down Expand Up @@ -126,16 +144,19 @@ This workflow will take the generated images and promote them to quay.io.

![Verify released awx-operator image](img/verify-released-awx-operator-image.png)

## Notify the AWX mailing list
Send an email to the [AWX Mailing List](mailto:[email protected]) with a message format of type "AWX Release" from the [mailing list triage standard replies](../.github/triage_replies.md#awx-release)
## Send notifications
Send notifications to the following groups:
* AWX Mailing List
* #social:ansible.com IRC (@newsbot for inclusion in bullhorn)
* #awx:ansible.com (no @newsbot in this room)
* #ansible-controller slack channel

## Send an IRC message over matrix to #social:ansible.com for bullhorn:
These messages are templated out for you in the output of `get_next_release.yml`.

@newsbot
We're happy to announce that [AWX version 21.1.0](https://github.com/ansible/awx/releases/tag/21.1.0) is now available!
We're happy to announce that [AWX Operator version 0.22.0](https://github.com/ansible/awx-operator/releases/tag/0.22.0) is now available!
Note: the slack message is the same as the IRC message.

## Send the same IRC message (less the @newsbot) to #awx:ansible.com
## Create operator hub PRs.
Operator hub PRs are generated via an Ansible Playbook. See someone on the AWX team for the location of the playbooks and instructions on how to run them.

## Revert a Release

Expand Down Expand Up @@ -165,4 +186,4 @@ Here are the steps needed to revert an AWX and an AWX-Operator release. Dependin

7. Navigate to the [PyPi](https://pypi.org/project/awxkit/#history) and delete the bad AWX tag and release that got published.

8. [Restart the Release Process](#releasing-awx-and-awx-operator)
8. [Restart the Release Process](#releasing-awx-and-awx-operator)
257 changes: 257 additions & 0 deletions tools/scripts/get_next_release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#!/usr/bin/env python

missing_modules = []
try:
import requests
except:
missing_modules.append('requests')
import json
import os
import re
import sys
import time

try:
import semantic_version
except:
missing_modules.append('semantic_version')

if len(missing_modules) > 0:
print("This requires python libraries to work; try:")
for a_module in missing_modules:
print(" pip install {}".format(a_module))
sys.exit(1)


def getCurrentVersions():
print("Getting current versions")
for repo in product_repos:
response = session.get('https://api.github.com/repos/ansible/{}/releases'.format(repo))
if 'X-RateLimit-Limit' in response.headers and int(response.headers['X-RateLimit-Limit']) <= 60:
print("Your key in .github_creds did not work right and you are using unauthenticated requests")
print("This script would likely overrun your available requests, exiting")
sys.exit(3)
versions['current'][repo] = response.json()[0]['tag_name']
print(" {}: {}".format(repo, versions['current'][repo]))


def getNextReleases():
#
# This loads the commits since the last release and gets their associated PRs and scans those for release_type: [xyz]
# Any X or Y changes also get captured for bullhorn release notes
#
for repo in product_repos:
response = session.get('https://api.github.com/repos/ansible/{}/compare/{}...devel'.format(repo, versions['current'][repo]))
commit_data = response.json()
pr_votes = {}
suggested_release_type = None
prs_missing_relese_type = 0
versions['release_notes'][repo] = []
for commit in commit_data['commits']:
response = session.get('https://api.github.com/repos/ansible/{}/commits/{}/pulls'.format(repo, commit['sha']))
prs = response.json()
for a_pr in prs:
# If we've already seen this PR we don't need to check again
try:
if a_pr['html_url'] in pr_votes:
continue
except:
print("Unable to check on PR")
print(json.dumps(a_pr, indent=4))
sys.exit(255)
append_title = False
pr_release = 'is non voting'
if a_pr and a_pr.get('body', None):
if 'Breaking Change' in a_pr['body']:
suggested_release_type = 'x'
pr_release = 'votes x'
append_title = True
elif 'New or Enhanced Feature' in a_pr['body']:
if suggested_release_type != 'x':
suggested_release_type = 'y'
pr_release = 'votes y'
append_title = True
elif 'Bug, Docs Fix or other nominal change' in a_pr['body']:
if suggested_release_type == None:
suggested_release_type = 'z'
pr_release = 'votes z'
# This was a format along the way
elif 'Bug or Docs Fix' in a_pr['body']:
if suggested_release_type == None:
suggested_release_type = 'z'
pr_release = 'votes z'
# Old PR format
elif (
'- Bug Report' in a_pr['body']
or '- Bug Fix' in a_pr['body']
or '- Bugfix Pull Request' in a_pr['body']
or '- Documentation' in a_pr['body']
or '- Docs Pull Request' in a_pr['body']
):
if suggested_release_type == None:
suggested_release_type = 'z'
pr_release = 'votes z (from old PR body)'
elif '- Feature Idea' in a_pr['body'] or '- Feature Pull Request' in a_pr['body']:
if suggested_release_type != 'x':
suggested_release_type = 'y'
pr_release = 'votes y (from old PR body)'
append_title = True
else:
prs_missing_relese_type += 1
else:
prs_missing_relese_type += 1

if append_title:
versions['release_notes'][repo].append("* {}".format(a_pr['title']))
print("PR {} {}".format(a_pr['html_url'], pr_release))
pr_votes[a_pr['html_url']] = pr_release

print("https://github.com/ansible/{}/compare/{}...devel".format(repo, versions['current'][repo]))
print("{} devel is {} commit(s) ahead of release {}".format(repo, commit_data['total_commits'], versions['current'][repo]))
if prs_missing_relese_type == 0:
print("\nAll commits voted, the release type suggestion is {}".format(suggested_release_type))
else:
total_prs = len(pr_votes)
voted_prs = total_prs - prs_missing_relese_type
print("From {} commits, {} of {} PRs voted".format(commit_data['total_commits'], voted_prs, total_prs))
if suggested_release_type:
print("\nOf commits with release type, the suggestion is {}".format(suggested_release_type))
else:
print("\nNone of the commits had the release type indicated")
print()

current_version = semantic_version.Version(versions['current'][repo])
if suggested_release_type.lower() == 'x':
versions['next'][repo] = current_version.next_major()
elif suggested_release_type.lower() == 'y':
versions['next'][repo] = current_version.next_minor()
else:
versions['next'][repo] = current_version.next_patch()


#
# Load the users session information
#
session = requests.Session()
try:
print("Loading credentials")
with open(".github_creds", "r") as f:
password = f.read().strip()
session.headers.update({'Authorization': 'bearer {}'.format(password), 'Accept': 'application/vnd.github.v3+json'})
except Exception:
print("Failed to load credentials from ./.github_creds")
sys.exit(255)

versions = {
'current': {},
'next': {},
'release_notes': {},
}

product_repos = ['awx', 'awx-operator']

#
# Get latest release version from releases page
#
getCurrentVersions()

#
# Scan PRs for release types
#
getNextReleases()

#
# Confirm the release number with the human
#
print(
'''
Next recommended releases:
AWX: {0}
Operator: {1}
'''.format(
versions['next']['awx'],
versions['next']['awx-operator'],
)
)

for product in product_repos:
version_override = input("Enter the next {} release number ({}): ".format(product, versions['next'][product]))
if version_override != '':
versions['next'][product] = version_override

#
# Generate IRC and Mailing list messages
#
print("Enter any known issues (one per line, empty line to end)")
known_issues = []
keep_getting_issues = True
while keep_getting_issues:
issue = input()
if issue == '':
keep_getting_issues = False
else:
known_issues.append(issue)

display_known_issues = ''
if len(known_issues) > 0:
display_known_issues = "\n".join(['Known Issues:'] + ['* {}'.format(item) for item in known_issues])

print(
'''
Bullhorn/irc list message:
@newsbot We're happy to announce that the next release of AWX, version {0} is now available!
Some notable features include:
{2}
In addition AWX Operator version {1} has also been released!
Some notable features include:
{3}
Please see the releases pages for more details:
AWX: [https://github.com/ansible/awx/releases/tag/{0}](https://github.com/ansible/awx/releases/tag/{0})
Operator: [https://github.com/ansible/awx-operator/releases/tag/{1}](https://github.com/ansible/awx-operator/releases/tag/{1})
{4}
'''.format(
versions['next']['awx'],
versions['next']['awx-operator'],
'\n'.join(versions['release_notes']['awx']),
'\n'.join(versions['release_notes']['awx-operator']),
display_known_issues,
)
)

print(
'''
Mailing list message:
Subject: Announcing AWX {0} and AWX-Operator {1}
Body:
Hi all,
We're happy to announce that the next release of AWX, version {0} is now available!
Some notable features include:
{2}
In addition AWX Operator version {1} has also been released!
Some notable features include:
{3}
Please see the releases pages for more details:
AWX: https://github.com/ansible/awx/releases/tag/{0}
Operator: https://github.com/ansible/awx-operator/releases/tag/{1}
{4}
-The AWX team.
'''.format(
versions['next']['awx'],
versions['next']['awx-operator'],
'\n'.join(versions['release_notes']['awx']),
'\n'.join(versions['release_notes']['awx-operator']),
display_known_issues,
)
)

0 comments on commit 07e30a3

Please sign in to comment.