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 - Proposal: Automated Kubebuilder Project Update Action #4302

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
211 changes: 211 additions & 0 deletions designs/update_action.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
| Authors | Creation Date | Status | Extra |
|-----------------|---------------|-------------|-------|
| @camilamacedo86 | 2024-11-07 | Implementable | - |

# Proposal: Automated Kubebuilder Project Update Action

This proposal aims to create a GitHub Action similar to Dependabot for Kubebuilder,
automating the process of regenerating scaffolds and preserving custom code when new
versions of Kubebuilder are released. This solution ensures that projects stay
updated with best practices, bug fixes, and features, ultimately improving
maintainability and adoption by reducing the complexity of manual updates.

## Example

This proposal introduces an automated GitHub Action to handle updates for projects created with Kubebuilder. When a new version of Kubebuilder is released, the Action would detect it, regenerate the project scaffold while preserving customizations, and open a pull request in the repository with the latest updates. For example:

1. A user creates a project with Kubebuilder `v4.4`.
2. When Kubebuilder `v4.5` is released, the Action regenerates the scaffold with `v4.5` in a separate directory.
3. A pull request is created with a merge of the user's customizations from the main branch into the regenerated scaffold,
allowing them to review and merge the updates seamlessly.

## Open Questions

1. How will projects handle breaking changes in Kubebuilder updates?

## Summary

TODO

## Motivation

Keeping projects created with Kubebuilder up-to-date with the latest best practices and features is challenging, especially as projects grow and custom code accumulates. Without automated support, developers often delay updates, leading to outdated configurations and the potential for increased technical debt.

This proposal seeks to:
- Facilitate easy updates of Kubebuilder projects.
- Encourage adherence to best practices.
- Make it simpler for developers to maintain the latest, most secure, and feature-rich versions of their projects.

### Goals

- Automatically detect and apply updates to Kubebuilder scaffolds without overwriting customizations.
- Provide pull requests that simplify the process of updating the users project.
- Help keep the projects updated with the latest changes in the scaffolds

### Non-Goals

- Managing or updating non-Kubebuilder project dependencies.
- Resolving complex customizations that directly conflict with updated scaffolds.
- Automatically merging pull requests without review from project maintainers.

## Proposal

### User Stories

- **As a Kubebuilder maintainer**, I want to ensure that users adhere to Kubebuilder scaffolds and best practices by
helping them keep their projects updated with minimal effort.
This will prevent users from deviating from the recommended structure and practices,
maintaining alignment with the project standards. By simplifying updates,
I can also ensure that users remain engaged and see long-term value in using Kubebuilder,
rather than becoming frustrated with manual maintenance.
- **As a user of Kubebuilder**, I want my project built with Kubebuilder to be kept up-to-date
with the latest scaffold best practices so that I can minimize maintenance work.
- **As a user of Kubebuilder**, I want a reliable way to apply Kubebuilder updates
across multiple repositories, saving time on manual updates.
- **As a user of Kubebuilder**, I want to ensure our codebases adhere to current standards,
improving security and maintainability without requiring excessive manual effort.

### Implementation Details/Notes/Constraints

The GitHub Action would be configured as follows:

1. **Version Tracking**:
- Record the initial Kubebuilder version used in each project (`clientVersion`) within the `PROJECT` file.
- When triggered, check for new releases of Kubebuilder.

2. **Three-Way Merge**:
- Generate the original scaffold from the stored version, `clientVersion`, in the `PROJECT` file.
- Regenerate the scaffold with the latest Kubebuilder version.
- Perform a three-way merge between the stored original scaffold, the customized main branch, and the updated scaffold. This preserves customizations while incorporating updates.

3. **PR Creation**:
- Open a pull request in the repository with the scaffold updates.
- Provide detailed descriptions of changes, including how conflicts were resolved, if applicable.
- Schedule updates weekly or on-demand to minimize disruption.

#### Example Workflow

The following example code illustrates the proposed idea but has not been evaluated.
This is an early, incomplete draft intended to demonstrate the approach and basic concept.

We may want to develop a dedicated command-line tool, such as `kubebuilder alpha update`,
to handle tasks like downloading binaries, merging, and updating the scaffold. In this approach,
the GitHub Action would simply invoke this tool to manage the update process and open the
Pull Request, rather than performing each step directly within the Action itself.

