Skip to content

Release Crystal 1.21.0 #428

Description

@straight-shoota

Release preparation

  1. Announce expected release date (2026-07-16) and time span for feature freeze (starting on 2026-02-02)
    • Feature freeze is about two weeks before release
  2. Set date on the milestone
  3. Prepare the changelog entry: (crystal) scripts/update-changelog.sh 1.21.0 from the HEAD of the release branch (or master) (Changelog for 1.21.0 crystal#17095)
  4. Start preparing release notes, publish draft in crystal-lang/crystal-website (summary of changes that are most relevant for users)
  5. Start feature freeze period (on 2026-02-02)
    • Either no merging of features into master or split off release branch for backporting bugfixes.
  6. Publish release PR draft
    • It should contain the expected date of the release.
    • It should be populated with updates to CHANGELOG.md, src/VERSION and the version in shard.yml.
  7. Ensure documentation for language and compiler changes and other relevant changes is up to date.
    • Crystal Book
      • Update language specification
      • Update compiler manual
      • Add or update guides / tutorials?
  8. Look for library updates, check and document compatibility at https://crystal-lang.org/reference/man/required_libraries.html and in lib bindings
  9. Ensure that test-ecosystem functions and succeeds on master

Release process (on 2026-07-16)

Source release

  1. Finalize the changelog PR
    • Make sure all changes are mentioned in the changelog
    • Check release date
    • Un-draft the PR
  2. Split off release branch release/1.21 from master to trigger Maintenance CI
  3. Verify Maintenance CI workflow succeeds on the HEAD of the release
    branch: https://app.circleci.com/pipelines/github/crystal-lang/crystal?branch=release%2F1.21
  4. Smoke test with test-ecosystem
  5. Merge the changelog PR
  6. Make the release and publish it on GitHub: (crystal) ../distribution-scripts/processes/scripts/make-crystal-release.sh (run from crystallang/crystal@1.21.0 work tree). This performs these steps:
    1. Tag & annotate the commit with the changelog using <M.m.p> pattern as version
    • git tag -s -a -m 1.21.0 1.21.0
    • git push --tags
    1. Publish Github release (https://github.com/crystal-lang/crystal/releases/new)
      • Copy the changelog section as description
      • Binaries are added later
  7. Close milestone (https://github.com/crystal-lang/crystal/milestones)
  8. Wait for the release build in circle CI (https://app.circleci.com/pipelines/github/crystal-lang/crystal)
  9. Fast-forward release/1.21 to master@1.21.0

Binary releases

  1. Download build artifacts from CircleCI and GitHub Actions: (distribution-scripts) ./processes/scripts/download-crystal-release-artifacts.sh $VERSION. This performs these steps:
    1. Search the release build from the latest CircleCI pipelines
    2. Download build artifacts from the CircleCI jobs:
      • crystal-*-darwin-*.tar.gz
      • crystal-*-linux-*.tar.gz
      • crystal-*.pkg
      • crystal-*-docs.tar.gz
    3. Search the release build in GitHub Actions
    4. Download the artifacts from the CircleCI job (MinGW-w64 CI, Windows CI)
    5. Compress and rename the GHA artifacts:
      • Windows CI: crystal/* -> crystal-1.21.0-windows-x86_64-msvc-unsupported.zip
      • Windows CI: crystal-installer/crystal-setup.exe -> crystal-1.21.0-windows-x86_64-msvc-unsupported.exe
      • MinGW-w64 CI: *-mingw-w64-crystal/* -> crystal-1.21.0-windows-*-gnu-unsupported.zip
  2. Upload build artifacts to the GitHub Release: (distribution-scripts) gh release -R crystal-lang/crystal upload 1.21.0 crystal-1.21.0*
  3. Publish the GitHub release
  4. Push changes to OBS for building linux packages
    1. Checkout https://github.com/crystal-lang/distribution-scripts and go to ./packages
    2. Configure build.opensuse.org credentials in environment variables:
      • export OBS_USER=
      • export OBS_PASSWORD=
    3. Update the crystal package: (distribution-scripts) ./obs-release.sh devel:languages:crystal crystal 1.21.0
      • Uses the docker image crystallang/osc to run the CLI client for OBS.
      • The script creates a branch in you home project, updates the version and pushes it back to OBS.
      • You can also run the commands from that file manually and check build locally with
        • osc build xUbuntu_20.04 x86_64
        • osc build Fedora_Rawhide x86_64
    4. Create the crystal1.21 package: (distribution-scripts) ./obs-new-minor.sh devel:languages:crystal crystal1.21 1.21.0 crystal1.20
    5. Now OBS builds the packages. It’s best to follow the build status in the browser:
      1. open https://build.opensuse.org/package/show/home:$OBS_USER:branches:devel:languages:crystal/crystal
      2. open https://build.opensuse.org/package/show/home:$OBS_USER:branches:devel:languages:crystal/crystal1.21
      3. Wait for all package build jobs to finish and succeed
    6. When everything is green, create a submit request against the original
      packages: Submit package link in the page actions (left sidebar) in your branch.
      • crystal
      • crystal1.21
    7. (optional) Verify package installation
      • (distribution-scripts/packages) OBS_PROJECT=devel:languages:crystal bats test
  5. Tag latest docker images
    • Versioned docker images have been pushed to Docker Hub.
    • Now just assign the latest tags:
    • (distribution-scripts) ./docker/apply-latest-tags.sh 1.21.0
  6. Publish snap package
  7. Check PR for homebrew: https://github.com/Homebrew/homebrew-core/pulls?q=is%3Apr+crystal+sort%3Aupdated-desc
    • It should've been automatically created

Publish documentation for the release

  1. Publish API docs
    1. Have AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env variables defined
    2. Run (distribution-scripts) make -C docs publish_docs release_latest_docs CRYSTAL_VERSION=1.21.0 to publish docs to api/1.21.0, apply redirect from api/latest to api/1.21.0 and set the 404 error page
  2. Publish Crystal book
    1. Make sure release/1.20 branch is merged into master (if not, create a PR; it needs to be merged as a merge commit)
    2. Create release/1.21 branch and push it to crystal-lang/crystal-book (deployment happens automatically in GHA)
    3. Verify that deployment was successful

Release announcements

  1. Publish release notes on the website
    • Make sure all links to API docs point to /api/1.21.0/
    • Insert number of changes and contributors
  2. Wait for website to build, then visit the release notes page. This should
    create a thread for comments on the forum.
    • Add tag release
    • Replace content with link to release notes (this should insert a preview card)
    • Publish the topic ("List topic" in the wrench icon)
  3. Announce on social media accounts (via Buffer; credentials are in Passbolt) and pin release posts
  4. Have the project manager post the release in https://opencollective.com/crystal-lang

Post-release

  1. Create a pull request to update master branch to use released version:
    (crystal) scripts/release-update.sh 1.21.0
    • Edit PREVIOUS_CRYSTAL_BASE_URL in .circleci/config.yml
    • Edit DOCKER_TEST_PREFIX in bin/ci
    • Edit prepare_build on_osx download package and folder
    • Edit .github/workflows/*.yml to point to docker image
    • Edit shell.nix latestCrystalBinary using nix-prefetch-url --unpack <url>
    • Branch: infra/release-update. Commit message: Update previous Crystal release 1.21.0
  2. Increment src/VERSION and version in shard.yml to the next minor plus -dev suffix
  3. Perform uncomment/todos left in the repo
  4. Merge release/1.21 branch into master (if the two have diverged)
    • This needs to be a merge commit. Those are disabled in the GitHub UI.

    • Create branch and PR:

      git fetch upstream release/1.21 master
      git switch -c merge/1.21.0 upstream/master
      git merge upstream/release/1.21
      # resolve conflicts
      git commit -m 'Merge `release/1.21`@`1.21.0` into master'
      git log --graph --decorate --pretty=oneline --abbrev-commit
      git push -u upstream merge/1.21.0
      gh pr create --title 'Merge `release/1.21`@`1.21.0` into `master`' --label 'topic:infrastructure' --assignee=@me --body-file - <<-'MD'
      **This PR must be merged as a _merge commit_!**
      
      ```sh
      git switch master
      git merge --ff-only merge/1.21.0
      # double check history
      git log --graph --decorate --pretty=oneline --abbrev-commit
      git push
      ```
      MD
    • Merge PR locally:

      git switch master
      git merge --ff-only merge/1.21.0
      # double check history
      git log --graph --decorate --pretty=oneline --abbrev-commit
      git push
    • GitHub branch protection rules normally prevent direct pushes to
      master. This needs to be deactivated for this purpose, which can be on a
      per-user basis.

    • In case master has diverged, --ff-only merge will fail. Then you can
      first rebase merge/1.21.0 on current master with git rebase master --rebase-merges.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions