Skip to content

Commit

Permalink
release script
Browse files Browse the repository at this point in the history
Move the release instructions to a step-by-step "manual" script, meaning that
for now almost nothing is automated. We have a couple of checks for existence
of files, but that's it's. In the future we can automate individual steps to
reduce release time.
  • Loading branch information
garfieldnate committed Jun 28, 2024
1 parent 422f5e9 commit 88e1d6e
Show file tree
Hide file tree
Showing 2 changed files with 311 additions and 42 deletions.
44 changes: 2 additions & 42 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,6 @@

## Current Release Process

* Changes to `SoarTutorial/*.docx` need to be manually exported from Word to `pdf/`.
* Update version numbers in Soar everywhere (see `example_version_bump.patch`). TODO: write some awk to do this automatically.
* Update version numbers in `txt/README`.
* Add a new release notes file under the `txt/` directory
* Add some cursory release notes in `txt/README`
* Clone all of SoarGroup's repos into a directory
* generate the manual via the makefile under `ManualSource`, or grab the built one from this repository's GH action workflow result. It should be placed in the `pdf/` directory.
* Download the Windows, macos-12 (x86-64), macos-latest (ARM) and Linux builds of Soar from the desired GH action workflow result.
* Fix the classpath in the manifest (https://github.com/SoarGroup/VisualSoar/issues/1) and build VisualSoar
* Convert VisualSoar's manual to pdf:
- `brew install basictex`
- open new shell
- `sudo tlmgr install soul`
- `cd VisualSoar/doc/usersman`
- `pandoc -o VisualSoar_UsersManual.pdf VisualSoar_UsersManual.docx`
* Gather the following jar's under SoarShuffler/jars:
- Eaters_TankSoar.jar
- commons-logging-1.1.1.jar
- log4j-1.2.15.jar
- stopwatch-0.4-with-deps.jar

VisualSoar and Eaters_TankSoar must be built from their repositories (although I had to fix VisualSoar, see https://github.com/SoarGroup/VisualSoar/issues/1), and the others are in the `lib/` directory in the VisualSoar repository. Note that the log4j one is *not* affected by the famous security bug.

* Set your environment variables for SoarShuffler. Here's my .env for an example (you can source this automatically using tools like [dotenv](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/dotenv)):

```bash
Expand All @@ -33,25 +10,8 @@ export SOAR_SHUFFLER_OUTPUT_DIR=./Soar-Release-$SOAR_RELEASE_VERSION
export SOAR_WIN_X86_64_COMPILED_DIR=~/Downloads/Soar_windows-x86-64_out
export SOAR_LINUX_X86_64_COMPILED_DIR=~/Downloads/Soar_linux-x86-64_out
export SOAR_MAC_X86_64_COMPILED_DIR=~/Downloads/Soar_mac-x86-64_out
export SOAR_MAC_ARM64_COMPILED_DIR=~/dev/workspaces/release_soar_workspace/Soar/out
export SOAR_MAC_ARM64_COMPILED_DIR=~/Downloads/Soar_mac-ARM64_out
export SOAR_GROUP_REPOS_HOME=~/dev/workspaces/release_soar_workspace
echo -e "\e[93mReminder: Check that $SOAR_MAC_ARM64_COMPILED_DIR is checked out at the tag you desire and is freshly recompiled\e[0m"
```

* Run SoarShuffle:

cd SoarShuffle
python3 soar_shuffler.py Soar_Projects_Filelist.txt

The script will tell you if it can't find any files that it needs. You'll probably need to run it a couple of times to hunt down all of the files you need. You'll probably want to `rm -rf SoarSuite` between runs, just to make sure you aren't keeping any old files in the release.

You'll get the release directories wherever you specified in the `SOAR_SHUFFLER_OUTPUT_DIR` env var.

* Finally, unzip the release directories in `SoarRelease/SoarSuite` and check that VisualSoar, the debugger, TankSoar, and SoarCLI all work with a simple double-click.
* Share the release with others and get feedback.
* Once you're happy with it, delete the directories you unzipped and, then zip/tarball up the `SoarRelease` directory and upload to the release on GitHub.
- `zip -r Soar-Release-<version>.zip Soar-Release-<version>`
- `tar -czvf Soar-Release-<version>.tar.gz Soar-Release-<version>`
* Upload the Soar and VisualSoar manuals to the release, as well
* Push a releases/$VERSION tag for Soar, and $VERSION tags for other Release-Support and VisualSoar.
* Update the Soar website with the new release information: https://github.com/SoarGroup/SoarGroup.github.io
* Run `python3 release.py`, which will walk you through all of the steps to create a release. Most of them are currently manual, unfortunately.
309 changes: 309 additions & 0 deletions release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
from dataclasses import dataclass
from pathlib import Path
import sys
from os import environ

PROJECT_DIR = Path(__file__).parent

SOAR_RELEASE_VERSION = environ.get("SOAR_RELEASE_VERSION")

SOAR_SHUFFLER_DIR = PROJECT_DIR / "SoarShuffler"

SOAR_SHUFFLER_OUTPUT_DIR = SOAR_SHUFFLER_DIR / f"Soar-Release-{SOAR_RELEASE_VERSION}"

SOAR_GROUP_REPOS_HOME = Path(environ.get("SOAR_GROUP_REPOS_HOME"))

SOAR_WIN_X86_64_COMPILED_DIR = Path(environ.get("SOAR_WIN_X86_64_COMPILED_DIR"))
SOAR_LINUX_X86_64_COMPILED_DIR = Path(environ.get("SOAR_LINUX_X86_64_COMPILED_DIR"))
SOAR_MAC_X86_64_COMPILED_DIR = Path(environ.get("SOAR_MAC_X86_64_COMPILED_DIR"))
SOAR_MAC_ARM64_COMPILED_DIR = Path(environ.get("SOAR_MAC_ARM64_COMPILED_DIR"))


@dataclass
class Step:
value: int = 1

def proceed(self, confirm=True, check_function=None, fail_message=None):
self.value += 1
if confirm:
input("Press [Enter] to continue...")
if check_function:
passed = False
while not passed:
try:
check_function()
passed = True
print("✅ Check passed")
except Exception as e:
print(e)
print("❌ Check failed!")
if fail_message:
print(fail_message)
input("Press [Enter] to re-try check...")
print()


def report_vars(step: Step):
print(f"Step {step.value}: Confirm following variables:")
print(f"{SOAR_RELEASE_VERSION=}")
print(f"{SOAR_SHUFFLER_OUTPUT_DIR=}")
print(f"{SOAR_GROUP_REPOS_HOME=}")
print(f"{SOAR_WIN_X86_64_COMPILED_DIR=}")
print(f"{SOAR_LINUX_X86_64_COMPILED_DIR=}")
print(f"{SOAR_MAC_X86_64_COMPILED_DIR=}")
print(f"{SOAR_MAC_ARM64_COMPILED_DIR=}")
step.proceed()


def export_tutorial(step: Step):
print(
f"Step {step.value}: Manually export changes to SoarTutorial/*.docx from Word to pdf/"
)
step.proceed()


def bump_version(step: Step):
# TODO: manual source will be unified with website version in the future.
print(
(
f"Step {step.value}: Update version number in ManualSource/manual.tex (look for 'SoarVersionRevision'). "
"Then push the changes so that the manual is rebuilt. "
)
)
step.proceed()

print(
(
f"Step {step.value}: Update version numbers in Soar everywhere (see example_version_bump.patch). "
"Then push the changes so that Soar is rebuilt with the correct version info."
)
)
step.proceed()

print(f"Step {step.value}: Update version numbers in txt/README.")
step.proceed()


def release_notes(step: Step):
release_notes_file = (
PROJECT_DIR / "txt" / f"Release_Notes_{SOAR_RELEASE_VERSION}.md"
)
print(
(
f"Step {step.value}: Create and fill {release_notes_file} using a previous release notes file as a template. "
"Ensure full correctness of file."
)
)
step.proceed(check_function=lambda: release_notes_file.resolve(strict=True))

print(
(
f"Step {step.value}: Add some cursory release notes in txt/README. "
"Ensure full correctness of file."
)
)
step.proceed()


def build_instructions(step: Step):
print(
f"Step {step.value}: Ensure build instructions in txt/Building_Soar.md are up-to-date."
)
step.proceed()


def clone_repos(step: Step):
print(
f"Step {step.value}: Clone the necessary SoarGroup repositories to {SOAR_GROUP_REPOS_HOME}"
)

def check():
SOAR_GROUP_REPOS_HOME.resolve(strict=True)
required_repos = [
"Other-Agent-Development-Tools",
"Domains-SoarQnA",
"Domains-SoarTextIO",
"Domains-WordNet",
"Domains-WordNet-with-Parse-Trees",
"Examples-and-Unsupported",
"Domains-RoomsWorld",
"Domains-InfiniteMario",
"Domains-DiceQnA",
"Domains-Dice",
"Domains-General-Game-Playing",
"Domains-Planning-Domain-Definition-Language",
"Agents",
"Domains-Eaters-TankSoar",
"VisualSoar",
]
for repo in required_repos:
repo_path = SOAR_GROUP_REPOS_HOME / repo
repo_path.resolve(strict=True)

step.proceed(check_function=check)


def manual_pdf(step: Step):
print(
(
f"Step {step.value}: Grab the latest manual build from this "
"repository's GH Actions artifacts and place it in pdf/."
)
)
step.proceed()


def download_builds(step: Step):
print(
(
f"Step {step.value}: Download the latest Soar builds from the Soar repo's GH Actions artifacts. "
"They should be unzipped and placed in the directories specified above for "
"SOAR_WIN_X86_64_COMPILED_DIR, SOAR_LINUX_X86_64_COMPILED_DIR, "
"SOAR_MAC_X86_64_COMPILED_DIR, and SOAR_MAC_ARM64_COMPILED_DIR."
)
)

def check():
SOAR_WIN_X86_64_COMPILED_DIR.resolve(strict=True)
SOAR_LINUX_X86_64_COMPILED_DIR.resolve(strict=True)
SOAR_MAC_X86_64_COMPILED_DIR.resolve(strict=True)
SOAR_MAC_ARM64_COMPILED_DIR.resolve(strict=True)

step.proceed(check_function=check)


def build_visual_soar(step: Step):
print(f"Step {step.value}: Build VisualSoar")
step.proceed()

print(
(
f"Step {step.value}: Convert VisualSoar's manual to pdf; if on Mac, do this:"
" - `brew install basictex`"
" - open new shell"
" - `sudo tlmgr install soul`"
" - `cd VisualSoar/doc/usersman`"
" - `pandoc -o VisualSoar_UsersManual.pdf VisualSoar_UsersManual.docx`"
)
)

def check():
(
SOAR_GROUP_REPOS_HOME
/ "VisualSoar"
/ "doc"
/ "usersman"
/ "VisualSoar_UsersManual.pdf"
).resolve(strict=True)

step.proceed(check_function=check)


def build_eaters_tanksoar(step: Step):
print(
f"Step {step.value}: Build Eaters_TankSoar.jar and place it under SoarShuffler/jars."
)
step.proceed(
check_function=lambda: (
SOAR_SHUFFLER_DIR / "jars" / "Eaters_TankSoar.jar"
).resolve(strict=True)
)


def gather_jars(step: Step):
required_jars = [
"commons-logging-1.1.1.jar",
"log4j-1.2.15.jar",
"stopwatch-0.4-with-deps.jar",
]
print(
f"Step {step.value}: Gather the following jar's under SoarShuffler/jars:\n"
+ "\n".join(map(lambda j: f" - {j}", required_jars))
)

def check():
for j in required_jars:
(SOAR_SHUFFLER_DIR / "jars" / j).resolve(strict=True)

step.proceed(check_function=check)


def run_soar_shuffler(step: Step):
print(
(
f"Step {step.value}: Run SoarShuffler:\n"
" - cd SoarShuffle\n"
" - python3 soar_shuffler.py Soar_Projects_Filelist.txt\n"
"The script will tell you if it can't find any files that it needs. You'll probably need to run it "
"a couple of times to hunt down all of the files you need. You'll probably want to `rm -rf SoarSuite` "
"between runs, just to make sure you aren't keeping any old files in the release."
)
)
step.proceed(check_function=lambda: SOAR_SHUFFLER_OUTPUT_DIR.resolve(strict=True))


def inspect_release(step: Step):
print(
(
f"Step {step.value}: Unzip SoarShuffler/Soar-Release-{SOAR_RELEASE_VERSION}/Soar_{SOAR_RELEASE_VERSION}-Multiplatform.zip "
"and ensure everything is in order. Check that VisualSoar, the debugger, TankSoar, and SoarCLI all work with a simple double-click."
)
)
step.proceed()

print(
f"Step {step.value}: Share the release with others and get feedback. Repeat this whole process if necessary."
)
step.proceed()


def upload_to_github(step: Step):
print(
(
f"Step {step.value}: Create a new release on GitHub: https://github.com/SoarGroup/Soar/releases/new. "
f"Type 'releases/{SOAR_RELEASE_VERSION} into the tag field and select 'Create new tag'."
"Copy the basic change notes from txt/README to the description and upload "
f"Soar_{SOAR_RELEASE_VERSION}-Multiplatform.zip and all of the documentation PDFs."
"Leave 'Set as a pre-release' *unchecked*, 'Set as the latest release' *checked* and hit 'Publish release'."
)
)
step.proceed()


def git_tag(step: Step):
print(
(
f"Step {step.value}: Push {SOAR_RELEASE_VERSION} tags for Release-Support and VisualSoar."
)
)
step.proceed()


def update_website(step: Step):
print(
(
f"Step {step.value}: Update the website with the new release information: https://github.com/SoarGroup/SoarGroup.github.io. "
"This includes adding a release announcement and updating download links for the manual and tutorial."
)
)
step.proceed()


def main(args):
step_counter = Step()
report_vars(step_counter)
export_tutorial(step_counter)
bump_version(step_counter)
release_notes(step_counter)
clone_repos(step_counter)
manual_pdf(step_counter)
download_builds(step_counter)
build_visual_soar(step_counter)
build_eaters_tanksoar(step_counter)
gather_jars(step_counter)
run_soar_shuffler(step_counter)
inspect_release(step_counter)


if __name__ == "__main__":
main(sys.argv[1:])

0 comments on commit 88e1d6e

Please sign in to comment.