Skip to content

Commit

Permalink
Support OCI registries (#9)
Browse files Browse the repository at this point in the history
* feat: add support for oci registries

Signed-off-by: Michele Palazzi <sysdadmin@m1k.cloud>
  • Loading branch information
ironashram committed Mar 16, 2024
1 parent a677045 commit f9bb31b
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 35 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ This GitHub Action checks for updates in the specified directory of YAML files.

The action walks through the specified directory and its subdirectories, looking for YAML files. For each YAML file, it reads the file and unmarshals the content into an `Application` manifest.

The action then checks if the `chart`, `url`, and `targetRevision` fields are present. If they are, it sends a GET request to the URL (`RepoURL`) and unmarshals the response getting the new chart verions.
The action then checks if the `chart`, `url`, and `targetRevision` fields are present. If they are, it sends a GET request to the URL (`RepoURL`) and unmarshals the response getting the new chart versions.

The action supports both Helm chart repositories and OCI registries. For OCI registries, it uses the `oras.land/oras-go` package to interact with the registry. Please note that currently only public repositories are supported.


The action then checks if there is a new release and opens PR with the updates if there is.

Expand Down Expand Up @@ -36,7 +39,7 @@ jobs:
fetch-depth: '0'

- name: Check updates for ArgoCD Apps
uses: ironashram/argocd-apps-action@v0.1.0
uses: ironashram/argocd-apps-action@v1.0.0
with:
target_branch: main
create_pr: true
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ runs:
steps:
- name: Download ArgoCD Apps Action Binary
env:
ACTION_VERSION: "v0.1.0"
ACTION_VERSION: "v1.0.0"
shell: bash
run: |
wget https://github.com/ironashram/argocd-apps-action/releases/download/${ACTION_VERSION}/argocd-apps-action-${ACTION_VERSION}-linux-amd64.tar.gz
Expand Down
104 changes: 103 additions & 1 deletion src/argoaction/parse.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package argoaction

import (
"context"
"strings"

"github.com/ironashram/argocd-apps-action/internal"
"github.com/ironashram/argocd-apps-action/models"
"github.com/ironashram/argocd-apps-action/utils"

"github.com/Masterminds/semver"
"oras.land/oras-go/v2/registry/remote"

"sigs.k8s.io/yaml"
)
Expand All @@ -24,7 +29,7 @@ var readAndParseYAML = func(osi internal.OSInterface, path string) (*models.Appl
return &app, nil
}

var getNewestVersion = func(targetVersion string, entries map[string][]struct {
var parseNativeNewest = func(targetVersion string, entries map[string][]struct {
Version string `yaml:"version"`
}) (*semver.Version, error) {
target, err := semver.NewVersion(targetVersion)
Expand All @@ -50,3 +55,100 @@ var getNewestVersion = func(targetVersion string, entries map[string][]struct {

return newest, nil
}

func getNewestVersionFromNative(url string, chart string, targetRevision string, action internal.ActionInterface) (*semver.Version, error) {
var index models.Index

body, err := utils.GetHTTPResponse(url)
if err != nil {
action.Debugf("failed to get HTTP response: %v\n", err)
return nil, err
}

err = yaml.Unmarshal(body, &index)
if err != nil {
action.Debugf("failed to unmarshal YAML body: %v\n", err)
return nil, err
}

if index.Entries == nil {
action.Debugf("No entries found in index at %s\n", url)
return nil, nil
}

if _, ok := index.Entries[chart]; !ok || len(index.Entries[chart]) == 0 {
action.Debugf("Chart entry %s does not exist or is empty at %s\n", chart, url)
return nil, nil
}

newest, err := parseNativeNewest(targetRevision, index.Entries)
if err != nil {
action.Debugf("Error comparing versions: %v\n", err)
return nil, err
}

return newest, nil
}

var parseOCINewest = func(tags *models.TagsList, targetVersion string, action internal.ActionInterface) (*semver.Version, error) {
target, err := semver.NewVersion(targetVersion)
if err != nil {
action.Debugf("Error parsing target version: %v\n", err)
return nil, err
}

var newest *semver.Version
for _, tag := range tags.Tags {
upstream, err := semver.NewVersion(tag)
if err != nil {
action.Debugf("Error parsing tag version: %v\n", err)
return nil, err
}

if target.LessThan(upstream) {
if newest == nil || newest.LessThan(upstream) {
newest = upstream
}
}
}

return newest, nil
}

func getNewestVersionFromOCI(url string, chart string, targetRevision string, action internal.ActionInterface) (*semver.Version, error) {
tags := &models.TagsList{}

url = strings.TrimSuffix(url, "/")
url = strings.Replace(url, "https://", "", 1)
url = strings.Replace(url, "http://", "", 1)
url = strings.Replace(url, "oci://", "", 1)
url = url + "/" + chart
repo, err := remote.NewRepository(url)
if err != nil {
return nil, err
}

ctx := context.Background()
err = repo.Tags(ctx, "", func(tagsResult []string) error {
for _, tag := range tagsResult {
convertedTag := strings.ReplaceAll(tag, "_", "+")
tags.Tags = append(tags.Tags, convertedTag)
}

return err
})

newest, err := parseOCINewest(tags, targetRevision, action)
if err != nil {
action.Debugf("Error comparing versions: %v\n", err)
return nil, err
}

if err != nil {
action.Debugf("Error getting tags: %v\n", err)
return nil, err
}

return newest, nil

}
2 changes: 1 addition & 1 deletion src/argoaction/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestGetNewestVersion(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result, err := getNewestVersion(tc.targetVersion, tc.entries)
result, err := parseNativeNewest(tc.targetVersion, tc.entries)

assert.Equal(t, tc.expected, result)
assert.Equal(t, tc.expectedErr, err)
Expand Down
37 changes: 7 additions & 30 deletions src/argoaction/process_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (
"github.com/Masterminds/semver"
"github.com/ironashram/argocd-apps-action/internal"
"github.com/ironashram/argocd-apps-action/models"
"github.com/ironashram/argocd-apps-action/utils"

"sigs.k8s.io/yaml"
)

var checkForUpdates = func(gitOps internal.GitOperations, githubClient internal.GitHubClient, cfg *models.Config, action internal.ActionInterface) error {
Expand Down Expand Up @@ -77,7 +74,7 @@ var processFile = func(path string, gitOps internal.GitOperations, githubClient
}

chart := app.Spec.Source.Chart
url := app.Spec.Source.RepoURL + "/index.yaml"
url := app.Spec.Source.RepoURL
targetRevision := app.Spec.Source.TargetRevision

if chart == "" || url == "" || targetRevision == "" {
Expand All @@ -87,33 +84,13 @@ var processFile = func(path string, gitOps internal.GitOperations, githubClient

action.Debugf("Checking %s from %s, current version is %s\n", chart, url, targetRevision)

body, err := utils.GetHTTPResponse(url)
if err != nil {
action.Debugf("failed to get HTTP response: %v\n", err)
return err
}

var index models.Index
err = yaml.Unmarshal(body, &index)
newest, err := getNewestVersionFromNative(url+"/index.yaml", chart, targetRevision, action)
if err != nil {
action.Debugf("failed to unmarshal YAML body: %v\n", err)
return err
}

if index.Entries == nil {
action.Debugf("No entries found in index at %s\n", url)
return nil
}

if _, ok := index.Entries[chart]; !ok || len(index.Entries[chart]) == 0 {
action.Debugf("Chart entry %s does not exist or is empty at %s\n", chart, url)
return nil
}

newest, err := getNewestVersion(targetRevision, index.Entries)
if err != nil {
action.Debugf("Error comparing versions: %v\n", err)
return err
newest, err = getNewestVersionFromOCI(url, chart, targetRevision, action)
if err != nil {
action.Debugf("Error getting newest version: %v\n", err)
return nil
}
}

if newest != nil {
Expand Down
4 changes: 4 additions & 0 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/sethvargo/go-githubactions v1.2.0
github.com/stretchr/testify v1.9.0
golang.org/x/oauth2 v0.18.0
oras.land/oras-go/v2 v2.4.0
sigs.k8s.io/yaml v1.4.0
)

Expand All @@ -28,6 +29,8 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
Expand All @@ -37,6 +40,7 @@ require (
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
Expand Down
6 changes: 6 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -174,5 +178,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
oras.land/oras-go/v2 v2.4.0 h1:i+Wt5oCaMHu99guBD0yuBjdLvX7Lz8ukPbwXdR7uBMs=
oras.land/oras-go/v2 v2.4.0/go.mod h1:osvtg0/ClRq1KkydMAEu/IxFieyjItcsQ4ut4PPF+f8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
5 changes: 5 additions & 0 deletions src/models/tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package models

type TagsList struct {
Tags []string
}

0 comments on commit f9bb31b

Please sign in to comment.