|
# Release Process |
|
|
|
The app is published in twice, in different build formats. |
|
|
|
- A [PyPI] distribution. This includes both a source distribution and built distribution (a wheel). Users install with `pip install invokeai`. The updater uses this build. |
|
- An installer on the [InvokeAI Releases Page]. This is a zip file with install scripts and a wheel. This is only used for new installs. |
|
|
|
## General Prep |
|
|
|
Make a developer call-out for PRs to merge. Merge and test things out. |
|
|
|
While the release workflow does not include end-to-end tests, it does pause before publishing so you can download and test the final build. |
|
|
|
## Release Workflow |
|
|
|
The `release.yml` workflow runs a number of jobs to handle code checks, tests, build and publish on PyPI. |
|
|
|
It is triggered on **tag push**, when the tag matches `v*`. It doesn't matter if you've prepped a release branch like `release/v3.5.0` or are releasing from `main` - it works the same. |
|
|
|
> Because commits are reference-counted, it is safe to create a release branch, tag it, let the workflow run, then delete the branch. So long as the tag exists, that commit will exist. |
|
|
|
### Triggering the Workflow |
|
|
|
Run `make tag-release` to tag the current commit and kick off the workflow. |
|
|
|
The release may also be dispatched [manually]. |
|
|
|
### Workflow Jobs and Process |
|
|
|
The workflow consists of a number of concurrently-run jobs, and two final publish jobs. |
|
|
|
The publish jobs require manual approval and are only run if the other jobs succeed. |
|
|
|
#### `check-version` Job |
|
|
|
This job checks that the git ref matches the app version. It matches the ref against the `__version__` variable in `invokeai/version/invokeai_version.py`. |
|
|
|
When the workflow is triggered by tag push, the ref is the tag. If the workflow is run manually, the ref is the target selected from the **Use workflow from** dropdown. |
|
|
|
This job uses [samuelcolvin/check-python-version]. |
|
|
|
> Any valid [version specifier] works, so long as the tag matches the version. The release workflow works exactly the same for `RC`, `post`, `dev`, etc. |
|
|
|
#### Check and Test Jobs |
|
|
|
- **`python-tests`**: runs `pytest` on matrix of platforms |
|
- **`python-checks`**: runs `ruff` (format and lint) |
|
- **`frontend-tests`**: runs `vitest` |
|
- **`frontend-checks`**: runs `prettier` (format), `eslint` (lint), `dpdm` (circular refs), `tsc` (static type check) and `knip` (unused imports) |
|
|
|
> **TODO** We should add `mypy` or `pyright` to the **`check-python`** job. |
|
|
|
> **TODO** We should add an end-to-end test job that generates an image. |
|
|
|
#### `build-installer` Job |
|
|
|
This sets up both python and frontend dependencies and builds the python package. Internally, this runs `installer/create_installer.sh` and uploads two artifacts: |
|
|
|
- **`dist`**: the python distribution, to be published on PyPI |
|
- **`InvokeAI-installer-${VERSION}.zip`**: the installer to be included in the GitHub release |
|
|
|
#### Sanity Check & Smoke Test |
|
|
|
At this point, the release workflow pauses as the remaining publish jobs require approval. Time to test the installer. |
|
|
|
Because the installer pulls from PyPI, and we haven't published to PyPI yet, you will need to install from the wheel: |
|
|
|
- Download and unzip `dist.zip` and the installer from the **Summary** tab of the workflow |
|
- Run the installer script using the `--wheel` CLI arg, pointing at the wheel: |
|
|
|
```sh |
|
./install.sh --wheel ../InvokeAI-4.0.0rc6-py3-none-any.whl |
|
``` |
|
|
|
- Install to a temporary directory so you get the new user experience |
|
- Download a model and generate |
|
|
|
> The same wheel file is bundled in the installer and in the `dist` artifact, which is uploaded to PyPI. You should end up with the exactly the same installation as if the installer got the wheel from PyPI. |
|
|
|
##### Something isn't right |
|
|
|
If testing reveals any issues, no worries. Cancel the workflow, which will cancel the pending publish jobs (you didn't approve them prematurely, right?). |
|
|
|
Now you can start from the top: |
|
|
|
- Fix the issues and PR the fixes per usual |
|
- Get the PR approved and merged per usual |
|
- Switch to `main` and pull in the fixes |
|
- Run `make tag-release` to move the tag to `HEAD` (which has the fixes) and kick off the release workflow again |
|
- Re-do the sanity check |
|
|
|
#### PyPI Publish Jobs |
|
|
|
The publish jobs will run if any of the previous jobs fail. |
|
|
|
They use [GitHub environments], which are configured as [trusted publishers] on PyPI. |
|
|
|
Both jobs require a maintainer to approve them from the workflow's **Summary** tab. |
|
|
|
- Click the **Review deployments** button |
|
- Select the environment (either `testpypi` or `pypi`) |
|
- Click **Approve and deploy** |
|
|
|
> **If the version already exists on PyPI, the publish jobs will fail.** PyPI only allows a given version to be published once - you cannot change it. If version published on PyPI has a problem, you'll need to "fail forward" by bumping the app version and publishing a followup release. |
|
|
|
##### Failing PyPI Publish |
|
|
|
Check the [python infrastructure status page] for incidents. |
|
|
|
If there are no incidents, contact @hipsterusername or @lstein, who have owner access to GH and PyPI, to see if access has expired or something like that. |
|
|
|
#### `publish-testpypi` Job |
|
|
|
Publishes the distribution on the [Test PyPI] index, using the `testpypi` GitHub environment. |
|
|
|
This job is not required for the production PyPI publish, but included just in case you want to test the PyPI release. |
|
|
|
If approved and successful, you could try out the test release like this: |
|
|
|
```sh |
|
# Create a new virtual environment |
|
python -m venv ~/.test-invokeai-dist --prompt test-invokeai-dist |
|
# Install the distribution from Test PyPI |
|
pip install --index-url https://test.pypi.org/simple/ invokeai |
|
# Run and test the app |
|
invokeai-web |
|
# Cleanup |
|
deactivate |
|
rm -rf ~/.test-invokeai-dist |
|
``` |
|
|
|
#### `publish-pypi` Job |
|
|
|
Publishes the distribution on the production PyPI index, using the `pypi` GitHub environment. |
|
|
|
## Publish the GitHub Release with installer |
|
|
|
Once the release is published to PyPI, it's time to publish the GitHub release. |
|
|
|
1. [Draft a new release] on GitHub, choosing the tag that triggered the release. |
|
1. Write the release notes, describing important changes. The **Generate release notes** button automatically inserts the changelog and new contributors, and you can copy/paste the intro from previous releases. |
|
1. Use `scripts/get_external_contributions.py` to get a list of external contributions to shout out in the release notes. |
|
1. Upload the zip file created in **`build`** job into the Assets section of the release notes. |
|
1. Check **Set as a pre-release** if it's a pre-release. |
|
1. Check **Create a discussion for this release**. |
|
1. Publish the release. |
|
1. Announce the release in Discord. |
|
|
|
> **TODO** Workflows can create a GitHub release from a template and upload release assets. One popular action to handle this is [ncipollo/release-action]. A future enhancement to the release process could set this up. |
|
|
|
## Manual Build |
|
|
|
The `build installer` workflow can be dispatched manually. This is useful to test the installer for a given branch or tag. |
|
|
|
No checks are run, it just builds. |
|
|
|
## Manual Release |
|
|
|
The `release` workflow can be dispatched manually. You must dispatch the workflow from the right tag, else it will fail the version check. |
|
|
|
This functionality is available as a fallback in case something goes wonky. Typically, releases should be triggered via tag push as described above. |
|
|
|
[InvokeAI Releases Page]: https://github.com/invoke-ai/InvokeAI/releases |
|
[PyPI]: https://pypi.org/ |
|
[Draft a new release]: https://github.com/invoke-ai/InvokeAI/releases/new |
|
[Test PyPI]: https://test.pypi.org/ |
|
[version specifier]: https://packaging.python.org/en/latest/specifications/version-specifiers/ |
|
[ncipollo/release-action]: https://github.com/ncipollo/release-action |
|
[GitHub environments]: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment |
|
[trusted publishers]: https://docs.pypi.org/trusted-publishers/ |
|
[samuelcolvin/check-python-version]: https://github.com/samuelcolvin/check-python-version |
|
[manually]: #manual-release |
|
[python infrastructure status page]: https://status.python.org/ |
|
|