mirror of
https://github.com/saltstack/salt-bootstrap.git
synced 2025-04-16 09:40:21 +00:00
Automated release process
Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
This commit is contained in:
parent
c9e42e1504
commit
50dd136e9a
3 changed files with 396 additions and 28 deletions
|
@ -9,22 +9,20 @@ jobs:
|
|||
checksums:
|
||||
name: Update Scripts Checksums
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
with:
|
||||
ref: stable
|
||||
|
||||
- name: Get bootstrap-salt.sh sha256sum
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
echo "SH=$(sha256sum bootstrap-salt.sh | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
echo "PS1=$(sha256sum bootstrap-salt.ps1 | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> $GITHUB_ENV
|
||||
|
||||
- name: Update Checksums
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
echo ${{ env.SH }} > bootstrap-salt.sh.sha256
|
||||
echo ${{ env.PS1 }} > bootstrap-salt.ps1.sha256
|
217
.github/workflows/release.yml
vendored
217
.github/workflows/release.yml
vendored
|
@ -1,45 +1,210 @@
|
|||
name: Release
|
||||
name: Cut Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
bootstrap:
|
||||
name: Update Release Checksums on Develop
|
||||
update-develop:
|
||||
name: Update CHANGELOG.md and bootstrap-salt.sh
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
permissions:
|
||||
contents: write # To be able to publish the release
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
- name: Check Branch Triggering Release
|
||||
run: |
|
||||
if [ "${{ github.ref_name }}" != "develop" ]
|
||||
then
|
||||
echo "This workflow should only be triggered from the develop branch"
|
||||
exit 1
|
||||
fi
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: develop
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: Update Git Settings
|
||||
run: |
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot] on behalf of ${{ github.event.sender.login }}"
|
||||
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Install Requirements
|
||||
run: |
|
||||
python3 -m pip install requests pre-commit
|
||||
pre-commit install --install-hooks
|
||||
|
||||
- name: Update Repository
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
python3 .github/workflows/scripts/cut-release.py --repo ${{ github.repository }}
|
||||
export CUT_RELEASE_VERSION=$(cat .cut_release_version)
|
||||
export CUT_RELEASE_CHANGES=$(cat .cut_release_changes)
|
||||
echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV
|
||||
echo "CUT_RELEASE_CHANGES=${CUT_RELEASE_CHANGES}" >> $GITHUB_ENV
|
||||
|
||||
- name: Show Changes
|
||||
run: |
|
||||
git status
|
||||
git diff
|
||||
|
||||
- name: Commit Changes
|
||||
run: |
|
||||
git commit -am "Update develop branch for the ${CUT_RELEASE_VERSION} release" || \
|
||||
git commit -am "Update develop branch for the ${CUT_RELEASE_VERSION} release"
|
||||
|
||||
- name: Push Changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: develop
|
||||
|
||||
- name: Upload Release Details
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: release-details
|
||||
path: |
|
||||
.cut_release_version
|
||||
.cut_release_changes
|
||||
|
||||
merge-develop-into-stable:
|
||||
name: Merge develop into stable
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
needs: update-develop
|
||||
permissions:
|
||||
contents: write # To be able to publish the release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: stable
|
||||
repository: ${{ github.repository }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update Git Settings
|
||||
run: |
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot] on behalf of @${{ github.event.sender.login }}"
|
||||
|
||||
- name: Download Release Details
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: release-details
|
||||
|
||||
- name: Update Environment
|
||||
run: |
|
||||
export CUT_RELEASE_VERSION=$(cat .cut_release_version)
|
||||
export CUT_RELEASE_CHANGES=$(cat .cut_release_changes)
|
||||
echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV
|
||||
echo "CUT_RELEASE_CHANGES=${CUT_RELEASE_CHANGES}" >> $GITHUB_ENV
|
||||
|
||||
- name: Merge develop into stable
|
||||
run: |
|
||||
git merge --no-ff -m "Merge develop into stable" origin/develop || touch .git-conflicts
|
||||
if [ -f .git-conflicts ]
|
||||
then
|
||||
git diff
|
||||
for f in $(git status | grep 'both modified' | awk '{ print $3 }')
|
||||
do
|
||||
git checkout --theirs $f
|
||||
git add $f
|
||||
done
|
||||
git commit -a -m "Merge develop into stable(auto resolving conflicts to the develop version)"
|
||||
fi
|
||||
|
||||
- name: Tag Release
|
||||
uses: mathieudutour/github-tag-action@v6.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
custom_tag: ${{ env.CUT_RELEASE_VERSION }}
|
||||
tag_prefix: ""
|
||||
create_annotated_tag: true
|
||||
|
||||
- name: Push Changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: stable
|
||||
tags: true
|
||||
|
||||
publish-release:
|
||||
name: Create GitHub Release
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
needs: merge-develop-into-stable
|
||||
permissions:
|
||||
contents: write # To be able to publish the release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: stable
|
||||
repository: ${{ github.repository }}
|
||||
- name: Download Release Details
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: release-details
|
||||
|
||||
- name: Update Environment
|
||||
run: |
|
||||
export CUT_RELEASE_VERSION=$(cat .cut_release_version)
|
||||
export CUT_RELEASE_CHANGES=$(cat .cut_release_changes)
|
||||
echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV
|
||||
echo "CUT_RELEASE_CHANGES=${CUT_RELEASE_CHANGES}" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Github Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: ${{ env.CUT_RELEASE_VERSION }}
|
||||
tag_name: ${{ env.CUT_RELEASE_VERSION }}
|
||||
body_path: .cut_release_changes
|
||||
target_commitish: stable
|
||||
prerelease: false
|
||||
generate_release_notes: false
|
||||
files: |
|
||||
bootstrap-salt.sh
|
||||
bootstrap-salt.ps1
|
||||
LICENSE
|
||||
|
||||
update-develop-checksums:
|
||||
name: Update Release Checksums on Develop
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
needs: publish-release
|
||||
permissions:
|
||||
contents: write # For action peter-evans/create-pull-request
|
||||
pull-requests: write # For action peter-evans/create-pull-request
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: stable
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: Get bootstrap-salt.sh sha256sum
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
echo "SH=$(sha256sum bootstrap-salt.sh | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: develop
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: Set up Python 3.7
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
|
||||
- name: Update Latest Release on README
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
python3 .github/workflows/scripts/update-release-shasum.py ${{ env.BS_VERSION }} ${{ env.SH }}
|
||||
|
||||
- name: Create Pull Request Against Develop
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
title: Update README.rst with ${{ env.BS_VERSION }} release sha256sum
|
||||
commit-message: Update README.rst with ${{ env.BS_VERSION }} release sha256sum
|
||||
|
@ -48,34 +213,36 @@ jobs:
|
|||
salt:
|
||||
name: Update Release on Salt Repo
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
needs: update-develop-checksums
|
||||
permissions:
|
||||
contents: write # For action peter-evans/create-pull-request
|
||||
pull-requests: write # For action peter-evans/create-pull-request
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: stable
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: Get bootstrap version
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: saltstack/salt
|
||||
ref: master
|
||||
path: salt-checkout
|
||||
|
||||
- name: Update bootstrap script on Salt
|
||||
if: github.repository == 'saltstack/salt-bootstrap'
|
||||
run: |
|
||||
cp bootstrap-salt.sh salt-checkout/salt/cloud/deploy/bootstrap-salt.sh
|
||||
|
||||
- name: Create Pull Request Against Develop
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
title: Update the bootstrap script to v${{ env.BS_VERSION }}
|
||||
title: "[DO NOT MERGE] Update the bootstrap script to v${{ env.BS_VERSION }}"
|
||||
path: salt-checkout
|
||||
commit-message: Update the bootstrap script to v${{ env.BS_VERSION }}
|
||||
delete-branch: true
|
||||
|
|
203
.github/workflows/scripts/cut-release.py
vendored
Normal file
203
.github/workflows/scripts/cut-release.py
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import pathlib
|
||||
import argparse
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent.parent.parent
|
||||
|
||||
|
||||
class ClassPropertyDescriptor:
|
||||
def __init__(self, fget, fset=None):
|
||||
self.fget = fget
|
||||
self.fset = fset
|
||||
|
||||
def __get__(self, obj, klass=None):
|
||||
if klass is None:
|
||||
klass = type(obj)
|
||||
return self.fget.__get__(obj, klass)()
|
||||
|
||||
def __set__(self, obj, value):
|
||||
if not self.fset:
|
||||
raise AttributeError("can't set attribute")
|
||||
type_ = type(obj)
|
||||
return self.fset.__get__(obj, type_)(value)
|
||||
|
||||
def setter(self, func):
|
||||
if not isinstance(func, (classmethod, staticmethod)):
|
||||
func = classmethod(func)
|
||||
self.fset = func
|
||||
return self
|
||||
|
||||
|
||||
def classproperty(func):
|
||||
if not isinstance(func, (classmethod, staticmethod)):
|
||||
func = classmethod(func)
|
||||
|
||||
return ClassPropertyDescriptor(func)
|
||||
|
||||
|
||||
class Session:
|
||||
|
||||
_instance = None
|
||||
|
||||
def __init__(self, endpoint=None):
|
||||
if endpoint is None:
|
||||
endpoint = "https://api.github.com"
|
||||
self.endpoint = endpoint
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update(
|
||||
{
|
||||
"Accept": "application/vnd.github+json",
|
||||
"Authorization": f"token {os.environ['GITHUB_TOKEN']}",
|
||||
}
|
||||
)
|
||||
|
||||
@classproperty
|
||||
def instance(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = cls()
|
||||
return cls._instance
|
||||
|
||||
def get(self, path, **kwargs):
|
||||
return self.session.get(f"{self.endpoint}/{path.lstrip('/')}", **kwargs)
|
||||
|
||||
def post(self, path, **kwargs):
|
||||
return self.session.post(f"{self.endpoint}/{path.lstrip('/')}", **kwargs)
|
||||
|
||||
def __enter__(self):
|
||||
self.session.__enter__()
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.session.__exit__(*args)
|
||||
|
||||
|
||||
def get_latest_release(options):
|
||||
response = Session.instance.get(f"/repos/{options.repo}/releases/latest")
|
||||
if response.status_code != 404:
|
||||
return response.json()["tag_name"]
|
||||
|
||||
print(
|
||||
f"Failed to get latest release. HTTP Response:\n{response.text}",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
print("Searching tags...", file=sys.stderr, flush=True)
|
||||
|
||||
tags = []
|
||||
page = 0
|
||||
while True:
|
||||
page += 1
|
||||
response = Session.instance.get(
|
||||
f"/repos/{options.repo}/tags", data={"pre_page": 100, "page": page}
|
||||
)
|
||||
repo_tags = response.json()
|
||||
added_tags = False
|
||||
for tag in repo_tags:
|
||||
if tag["name"] not in tags:
|
||||
tags.append(tag["name"])
|
||||
added_tags = True
|
||||
if added_tags is False:
|
||||
break
|
||||
|
||||
return list(sorted(tags))[-1]
|
||||
|
||||
|
||||
def get_generated_changelog(options):
|
||||
response = Session.instance.post(
|
||||
f"/repos/{options.repo}/releases/generate-notes",
|
||||
json={
|
||||
"tag_name": options.release_tag,
|
||||
"previous_tag_name": options.previous_tag,
|
||||
"target_commitish": "develop",
|
||||
},
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return response.text
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--repo", required=True, help="The <user>/<repo> to use")
|
||||
parser.add_argument("--release-tag", required=False, help="The tag of the release")
|
||||
parser.add_argument(
|
||||
"--previous-tag",
|
||||
required=False,
|
||||
help="The previous release tag. If not passed, the GH Api will be queried for it.",
|
||||
)
|
||||
|
||||
changelog_file = REPO_ROOT / "CHANGELOG.md"
|
||||
|
||||
if not os.environ.get("GITHUB_TOKEN"):
|
||||
parser.exit(status=1, message="GITHUB_TOKEN environment variable not set")
|
||||
|
||||
options = parser.parse_args()
|
||||
if not options.release_tag:
|
||||
options.release_tag = f"v{datetime.utcnow().strftime('%Y.%m.%d')}"
|
||||
if not options.previous_tag:
|
||||
options.previous_tag = get_latest_release(options)
|
||||
|
||||
print(
|
||||
f"Creating changelog entries from {options.previous_tag} to {options.release_tag} ...",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
|
||||
changelog = get_generated_changelog(options)
|
||||
if not isinstance(changelog, dict):
|
||||
parser.exit(
|
||||
status=1,
|
||||
message=f"Unable to generate changelog. HTTP Response:\n{changelog}",
|
||||
)
|
||||
|
||||
cut_release_version = REPO_ROOT / ".cut_release_version"
|
||||
print(
|
||||
f"* Writing {cut_release_version.relative_to(REPO_ROOT)} ...",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
cut_release_version.write_text(options.release_tag)
|
||||
|
||||
cut_release_changes = REPO_ROOT / ".cut_release_changes"
|
||||
print(
|
||||
f"* Writing {cut_release_changes.relative_to(REPO_ROOT)} ...",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
cut_release_changes.write_text(changelog["body"])
|
||||
|
||||
print(
|
||||
f"* Updating {changelog_file.relative_to(REPO_ROOT)} ...",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
changelog_file.write_text(
|
||||
f"# {changelog['name']}\n\n"
|
||||
+ changelog["body"]
|
||||
+ "\n\n"
|
||||
+ changelog_file.read_text()
|
||||
)
|
||||
|
||||
bootstrap_script_path = REPO_ROOT / "bootstrap-salt.sh"
|
||||
print(
|
||||
f"* Updating {bootstrap_script_path.relative_to(REPO_ROOT)} ...",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
bootstrap_script_path.write_text(
|
||||
re.sub(
|
||||
r'__ScriptVersion="(.*)"',
|
||||
f'__ScriptVersion="{options.release_tag.lstrip("v")}"',
|
||||
bootstrap_script_path.read_text(),
|
||||
)
|
||||
)
|
||||
parser.exit(status=0, message="CHANGELOG.md and bootstrap-salt.sh updated\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Reference in a new issue