Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add workflow to bump go module across repos #508

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
79 changes: 79 additions & 0 deletions .github/workflows/go-module-bump-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Go Module bump (template)

on:
workflow_dispatch: # Manual workflow trigger
inputs:
go-module:
description: "Go module to bump"
required: true
version:
description: "Go module version"
default: "latest"
required: true

defaults:
run:
shell: bash

jobs:
go-mod-bump:
name: Go Module bump (template)
runs-on: ubuntu-latest
strategy:
fail-fast: false # Keep running if one leg fails.
matrix:
include: []

steps:
- name: Configure Git user
run: |
git config --global user.email "[email protected]"
git config --global user.name "serverless-qe"

- name: Checkout repo
uses: actions/checkout@v4
with:
repository: openshift-knative/${{ matrix.repo }}
ref: ${{ matrix.branch }}

- name: Check if ${{ inputs.go-module }} is in go.mod
id: gomod-check
run: |
if grep -iP "\t${{ inputs.go-module }} " go.mod; then
echo "${{ inputs.go-module }} found in projects go.mod"
echo "module-exists=true" >> "$GITHUB_OUTPUT"
else
echo "${{ inputs.go-module }} not found in projects go.mod"
echo "module-exists=false" >> "$GITHUB_OUTPUT"
fi

- name: Bump Go module
if: steps.gomod-check.outputs.module-exists == 'true'
run: |
go get ${{ inputs.go-module }}@${{ inputs.version }}

if [[ -n "${{ matrix.postUpdateCmd }}" ]]; then
${{ matrix.postUpdateCmd }}
fi

- name: Create Pull Request
if: steps.gomod-check.outputs.module-exists == 'true'
env:
GH_TOKEN: ${{ secrets.SERVERLESS_QE_ROBOT }}
GITHUB_TOKEN: ${{ secrets.SERVERLESS_QE_ROBOT }}
run: |
set -x
git remote add fork "https://github.com/serverless-qe/hack.git"
branch="$(echo "bump-${{ inputs.go-module }}-${{ inputs.version }}-${{ matrix.branch }}" | tr '[:upper:]' '[:lower:]')"
remote_exists=$(git ls-remote --heads fork "$branch")
if [ -z "$remote_exists" ]; then
# remote doesn't exist.
git push "https://serverless-qe:${GH_TOKEN}@github.com/serverless-qe/${{ matrix.repo }}.git" "$branch:$branch" -f || exit 1
fi
git fetch fork "$branch"
if git diff --quiet "fork/$branch" "$branch"; then
echo "Branches are identical. No need to force push."
else
git push "https://serverless-qe:${GH_TOKEN}@github.com/serverless-qe/${{ matrix.repo }}.git" "$branch:$branch" -f
fi
gh pr create --base main --head "serverless-qe:$branch" --title "[${{ matrix.branch }}] Bump ${{ inputs.go-module }} to ${{ inputs.version }}" --body "Bumping ${{ inputs.go-module }} to ${{ inputs.version }}" || true
183 changes: 183 additions & 0 deletions .github/workflows/go-module-bump.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Go Module bump
on:
workflow_dispatch: # Manual workflow trigger
inputs:
go-module:
description: "Go module to bump"
required: true
version:
description: "Go module version"
default: "latest"
required: true
defaults:
run:
shell: bash
jobs:
go-mod-bump:
name: Go Module bump
runs-on: ubuntu-latest
strategy:
fail-fast: false # Keep running if one leg fails.
matrix:
include:
- repo: backstage-plugins
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: backstage-plugins
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: backstage-plugins
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: backstage-plugins
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: client
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: client
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: eventing-hyperfoil-benchmark
branch: main
postUpdateCmd: make generate-release
- repo: eventing-istio
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: eventing-istio
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: eventing-istio
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: eventing-istio
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: eventing-kafka-broker
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: eventing-kafka-broker
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: eventing-kafka-broker
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: eventing-kafka-broker
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: eventing
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: eventing
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: eventing
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: eventing
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: kn-plugin-event
branch: release-1.15
- repo: kn-plugin-event
branch: release-1.16
- repo: kn-plugin-func
branch: release-v1.15
- repo: kn-plugin-func
branch: release-v1.16
- repo: kn-plugin-func
branch: serverless-1.34
- repo: serverless-operator
branch: main
postUpdateCmd: make generated-files
- repo: serverless-operator
branch: release-1.35
postUpdateCmd: make generated-files
- repo: serverless-operator
branch: release-1.36
postUpdateCmd: make generated-files
- repo: net-istio
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: net-istio
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: net-istio
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: net-istio
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: net-kourier
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: net-kourier
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: net-kourier
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: net-kourier
branch: release-v1.16
postUpdateCmd: make generate-release
- repo: serving
branch: release-v1.12
postUpdateCmd: make generate-release
- repo: serving
branch: release-v1.14
postUpdateCmd: make generate-release
- repo: serving
branch: release-v1.15
postUpdateCmd: make generate-release
- repo: serving
branch: release-v1.16
postUpdateCmd: make generate-release
steps:
- name: Configure Git user
run: |
git config --global user.email "[email protected]"
git config --global user.name "serverless-qe"
- name: Checkout repo
uses: actions/checkout@v4
with:
repository: openshift-knative/${{ matrix.repo }}
ref: ${{ matrix.branch }}
- name: Check if ${{ inputs.go-module }} is in go.mod
id: gomod-check
run: |
if grep -iP "\t${{ inputs.go-module }} " go.mod; then
echo "${{ inputs.go-module }} found in projects go.mod"
echo "module-exists=true" >> "$GITHUB_OUTPUT"
else
echo "${{ inputs.go-module }} not found in projects go.mod"
echo "module-exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Bump Go module
if: steps.gomod-check.outputs.module-exists == 'true'
run: |
go get ${{ inputs.go-module }}@${{ inputs.version }}

