Skip to content

Commit

Permalink
feat: added go script to update github repo vars
Browse files Browse the repository at this point in the history
Signed-off-by: Dipankar Das <[email protected]>

added parallel processing

Signed-off-by: Dipankar Das <[email protected]>

Update scripts/repo-variable-writer.go

Co-authored-by: Ross Fairbanks <[email protected]>
Signed-off-by: Dipankar Das <[email protected]>

updated the url generator

Signed-off-by: Dipankar Das <[email protected]>

improved the unnecessary copy of slice in for-range

Signed-off-by: Dipankar Das <[email protected]>

refactor cmd/http.go

Signed-off-by: Dipankar Das <[email protected]>

moved the package to a new folder

Signed-off-by: Dipankar Das <[email protected]>

refactor variable and function names

Signed-off-by: Dipankar Das <[email protected]>
  • Loading branch information
dipankardas011 committed Jun 17, 2024
1 parent eb0b41d commit b506150
Show file tree
Hide file tree
Showing 14 changed files with 520 additions and 1 deletion.
37 changes: 37 additions & 0 deletions .github/workflows/project-trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Reconciles Project Versions and triggers them

on:
schedule:
- cron: '0 0 * * 0'
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.ref }}
cancel-in-progress: false

jobs:
get-latest-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '^1.22.3'

- name: build the binary
working-directory: cmd/github-project-update-dispatch
run: |
go get -d
go build -v -o ../../proj-trigger .
- name: trigger updated projects
env:
GH_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
LOG_LEVEL: DEBUG # yet to use this
run: |
./proj-trigger -c projects/projects.json
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
infrastructure/equinix-metal/.terraform/
infrastructure/equinix-metal/terraform.tfvars
infrastructure/equinix-metal/.terraform.lock.hcl
infrastructure/equinix-metal/.terraform.lock.hcl
website/public/
website/resources/
website/node_modules/
.idea
22 changes: 22 additions & 0 deletions cmd/github-project-update-dispatch/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"encoding/json"
"flag"
"os"
)

func initProjects() (resp *Projects, err error) {
var locProjectMetaFile string

flag.StringVar(&locProjectMetaFile, "c", "projects/projects.json", "Full path of the metadata file for projects")
flag.Parse()

_b, err := os.ReadFile(locProjectMetaFile)
if err != nil {
return
}

err = json.Unmarshal(_b, &resp)
return
}
65 changes: 65 additions & 0 deletions cmd/github-project-update-dispatch/github_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package main

import (
"fmt"
"net/url"
"os"
"strings"
)

func NewGHRepoVarStorage() (*GithubRepository, error) {
v, ok := os.LookupEnv(EnvGithubPatVarName)
if !ok || len(v) == 0 {
return nil, fmt.Errorf("the environment variable for github pat is missing")
}
return &GithubRepository{githubToken: v}, nil
}

func generateVariableName(projName string) string {
return strings.ToLower(projName + "_version")
}

func gitHubRepoEndpoint(
org, repo string,
operation githubAPIEndpointType,
variableName, workflowFileName string) (result string, err error) {

baseUrl := "https://api.github.com"
urlPath := []string{"repos", org, repo, "actions"}

switch operation {
case GHRepoVariableEndpoint:
urlPath = append(urlPath, "variables", variableName)
case GHWorkflowDispatchEndpoint:
urlPath = append(urlPath, "workflows", workflowFileName, "dispatches")
case GHLatestRelease:
urlPath = append(urlPath, "releases", "latest")
}

result, err = url.JoinPath(baseUrl, urlPath...)
return
}

func (obj *GithubRepository) genURLAndHeaders(
endpointType githubAPIEndpointType,
variableName string, workflowFileName string,
) (*string, map[string]string, error) {

url, err := gitHubRepoEndpoint(
GHRepoOrganizationName,
GHRepoName,
endpointType,
variableName,
workflowFileName,
)
if err != nil {
return nil, nil, err
}

return &url,
map[string]string{
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + obj.githubToken,
"X-GitHub-Api-Version": "2022-11-28",
}, nil
}
125 changes: 125 additions & 0 deletions cmd/github-project-update-dispatch/github_api_repo_vars.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"strings"
"time"
)

func (obj *GithubRepository) UpdateRepoVariable(projName, newVersion string) error {
variableName := generateVariableName(projName)

url, header, err := obj.genURLAndHeaders(GHRepoVariableEndpoint, variableName, "")
if err != nil {
return err
}

newVariableData := struct {
Name string `json:"name"`
Val string `json:"value"`
}{
Name: strings.ToUpper(variableName),
Val: newVersion,
}

var _newVariableData bytes.Buffer

if err := json.NewEncoder(&_newVariableData).Encode(newVariableData); err != nil {
return fmt.Errorf("failed to serialize the body: %v", err)
}

resp, err := NewHTTPClient(
http.MethodPatch,
*url,
time.Minute,
&_newVariableData,
header,
)
if err != nil {
return err
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("status code was not 204, got: %v", resp.StatusCode)
}

return nil
}

