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
85 changes: 85 additions & 0 deletions .ci/scripts/docgen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python3

import os
import yaml
from dataclasses import dataclass
from typing import List
from urllib.parse import urlparse, urlunparse

@dataclass
class PolicyMetadata:
dir: str
version: str
description: str
path: str

def find_policy_yaml(start_dir=".") -> List[str]:
"""Recursively search for files named 'Policy.yaml'."""
matches = []
for root, _, files in os.walk(start_dir):
if "Policy.yaml" in files:
matches.append(os.path.join(root, "Policy.yaml"))
return matches

def load_policy_metadata(file_path: str) -> PolicyMetadata:
"""Load a Policy.yaml file and unmarshal it into a PolicyMetadata object."""
with open(file_path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f) or {}

dir_name = os.path.dirname(file_path)
return PolicyMetadata(
dir=data.get("dir", dir_name),
version=data.get("version", ""),
description=data.get("description", ""),
path=file_path,
)

def generate_markdown_table(policies: List[PolicyMetadata]) -> str:
"""Generate a Markdown table from a list of PolicyMetadata objects."""
header = "| URL | Version | Description | Link |\n"
separator = "|------------|----------|-----------|---------| \n"
rows = []
for p in policies:
description = p.description.replace("\n", " ").strip()
ghcr_path = f"ghcr.io/updatecli/policies/{os.path.basename(p.path)}"
readme_url = replace_filename_in_url(f"https://github.com/updatecli/policies/tree/main/{p.path}", "README.md")
rows.append(f"| `{ghcr_path or '-'}` | {p.version or '-'} | {description or '-'} | {f"[link]({readme_url})" } |")
return header + separator + "\n".join(rows)

def replace_filename_in_url(url: str, new_filename: str) -> str:
# Parse the URL
parsed = urlparse(url)

# Split the path and replace the last part with the new filename
path_parts = parsed.path.split('/')
path_parts[-1] = new_filename
new_path = '/'.join(path_parts)

# Rebuild the URL with the new path
new_url = urlunparse(parsed._replace(path=new_path))
return new_url

# Example usage
original_url = "https://github.com/updatecli/policies/blob/main/updatecli/policies/file/Policy.yaml"
new_url = replace_filename_in_url(original_url, "Readme.md")

def main():
policies = []
for policy_file in find_policy_yaml("."):
try:
metadata = load_policy_metadata(policy_file)
policies.append(metadata)
except Exception as e:
print(f"⚠️ Error parsing {policy_file}: {e}")

if not policies:
print("No Policy.yaml files found.")
return

markdown = generate_markdown_table(policies)

with open("POLICIES.md", "w", encoding="utf-8") as f:
f.write(markdown)

if __name__ == "__main__":
main()
30 changes: 30 additions & 0 deletions .github/workflows/updatecli.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: updatecli
on:
workflow_dispatch:
push:
branches: [main]
schedule:
# Run every hour
- cron: "0 * * * *"
jobs:
updatecli:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: "Checkout"
uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0
- name: "Setup updatecli"
uses: "updatecli/updatecli-action@144e241dd804cca91d5a5f362c98b71e7d3ea057" # v2
- uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1
id: generate_token
if: github.ref == 'refs/heads/main'
with:
app-id: ${{ secrets.UPDATECLIBOT_APP_ID }}
private-key: ${{ secrets.UPDATECLIBOT_APP_PRIVKEY }}
- name: "Run updatecli"
if: github.ref == 'refs/heads/main'
run: "updatecli compose apply"
env:
UPDATECLI_GITHUB_USERNAME: ${{ secrets.UPDATECLI_BOT_GITHUB_ACTOR }}
UPDATECLI_GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
160 changes: 148 additions & 12 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,11 +1,73 @@
= README

image:https://www.updatecli.io/images/updatecli.png[alt=Updatecli,float="right",align="center",width=200,height=200]

link:https://matrix.to/#/#Updatecli_community:gitter.im[image:https://img.shields.io/matrix/updatecli:matrix.org[]]
link:https://github.com/updatecli/policies/blob/main/LICENSE[image:https://img.shields.io/github/license/updatecli/policies[GitHub]]
link:https://img.shields.io/github/actions/workflow/status/updatecli/policies/validate.yaml?branch=main[image:https://img.shields.io/github/actions/workflow/status/updatecli/policies/validate.yaml?branch=main[GitHub Workflow Status]]