if [[ -n "${{ matrix.postUpdateCmd }}" ]]; then
${{ matrix.postUpdateCmd }}
fi
- name: Create Pull Request
if: steps.gomod-check.outputs.module-exists == 'true'
env:
GH_TOKEN: ${{ secrets.SERVERLESS_QE_ROBOT }}
GITHUB_TOKEN: ${{ secrets.SERVERLESS_QE_ROBOT }}
run: |
set -x
git remote add fork "https://github.com/serverless-qe/hack.git"
branch="$(echo "bump-${{ inputs.go-module }}-${{ inputs.version }}-${{ matrix.branch }}" | tr '[:upper:]' '[:lower:]')"
remote_exists=$(git ls-remote --heads fork "$branch")
if [ -z "$remote_exists" ]; then
# remote doesn't exist.
git push "https://serverless-qe:${GH_TOKEN}@github.com/serverless-qe/${{ matrix.repo }}.git" "$branch:$branch" -f || exit 1
fi
git fetch fork "$branch"
if git diff --quiet "fork/$branch" "$branch"; then
echo "Branches are identical. No need to force push."
else
git push "https://serverless-qe:${GH_TOKEN}@github.com/serverless-qe/${{ matrix.repo }}.git" "$branch:$branch" -f
fi
gh pr create --base main --head "serverless-qe:$branch" --title "[${{ matrix.branch }}] Bump ${{ inputs.go-module }} to ${{ inputs.version }}" --body "Bumping ${{ inputs.go-module }} to ${{ inputs.version }}" || true
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ unit-tests:
rm -rf openshift/project/.github

mkdir -p openshift
go run ./cmd/generate-ci-action --input ".github/workflows/release-generate-ci-template.yaml" --config "config/" --output "openshift/release-generate-ci.yaml"
go run ./cmd/generate-ci-action --config "config/" --output "openshift/"
# If the following fails, please run 'make generate-ci-action'
diff -r "openshift/release-generate-ci.yaml" ".github/workflows/release-generate-ci.yaml"

Expand Down
9 changes: 2 additions & 7 deletions cmd/generate-ci-action/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@ func main() {
defer cancel()

inputConfig := flag.String("config", filepath.Join("config"), "Specify repositories config")
inputAction := flag.String("input", filepath.Join(".github", "workflows", "release-generate-ci-template.yaml"), "Input action (template)")
outputAction := flag.String("output", filepath.Join(".github", "workflows", "release-generate-ci.yaml"), "Output action")
outputFolder := flag.String("output", filepath.Join(".github", "workflows"), "Output folder for the actions")
flag.Parse()

err := action.UpdateAction(ctx, action.Config{
InputAction: *inputAction,
InputConfigPath: *inputConfig,
OutputAction: *outputAction,
})
err := action.Generate(ctx, *inputConfig, *outputFolder)
if err != nil {
log.Fatal(err)
}
Expand Down
96 changes: 96 additions & 0 deletions pkg/action/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package action

import (
"bytes"
"cmp"
"context"
"fmt"
"path/filepath"
"sort"

"gopkg.in/yaml.v3"
)

type Config struct {
InputAction string
InputConfigPath string
OutputAction string
}

func Generate(ctx context.Context, inputConfig string, outputFolder string) error {
if err := UpdateAction(ctx, Config{
InputConfigPath: inputConfig,
InputAction: ".github/workflows/release-generate-ci-template.yaml",
OutputAction: filepath.Join(outputFolder, "release-generate-ci.yaml"),
}); err != nil {
return fmt.Errorf("could not generate update action: %w", err)
}

if err := GoModuleBumpAction(ctx, Config{
InputConfigPath: inputConfig,
InputAction: ".github/workflows/go-module-bump-template.yaml",
OutputAction: filepath.Join(outputFolder, "go-module-bump.yaml"),
}); err != nil {
return fmt.Errorf("could not generate Go module bump action: %w", err)
}

return nil
}

func AddNestedField(node *yaml.Node, value interface{}, prepend bool, fields ...string) error {

for i, n := range node.Content {

if i > 0 && node.Content[i-1].Value == fields[0] {

// Base case for scalar nodes
if len(fields) == 1 && n.Kind == yaml.ScalarNode {
n.SetString(fmt.Sprintf("%s", value))
break
}
// base case for sequence node
if len(fields) == 1 && n.Kind == yaml.SequenceNode {

if v, ok := value.([]interface{}); ok {
var s yaml.Node

b, err := yaml.Marshal(v)
if err != nil {
return err
}
if err := yaml.NewDecoder(bytes.NewBuffer(b)).Decode(&s); err != nil {
return err
}

if prepend {
n.Content = append(s.Content[0].Content, n.Content...)
} else {
n.Content = append(n.Content, s.Content[0].Content...)
}

// print list entries in a single line each
n.Style = yaml.LiteralStyle
}
break
}

// Continue to the next level
return AddNestedField(n, value, prepend, fields[1:]...)
}

if node.Kind == yaml.DocumentNode {
return AddNestedField(n, value, prepend, fields...)
}
}

return nil
}

func sortedKeys[K cmp.Ordered, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
return keys
}
Loading
Loading