-
Notifications
You must be signed in to change notification settings - Fork 59
chore: add support for separate module versioning to CI #426
Changes from 29 commits
7f130f2
b0069e2
0611ef2
2269e58
c6cffc8
9bc5419
9b89ef4
038ef33
0b7a602
7d481e8
d5ecb98
7c95af8
324a383
96657d7
1a1dd69
4dbe948
bd1703b
6f2fe83
2998721
d63b332
a6984fb
0c4f954
fb3ae6f
6d925ca
bdd8dba
3f0615b
8200f2d
70e5da7
e4e5c73
57fc91f
68f5396
8aa9154
974f3f6
2086134
6b1b617
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,16 +51,3 @@ jobs: | |
uses: crate-ci/[email protected] | ||
- name: Lint | ||
run: bun lint | ||
- name: Check version | ||
shell: bash | ||
run: | | ||
# check for version changes | ||
./update-version.sh | ||
# Check if any changes were made in README.md files | ||
if [[ -n "$(git status --porcelain -- '**/README.md')" ]]; then | ||
echo "Version mismatch detected. Please run ./update-version.sh and commit the updated README.md files." | ||
git diff -- '**/README.md' | ||
exit 1 | ||
else | ||
echo "No version mismatch detected. All versions are up to date." | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
name: Auto Update README Version | ||
|
||
# This workflow runs when a new tag is pushed with the format release/module-name/vX.Y.Z | ||
# It automatically updates the corresponding README.md file with the new version | ||
# and creates a PR that is auto-approved and auto-merged. | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'release/*/v*' # Matches tags like release/module-name/v1.0.0 | ||
|
||
jobs: | ||
update-readme: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: write # Needed to push branches | ||
pull-requests: write # Needed to create and manage PRs | ||
|
||
steps: | ||
# Check out the repository | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 # We need the full history to check tags | ||
|
||
# Set up the Bun JavaScript runtime | ||
- name: Setup Bun | ||
uses: oven-sh/setup-bun@v2 | ||
with: | ||
bun-version: latest | ||
|
||
# Install dependencies | ||
- name: Install dependencies | ||
run: bun install | ||
|
||
# Extract information from the tag that triggered this workflow | ||
- name: Extract tag information | ||
id: tag | ||
run: | | ||
# Parse the tag name (e.g., "release/code-server/v1.2.3") | ||
TAG_NAME="${GITHUB_REF#refs/tags/}" | ||
# Extract module name (the middle part) | ||
MODULE_NAME=$(echo $TAG_NAME | cut -d'/' -f2) | ||
# Extract version (the last part, without the 'v' prefix) | ||
VERSION=$(echo $TAG_NAME | cut -d'/' -f3 | sed 's/^v//') | ||
|
||
# Make these values available to other steps | ||
echo "MODULE_NAME=$MODULE_NAME" >> $GITHUB_OUTPUT | ||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | ||
echo "TAG_NAME=$TAG_NAME" >> $GITHUB_OUTPUT | ||
|
||
# Check if README needs updating | ||
- name: Check if README version needs updating | ||
id: check | ||
run: | | ||
matifali marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Make the script executable | ||
chmod +x ./update-version.sh | ||
matifali marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Check if README version matches tag version | ||
# The script will exit with 0 if versions match, 1 if they don't | ||
if ./update-version.sh --check "${{ steps.tag.outputs.MODULE_NAME }}" "${{ steps.tag.outputs.VERSION }}"; then | ||
echo "NEEDS_UPDATE=false" >> $GITHUB_OUTPUT | ||
echo "README version already matches tag version - no update needed" | ||
else | ||
echo "NEEDS_UPDATE=true" >> $GITHUB_OUTPUT | ||
echo "README version doesn't match tag version - update needed" | ||
fi | ||
|
||
# Update README with new version | ||
- name: Update README version | ||
if: steps.check.outputs.NEEDS_UPDATE == 'true' | ||
run: | | ||
# Set git identity for commits | ||
git config user.name "cdrci" | ||
git config user.email "[email protected]" | ||
|
||
# Update the README with the new version | ||
chmod +x ./update-version.sh | ||
./update-version.sh "${{ steps.tag.outputs.MODULE_NAME }}" "${{ steps.tag.outputs.VERSION }}" | ||
echo "Updated README version to ${{ steps.tag.outputs.VERSION }}" | ||
|
||
# Create PR with the changes | ||
- name: Create PR for version update | ||
if: steps.check.outputs.NEEDS_UPDATE == 'true' | ||
id: create-pr | ||
env: | ||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
run: | | ||
# Set variables for PR creation | ||
MODULE="${{ steps.tag.outputs.MODULE_NAME }}" | ||
VERSION="${{ steps.tag.outputs.VERSION }}" | ||
BRANCH="automated-update-$MODULE-$VERSION" | ||
PR_TITLE="chore: update $MODULE version to $VERSION" | ||
|
||
# Create a branch for the PR | ||
git checkout -b "$BRANCH" | ||
|
||
# Commit the changes | ||
git add "$MODULE/README.md" | ||
git commit -m "$PR_TITLE" | ||
|
||
# Push the branch to the repository | ||
git push origin "$BRANCH" | ||
|
||
# Create a PR using GitHub CLI | ||
PR_URL=$(gh pr create \ | ||
--title "$PR_TITLE" \ | ||
--body "Updates README version to match tag ${{ steps.tag.outputs.TAG_NAME }}" \ | ||
--base main \ | ||
--head "$BRANCH") | ||
|
||
echo "Created PR: $PR_URL" | ||
|
||
# Extract PR number from the URL | ||
PR_NUMBER=$(echo "$PR_URL" | grep -o '[0-9]*$') | ||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT | ||
|
||
# Enable auto-merge for the PR | ||
gh pr merge "$PR_NUMBER" --auto --squash | ||
echo "Enabled auto-merge for PR #$PR_NUMBER" | ||
|
||
# Auto-approve the PR | ||
- name: Auto-approve PR | ||
matifali marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if: steps.create-pr.outputs.pr_number | ||
uses: hmarr/auto-approve-action@v3 | ||
with: | ||
pull-request-number: ${{ steps.create-pr.outputs.pr_number }} | ||
github-token: ${{ secrets.GITHUB_TOKEN }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,20 +56,42 @@ module "example" { | |
> [!WARNING] | ||
> When creating a new release, make sure that your new version number is fully accurate. If a version number is incorrect or does not exist, we may end up serving incorrect/old data for our various tools and providers. | ||
|
||
Much of our release process is automated. To cut a new release: | ||
The release process is automated and follows these steps: | ||
|
||
1. Navigate to [GitHub's Releases page](https://github.com/coder/modules/releases) | ||
2. Click "Draft a new release" | ||
3. Click the "Choose a tag" button and type a new release number in the format `v<major>.<minor>.<patch>` (e.g., `v1.18.0`). Then click "Create new tag". | ||
4. Click the "Generate release notes" button, and clean up the resulting README. Be sure to remove any notes that would not be relevant to end-users (e.g., bumping dependencies). | ||
5. Once everything looks good, click the "Publish release" button. | ||
1. Create a PR with your module changes | ||
|
||
Once the release has been cut, a script will run to check whether there are any modules that will require that the new release number be published to Terraform. If there are any, a new pull request will automatically be generated. Be sure to approve this PR and merge it into the `main` branch. | ||
- You **do not** need to update the version number in the README.md file | ||
- Focus on implementing your feature or fix | ||
|
||
Following that, our automated processes will handle publishing new data for [`registry.coder.com`](https://github.com/coder/registry.coder.com/): | ||
2. Have your PR reviewed, approved, and merged to main | ||
|
||
1. Publishing new versions to Coder's [Terraform Registry](https://registry.terraform.io/providers/coder/coder/latest) | ||
2. Publishing new data to the [Coder Registry](https://registry.coder.com) | ||
3. After merging to main, a maintainer will: | ||
|
||
- Create and push an annotated tag with an appropriate version based on your changes: | ||
|
||
```shell | ||
# Create an annotated tag with an exact version number | ||
./release.sh module-name 1.2.3 | ||
|
||
# Push the tag to the repository | ||
git push origin release/module-name/v1.2.3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One issue with this approach is that the tag will not include the updated README, it'll be updated after tagging meaning when you It's perhaps a minor thing, but makes me question the release method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice observation. Do you have any suggestions on a better approach? We would have to reverse the behavior where the user chooses a tag, commits that to README, and then pushes a tag that matches that. |
||
``` | ||
|
||
- View all modules and their current versions with: | ||
|
||
```shell | ||
./release.sh --list | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice 👍🏻 |
||
``` | ||
|
||
- The tag will follow the format: `release/module-name/v1.0.0` | ||
|
||
4. When the tag is pushed, a GitHub Action will automatically: | ||
- Update the module's README.md version to match the tag | ||
- Create a PR with the version update by github-actions[bot] | ||
- Auto-approve and auto-merge the version update PR | ||
- No manual action required - the version will be updated automatically | ||
|
||
Following that, our automated processes will handle publishing new data to [`registry.coder.com`](https://registry.coder.com): | ||
|
||
> [!NOTE] | ||
> Some data in `registry.coder.com` is fetched on demand from the Module repo's main branch. This data should be updated almost immediately after a new release, but other changes will take some time to propagate. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# release.sh - Creates annotated tags for module releases | ||
# | ||
# This script is used by maintainers to create annotated tags for module releases. | ||
# It supports two main modes: | ||
# 1. Creating a new tag for a module: ./release.sh module-name X.Y.Z | ||
# 2. Listing all modules with their versions: ./release.sh --list | ||
# | ||
# When a tag is pushed, it triggers a GitHub workflow that updates README versions. | ||
|
||
set -euo pipefail | ||
|
||
# Handle --list option to show all modules and their versions | ||
if [[ "$#" -eq 1 && "$1" == "--list" ]]; then | ||
# Function to extract version from README | ||
extract_version() { | ||
grep -o 'version *= *"[0-9]\+\.[0-9]\+\.[0-9]\+"' "$1" | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "0.0.0" | ||
} | ||
|
||
# Display header for module listing | ||
echo "Listing all modules and their latest versions:" | ||
echo "--------------------------------------------------" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not enough |
||
printf "%-30s %-15s %s\n" "MODULE" "README VERSION" "LATEST TAG" | ||
echo "--------------------------------------------------" | ||
|
||
# Loop through all directories that look like modules | ||
for dir in */; do | ||
if [[ -d "$dir" && -f "${dir}README.md" && "$dir" != ".git/" ]]; then | ||
module_name="${dir%/}" | ||
# Get version from README | ||
readme_version=$(extract_version "${dir}README.md") | ||
# Get latest tag for this module | ||
latest_tag=$(git tag -l "release/${module_name}/v*" | sort -V | tail -n 1) | ||
tag_version=$([ -n "$latest_tag" ] && echo "$latest_tag" | sed 's|release/'"${module_name}"'/v||' || echo "none") | ||
matifali marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Display module info | ||
printf "%-30s %-15s %s\n" "$module_name" "$readme_version" "$tag_version" | ||
fi | ||
done | ||
|
||
echo "--------------------------------------------------" | ||
exit 0 | ||
fi | ||
|
||
# Handle --dry-run option | ||
DRY_RUN=false | ||
if [[ "$1" == "--dry-run" ]]; then | ||
matifali marked this conversation as resolved.
Show resolved
Hide resolved
|
||
DRY_RUN=true | ||
shift | ||
fi | ||
|
||
# Validate arguments | ||
if [[ "$#" -ne 2 ]]; then | ||
echo "Usage: ./release.sh [--dry-run] module-name X.Y.Z" | ||
echo " or: ./release.sh --list" | ||
exit 1 | ||
fi | ||
|
||
MODULE_NAME="$1" | ||
VERSION="$2" | ||
|
||
# Validate version format | ||
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
echo "Error: Version must be in format X.Y.Z" | ||
exit 1 | ||
fi | ||
|
||
# Function to extract version from README | ||
extract_version() { | ||
grep -o 'version *= *"[0-9]\+\.[0-9]\+\.[0-9]\+"' "$1" | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "0.0.0" | ||
} | ||
|
||
# Check if module exists | ||
if [[ ! -d "$MODULE_NAME" || ! -f "$MODULE_NAME/README.md" ]]; then | ||
echo "Error: Module directory not found or missing README.md" | ||
exit 1 | ||
fi | ||
|
||
# Get current README version and construct tag name | ||
README_VERSION=$(extract_version "$MODULE_NAME/README.md") | ||
TAG_NAME="release/$MODULE_NAME/v$VERSION" | ||
|
||
# Check if tag already exists | ||
if git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then | ||
echo "Error: Tag $TAG_NAME already exists" | ||
exit 1 | ||
fi | ||
|
||
# Display release information | ||
echo "Module: $MODULE_NAME" | ||
echo "Current README version: $README_VERSION" | ||
echo "New tag version: $VERSION" | ||
echo "Tag name: $TAG_NAME" | ||
|
||
# Create the tag (or simulate in dry-run mode) | ||
if [[ "$DRY_RUN" == "false" ]]; then | ||
# Create annotated tag | ||
git tag -a "$TAG_NAME" -m "Release $MODULE_NAME v$VERSION" | ||
echo "Success! Tag '$TAG_NAME' created." | ||
echo "To complete the release: git push origin $TAG_NAME" | ||
echo "" | ||
echo "When pushed, this will trigger the GitHub Action to:" | ||
echo "- Update the README.md version" | ||
echo "- Create a PR with the update" | ||
echo "- Auto-approve and merge the PR" | ||
else | ||
echo "[DRY RUN] Would create tag: $TAG_NAME" | ||
fi | ||
|
||
exit 0 |
Uh oh!
There was an error while loading. Please reload this page.