```yaml

name: Update Kubebuilder Scaffold

on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # Run weekly to check for new Kubebuilder versions

jobs:
update-scaffold:
runs-on: ubuntu-latest

steps:
- name: Check out the repository
uses: actions/checkout@v2
with:
fetch-depth: 0 # Ensures the full history is checked out

- name: Set up environment and dependencies
run: |
sudo apt-get update
sudo apt-get install -y jq curl

- name: Read Kubebuilder version from PROJECT file
id: read_version
run: |
export INITIAL_VERSION=$(grep "clientVersion" PROJECT | awk '{print $2}')
echo "::set-output name=initial_version::$INITIAL_VERSION"

- name: Download and install the initial Kubebuilder version
run: |
curl -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/${{ steps.read_version.outputs.initial_version }}/kubebuilder_${{ steps.read_version.outputs.initial_version }}_linux_amd64.tar.gz -o kubebuilder_initial.tar.gz
tar -zxvf kubebuilder_initial.tar.gz
sudo mv kubebuilder /usr/local/kubebuilder_initial

- name: Generate initial scaffold in `scaffold_initial` directory
run: |
mkdir scaffold_initial
cp -r . scaffold_initial/
cd scaffold_initial
/usr/local/kubebuilder_initial/bin/kubebuilder init
cd ..

- name: Check for the latest Kubebuilder release
id: get_latest_version
run: |
export LATEST_VERSION=$(curl -s https://api.github.com/repos/kubernetes-sigs/kubebuilder/releases/latest | jq -r .tag_name)
echo "::set-output name=latest_version::$LATEST_VERSION"

- name: Download and install the latest Kubebuilder version
run: |
curl -L https://github.com/kubernetes-sigs/kubebuilder/releases/download/${{ steps.get_latest_version.outputs.latest_version }}/kubebuilder_${{ steps.get_latest_version.outputs.latest_version }}_linux_amd64.tar.gz -o kubebuilder_latest.tar.gz
tar -zxvf kubebuilder_latest.tar.gz
sudo mv kubebuilder /usr/local/kubebuilder_latest

- name: Generate updated scaffold in `scaffold_updated` directory
run: |
mkdir scaffold_updated
cp -r . scaffold_updated/
cd scaffold_updated
/usr/local/kubebuilder_latest/bin/kubebuilder init
cd ..

- name: Copy current project into `scaffold_current` directory
run: |
mkdir scaffold_current
cp -r . scaffold_current/

- name: Perform three-way merge with scaffolds
run: |
# Create a temporary directory to hold the final merged version
mkdir merged_scaffold
# Run three-way merge using scaffold_initial, scaffold_current, and scaffold_updated
# Adjusting merge strategy and paths to use directories
diff3 -m scaffold_current scaffold_initial scaffold_updated > merged_scaffold/merged_files

- name: Copy merged files back to main directory
run: |
cp -r merged_scaffold/* .
git add .
git commit -m "Three-way merge with Kubebuilder updates and custom code"

- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
commit-message: "Update scaffold to Kubebuilder ${{ steps.get_latest_version.outputs.latest_version }}"
title: "Update scaffold to Kubebuilder ${{ steps.get_latest_version.outputs.latest_version }}"
body: |
This pull request updates the scaffold with the latest Kubebuilder version ${{ steps.get_latest_version.outputs.latest_version }}.
branch: kubebuilder-update-${{ steps.get_latest_version.outputs.latest_version }}
```

### Risks and Mitigations

- **Risk**: Potential conflicts with heavily customized code.
- *Mitigation*: GitHub as other tools provide a preview mode where users can inspect conflicts before the merge is attempted.

### Proof of Concept

NA

## Drawbacks

- **Complexity**: Implementing three-way merges and maintaining compatibility across
multiple Kubebuilder versions can add complexity to the Action.

## Alternatives

- **Manual Update Workflow**: Continue with manual updates where users regenerate
and merge changes independently, though this is time-consuming and error-prone.
- **Use alpha generate command**: Continue with updates partial automated provided
by the alpha generate command.
- **Dependabot Integration**: Leverage Dependabot for dependency updates, though this
doesn’t fully support scaffold updates and could lead to incomplete upgrades.