func (obj *GithubRepository) ReadRepoVariable(projName string) (*string, error) {
variableName := generateVariableName(projName)
url, header, err := obj.genURLAndHeaders(GHRepoVariableEndpoint, variableName, "")
if err != nil {
return nil, err
}

resp, err := NewHTTPClient(
http.MethodGet,
*url,
time.Minute,
nil,
header,
)
if err != nil {
return nil, err
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code was not 200, got: %v", resp.StatusCode)
}

var variableData struct {
VariableValue string `json:"value"`
}

if err := json.NewDecoder(resp.Body).Decode(&variableData); err != nil {
return nil, fmt.Errorf("failed deserialize response body: %v", err)
}

return &variableData.VariableValue, nil
}

func fetchLatestRelease(org, proj string) (*string, error) {

url, err := gitHubRepoEndpoint(
GHRepoOrganizationName,
GHRepoName,
GHLatestRelease,
"", "",
)
if err != nil {
return nil, err
}

resp, err := NewHTTPClient(
http.MethodGet,
url,
time.Minute, nil, nil)
if err != nil {
return nil, err
}

defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code was not 200, got: %v", resp.StatusCode)
}

var release struct {
TagName string `json:"tag_name"`
}

if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
return nil, fmt.Errorf("failed deserialize response body: %v", err)
}

slog.Info("Latest Release", "Proj", proj, "Org", org, "Ver", release.TagName)

return &release.TagName, nil
}
75 changes: 75 additions & 0 deletions cmd/github-project-update-dispatch/github_api_repo_workflows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"time"
)

func (obj *GithubRepository) DispatchCall(projData Project, version string) error {
projToWorkflowTable := map[string]string{
"falco": "falco.yaml",
}

workflowFileName, found := projToWorkflowTable[projData.Name]
if !found {
return fmt.Errorf("failed to find the workflow file related to project: %s", projData.Name+"/"+projData.Organization)
}

url, header, err := obj.genURLAndHeaders(GHWorkflowDispatchEndpoint, "", workflowFileName)
if err != nil {
return err
}

type WorkflowData struct {
Ref string `json:"ref"`
Inputs struct {
CncfProject string `json:"cncf_project"`
Version string `json:"version"`
CncfProjectSub string `json:"cncf_project_sub"`
} `json:"inputs"`
}

for i := range projData.SubComponents {
workflowData := WorkflowData{}
workflowData.Inputs.CncfProject = projData.Name
workflowData.Ref = "main" // TODO: need to figure it out
workflowData.Inputs.Version = version
workflowData.Inputs.CncfProjectSub = projData.SubComponents[i]

var _newWorkflowData bytes.Buffer

if err := json.NewEncoder(&_newWorkflowData).Encode(workflowData); err != nil {
return fmt.Errorf("failed to serialize the body: %v", err)
}

resp, err := NewHTTPClient(
http.MethodPost,
*url,
time.Minute,
&_newWorkflowData,
header,
)
if err != nil {
return err
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf(
"failed in workflowDispatch, status code was not 204, got: %v",
resp.StatusCode)
}

slog.Info("Successfully workflow_dispatch",
"Proj", projData.Name,
"Org", projData.Organization,
"Ver", version,
"Subcomponent", projData.SubComponents[i])
}

return nil
}
10 changes: 10 additions & 0 deletions cmd/github-project-update-dispatch/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/cncf-tags/green-reviews-tooling/cmd/github-project-update-dispatch

go 1.22.3

require gotest.tools v2.2.0+incompatible

require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
)
6 changes: 6 additions & 0 deletions cmd/github-project-update-dispatch/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
17 changes: 17 additions & 0 deletions cmd/github-project-update-dispatch/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"testing"

"gotest.tools/assert"
)

func TestConstants(t *testing.T) {
assert.Equal(t, EnvGithubPatVarName, "GH_TOKEN")
assert.Equal(t, GHRepoOrganizationName, "cncf-tags")
assert.Equal(t, GHRepoName, "green-reviews-tooling")

assert.Equal(t, GHRepoVariableEndpoint, githubAPIEndpointType(0))
assert.Equal(t, GHWorkflowDispatchEndpoint, githubAPIEndpointType(1))
assert.Equal(t, GHLatestRelease, githubAPIEndpointType(2))
}
Loading

0 comments on commit b506150

Please sign in to comment.