Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/update-metadata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Update Metadata on Tag

on:
push:
tags:
- 'v*.*.*'

jobs:
update-metadata:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.22.3'

- name: Run metadata update script
working-directory: ./hack/tools/metadataupdate
env:
REPO_DIR: $GITHUB_WORKSPACE
run: |
go run main.go --contract v1beta1 --repo-dir "${{ github.workspace }}"

- name: Check for changes
id: git-check
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git add "$GITHUB_WORKSPACE/metadata.yaml"
if [[ -n $(git diff --cached) ]]; then
echo "changes=true" >> $GITHUB_ENV
else
echo "changes=false" >> $GITHUB_ENV
fi

- name: Commit and Push Changes
if: env.changes == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_NAME=update-metadata-${{ github.ref_name }}
git checkout -b "$BRANCH_NAME"
git commit -m "Update metadata.yaml for next release"
git push origin "$BRANCH_NAME"

- name: Create Pull Request
if: env.changes == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${GITHUB_REF##*/}"
PR_TITLE="Update metadata.yaml for next release"
PR_BODY="This PR was automatically created by the release workflow. It adds the next minor release to metadata.yaml based on the new tag (${TAG})."
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--label "area/release" \
--head "$BRANCH_NAME" \
--base "main" \

3 changes: 3 additions & 0 deletions docs/src/05_developers/01_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ git push upstream ${RELEASE_TAG}

This will trigger a [release GitHub action](https://github.com/rancher-sandbox/cluster-api-addon-provider-fleet/actions/workflows/release.yaml) that creates a release with `CAAPF` components.

4. Wait for the [update metadata](https://github.com/rancher/cluster-api-addon-provider-fleet/blob/main/.github/workflows/update-metadata.yaml) workflow to pass successfully.
This workflow will update the `metadata.yaml` file in the root of the repository preparing it for the next release.

## Versioning

CAAPF follows [semantic versioning](https://semver.org/) specification.
Expand Down
5 changes: 5 additions & 0 deletions hack/tools/metadataupdate/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/rancher/cluster-api-addon-provider-fleet/hack/tools/metadataupdate

go 1.22.3

require gopkg.in/yaml.v3 v3.0.1
4 changes: 4 additions & 0 deletions hack/tools/metadataupdate/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
136 changes: 136 additions & 0 deletions hack/tools/metadataupdate/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package main

import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"gopkg.in/yaml.v3"
)

type Metadata struct {
APIVersion string `yaml:"apiVersion"`
ReleaseSeries []ReleaseSeries `yaml:"releaseSeries"`
}

type ReleaseSeries struct {
Major int `yaml:"major"`
Minor int `yaml:"minor"`
Contract string `yaml:"contract"`
}

func main() {
contractFlag := flag.String("contract", "v1beta1", "Contract value for new release entry")
repoDir := flag.String("repo-dir", ".", "Root directory of the repository")
flag.Parse()

tag := os.Getenv("GITHUB_REF_NAME")
if tag == "" {
log.Fatal("GITHUB_REF_NAME environment variable not set")
}

log.Printf("Processing tag: %s", tag)

major, minor, isPatch, err := parseTag(tag)
if err != nil {
log.Fatal(err)
}

if isPatch {
log.Printf("Skipping patch release: %s", tag)
return
}

log.Printf("Adding new release with major: %d, minor: %d+1, contract: %s", major, minor, *contractFlag)

metadataPath := filepath.Join(*repoDir, "metadata.yaml")

metadata, err := readMetadata(metadataPath)
if err != nil {
log.Fatalf("Failed to read metadata file: %v", err)
}

newRelease := ReleaseSeries{
Major: major,
Minor: minor + 1,
Contract: *contractFlag,
}

for _, release := range metadata.ReleaseSeries {
if release.Major == newRelease.Major && release.Minor == newRelease.Minor {
log.Printf("Release %d.%d already exists, skipping", newRelease.Major, newRelease.Minor)
return
}
}

metadata.ReleaseSeries = append(metadata.ReleaseSeries, newRelease)

if err := writeMetadata(metadataPath, metadata); err != nil {
log.Fatalf("Failed to write metadata file: %v", err)
}

log.Printf("Successfully updated metadata.yaml with new release: %d.%d", newRelease.Major, newRelease.Minor)
}

func parseTag(tag string) (int, int, bool, error) {
// Regular expression to match version tags like v0.8.0 or v0.8.1
re := regexp.MustCompile(`^v(\d+)\.(\d+)\.(\d+)$`)
matches := re.FindStringSubmatch(tag)

if len(matches) != 4 {
return 0, 0, false, fmt.Errorf("invalid tag format: %s", tag)
}

major, err := strconv.Atoi(matches[1])
if err != nil {
return 0, 0, false, fmt.Errorf("invalid major version: %s", matches[1])
}

minor, err := strconv.Atoi(matches[2])
if err != nil {
return 0, 0, false, fmt.Errorf("invalid minor version: %s", matches[2])
}

patch, err := strconv.Atoi(matches[3])
if err != nil {
return 0, 0, false, fmt.Errorf("invalid patch version: %s", matches[3])
}

isPatch := patch > 0

return major, minor, isPatch, nil
}

func readMetadata(path string) (Metadata, error) {
var metadata Metadata

data, err := os.ReadFile(path)
if err != nil {
return metadata, err
}

err = yaml.Unmarshal(data, &metadata)
if err != nil {
return metadata, err
}

return metadata, nil
}

func writeMetadata(path string, metadata Metadata) error {
var sb strings.Builder
encoder := yaml.NewEncoder(&sb)
encoder.SetIndent(2)
defer encoder.Close()

if err := encoder.Encode(metadata); err != nil {
return err
}

return os.WriteFile(path, []byte(sb.String()), 0644)
}