This repository contains a list of common Updatecli published on ghcr.io/updatecli/policies/**
These repository contains a list of common Updatecli policies that can be used to automate the update of various software components.
These policies are published on `ghcr.io/updatecli/policies` docker registry and can be used directly by Updatecli users.
Policies are designed to be as generic as possible to fit most use cases and can be customized via values files at runtime.
They follow semantic versioning to ensure compatibility and stability.

== Policies

A list of all available policies can be found link:./POLICIES.md[here].

== Quick Start

Pull and inspect a policy manifest:

[source,shell]
----
updatecli manifest show ghcr.io/updatecli/policies/autodiscovery/golang:latest
----

Run a single policy (dry-run):

[source,shell]
----
updatecli diff ghcr.io/updatecli/policies/autodiscovery/golang:latest
----

Apply a single policy:

[source,shell]
----
updatecli apply --config ghcr.io/updatecli/policies/autodiscovery/golang:latest
----

Compose multiple policies using an updatecli-compose file:

* Create `updatecli-compose.yaml` (example below).
* Run:
[source,shell]
----
updatecli compose apply --config ./updatecli-compose.yaml
----

.updatecli-compose.yaml
----
policies:
- policy: "ghcr.io/updatecli/policies/autodiscovery/golang:latest"
- policy: "ghcr.io/updatecli/policies/autodiscovery/npm:latest"
----

Please be aware that each policies comes with its own set of configuration options so please refer to the policy documentation for more information.
You can replace the policy `ghcr.io/updatecli/policies/autodiscovery/all:latest` by any other policy available in this repository.

== Authentication / Registry

Policies are published on `ghcr.io`. Public pulls usually work, but authenticating reduces rate-limiting:

[source,shell]
----
docker login ghcr.io
----

If you need to pull private policies, provide credentials via your container/runtime or via Updatecli's registry auth options.

== HOWTO

Expand All @@ -23,24 +85,24 @@ Each policies defines in this repository are automatically published on ghcr.io

We can see the content of the policy by running:

updatecli manifest show ghcr.io/updatecli/policies/<a policy name>:latest
updatecli manifest show --config updatecli.d --values values.yaml

**Use**

They are two ways to execute an Updatecli policy, either running one policy or several policies at once.
There are two ways to execute an Updatecli policy, either running one policy or several policies at once.

One policy can be executed by running:

updatecli apply --config ghcr.io/updatecli/policies/<a policy name>:latest
updatecli apply --config ghcr.io/updatecli/policies/<policy-path>:<version>


IMPORTANT: Any values files specified at runtime will override default values setting from the policy bundle

Assuming we have a file named `update-compose.yaml`, multiple policies can be composed and executed by running:
Assuming we have a file named `updatecli-compose.yaml`, multiple policies can be composed and executed by running:

updatecli compose apply
updatecli compose apply --config ./updatecli-compose.yaml

.update-compose.yaml
.updatecli-compose.yaml
```yaml
policies:
- policy: "ghcr.io/updatecli/policies/autodiscovery/golang:latest"
Expand All @@ -51,7 +113,80 @@ More information about Updatecli compose feature can be found link:https://www.u

== CONTRIBUTING

Policies can be added by creating a new folder under `updatecli/policies` directory.
Thank you for your interest in contributing to this project.
Here is a none exclusive list of contribution you can do.

=== Documentation

This project would benefit from clearer policy README files. Please improve each policy's README to explain how to use and configure the policy.

To inspect a policy bundle locally (manifest and default values):

[source,shell]
----
# Show the generated manifest (uses files in the policy bundle directory)
updatecli manifest show --config updatecli.d --values values.yaml

# Show the manifest and render a graph (Mermaid)
updatecli manifest show --config updatecli.d --values values.yaml --graph --graph-flavor mermaid
----

Notes:
* `--config updatecli.d` reads policy manifests shipped inside the policy bundle.
* `--values values.yaml` overrides default policy values for local inspection.

When running policies, prefer pinning by version or digest to ensure reproducible runs:
* By tag: `ghcr.io/updatecli/policies/autodiscovery/golang:1.0.0`
* By digest: `ghcr.io/updatecli/policies/autodiscovery/golang@sha256:<digest>`

Authentication:
* Public pulls usually work, but authenticating with GHCR reduces rate limits:
[source,shell]
----
docker login ghcr.io
----
* For private bundles, provide registry credentials to your runtime or via Updatecli's registry auth options.

Publishing:
* Policies in this repository are published automatically by CI when `Policy.yaml` version is bumped.
* See the `Policy.yaml` template below and ensure you update the `version` field for releases.

Policy inspection and usage summary:
* Inspect: `updatecli manifest show --config updatecli.d --values values.yaml`
* Dry-run: `updatecli diff ghcr.io/updatecli/policies/<path>:<version>`
* Apply: `updatecli apply --config ghcr.io/updatecli/policies/<path>:<version>`

Tip: add a short example `values.yaml` in each policy README to help users test quickly.

=== Updating Policy

Before changing an existing policy, open a GitHub issue to discuss the proposed change. Use the issue to explain:
* Motivation and user impact
* Backwards compatibility implications
* Required changes to `Policy.yaml`, `values.yaml`, or `updatecli.d`
* Testing plan (how the change will be validated)

When preparing a PR:
* Bump `Policy.yaml` version for behavioural changes (semantic versioning).
* Update `CHANGELOG.md` and the policy `README.md` with usage and configuration changes.
* Add or update `values.yaml` examples if defaults change.
* Ensure policy validation CI (lint/manifest tests) passes.

PR checklist:
* [ ] Issue opened describing the change (link in PR)
* [ ] `Policy.yaml` version updated when needed
* [ ] `CHANGELOG.md` updated
* [ ] README and example `values.yaml` updated
* [ ] All CI checks pass (policy validation workflow)

Notes:
* Policies are published automatically by CI when `Policy.yaml.version` is updated.
* For large or breaking changes, discuss a migration plan in the issue and notify maintainers.
* For security-related changes, include an explanation and coordinate disclosure with maintainers.

=== New Policy

A new policy can be added by creating a new folder under the `updatecli/policies` directory.
The subfolder path will be used as the policy name.

For example if we want to create a policy named `autodiscovery/golang`, we need to create a folder named `updatecli/policies/autodiscovery/golang`.
Expand Down Expand Up @@ -89,12 +224,13 @@ Any change to the policy code must be reflected by a new version. Policies are a

=== Why a monorepo ?

A monorepo is a repository that contains multiple projects. In our case, we have a single repository that contains multiple Updatecli policies.
A monorepo simplifies policy discovery and publishing while we build tooling and CI. We may split later if needed.

We are still in a very early stage and we are not sure yet if we will keep this repository as a monorepo or if we will split it into multiple repositories.
== Thanks to all the contributors ❤️

But it is easier to handle a monorepo than multiple repositories while we build the tooling and the process to manage Updatecli policies.
link:https://github.com/updatecli/policies/graphs/contributors"[image:https://contrib.rocks/image?repo=updatecli/policies[]]

== LINKS

* link:https://www.updatecli.io/docs/core/compose/[here]
* link:https://www.updatecli.io/docs/core/compose/[Updatecli Compose documentation]
* link:./POLICIES.md[Full Policy list]
12 changes: 12 additions & 0 deletions updatecli-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
policies:
- name: Local Updatecli policies
config:
- updatecli/updatecli.d
values:
- updatecli/values.d/scm.yaml

- name: Update githubactions
policy: ghcr.io/updatecli/policies/autodiscovery/githubaction:0.2.1@sha256:cfddec11464cc09615135f0f1e069f00ad24d28edc7cc6a4e8224e04c3699008
values:
- updatecli/values.d/scm.yaml
- updatecli/values.d/githubaction.yaml
40 changes: 40 additions & 0 deletions updatecli/updatecli.d/policies.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Update POLICIES.md

actions:
default:
title: "deps: update POLICIES.md"
kind: github/pullrequest
scmid: default
spec:
automerge: true
labels:
- documentation

scms:
default:
kind: github
spec:
branch: "{{ .scm.branch }}"
email: "{{ .scm.email }}"
owner: "{{ .scm.owner }}"
repository: "{{ .scm.repository }}"
user: "{{ .scm.user }}"

conditions:
python:
name: Check if Python is installed
kind: shell
spec:
command: "python3 --version"

targets:
policies:
name: update POLICIES.md
kind: shell
spec:
command: .ci/scripts/docgen.py
changedif:
kind: file/checksum
spec:
files:
- "POLICIES.md"
3 changes: 3 additions & 0 deletions updatecli/values.d/githubaction.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
spec:
digest: true
rootdir: '.github'
9 changes: 9 additions & 0 deletions updatecli/values.d/scm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
scm:
commitusingapi: true
enabled: true
user: updatecli
email: bot@updatecli.io
owner: updatecli
repository: policies
username: "updatecli-bot"
branch: main