From 402623fd607abc9815c36e55aac5800e233e0b57 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 09:43:19 +1000 Subject: [PATCH 001/115] Adding registry automation --- .github/workflows/registry-updates.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/registry-updates.yaml diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml new file mode 100644 index 00000000..5a9ccbc2 --- /dev/null +++ b/.github/workflows/registry-updates.yaml @@ -0,0 +1,23 @@ +name: Update Hub DB from GH Registry + +on: + push: + branches: + - lyndon/registry-automation # TODO: Remove the branch response + + pull_request: + types: [closed] + +jobs: + upload_to_s3: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: List changed files + id: list_files + run: | + git diff --name-only ${{ github.event.before }} ${{ github.event.after }} > changed_files.txt + From 4c6abfa10b0af22bf341aa79e4f58188fb8e1494 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 09:45:52 +1000 Subject: [PATCH 002/115] check for first commit --- .github/workflows/registry-updates.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 5a9ccbc2..7c6a0326 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -16,8 +16,20 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Check if it's the first commit on branch + id: check_first_commit + run: | + if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then + echo "::set-output name=first_commit::true" + else + echo "::set-output name=first_commit::false" + fi + - name: List changed files id: list_files run: | - git diff --name-only ${{ github.event.before }} ${{ github.event.after }} > changed_files.txt - + if [ "${{ steps.check_first_commit.outputs.first_commit }}" == "true" ]; then + git ls-tree --name-only -r ${{ github.sha }} > changed_files.txt + else + git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt + fi From fd4d8d3146e5a8cfe70ce9c7a769cc7776498ea7 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 09:47:34 +1000 Subject: [PATCH 003/115] different listing logic --- .github/workflows/registry-updates.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 7c6a0326..2b59281c 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -29,7 +29,8 @@ jobs: id: list_files run: | if [ "${{ steps.check_first_commit.outputs.first_commit }}" == "true" ]; then - git ls-tree --name-only -r ${{ github.sha }} > changed_files.txt + git log --pretty=format:'' --name-only --max-parents=0 ${{ github.sha }} > changed_files.txt else git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt fi + From 57c84db3df07d22de1e3d142f50b539bf89fc9fd Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 09:50:33 +1000 Subject: [PATCH 004/115] testing logic for changed files --- .github/workflows/registry-updates.yaml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 2b59281c..753b9ef7 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -16,21 +16,14 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Check if it's the first commit on branch - id: check_first_commit - run: | - if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then - echo "::set-output name=first_commit::true" - else - echo "::set-output name=first_commit::false" - fi - - name: List changed files id: list_files run: | - if [ "${{ steps.check_first_commit.outputs.first_commit }}" == "true" ]; then - git log --pretty=format:'' --name-only --max-parents=0 ${{ github.sha }} > changed_files.txt + if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then + git diff --name-only ${{ github.sha }} > changed_files.txt else git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt fi + cat changed_files.txt + From eb2a54e77a07c956982ac6a83a2833c1189e29e3 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 10:22:50 +1000 Subject: [PATCH 005/115] depth --- .github/workflows/registry-updates.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 753b9ef7..070362af 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -15,6 +15,9 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: List changed files id: list_files From c10217f2f2810911f6f007000ac9d835e393901e Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 11:37:44 +1000 Subject: [PATCH 006/115] pseudocode --- .github/workflows/registry-updates.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 070362af..c7a1983a 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -18,7 +18,6 @@ jobs: with: fetch-depth: 0 - - name: List changed files id: list_files run: | @@ -30,3 +29,11 @@ jobs: cat changed_files.txt + - name: Pseudocode for Next steps + id: next_steps + run: | + echo Download tgz + echo Extract + echo Re-upload tgz + echo Build payload for API + echo PUT to API (gql) From 63be059b5066c44173d2905fce4832d3f4734f1a Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 11:40:34 +1000 Subject: [PATCH 007/115] quotes --- .github/workflows/registry-updates.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index c7a1983a..b74bf1ec 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -32,8 +32,8 @@ jobs: - name: Pseudocode for Next steps id: next_steps run: | - echo Download tgz - echo Extract - echo Re-upload tgz - echo Build payload for API - echo PUT to API (gql) + echo 'Download tgz' + echo 'Extract' + echo 'Re-upload tgz' + echo 'Build payload for API' + echo 'PUT to API (gql)' From 929ca8bdfe029b7edefb49b357042b11327eee3c Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 11:44:32 +1000 Subject: [PATCH 008/115] paths --- .github/workflows/registry-updates.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index b74bf1ec..71e065c0 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -4,9 +4,14 @@ on: push: branches: - lyndon/registry-automation # TODO: Remove the branch response + paths: + - registry/** + pull_request: types: [closed] + paths: + - registry/** jobs: upload_to_s3: From 5c9d22bcd3bc7711c30935965c55f4424f79b509 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 11:45:42 +1000 Subject: [PATCH 009/115] readme update for testing purposes --- registry/sendgrid/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/registry/sendgrid/README.md b/registry/sendgrid/README.md index 97d22e0e..22baedbe 100644 --- a/registry/sendgrid/README.md +++ b/registry/sendgrid/README.md @@ -64,3 +64,4 @@ Include the connector URL in your Hasura V3 project metadata: Please [https://github.com/hasura/ndc-sendgrid/issues/new](submit a Github issue) if you encounter any problems! + From 5d26c80c0f4d590c70d195efbf342ddf415909a6 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 11:54:23 +1000 Subject: [PATCH 010/115] readme update for testing purposes --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 71e065c0..62efb8c8 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -14,7 +14,7 @@ on: - registry/** jobs: - upload_to_s3: + update_registry_db: runs-on: ubuntu-latest steps: From a8341b42a94ec077cc0b02cd7bad041f2e1d64cc Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Tue, 16 Apr 2024 12:22:30 +1000 Subject: [PATCH 011/115] comments --- .github/workflows/registry-updates.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 62efb8c8..d0bc1bba 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,8 +37,12 @@ jobs: - name: Pseudocode for Next steps id: next_steps run: | - echo 'Download tgz' - echo 'Extract' - echo 'Re-upload tgz' - echo 'Build payload for API' - echo 'PUT to API (gql)' + echo 'Detect status - added/modified/removed files' + echo 'for each removed connector, remove from registry db' + echo 'for each added connector, create a stub in the registry db' + echo 'for each modified connector:' + echo ' * Download tgz' + echo ' * Re-upload tgz' + echo ' * Extract' + echo ' * Build payload for API' + echo ' * PUT to API (gql)' From b4cba7d21c2b2f7dde4b321e80558da92cef35a8 Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Mon, 29 Apr 2024 15:02:32 +1000 Subject: [PATCH 012/115] testing registry automation go --- .github/workflows/registry-updates.yaml | 14 +++++++ registry-automation/LICENSE | 0 registry-automation/cmd/root.go | 51 +++++++++++++++++++++++++ registry-automation/go.mod | 9 +++++ registry-automation/go.sum | 10 +++++ registry-automation/main.go | 11 ++++++ 6 files changed, 95 insertions(+) create mode 100644 registry-automation/LICENSE create mode 100644 registry-automation/cmd/root.go create mode 100644 registry-automation/go.mod create mode 100644 registry-automation/go.sum create mode 100644 registry-automation/main.go diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index d0bc1bba..3ac0be96 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -46,3 +46,17 @@ jobs: echo ' * Extract' echo ' * Build payload for API' echo ' * PUT to API (gql)' + + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v4 + with: + go-version: 1.21.x + + - name: Display Go version + run: go version + + - name: Run registry automaion program + run: | + cd registy-automation + go run main.go + diff --git a/registry-automation/LICENSE b/registry-automation/LICENSE new file mode 100644 index 00000000..e69de29b diff --git a/registry-automation/cmd/root.go b/registry-automation/cmd/root.go new file mode 100644 index 00000000..9d76aa22 --- /dev/null +++ b/registry-automation/cmd/root.go @@ -0,0 +1,51 @@ +/* +Copyright © 2024 NAME HERE + +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + + + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "registry-automation", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.registry-automation.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + + diff --git a/registry-automation/go.mod b/registry-automation/go.mod new file mode 100644 index 00000000..c7e9921d --- /dev/null +++ b/registry-automation/go.mod @@ -0,0 +1,9 @@ +module github.com/hasura/ndc-hub/registry-automation + +go 1.21.4 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/registry-automation/go.sum b/registry-automation/go.sum new file mode 100644 index 00000000..d0e8c2c3 --- /dev/null +++ b/registry-automation/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/registry-automation/main.go b/registry-automation/main.go new file mode 100644 index 00000000..8c2d80b2 --- /dev/null +++ b/registry-automation/main.go @@ -0,0 +1,11 @@ +/* +Copyright © 2024 NAME HERE + +*/ +package main + +import "github.com/hasura/ndc-hub/registry-automation/cmd" + +func main() { + cmd.Execute() +} From 7f4c2a646056898370f379bdde7303c061dde09e Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Mon, 29 Apr 2024 15:04:36 +1000 Subject: [PATCH 013/115] fixing type --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 3ac0be96..e286f2a0 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -57,6 +57,6 @@ jobs: - name: Run registry automaion program run: | - cd registy-automation + cd registry-automation go run main.go From 9cb0a80f113cb2fdda285dfc7aa0cc383d1d5e8e Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Mon, 29 Apr 2024 15:08:13 +1000 Subject: [PATCH 014/115] readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8e798367..c617d1ef 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,4 @@ implementation][NDC reference]. [NDC specification]: http://hasura.github.io/ndc-spec/ [NDC reference]: https://github.com/hasura/ndc-spec/tree/main/ndc-reference + From 8b1fade36f6b5559324180fda00ffa2eff2ef99a Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Mon, 29 Apr 2024 15:10:06 +1000 Subject: [PATCH 015/115] sg test change --- registry/sendgrid/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/registry/sendgrid/README.md b/registry/sendgrid/README.md index 22baedbe..97d22e0e 100644 --- a/registry/sendgrid/README.md +++ b/registry/sendgrid/README.md @@ -64,4 +64,3 @@ Include the connector URL in your Hasura V3 project metadata: Please [https://github.com/hasura/ndc-sendgrid/issues/new](submit a Github issue) if you encounter any problems! - From 589ea1e080ae2b00924e2d335ac4937b84ce524c Mon Sep 17 00:00:00 2001 From: Lyndon Maydwell Date: Wed, 1 May 2024 11:15:51 +1000 Subject: [PATCH 016/115] WIP --- .github/workflows/registry-updates.yaml | 7 +- registry-automation/cmd/ci.go | 326 ++++++++++++++++++++++++ registry-automation/cmd/root.go | 18 +- registry-automation/go.mod | 11 +- registry-automation/go.sum | 34 +++ 5 files changed, 374 insertions(+), 22 deletions(-) create mode 100644 registry-automation/cmd/ci.go diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index e286f2a0..7390c565 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -47,16 +47,13 @@ jobs: echo ' * Build payload for API' echo ' * PUT to API (gql)' - - name: Setup Go ${{ matrix.go-version }} + - name: Setup Go uses: actions/setup-go@v4 with: go-version: 1.21.x - - name: Display Go version - run: go version - - name: Run registry automaion program run: | cd registry-automation - go run main.go + go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go new file mode 100644 index 00000000..6b7b21d3 --- /dev/null +++ b/registry-automation/cmd/ci.go @@ -0,0 +1,326 @@ +/* +Copyright © 2024 Hasura +*/ +package cmd + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "math/rand" + "net/http" + "os" + "os/exec" + "path" + "path/filepath" + "time" + + "github.com/machinebox/graphql" + "github.com/spf13/cobra" +) + +// ciCmd represents the ci command +var ciCmd = &cobra.Command{ + Use: "ci", + Short: "Run the CI workflow for hub registry publication", + Run: runCI, +} + +func init() { + rootCmd.AddCommand(ciCmd) + + // Path for the changed files in the PR + var cfpE = os.Getenv(`CHANGED_FILES_PATH`) + ciCmd.PersistentFlags().String("changed-files-path", cfpE, "path to a line-separated list of changed files in the PR") + if cfpE == "" { + ciCmd.MarkPersistentFlagRequired("changed-files-path") + } + + // Location of the registry files + var rfpE = os.Getenv(`CONNECTOR_HUB_DIRECTORY`) + ciCmd.PersistentFlags().String("connector-hub-directory", rfpE, "path to the connector hub checkout directory") + if rfpE == "" { + ciCmd.MarkPersistentFlagRequired("connector-hub-directory") + } + + // TODO: Check + rand.Seed(time.Now().UnixNano()) +} + +func runCI(cmd *cobra.Command, args []string) { + + // For each connector where a change is detected... + + var changed_files = map[string]bool{} + var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() + file, err := os.Open(changed_files_path) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + changed_files[filepath.Dir(scanner.Text())] = true // Just assume we'll treat each connector as if everything has changed. + } + + if err := scanner.Err(); err != nil { + panic(err) + } + + var hub_directory = cmd.PersistentFlags().Lookup("connector-hub-directory").Value.String() + + for k := range changed_files { + respondToChangedConnector(path.Join(hub_directory, k)) + } + +} + +func respondToChangedConnector(changed_connector_path string) { + // Detect status - added/modified/removed files + // for each removed connector, remove from registry db + // for each added connector, create a stub in the registry db + // for each modified connector: + // * Download tgz + // * Re-upload tgz + // * Extract + // * Build payload for API + // * PUT to API (gql) + + const logo_file = "logo.png" + const metadata_file = "metadata.json" + const readme_file = "README.md" + + var logo_path = path.Join(changed_connector_path, logo_file) + var metadata_path = path.Join(changed_connector_path, metadata_file) + var readme_path = path.Join(changed_connector_path, readme_file) + + fmt.Println(changed_connector_path) + fmt.Println(logo_path) + fmt.Println(metadata_path) + fmt.Println(readme_path) + + // Read the metadata + var metadata_info = readJSONFile(metadata_path) // Read metadata file + + // Fetch, parse, and reupload the TGZ + tgz_url := getStringFromPath([]string{"foo", "bar", "baz"}, metadata_info) // TODO // Get the url for the TGZ + tgz_path := getTempFilePath("/tmp") + downloadFile(tgz_url, tgz_path, map[string]string{}) // TODO: Auth headers + extracted_tgz_path := "path/to/extract/directory" // TODO + err := extractTarGz(tgz_path, extracted_tgz_path) + if err != nil { + fmt.Println("Error:", err) + return + } + + var tgz_info = readJSONFile(path.Join(extracted_tgz_path, "metadata.json")) // TODO: Check + var tgz_new_url = "https://todo.com" + uploadFile(tgz_path, tgz_new_url, map[string]string{}) + + // Build payload for registry upsert + // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? + var registry_payload = buildRegistryPayload(metadata_info, tgz_info, tgz_new_url) + + // Upsert + updateRegistryGQL(registry_payload) +} + +func buildRegistryPayload(metadata_info map[string]interface{}, tgz_info map[string]interface{}, tgz_url string) map[string]interface{} { + return map[string]interface{}{} // TODO +} + +func updateRegistryGQL(payload map[string]interface{}) { + // Example: https://stackoverflow.com/questions/66931228/http-requests-golang-with-graphql + + client := graphql.NewClient("https://") + ctx := context.Background() + + req := graphql.NewRequest(` + query ($key: String!) { + items (id:$key) { + field1 + field2 + field3 + } + } + `) + + req.Var("key", "value") + + var respData map[string]interface{} + + if err := client.Run(ctx, req, &respData); err != nil { + panic(err) + } + +} + +// Helper functions + +func downloadFile(sourceURL, destination string, headers map[string]string) error { + // Create a new HTTP client + client := &http.Client{} + + // Create a new GET request + req, err := http.NewRequest("GET", sourceURL, nil) + if err != nil { + return fmt.Errorf("error creating request: %v", err) + } + + // Add headers + for key, value := range headers { + req.Header.Set(key, value) + } + + // Send the request + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error sending request: %v", err) + } + defer resp.Body.Close() + + // Create the destination file + outFile, err := os.Create(destination) + if err != nil { + return fmt.Errorf("error creating destination file: %v", err) + } + defer outFile.Close() + + // Write the response body to the file + _, err = io.Copy(outFile, resp.Body) + if err != nil { + return fmt.Errorf("error writing to file: %v", err) + } + + return nil +} + +func readJSONFile(location string) map[string]interface{} { + // Read the file + fileBytes, err := ioutil.ReadFile(location) + if err != nil { + panic(fmt.Errorf("error reading file: %v", err)) + } + + // Parse JSON + var data map[string]interface{} + if err := json.Unmarshal(fileBytes, &data); err != nil { + panic(fmt.Errorf("error parsing JSON: %v", err)) + } + + return data +} + +func getStringFromPath(path []string, m map[string]interface{}) string { + var current interface{} = m + + // Traverse the path + for _, key := range path { + // Check if current element is a map + if currentMap, ok := current.(map[string]interface{}); ok { + // Check if key exists in the current map + if val, found := currentMap[key]; found { + current = val + } else { + return "" // Key not found, return empty string + } + } else { + return "" // Current element is not a map, return empty string + } + } + + // Check if the final value is a string + if value, ok := current.(string); ok { + return value + } + + return "" // Final value is not a string, return empty string +} + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +// generateRandomFileName generates a random file name based on the current time. +func generateRandomFileName() string { + b := make([]byte, 10) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} + +// getTempFilePath generates a random file name in the specified directory. +func getTempFilePath(directory string) string { + // Ensure the directory exists + err := os.MkdirAll(directory, os.ModePerm) + if err != nil { + panic(fmt.Errorf("error creating directory: %v", err)) + } + + // Generate a random file name + fileName := generateRandomFileName() + + // Create the file path + filePath := filepath.Join(directory, fileName) + + // Check if the file already exists + _, err = os.Stat(filePath) + if !os.IsNotExist(err) { + // File exists, generate a new name + fileName = generateRandomFileName() + filePath = filepath.Join(directory, fileName) + } + + return filePath +} + +func uploadFile(sourceFilePath, destinationURL string, headers map[string]string) { + // Open the file + file, err := os.Open(sourceFilePath) + if err != nil { + panic(fmt.Errorf("error opening file: %v", err)) + } + defer file.Close() + + // Create a new HTTP request with a POST method + req, err := http.NewRequest("POST", destinationURL, file) + if err != nil { + panic(fmt.Errorf("error creating request: %v", err)) + } + + // Add headers to the request + for key, value := range headers { + req.Header.Set(key, value) + } + + // Create an HTTP client + client := &http.Client{} + + // Send the request + resp, err := client.Do(req) + if err != nil { + panic(fmt.Errorf("error sending request: %v", err)) + } + defer resp.Body.Close() + + // Check the response status code + if resp.StatusCode != http.StatusOK { + panic(fmt.Errorf("upload failed with status code: %d", resp.StatusCode)) + } +} + +func extractTarGz(src, dest string) error { + // Run the tar command with the -xzf options + cmd := exec.Command("tar", "-xzf", src, "-C", dest) + + // Execute the command + if err := cmd.Run(); err != nil { + return fmt.Errorf("error extracting tar.gz file: %v", err) + } + + return nil +} diff --git a/registry-automation/cmd/root.go b/registry-automation/cmd/root.go index 9d76aa22..d3a23760 100644 --- a/registry-automation/cmd/root.go +++ b/registry-automation/cmd/root.go @@ -1,6 +1,5 @@ /* -Copyright © 2024 NAME HERE - +Copyright © 2024 Hasura */ package cmd @@ -10,21 +9,10 @@ import ( "github.com/spf13/cobra" ) - - // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "registry-automation", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, + Short: "Commands associated with automation for the hub registry", } // Execute adds all child commands to the root command and sets flags appropriately. @@ -47,5 +35,3 @@ func init() { // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } - - diff --git a/registry-automation/go.mod b/registry-automation/go.mod index c7e9921d..b471be51 100644 --- a/registry-automation/go.mod +++ b/registry-automation/go.mod @@ -2,8 +2,17 @@ module github.com/hasura/ndc-hub/registry-automation go 1.21.4 +require github.com/spf13/cobra v1.8.0 + require ( + github.com/andybalholm/brotli v1.0.1 // indirect + github.com/golang/snappy v0.0.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect + github.com/klauspost/pgzip v1.2.5 // indirect + github.com/machinebox/graphql v0.2.2 // indirect + github.com/nwaples/rardecode v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/ulikunitz/xz v0.5.9 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect ) diff --git a/registry-automation/go.sum b/registry-automation/go.sum index d0e8c2c3..eb4b546b 100644 --- a/registry-automation/go.sum +++ b/registry-automation/go.sum @@ -1,10 +1,44 @@ +github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.4 h1:kz40R/YWls3iqT9zX9AHN3WoVsrAWVyui5sxuLqiXqU= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo= +github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= +github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= +github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= +github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= +github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= +github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From b737f207a4cdf558b0c81893fffe785033644007 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 10 Jul 2024 17:00:14 +0530 Subject: [PATCH 017/115] use tj-actions/changed-files to get the list of changed files --- .github/workflows/registry-updates.yaml | 110 +++++++++++++++++------- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 7390c565..ce1fd133 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -9,7 +9,7 @@ on: pull_request: - types: [closed] + types: [opened, synchronize, reopened, closed] paths: - registry/** @@ -23,37 +23,87 @@ jobs: with: fetch-depth: 0 - - name: List changed files - id: list_files - run: | - if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then - git diff --name-only ${{ github.sha }} > changed_files.txt - else - git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt - fi + - name: Get changed files and write the outputs to a JSON file + id: changed-files-write-output-files-json + uses: tj-actions/changed-files@v44 + with: + write_output_files: true + json: true + files: | + registry/** - cat changed_files.txt - - name: Pseudocode for Next steps - id: next_steps + - name: Verify the contents of the .github/outputs/added_files.json file run: | - echo 'Detect status - added/modified/removed files' - echo 'for each removed connector, remove from registry db' - echo 'for each added connector, create a stub in the registry db' - echo 'for each modified connector:' - echo ' * Download tgz' - echo ' * Re-upload tgz' - echo ' * Extract' - echo ' * Build payload for API' - echo ' * PUT to API (gql)' - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.x + cat "**** OUTPUT ******************" + cat .github/outputs/added_files.json - - name: Run registry automaion program - run: | - cd registry-automation - go run main.go ci + # - name: Get the list of changed files + # id: changed-files + # run: | + # echo "Fetching list of changed files..." + # CHANGED_FILES=$(jq -r '.pull_request | .head.sha as $head | .base.sha as $base | [.head.repo.full_name, $head, $base] | @sh' <<< "$GITHUB_EVENT") + # IFS=' ' read -r REPO HEAD_SHA BASE_SHA <<< "$CHANGED_FILES" + # git diff --name-only $BASE_SHA $HEAD_SHA > changed_files.txt + # cat changed_files.txt + # env: + # GITHUB_EVENT: ${{ toJson(github.event) }} + + # - name: Display changed files + # run: cat changed_files.txt + + # - name: Get the actual changes in the files + # run: | + # echo "Fetching actual changes..." + # while read -r FILE; do + # echo "Changes in $FILE:" + # git diff $BASE_SHA $HEAD_SHA -- "$FILE" + # done < changed_files.txt + # env: + # BASE_SHA: ${{ steps.changed-files.outputs.base }} + # HEAD_SHA: ${{ steps.changed-files.outputs.head }} + + # - name: List changed files + # id: list_files + # run: | + # if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then + # git diff --name-only ${{ github.sha }} > changed_files.txt + # else + # git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt + # fi + + # cat changed_files.txt + + # - name: Get the actual changes in the files + # run: | + # echo "Fetching actual changes ..." + # while read -r FILE; do + # echo "Changes in $FILE: " + # git diff $BASE_SHA $HEAD_SHA -- "$FILE" + # done < changed_files.txt + # env: + # BASE_SHA: ${{ steps.list_files.outputs.base }} + # HEAD_SHA: ${{ steps.list_files.outputs.head }} + + # - name: Pseudocode for Next steps + # id: next_steps + # run: | + # echo 'Detect status - added/modified/removed files' + # echo 'for each removed connector, remove from registry db' + # echo 'for each added connector, create a stub in the registry db' + # echo 'for each modified connector:' + # echo ' * Download tgz' + # echo ' * Re-upload tgz' + # echo ' * Extract' + # echo ' * Build payload for API' + # echo ' * PUT to API (gql)' + + # - name: Setup Go + # uses: actions/setup-go@v4 + # with: + # go-version: 1.21.x + # - name: Run registry automaion program + # run: | + # cd registry-automation + # go run main.go ci From 9474d89b3b928c27fd875f6924490511c44003b9 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 12:33:33 +0530 Subject: [PATCH 018/115] add a mock test package for azure cosmos --- registry/azure-cosmos/metadata.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/registry/azure-cosmos/metadata.json b/registry/azure-cosmos/metadata.json index 46b72c45..f78f8c5e 100644 --- a/registry/azure-cosmos/metadata.json +++ b/registry/azure-cosmos/metadata.json @@ -15,6 +15,17 @@ "is_verified": true, "is_hosted_by_hasura": true, "packages": [ + { + "version": "test", + "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/test/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" + }, + "source": { + "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" + } + }, { "version": "0.1.3", "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.3/connector-definition.tgz", From 82ad61ae58ab4489200c34dbd19e10c51d279e31 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 12:54:17 +0530 Subject: [PATCH 019/115] add a sample test registry automation --- registry/registry-automation-test/README.md | 171 ++++++++++++++++++ registry/registry-automation-test/logo.png | Bin 0 -> 38264 bytes .../registry-automation-test/metadata.json | 68 +++++++ 3 files changed, 239 insertions(+) create mode 100644 registry/registry-automation-test/README.md create mode 100644 registry/registry-automation-test/logo.png create mode 100644 registry/registry-automation-test/metadata.json diff --git a/registry/registry-automation-test/README.md b/registry/registry-automation-test/README.md new file mode 100644 index 00000000..70df2d45 --- /dev/null +++ b/registry/registry-automation-test/README.md @@ -0,0 +1,171 @@ +# Azure Cosmos DB for NoSQL Connector + +[![Docs](https://img.shields.io/badge/docs-v3.x-brightgreen.svg?style=flat)](https://hasura.io/docs/3.0/latest/connectors/azure-cosmos/) +[![ndc-hub](https://img.shields.io/badge/ndc--hub-azure--cosmos-blue.svg?style=flat)](https://hasura.io/connectors/azure-cosmos) +[![License](https://img.shields.io/badge/license-Apache--2.0-purple.svg?style=flat)](LICENSE.txt) +[![Status](https://img.shields.io/badge/status-alpha-yellow.svg?style=flat)](./readme.md) + +With this connector, Hasura allows you to instantly create a real-time GraphQL API on top of your data models in Azure Cosmos DB for NoSQL Database containers. This connector supports Azure Cosmos DB for NoSQL's functionalities listed in the table below, allowing for efficient and scalable data operations. + +This connector is built using the [TypeScript Data Connector SDK](https://github.com/hasura/ndc-sdk-typescript) and implements the [Data Connector Spec](https://github.com/hasura/ndc-spec). + +- [Connector information in the Hasura Hub](https://hasura.io/connectors/azure-cosmos) +- [Hasura V3 Documentation](https://hasura.io/docs/3.0) + +## Features + +Below, you'll find a matrix of all supported features for the Azure Cosmos DB for NoSQL connector: + +| Feature | Supported | Notes | +| ------------------------------- | --------- | ----- | +| Native Queries + Logical Models | ✅ | | +| Simple Object Query | ✅ | | +| Filter / Search | ✅ | | +| Simple Aggregation | ✅ | | +| Sort | ✅ | | +| Paginate | ✅ | | +| Nested Objects | ✅ | | +| Nested Arrays | ✅ | | +| Nested Filtering | ❌ | | +| Nested Sorting | ❌ | | +| Nested Relationships | ❌ | | + + +## Before you get Started + +1. Create a [Hasura Cloud account](https://console.hasura.io) +2. Install the [CLI](https://hasura.io/docs/3.0/cli/installation/) +3. Install the [Hasura VS Code extension](https://marketplace.visualstudio.com/items?itemName=HasuraHQ.hasura) +4. [Create a supergraph](https://hasura.io/docs/3.0/getting-started/init-supergraph) +5. [Create a subgraph](https://hasura.io/docs/3.0/getting-started/init-subgraph) + +## Using the connector + +To use the Azure Cosmos DB for NoSQL connector, follow these steps in a Hasura project: +(Note: for more information on the following steps, please refer to the Postgres connector documentation [here](https://hasura.io/docs/3.0/getting-started/connect-to-data/connect-a-source)) + + +### 1. Init the connector +(Note: here and following we are naming the subgraph "my_subgraph" and the connector "my_azure_cosmos") + + ```bash + ddn connector init my_azure_cosmos --subgraph my_subgraph --hub-connector hasura/azure-cosmos + ``` + +### 2. Add your Azure Cosmos DB for NoSQL credentials + +Add you credentials to `my_subgraph/connector/my_azure_cosmos/.env.local` + +```env title="my_subgraph/connector/my_azure_cosmos/.env.local" +OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://local.hasura.dev:4317 +OTEL_SERVICE_NAME=my_subgraph_my_azure_cosmos +AZURE_COSMOS_DB_NAME= +AZURE_COSMOS_ENDPOINT= +AZURE_COSMOS_KEY= +AZURE_COSMOS_NO_OF_ROWS_TO_FETCH= +``` + +Note: `AZURE_COSMOS_CONNECTOR_NO_OF_ROWS_TO_FETCH` is an optional field, with 100 rows to be fetched by default. + +### 3. Introspect your indices + +From the root of your project run: + +```bash title="From the root of your project run:" +ddn connector introspect --connector my_subgraph/connector/my_azure_cosmos/connector.yaml +``` + +If you look at the `config.json` for your connector, you'll see metadata describing your Azure Cosmos DB for NoSQL mappings. + +### 4. Create the Hasura metadata + +Run the following from the root of your project: + +```bash title="Run the following from the root of your project:" +ddn connector-link add my_azure_cosmos --subgraph my_subgraph +``` + +The generated file has two environment variables — one for reads and one for writes — that you'll need to add to your +subgraph's `.env.my_subgraph` file. Each key is prefixed by the subgraph name, an underscore, and the name of the +connector. Ensure the port value matches what is published in your connector's docker compose file. + +```env title="my_subgraph/.env.my_subgraph" +MY_SUBGRAPH_MY_AZURE_COSMOS_READ_URL=http://local.hasura.dev:8081 +MY_SUBGRAPH_MY_AZURE_COSMOS_WRITE_URL=http://local.hasura.dev:8081 +``` + +### 5. Start the connector's docker compose + +Let's start our connector's docker compose file. Run the following from the connector's subdirectory inside a subgraph: + +```bash title="Run the following from the connector's subdirectory inside a subgraph:" +docker compose -f docker-compose.my_azure_cosmos.yaml up +``` + +This starts our Azure Cosmos DB for NoSQL connector on the specified port. We can navigate to the following address, with the port +modified, to see the schema of our Azure Cosmos DB for NoSQL source: + +```bash +http://localhost:8081/schema +``` + +### 6. Include the connector in your docker compose + +Kill the connector by pressing `CTRL+C` in the terminal tab in which the connector is running. + +Then, add the following inclusion to the docker compose `docker-compose.hasura.yaml` in your project's root directory, taking care to modify the +subgraph's name. + +```yaml title="docker-compose.hasura.yaml" +include: + - path: my_subgraph/connector/my_azure_cosmos/docker-compose.my_azure_cosmos.yaml +``` + +Now, whenever running the following, you'll bring up the GraphQL engine, observability tools, and any connectors you've +included. From the root of your project, run: + +```bash title="From the root of your project, run:" +HASURA_DDN_PAT=$(ddn auth print-pat) docker compose -f docker-compose.hasura.yaml watch +``` + +### 7. Update the new DataConnectorLink object + +Finally, now that our `DataConnectorLink` has the correct environment variables configured for the Azure Cosmos DB for NoSQL connector, +we can run the update command to have the CLI look at the configuration JSON and transform it to reflect our database's +schema in `hml` format. In a new terminal tab from the root of your project, run: + +```bash title="From the root of your project, run:" +ddn connector-link update my_azure_cosmos --subgraph my_subgraph +``` + +After this command runs, you can open your `my_subgraph/metadata/my_azure_cosmos.hml` file and see your metadata completely +scaffolded out for you 🎉 + +### 8. Import _all_ your indices + +You can do this in one convenience command. From the root of your project, run: + +```bash title="From the root of your project, run:" +ddn connector-link update my_azure_cosmos --subgraph my_subgraph --add-all-resources +``` + +### 9. Create a supergraph build + +Pass the `local` subcommand along with specifying the output directory as `./engine` in the root of the project. This +directory is used by the docker-compose file to serve the engine locally. From the root of your project, run: + +```bash title="From the root of your project, run:" +ddn supergraph build local --output-dir ./engine +``` + +You can now navigate to +[`https://console.hasura.io/local/graphql?url=http://localhost:3000`](https://console.hasura.io/local/graphql?url=http://localhost:3000) +and interact with your API using the Hasura Console. + +## Contributing + +We're happy to receive any contributions from the community. Please refer to our [development guide](https://github.com/hasura/ndc-azure-cosmos-connector/blob/main/docs/development.md). + +## License + +The Hasura Azure Cosmos DB for NoSQL connector is available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/registry/registry-automation-test/logo.png b/registry/registry-automation-test/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..001667d864a9bb07f7389f2534dec3a2514e86eb GIT binary patch literal 38264 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 literal 0 HcmV?d00001 diff --git a/registry/registry-automation-test/metadata.json b/registry/registry-automation-test/metadata.json new file mode 100644 index 00000000..f78f8c5e --- /dev/null +++ b/registry/registry-automation-test/metadata.json @@ -0,0 +1,68 @@ +{ + "overview": { + "namespace": "hasura", + "description": "Connect to a Azure Cosmos DB for NoSQL and expose it to Hasura v3 Project", + "title": "Azure Cosmos DB for NoSQL Connector", + "logo": "logo.png", + "tags": [], + "latest_version": "v0.1.3" + }, + "author": { + "support_email": "support@hasura.io", + "homepage": "https://hasura.io", + "name": "Hasura" + }, + "is_verified": true, + "is_hosted_by_hasura": true, + "packages": [ + { + "version": "test", + "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/test/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" + }, + "source": { + "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" + } + }, + { + "version": "0.1.3", + "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.3/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" + }, + "source": { + "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" + } + }, + { + "version": "0.1.2", + "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.2/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "09ce246a9039d2aaf799a7e0402b243fb3763ba802535348a9fee243de1bf1b7" + }, + "source": { + "hash": "f67b2f80d64175a055a9489d4e59f30d5d3870a0" + } + } + ], + "source_code": { + "is_open_source": true, + "repository": "https://github.com/hasura/ndc-azure-cosmos-connector/", + "version": [ + { + "tag": "v0.1.3", + "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905", + "is_verified": true + }, + { + "tag": "v0.1.2", + "hash": "f67b2f80d64175a055a9489d4e59f30d5d3870a0", + "is_verified": true + } + ] + } + } From a14b41979cdd769d2f2687a15a64761cb1b33cfa Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 12:57:57 +0530 Subject: [PATCH 020/115] print changed files using env vars --- .github/workflows/registry-updates.yaml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index ce1fd133..20211802 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -20,23 +20,19 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Get changed files and write the outputs to a JSON file - id: changed-files-write-output-files-json + - name: Get all changed files and use a comma separator in the output + id: changed-files uses: tj-actions/changed-files@v44 with: - write_output_files: true json: true - files: | - registry/** - - - name: Verify the contents of the .github/outputs/added_files.json file + - name: Print all the files that have been modified + env: + CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} run: | - cat "**** OUTPUT ******************" - cat .github/outputs/added_files.json + echo "**************" + echo "added files are $CHANGED_FILES" # - name: Get the list of changed files # id: changed-files From b2cc717ba488c78c5db9876072f040e02f0d0bb9 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:01:41 +0530 Subject: [PATCH 021/115] add fetch depth 1 --- .github/workflows/registry-updates.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 20211802..e9ef8247 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -20,6 +20,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + with: + fetch_depth: 1 - name: Get all changed files and use a comma separator in the output id: changed-files From 89ba3550c325e7553584ad68235d404d7bed03a9 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:07:00 +0530 Subject: [PATCH 022/115] cat the added files --- .github/workflows/registry-updates.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index e9ef8247..673b3664 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -28,13 +28,13 @@ jobs: uses: tj-actions/changed-files@v44 with: json: true + write_output_files: true - - name: Print all the files that have been modified - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + + - name: Print out all the changed files run: | echo "**************" - echo "added files are $CHANGED_FILES" + cat .github/outputs/added_files.json # - name: Get the list of changed files # id: changed-files From 55ae384ca5f46e630537889d50dbd6a8703dfd2b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:10:38 +0530 Subject: [PATCH 023/115] Just get registry files --- .github/workflows/registry-updates.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 673b3664..45070342 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -29,6 +29,8 @@ jobs: with: json: true write_output_files: true + files: | + registry/** - name: Print out all the changed files From 71535a1714667f1bd82aa3c85e00055dc718575b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:12:09 +0530 Subject: [PATCH 024/115] registry /* --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 45070342..384b7c9f 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -30,7 +30,7 @@ jobs: json: true write_output_files: true files: | - registry/** + registry/* - name: Print out all the changed files From 82efb8c75822ce8d59670c1f5a16b897f3893a38 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:16:00 +0530 Subject: [PATCH 025/115] print all changed files --- .github/workflows/registry-updates.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 384b7c9f..67e33dfe 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -28,15 +28,16 @@ jobs: uses: tj-actions/changed-files@v44 with: json: true - write_output_files: true files: | - registry/* + registry/** - name: Print out all the changed files + env: + ALL_CHANGED_FILES: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - cat .github/outputs/added_files.json + echo "$ALL_CHANGED_FILES" | jq . # - name: Get the list of changed files # id: changed-files From 15933ca5df44b8e4c9620dbe12112be064737164 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:17:23 +0530 Subject: [PATCH 026/115] remove toJson --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 67e33dfe..d35c57ef 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -34,7 +34,7 @@ jobs: - name: Print out all the changed files env: - ALL_CHANGED_FILES: ${{ toJson(steps.changed-files.outputs) }} + ALL_CHANGED_FILES: ${{ steps.changed-files.outputs }} run: | echo "**************" echo "$ALL_CHANGED_FILES" | jq . From d92c5a7cb1d0651ff20f87d3f7eee3c0b2277d58 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:18:53 +0530 Subject: [PATCH 027/115] remove toJson --- .github/workflows/registry-updates.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index d35c57ef..30eb0912 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -34,10 +34,10 @@ jobs: - name: Print out all the changed files env: - ALL_CHANGED_FILES: ${{ steps.changed-files.outputs }} + ALL_CHANGED_FILES: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "$ALL_CHANGED_FILES" | jq . + echo "$ALL_CHANGED_FILES" # - name: Get the list of changed files # id: changed-files From 55ae345d8b2d10223d280646536d0b2b12fce4b0 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 13:23:04 +0530 Subject: [PATCH 028/115] print out added and modified files separately --- .github/workflows/registry-updates.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 30eb0912..747baaa5 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -34,10 +34,12 @@ jobs: - name: Print out all the changed files env: - ALL_CHANGED_FILES: ${{ toJson(steps.changed-files.outputs) }} + ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} + MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} run: | echo "**************" - echo "$ALL_CHANGED_FILES" + echo "added files are $ADDED_FILES" + echo "modified files are $MODIFIED_FILES" # - name: Get the list of changed files # id: changed-files From 1c370ab77c8b6218e3a3f9ef7460eb794abad4ff Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:01:54 +0530 Subject: [PATCH 029/115] remove `json: true` --- .github/workflows/registry-updates.yaml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 747baaa5..75519b92 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -27,7 +27,6 @@ jobs: id: changed-files uses: tj-actions/changed-files@v44 with: - json: true files: | registry/** @@ -41,30 +40,6 @@ jobs: echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" - # - name: Get the list of changed files - # id: changed-files - # run: | - # echo "Fetching list of changed files..." - # CHANGED_FILES=$(jq -r '.pull_request | .head.sha as $head | .base.sha as $base | [.head.repo.full_name, $head, $base] | @sh' <<< "$GITHUB_EVENT") - # IFS=' ' read -r REPO HEAD_SHA BASE_SHA <<< "$CHANGED_FILES" - # git diff --name-only $BASE_SHA $HEAD_SHA > changed_files.txt - # cat changed_files.txt - # env: - # GITHUB_EVENT: ${{ toJson(github.event) }} - - # - name: Display changed files - # run: cat changed_files.txt - - # - name: Get the actual changes in the files - # run: | - # echo "Fetching actual changes..." - # while read -r FILE; do - # echo "Changes in $FILE:" - # git diff $BASE_SHA $HEAD_SHA -- "$FILE" - # done < changed_files.txt - # env: - # BASE_SHA: ${{ steps.changed-files.outputs.base }} - # HEAD_SHA: ${{ steps.changed-files.outputs.head }} # - name: List changed files # id: list_files From fbd3c1b5459c3342f68984909180119a32913ec1 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:03:18 +0530 Subject: [PATCH 030/115] add \n separator --- .github/workflows/registry-updates.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 75519b92..4efb99e6 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -27,6 +27,7 @@ jobs: id: changed-files uses: tj-actions/changed-files@v44 with: + separator: "\n" files: | registry/** From cf5161cc42dbb1bb7d877f39c930d6ed7a5fd836 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:06:22 +0530 Subject: [PATCH 031/115] print out DELETED files --- .github/workflows/registry-updates.yaml | 4 +++- registry/azure-cosmos/logo.png | Bin 38264 -> 0 bytes 2 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 registry/azure-cosmos/logo.png diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 4efb99e6..723ed0e8 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -36,10 +36,12 @@ jobs: env: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} + DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} run: | echo "**************" - echo "added files are $ADDED_FILES" + echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" + echo "modified files are $DELETED_FILES" # - name: List changed files diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png deleted file mode 100644 index 001667d864a9bb07f7389f2534dec3a2514e86eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38264 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 From ed2088295b8c0aeffd30a7c76e241b9f1f85faed Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:08:23 +0530 Subject: [PATCH 032/115] use deleted files --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 723ed0e8..1abf1377 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -41,7 +41,7 @@ jobs: echo "**************" echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" - echo "modified files are $DELETED_FILES" + echo "deleted files are $DELETED_FILES" # - name: List changed files From 8f98cd2dee721168fdf9d627804aa91a880b1e88 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:10:13 +0530 Subject: [PATCH 033/115] add azure-cosmos logo back --- registry/azure-cosmos/logo.png | Bin 0 -> 38264 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 registry/azure-cosmos/logo.png diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..001667d864a9bb07f7389f2534dec3a2514e86eb GIT binary patch literal 38264 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 literal 0 HcmV?d00001 From 77d51d1c8b260cd7ae0ad5b78a6b185ddea1743c Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:10:52 +0530 Subject: [PATCH 034/115] delete azure cosmos logo --- registry/azure-cosmos/logo.png | Bin 38264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 registry/azure-cosmos/logo.png diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png deleted file mode 100644 index 001667d864a9bb07f7389f2534dec3a2514e86eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38264 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 From 6666be3e6359307629c3a4b5d82f9f11b7629c5d Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:11:53 +0530 Subject: [PATCH 035/115] delete registry-automation-test logo.png --- registry/registry-automation-test/logo.png | Bin 38264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 registry/registry-automation-test/logo.png diff --git a/registry/registry-automation-test/logo.png b/registry/registry-automation-test/logo.png deleted file mode 100644 index 001667d864a9bb07f7389f2534dec3a2514e86eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38264 zcmb?iWmjBHkjCAe;O?Ff+}+*X2@>2TxVw9BcXt?MaDvMK!3pjVB(TG~XaB)|m~+p$ zx2L=Msj4pRC>14XRHRQx5D*ZkvN95C5D-x85D<_?2yoyxIY%_B;0L0UjIJvL1Tyx= z4-z6fmjD8S970w?RKqLxtk=88K-#_*cf> z9Dzsw4Wjwu0g+#vvhZ*s!Z@M{#U`B{#X}n z;;bpsnS(#AXZAnr)HcxuT-_)EVvB;R+9s)#&HN-OAE-XV7X)3q!D4dD&x=LN(Kj>> z{kLR!!UrYZ9yS%IFwsarPe$VZ$R-1?$Tw4MG{zjd_bD^a?Z)w5oAQH1U=%)kete3Y zs{ng>ejLIi9*e1BgxC$3AmxG`*x2%+3J5y!UB(_uE-UNp;rP(~4;=f3z+g+SbwyBw z;>Ro-S15($BC)Oc)IZ;wd`yY`-{&kY0A^k`IvEg{No*&n4vEmMLV6Mk%O$O9FsL&0>A+O7^M>}wm%|1ykay7Wdc-_~U?q>BdE zg==CAr%G5zb-UzLYfPL4ed^=y{!z07Uh6ZEi{h-9%`Ae|0%A_SZgZ94l*(CY@Z$2o4h2MB#oN}TsG z38B8H?YB*XEyP#t)CVi+RC{tiH&9m3Tnxbn>z=Qeu6^_XOc#sxR*7FDue5({Y?kQ< z0sakillf)Z1-e8lxK$Z`h?^TeST+@M6n#IZknAeLyb6-wut7joV+i&6A=Y1K{WqJ> z6(PZF%W9W&g!GY98p37fg_-+;m>0_59DnJ*nqv?U;6U>hS^8p6!Q>(@rlNW`EioBZLYJyAeAsd`v=;3^Lq* z+WzXeLubGk<_P>x)|MBzND|70>8%a7emKE4$hABks-{U!8PW&Vn!kc(zBKiNIR4Y? z)(=>sYr8*x@nL35{eh00y95A1x1i$2BW&o5-R^wf0x0`)kAg9_LIW><0+v@29hBJx zobT8NVkQCY=GiDnjDS6Q@SRWvkTYAZ@B#5W2Wz ziWCpZh7R*hoPghDqjbj#Tkz2_z7nV!`c^y~z!4r}Yh^o7qmo%FX@$woPtRFRj}pU< zOn^xM0jDueQSu{kV&h98c_RF%CNByx6dKeE4jTDc`GEST2IElw{WamFT|%_0npq2< zt~h*lX%@!vbDFQh76_RI!T6O8n%fqsxC18bRQ7ZSu~QU5@IN*O6!#{kgRbse&51i~ zQO(KM57-5zi9la?&RHyuaK~+v>=}n_ASQ9OpsJ}&cqi0CRZY?X7?wf7$;nM3st9FV zgM9*bdJsre`5jFO3plrF`D3-0pI8v1(H-fXosvmg!7B?~u6 zXb(VC^+Ih&DYd{Z2?RuXy&Dr0a9-d|zVwL9&l*<+nNAyMv~5l@j^D6`x(2PK8Xc*~ z_y3wl;w4{*$q;!&V#En@Hc?1L#Jv#_mCMTUM_M_!ecf|s+AqA2IyrXGVD-uj+9hb7 zXTZZ~(l9MW&{tWesKK>NN8%02WjyYCr%;{PAclG<-Y^QiEZR^A@+I@hrF(U%E!Vtz zgdf2+2levhFc)B&5=HlaRmo8?h5GyYR_;Bkm~$Y~4z?~J=&i?WNVJ3l8F)gqV`4Q0 zienr#1yvOJ%l@A#A|V2NNzx$#Pf=6~I6%TN(w*=99t3syswtIU&*!GrDbkayToH0G z^0lWc2B1tDE+r?ZRlUSQjUm6<1?9cabu9h98R9aGuR@=j8)%ETU!wFYEmxo6iV*ic zC|zMq(eEOWk?*wk%+@{T9S{SU2sL0>AOf&bM-I*<2Z$x$RX7oB$)T~JAS==~Qz%tn zSRnT3u@UyjBSZ>By>YyVcT}UFosQWO3P;Mvlm$k_p_Q-GruRq$(NR^sNAhAz;B-h} zYBX2LofrX#P?IWfT_mP#MSxIxPe@~CoDPn_P|$0r$*jf|lvQ}+x#>Ugpac*8_+r?w z7*E!;?{56@4CFnw+UYd6aP*v^q1B=Z(B47-#$T}Xu9#V{C?RDcVo``GnJYXgnG7W| zy8B}=PCs8)BTn`P1P5x#`z4ScIWS3gkAdjd{WF9)22ARrmZ!ZI(oHB405R1z`W^%x zG}EwDPA2HL2=Utr_Mn@Ff$1>H0%Y31$1`69_KwoMvqz9K2}j!^?!=(pYVjTGc=j;S zaBh0`bC~vln`osBZ5MLa!C|+EYoT~wGe#yF>4A{060w&dV+7K!#@M(_t!>jyhxEF3 zVl4Lt7b#*1){bgn<}Kuo;DkJPfK~% zfp&N>SV4jVHFuP1O?YYeb?)H@^`_r`gFWJPNEgrUEmz zhv2f?9o6(3)1R0imdF}RHyn0Orn!WGUN$IOi(h8RoNOl57;)*9Pty627w`c}jep-& zo>&82UpLVbTy_MRQQ%i%CButLIAX|6)K@YM$MxqNAiH(I1qx~h0uQO>@|=gIittZBa~0S!5)@pHlOgBV z?Fu(Yvy_HiXrXYiWtd@J`9T?lyL2HSYmQIvv)xU|^&lib{MJ0+4-;sQSHAkY@Ur@t zqCWO`VF5UY)Xw`V5#WWGwKzh5L}d@7OJ2mFU-OwsV}q?t{+ardGOD|v`#83=rgWiH zzI0kFCG0P{@T0>~EqekIoiaUq{5e$gdH!r;f46_MOj)emc5o8B+0VIUVuN(#~wti;_f=D4<|Shr7Zm7*jDP&hb%JrT=O(r~Ld7e9g<{VIdVhN61y z3zpgvUuD%N#tH2hK>hP!J_}ig16r5~cHt}Sm6{1`6)z&=I(0sctyD{-uk;XGSUft# z8uxTGVQVwTTwd9)BzAhV*pizVt%TV6Rd#;jtQ^Ji`Q4*|yHBOEea1p=k-`@RWTg2X zA09SqeTRB;7Nk<@k9GzF%F-O*J+5BY(*}MttkBC@-o~8zt@g=vnISJ8OV5uVzhMLo zO`L79>i9usF?b6TG+Mdh@^w79?s^3wvRxDOh4e;c&Z^j$?Dw2p;q((IWur%IM2s~X z0_7bhBikbM^ZfvSTD30C!FcDt#ito#|2|L<1UuHBfgY%BhNFlGfee6{XS1}q`TEw= zFS7*(&B5I-yDRH7{9;-TIEqGqC7mpYT*hV!_sAuk_(d0` z3-|s?qEo|1lRv3$;o@ty1iCx!R_7EP$rU7*C$8Oa!#2Yxzju1@w%?CfgBDy~Bj&gm zjIJYDWtjR25iT`#mQ#l0N{wwi@pq^q(5~b9bmVuNHf;~lYM}g~uZYNVrV%@3Z}lk6 zXuF;b{2P;_(&Ekc?@GD@Z zIiNQZ?`$G`$ER8O7wLs}P(K9gFn8{C(k!?wh+j{Y(gm~6@^cc3!r@4Am_exs zKqK4I(ZpQaQPS0?c>CG4&}|-9*1ee}jai+2Nx}3yz4M92&bky% zO6?8n%#jiYC*UWxfzPy@cL!+4i!b8+mv`BSt*^U@YP2w}7u|$Y`>x84t)|fHuOYvl zqm`%*`$uxurvA7webIdU$g*rqRx^6MavNK*2I|?YsPt8_F^4byCx)CPn>B&QZbMA* zu>cDWE?EkyqGDut+T}c+`iA}0q?&>=kRT4u&cc)PR^TS%+RC|?K;9rS!R*~y;Z9rg zlVWOr%DkaBzf|XM9|*70nbMnDr8Ys^EzeU7(W_6?9byv7oDuHHVKMw5tl1WYhlvs| zP+Xmg3r8MXqEv`HYZ8|KN&ZjdX+vj=3%k^`N;(Ui%w`KG`_1uN-5wtv61ZL}3k`ZG z*r1|dIoa~c;Ar;32`&U>=m?njpRr7l2tkaxp_nETsl1FR&{_Gpk8q_5u{XcL(GB{; zYXX6?{6}n!W#n9L#U=jAeU+pXO%V1Hb5&;@IN~no>wQP#%UQD{0kwr_k1SzLgNVPv zuIkcO+Gx`V8^fZN+y{ZxPmp_GcJrmk9ab){$i`bjhZ-R}^eonUDao}zsZAD(^U&fq zdk!P3{#QG{>GaOQn$9dYecI=A+KQtf#4zU|ssTvNd`T}nFQ@|s6EZ+RP>3XtOwiCL zc2+%+$UpX}n;I1$qRSWX# zK1OfKj~#A>U%gN=H?oE0r#dx;M}CUI8)6l08193p@)&RS*8f+!lmDdlO;WQmT&-M5 zAViHxv1@m%#R-*TiO8sm&Z3Db>vbLb=uq1sJ7vNmvQ3!d zcvBm1N125mi5+aW7VOKE^PS(4E*07*;TF1l0w4$B$27!~c0iT^NXMJciI_&5Z=`6-@uJ|k*MDm$73mh|$a$p2yi*i}6T*_JMf<)8;Qw2zd> zP7%CYWy#;zfl2-2_6>Od>uuAwh9kTR-$xc`iwM>qS3{Itjc-n>eiaqEJ6J@HO|Jx! z9D!}KGFj%*H~68x%E|sN%DJg_vJH;x%2F&#T!a)0Hlp29Vzjn8vOznYYmJKKYyu5V zOJknu3{TFaj%dIR|D#W91x^+Iv(*f!X+*ExKrKO@_)x zA8Jag!Riy*4E+~tVjhq0?LZ=5-q&%i>haYKme8Aj>=KzzxrF-Lj(EK$<$V6u2!^E7K>O+i-#SArOW^{w44U6 z7EUpEzNGT=285stJCH#9_-v@Hg1KNZ>QVP_TWkDJ=g34CCe$PF4t9sc@0&QrUCs9~ zstWdg4KMkfJqZS!#wk5qVJ|#-JKZgfpeuyRWPU z6&~T~e<~c?cdMwy@pvC4zuG6<_o1vel-Uyl8{*B|8%gpsPp4)+bEtk*O9v|i3cBXR zZdTg9Pa}#F1Gc)vy-~EmU=n=aG|-6mPzahULHm5kvN91p>Pjj#$fHHIFAo5`@XM~g zSY_Tjw;5U>@q-&(z^r@1X@~l~=q0RPFrQ~7yyAX+1NMF4wEK_|g~(uUumLil@`M*JsGkW9QPEH8og4@JKZ0v8Ge;L5ZwLNe4}SW4$u>OA`W5tJ#w(3 z90>3&aN0!jws{xYDxaX!;F*u-mOz9t>NCsqKEJv={z&5S4K1ljJoOA%0G}_J=#6dV z6{c_MjG4{GgZnAAm7z_A7Wv92TxI@9Oc#dAkwh(5{?_HDGT6xTQ;gLJ5B=nJWfnu) zz8{JB!-dH4sP$ZrnN>9Lm(-a~HsJz~M_vtfGc|3HxpMX)NzJ#VORTbAJOizIe>c$!1Y)!DR>&if<2Ax6&I zZ1#`q6~4`@f{HRYG(z8r`tO$!rR0iAq8M+KUHgp8cRAfAdKcv65_=_pFQx3T3a+4d zWKWvNdoq&;o9*30F2hEHQU0c9Xg}_OF^JMERRP0E>DWwaRsrn!DFatKr5=j?DvwR6 zO;P^tD%zE>R33!a8b3AP@5A-M^)UR~^v1uF-c>rDHoj%eWP#e3nP!C9C3_w{aLbL$*qmuARd?&ddo__*N4`aB z-!j%74qxO%pkNMQE#?dMq1y}0LfMPgz$j%L4Yl|=5VO?sH#aQ>2yXsYX5oGPoIvka zpOl9*LiyU?3-48h?FT3g zBBrbbn|9f)fmzZ)R$hYzRJnC0u4V{becVOzx5HMrBtbvHzs> z(^zL8bdUX*zHD4egh7WB$PrsLnmJ8JIdgA&4L8$=do?612?(eEA#dxa75N5KdFl6w zkLxNke(5L{8}-{Pa?iV;TBbVc_d`K@ks%sAjew}iK^$UpSvqGsOeU%A@Age_o|Zy` zFos0~7gYe{P6kZ=K3yLs5RD4y6{f;BLI*Q{oJsgpLBVn>@R%_4Mi^>m^=A$HiMvke zzwpdRxA?iUCl`)jd>^il`WdQ z9{lnPi60JnfK_03WC)`s%N_ zNmmznqLD=#u~%L(y>Kx0Hl@nSo*yMNXEf47?h4`0C07Hj?}LJQQ8vBm_uD9jXIBrwhU9`C$EcQU-+ z^P5dxV&5*dI%DC3$XW;Q;o44Pg*>IP-@@+Pa)|-~kg5TOD>9vF@}<9moI)Rsec%}0 zI7HHUMq=)fiKMO7eOPDWYcA@Yo5hE}6)UyTCQr*?vEt6{PP9bsnZCresM^t8H=QsD znDxa5idry@ZwXnoXF4Mj%3^TF*C2VsKG+!tz^_tP-F(t80z#-kqLhcNbtXQELn23r z;h|=bf**%yp;HrZ`}1N1tCZn1KgsqcR&sS6JftY2Z$fSuyJ~NdVrG05eYIZi-SRcs zp|6O;3>aZa=Rm4PSr$crS$>SDtDu4cgy$%TwOo3m$e4_d+BrhnwNEb&zBPPH4#asD zEYCKZRS7o#syesn6P{g{nmxXba@(`xHk;MOcd6B~q6tT@jvR&){1lIL)US${QK~G+iNVIvd1}Y zw4@`l_~=jQo4*?W*9+htEN*)7%g<$CQ0wW=4IS)L85Zj7Yf~->QAMjHQhK%uMm}zK z5z6|@r7BKG;xjPCR)}y+C_rvw@GbcdM=+c{6a`FWOZA^s*rjI)6&*}RrAtsy-9IP+ zFip1H*DcGeymf0LmyueY10@AimYBZSQii8<*iTELQm8Yii|0flG=j{LE0D}03*_#T z48}NI#gq(ktxivvfiucn*{EY_BXZ{R5Sps4USi&NB0Efay8~&Neh;molEDK|S`*5Wp!AcE9b*IX_1^JqX%5qdH*(S=;`s|#K z(h_UF6p=b#lEK`H;{*;v*FdxQ<@`DA_5h3XlQ)*PUUfBQ5Va+yx~;vIlGiu~uTiHE zFe+wYiVR8q>vT3{kO(Wyz8WAm=*J#j$y3~3xYvz}=-cghR0 zmGR%o=aHD^x;*!&w9b)uLm-}v6~D7_{ByV}Grzebzl1!O|E0$BQD&Xf8UF3SWY#DB zoMExH;n*y~C@WWDv9j!)N=uJ3(^5TdAOtChqK zF8t_y%oJCGvQXrW zno|Z@pMYxCvSy<)2NI!)G!~RX#6xne4=|XP9<1BJsJupxJ)-ehDU_Q#ntCu6)Y!Ss zuQ!9j{nr`j|HkDL^tsK$rA9dwN=$o}^w{asfky)V;POR&9Xlp_`rQGw6LrBiprLI$ zd}6l&)D{KCsDv!huza()f`&iMR00PI5fVO^v*~KaM2e)mOB?MQW7fY;LpID)A)lnK zhkUuiA!bcbU%FA$Oq?@}t>f@8f&}d>!A`Wfj%@4QA+Mcg{BM5S#06~&%C-8L;=$a( ztHgZIz#$UT^b@Cpe z#LZ9cFg{@eBGn`E1{xjB^mWzQCu=!HLo5a;s>$RA$+Um79flvHikXerE8PiVyUM(x zW?hr2;v*G*)!KIuYo{>ir4gs?RU;7B=GX4;6i#dq6;hjlxhy#ZS-&YTmXj|$P-E~5 zyVvxG)gemw_rQP8ERTI&D|NH^T+k8f$7fm`h^>v2^{RWFT5HYVHBU&=nl zwm3YO>Q=)jo+jg>w}yW@FA8!TQTI;T6-Nv4op|j8&P4TL9sVPD6fHCQy{@)>aD@Z5 zlU#n!OU=CB4cm@}<--)lZqi)U$X@0QmA_wjFfY)c@|NCXI|9`OR=ySFUwmYBn82Rz zDDBN_2%ufV3(gc}har@WL|_WPLr*W|&>x&BDVYbs@|LPuM8{F9V)Yi4$LCENOY}(a zgKU5dGfG^vLNznp`A&$jT}$S;5eZFXFOJg>B*oCqzbU$WGQOQ+^0FXbj&dzKy+J+auIo9ywmIZy?!ygL- zr#6D#o@?;@u?`=+7vaZ{_{F78!A0 z88&^5lJW+bv>LjePL4SEr}y=|*BC-XZQ+n4s z%{tOW1XtUiMD@FkZZpLz-TS?Yga#|6XeK2xt0$X&3!|bEXgp?Oq__QNP`=*QxlUOy zT#dHFlcr3<@0Kz}I|XmPcrZh=fG>_Dlxfe%m_`J+GTtcRy;qMFPIKg8c9|0`hVcUm|{wvp+;%9;#ll;+ophgf!`kHa6wJO3H~XR7k2EC*0*${4a?jmiVqW%%?MVOPD5Osa8rw%zaAFGyyTi+ z))%@ggJj(N@v3Xb0G+r7VP=ZTrjO|70;E2L}xW(;K(vPDRR`znvxL|gquScMgX})R5o~LCs4IT zZMN1hbw0V-=6$9E#Nf@SyUj>Us&tSxE{7F|{LbtCLwAj^$Y^3;ZLl#Wf-~>|edTx7 zxd$`qTAe6{6C?YETsxxx(?oCW-SIK25cFOa@6>po!gedpc0= z-ES_k*t;W^);`T);v;Ndya(@i}ittJNdm-o!i_-u7d|gyhgqKUnWNf zX<6W@v5DZx8`BFi@tZkz$OsNs>&-xX>$>B4?h-a9R4AlD2gl^bVAj91Owul&g;T1DcqC$t zlT&N0`1@nq9!8dpNUVB3C1M#t;na)oST(axP<;i99da_U}V z5ke(rdsU9ohD$W?UxwDmYrrkyvsz^lnv0vNZe_VKG{+g@#jN4+AM!SZs+AVqWAQd~ zCf%}12$%s`#AtDh+PH^oF8=)G16S^vy{LO`UOa`neu5fTne_mlQn~cbwYM9KT%@c2 zfn)rF;nU;q;Sn?NGsu+V={9(!^R8<}LpZc;tCemMs;XG6m0oGt-A#tByOL8KU_Vq0 z_+Zy=8`YSd*S+CK+4x@Er)Xf=>Yr?{(Kp@EZS=}`{4Hx)z-}!`#=*EYcOB7H@j31@ zMlDY^GLN}tHfism8-HSX3-dXmj=stScq|S>P$?c zgwS37;2K4Kw;^SxnEGrNeUd(UyUrYe?&ygPsLmh1&U8Yo2c1huIMl}2IsuwB&Ne$Z zBlJ2@C4o_#B|_S|9pW$Gs{=JIsvxHR7A3T))uzR9?6RVQ*E?QW@CTOz@7S>3@I~Xf z_+Qn$&l7Y=s;U#dL^yqOA7Kb)gnhWprnlAVp^n6CbSS>g8lrq~QdNT|#ixt!q>wEd zq2Pn+?zI&NhB4i1X*a9Q4}lY-JshgYLEC|yOsG1OPqUX>W+6ZeC0Ay)^HP&T#clxutlew*-a=-xvF5c*D#?;bS>92=?V0)2zN&gO%Op~dNV%tWXcCgqyUNi$oIVAbMbGb}z zA$(E2l1La5fKFE#RFr@ApOigdolBd{uLj9_=7+D3tJYrNF}#1daMyTJr$E`S=zgY; z+EH-2h+@-q<-7`s=k75KVF$v}+ktkBc0eluv&KS#>R|h%{OxwSd8@0@3q#`Edx4` z;APyDv=>0;m3XHb-1waS@^A<9ws3k(7Oq{3>s9-+kbe>jmtxdWemC_%v}hoT zKC6PD0*8nafQM05;6-bGvRk_7O^0Hq`KkvrRhp_@ZamQ(5f8Q*ytAbL5y|efIH*e6 zS~+YGgFR_{t~1p&%ApG+j#{damw-u|ka7ixtY3%oeo{pZ=NueyT}JVAG9*YFB(8^2 za_Bso?}~c&JUa6Jxzs1v8v^!D14KoPLz zz7`;OP1$x81(JdZwu_Gu@6dn|G3d}C#0F(ddUBx`$G=#`sfuD_%5VrT8)U88+2%o4 zZ=FH187XjrlYz~ZD-OT=da3>a!X6vIwOC1g;WW`uXvx2P;O6T8NO*_weGWlC)1~|K zC1}jq#7*jf&7oVIYglS~J%I(q-q|b)Q9Fx5VQPkpffWlB4b;BYtW^&%0~&#hnIe&k zqdmK8!n6FF`iZGc&6|uV8<&O`4ILe;oqZv`yi1)hW;IYN9HJsMy8?0{O{w)KT0$Xl zqMfMgi3zk1Q4s2dDPqb;y@I;mZ!2HhnwO_H7cSb2{zdlT|CPyE4(NOWhhZ=0tv6mo ze!f01!ci*=WEJ_!P0A4YC%GuWju%ODRoXp>oF zLv*jXq5@JizEAI2=xJ0{JEx3PHDE@LApN9h@wIs3lN`66YQ2c%95_U_h8*6&j;X zJsR`L?19n4td!Bd>e`OF&N~E&5I3^vyeX{h029!4LgYh~Kl!fN*md2E3fX3f60&)k} zJ9I1PPZbzZNW}bYKCb3xUfEb|;T_c(?#`A521O%yaCK-vA?0auy_{yXc1UxUOamk( zJv^5=XWQi|)Um$@`s?982VYG)Er9vJ_kZ)#$of9;N8m1w?8M0*OSO0UqG{#G4SRIu zV-ozYzCOrcbJja;<3ly}R5v9Z7A`K_h$0OL7&3Ptn`@&a#2<=~@c;bv>*zVqo?o{| zqTZ${ES@FzWRr;@-J$Wb?47s&pqlbzg(;40qu+Ejfk)b3sGvAxF;-rR=|jnBbZqZ3 zpa>t2=bnw10E^+OlI4>cD})i#dK;6;`}w-^%`NxS!yN&*uI7`&&I4~z`D7ll_FDqi6zr!I-<-alP*OaEx-Jv;E>v0i}<_)=~5K?{_gK2W2&+{R?64(3u`zh_Q384eZvIO_d z3;`WKHSj(|iA?aXI~a&b&EG_rhymg%;x;jJrrmtXo*uB@@;tb9sTnDY>h?(d_ny9J z%15j=G?Ua~u`Q*!p!NqX7S%3$M(58D39VT9QMQg;$_3Q4nwwcl`Nn%p19y{tOwLYS zJ+s&z`drV$ekPEc95H@h>n&z+ZZ`~ZOaBUKEiD{WE1qWeqo8f5z5MHksX*sCg(W9q zO7TpAk#7~J8K-50nyLxeDJy(GNng9B1$WkYlHtl~W%*AAoxIVG$jjHsH4Pho)+2r? znl(6@k!Uo7nnIS8kmn%j=h?p3pC{&Gy8@KP?2GYQO>gWp|2WOG!aEFZcYy=wOM-5} zo&busP{277?;_fJ{?@QH7>IGp?ggxHHb|?r?lUxjwq~;hn|=!Fs?stHEbFDrUjvRz zYL1Q_{&ZXE$3$T70Y_7E`1oQ&G2XT#&Y${ZD$nk~Y~e^xQ}P2elskfYkJ zBx9RuqiJrI#EzJzJplm7V_RqX(<(B$NY9(z>EtHSGcU{ZIx>T`Hwdm1r(W-Clg*ok zp#5fP8W?FG_C%+2qA8yUsu!lC=eiov^52w$^{02dO9Sm%+TEXsjavZB0d zL+!JF$s2WR`4l0$9_cdC2vudn@^*D{oZlp1W84)URFT|K&E(&5fT#_YwgW^;3LMGz zyQLXpWx?k3aQZ(Y%GCmA;M#un#Bl%9S)TX1WD~x%bNn6=sQi78i#vm%R*lkgFZm1OGbPQp{(q$>7Y9-LY*6KPfIobzHWGSBj%0CCi*2 zHf>VF&I==Q21(;xqeHd{9I-fgXWjPcSNwG4{)eUTh`*d1l~`$?zKT-nKmKU|z~gea zQM6zI483>MzvfXrwYBaX>wcV?q?gYll-o5EWohVNiHT7bRn8l^X~`?vXYOd6rhBeKS#oCHAEG0^AMAfd4)66k z)(q#|LGHhfiAYy2oB6n;l{b_FYvd^Zu2l%YOieHhMwu17MIE2q5?XTSF<~k zK*YgHP1A}FYP>5rI?Ag(&|pQ=C>3GqkOa(c5KNBZ(WLP>aHLba6nUt=1?@0q>suO6!O6_~!yk=DtSX_%u6|iJa+!`~ws!wGyIS>So z+?j!3<0Bltekb3y1cvYXp>-T#Cb|vqg4(}--!MM=r7~}Tmb-PB*%x3Fd)W%^4!Ya} z8}RmylX7{Hc8JCq0xTE=Eoq|0YBmx3cbz3HhniSP`*!i%j@{N0wcY*SGQP6ABhlqs zG)qgI&4w!+L`5Sw%ysU@P*F;MzwB|G4?)Zb(VEa1PoEbTG>Mw<8s=tnsb99-7v4sJTw4J~~AFwrEepgg=K zE;GIX@?^q+6P~LE-h-{emgkFcj9J#j{H}mg{w8eq>?n`nd!|)gB(C^X z425CEe`gAQW94rf1Sn)*An8VLE8>pnWP38rDrkd=0V6Gy(RjP}o8{~-xvubXL(&1e zj_(|a=|=@!j*j-4TeZG!US2=?@w_x&=|oReyoz-8p??cVk=lXf@9iT`bBUqEENY?H zQv8+An)r7-A|Xzz=kk+Y>xgpe;z4&jzq$goO|6YJ875tuu{?w>a5tL9)=M__JR70W zPo~MKP*0jTcoa*-oiu2GfeA|3xm_6%TK5Z|jD=t(_&O*TU(Q#CS3J4Zw$U(WOrd{g zFv8#UiT?LK@#W7QpI?%7hG{c8QC2L;Ho1f{c=Ybgh*oXIH!_+0<`)@bb$3adGC1jXc}`QY5T!-o z&a^z0TEl~RZESJfl8-7NCOtC$TAM`W;0Roh{`(zUd6pb27fXazPsVTIkHtBf&|Ete zc9MzC<|z(2V%!>_d~Sn){{_5UlQ8QKMxa@Q1}+U+&KRytdLE%Gi##?iD{i1@tC1!j zO|)>c{Tj3B$eB-la(M=#gg7Q|ZA)p>IfWnx!V|wHUVE$QP7>7XQ@hqUm4gFt!Sk<0 zUHR7zd(TgmiV(R9Uo#eMxn0z->Dwy#aAhQZQuDT$J2PZO)`y*bHnuZ1G+zpVc1vHM7i`7C2-m9qZFE{Fc{? ztqml-rERpH>!0f&QlxLAyI5ygD*~__W@EEGY-Cn-a2)|Nouy&a{-G%F{ZNcKF)%tj zMs8w=&(i64Q%~I4E6QD%X~WS7yTspNd;OIJ3&31%7jmFhA!lq#4wV|OQ(|7?OP6tKvA5D<44dWz zpC#qFnk5Y4Ngg_FqrtZ8MsQ8%XD!pKD0PkPc}8&eyOp?zD2wEH_1QOdTh4q z+8;?;^6bD9JzLn>z+i#S=d$t8tzy^lGBOXYdHzJm#HUj*1Ui#q9{u8iouu45bREKb(80m_5R( zg2$XwlAO1?m+ZW@oAT69Q`dptSthbW6id0zB}G~xfNz4l1u^(3k-?m5ssoquwUI6W zzoFvl1eZAn>%B3$}WRK%2cQLUYU+s}KMsQ(4-6XB~Uhaqvy^TT|0a41bmwMd}|vNnQLnE{fjrhq_! zh|9kr+DZHtFQdG+{E4ek#t&=FHD5b*@@}%1^r9Q*yty#&)DO0^_%RbN8-d5B>=&^^?_$~g)FKxQ#N(;&Kjc#Aj`B5wIL zg9pnQ0^uce8gW@I!qvaZH+w$lK^-_frp!8+#z!%CH3;O@nE72TP^C}9Y@)5tyR7}W zQLA0ELw={#Qw1{_xsy8$y#JtyoaXyJx)Xv7qYm-A5081YC#_aFv_1};bvtR4iB&NQcmhZKZgL(|UWqZI-`hi37&F5(%aBnczW(s!G2GiMm z`)}y_BOIlMj`msCm74_lfu}h`P+$aMIM=bKj}=(#>y{{-(*rrdQO zhtcG8j})eh{fE~wrn1Pi4L|ic=rrD!7M*!jX@Nlhw71t0Y<5A>LFa*yw2T3dy?>HX zePCJ_ouLZ5aU&ZfzcYp1a(}Ng`KUkSI7PpmhbHY0Y#4r$4%7qeM0$0QS2R?=i~jhj zvhE(&;O`(ZIaUlmJNkt};4Q!)Ng1k(Z5TqGQ?I&4qKx1sak^~3W&A_H#wN<5Ui@s; zXe*P8mX-!9#qafJ-OwN9Ke1?`wrRyenskZ&s-l9Xr##15ogc+KR{8du=9V`xB#mF- zOdkGBc3;zMcY85#pO8&*E(Eb=e!%TsygT0>ajHrE<=`~MWA0rENK1{~y2YfZ3+9+Rw0Up5SeEfeo!4C-h1>89YU^78Q1A}G_n z-=64fh&IK(rF3*$Cs)~jc$Lg@in9`!DW?|QO%qSV-1u+sqx9RP;(uNmddo0RiE#K= zr28-0pEGfZM?+7$I^eMhnV@;5YMSq5ZXFlOD#Y28iFmO{idpMfP;z)s5d)1OG8*2mOnG z7;zJO9dI=@V?MQVTjU1RCvAG{Y2;d2^zrM7SoP$!f3hvzsd#Z(4%={|*wohYh* zoyMtmu-84gNrNaj|G|G*qAbpPl49Oz1xVJ zjL=j<88tmL2@)7@vAmg?%>yTb3UJ=%ZkaZ6*|EX*Uv%+)e4h%dfhFEi!XX{&?oDx? z%nt9cNW-&>`Tv}EBMHw>NtHVj%{te~y4tT^EI&KGKv?UlnN)Y+Nr0n=Ue=fi=AGtv z3nDy2@4vnN)%fTehXKQmh8#4?9UnN#Z@Mc({J38$++M6lm)n{8vsH!#!;?N`tTz!^ zOn*|!gNyW4Br$ZIu*;NRDU)KlsAPPW+;DWW6YWnQtP`1KhSJ28Urcsw4DLJWaO48T zSKaXbYc-bGuU1Z?iFf|2YbSn+;iR~QwsB%DwK9y;4_e95|H&9W3L79!eauyH$Ei^i zl$fbz2Tk_zxyc6+W89}M7!3VrI?zGb( z8jp7#OeF)^~X!@oAuq^^KE< zt*&CW_FDO}amuKqcQTVkOX5h(!AxEkZ@+Hkdb*ZMBtb>I=WxmJWw+?=1fx~o==#-8 zklv+D=hCns$4`{a_tp0cpL~kV{{LZfRQvDG%e`8zr@O!Y@P4Qz4&#m$MsrZFS1PMK zm&#OCz3=fKN$k{V{nz#IO>`U<8FJm?iLK5^)as>{5F^hzwaMxKe1vRV!0@etc%rjo z_%iIiHW6m6C>PK4%*wh8_f5*Pq}I0I*Uw~gRw>lZyc-C2=f{lEfi5)T|IvUfA2sko zq4Tf@%dRKZ8=T+Df0`BM`crBH?BaVCW3ZG->rcA%)4n%QFyK7L+GYtKu3|$&ja;j z2PZk{GSMT#UI9_(_uoCgTFajUov61HdHMAzy0>rq7>>AZONPb8ji83BRkyl{8SSe>n~$#lcYZ1vQrOWN_w#M~M7}MSNaKUg z>5{Ympw1Uz^9O5YLHa%q@e)?SRdp3zI!sJO>GIc+5U`BPh-BiD^c^ZuXho%O6VJW5UPfJ*5l#su+i`UZeN zT%>%V1HRpg*-8;|A9tv)M+W4Y>;0N3$)S1S)E|5^qrZ?Z5h{(&e zKaYB+tzPB6kmM6_Tpm-3)t>hleR=AQ<3EAw{8zFFdRhbRiJh>#xA6!o-I6eibyA2+ z4M)h@sQTI`lilhr=|)V6Nf(zA`1;Hj|6;J*Oc75Kg5RF&h6302wGSQAkfW&c1(LR# z02M`tqtD)nMjMwzUN6t(wBdJ3WCzBx6e{R28zbKSrddJK`}#xWl}2Kg1QHgUrUg5v zf97_fs4=e-YRZ+PnHak*mdi9PrR&&47KDYU>Jr$q=!Rb;|TVwO$zDS*v zKZ4X-i>|c?ctmv2g)5#1Uvd^YsW+TQ1KS%=S0D{sJ8JEaC|NLWZg(NT4z6+O-5>8 zpFtn>etU7ixK7YHxt%&afmGHz87nC}Jv&;>wKp%rUkMHam5xZ(zMamP7GVjA<0s*8 zQlnkNWapjdgxlM}sr`EWA3xvH{fDF3qBEiI9!EKchmSWkc@b!RB@CZM z=ug$|?Y0O>)!rJomUAr7v797d#)}zktfR3VGl4TB?2&l(30TQ=s--z}p}Hz1Z+5#Z zC7B7VR+Q-)lrw_BC*AN)>|WBEe+TmXE#IO;s=B>gUCze)Gk+}oeLqy{aQkIpvY;&N z!+A1@)H>(2pcc^~qVQhzeUawAXYGnMREX=jG;yF^+kRA%@zfVnkqrY!O#;+KQ=xF%(I_bugFqjdGM{h`RG^kyf-)p~ZAFTjd^&dCrVmqMQGDSa(hpXQ0(ZH( zbS6i0b#z1M^F5aCyv1ZZKWgKkIi+HswHq>avnWX+#;B(*cBPJTt{KMP7*^2GAzdmq zOGOzId6hl9P zj^zHvimf5uwT@A+Tl|WMhxia{vOyL3R)zz#{7_S)Pr>rjWL~(+Y_lB^s@|v7p+rQ- zq(TH$WNFk(kI1UV`;S|ew6VA?rbE>2PJeR`Lk|AN3aRiU)+L}o`2cYd{j6b$01Nca zdqQn~eIJoi=6+BJ20dGxuAJ($v7p}4DyB@BL-h|UXx(^Nv{vKoznMJ!kQxhIvcynI zy~ZmHKT5&g$QLt#I3v3Bgd(&JPAO;soHVNQC<`zSNip-*cnB`PAB13PqwiBpq`KCCcorqLRz2;G zLGk72LMPw3N4{5qU)NsOLT7eb$drNh9}oGi*d;2%IEZxT5K87pA=o?oV%Gmep>M8^ z&?E3f*zOVqkwA=rfccP%g>CP7uqW(xd=Mx;3yKbVZdX05Cl(QB+jGzSNaT$C1NN#` z=FY>O@yQtb0H2KUk_?LE3I`v85@ZJ$=B!E2cg=K@);NR1CIj|19@DWz=^0?{eDbu(6?|!lh}_jW$;(64AKb96keF{ zsd1Ahpb$)YxjzvFRWSsG3T*v5s#5Km5Fe`S@MJR##(}LTB8W@wJW&7HwQkThvP3K*L;M8JSBF51Pr^X^5%gS*BEf0B`XdOQ0^s zb^We;V3h*(FEJI>K0Go~GZNwHmDAP~qisyi+bGOt2{U0%UV3z8L1!|WMDcfx7VVBP z_mWtUkLGFO{kz-h`X8rU@-;p=up@qXf|t?w=U1eFqSbH=_~C}c>-F&A2m{lVUYFCc@))#=Ylb80E3)bB(?sbZ(_Xk`J?0g@O49r zA;wQ14~fYR*+`;;2-2o1Zhav4L^r(}g`nwG2fPm~PzC;3enhhRklxf@T=WwPc0_k!fcwPVK{&I z=cn4c2%-Q|ur{eLjzm8Ed8bp6;F)sgY17{p|3MiHcRIxls?o;gj#+=TZY&Lq0{&+`@D!xo@k}K8*Qyu{jlczb%Ds6aBAaUGSMZR*AC;o z%aGdeN*$prJo!hvUYw#Yj=+Z*qV$?r=S??3*n%h5mn#-wU^Bg%6sl9P_di>NOF6Uo z?&EWXnz2s~IBaeaa3f~YR-5stpN;kB( zi69g?d_{Z$^~reL^`94X?)b@fuWLPL`2Wyku=f{eKqlmd(wl`;azb6tqBvYx`bN7pBjI|$C zr#J1fAT7=vUb+-B`99Bjqu}$@ zKiHmOlUG|A5?V4qA^3vyU~C3g5lEkxYtPd~1T$)BxIwtlpL>ppK31X6&C_l^pQoGl z?4NgcLW@)|r|+&gm)$K8{>we zni;t0ampV&`|;rE|2C_kyXsS|c501CgT$`u0F6uUZ*lk7RcSuDh%B4E^?W>A=8o8$ zzCg}y9gSEtNbnII@ld#NOItM<_bJ!^wP{k$f75DfuZVxw=b>TXao^_cr2Gbz1r^>A zw(3HI^GYKLh4-iKuCZhSgk;$r!avnbQEmLpO0@F8m9eP(4QJWn+NSfxWy72VxToMU za!sCzddBtx{`+#Le_OKKPIz_dXet)^zuHxZic#X$ZZ=Jj(}YQ`JJ?5-(_S|LZ}u5f zC?BqcgP)o|-`S{*0wklS#>3)uRKwrsOkzScbQ{`G?i51Ty^fd*2=ge zfP_;C$+b2nOv#CMn&bnyH%c_k(=UciXta#{ZZkG4VIvx9wQz4g107nNN6N9o!# z!2(fqGi?K3VZeK?i;(1PjmEIJHS^0oK~ib90~^WgAFv07HS3dF3FMkg5|_1Wp`{3| zjjXVt>}C){KVsv@`IITAo0`ji0UEl9U62z^N8}d$oGdS(R)pb0un7CgVnS?;`d~hB5Jqotnt$OKuF!z0N;DM8U^i~C>c zeJ$1&;K?OQoukadZ8wf*xUVB`C_tJ}?oi42<98bqt5!u3Z;iq=HGp9kRPsE~e5YU( zVV5j)Gg>|9r$D*-g5RV*>TYYOwO?3$9l%9KRaz!atx^oH_c z?GM3=@oi@_Ecx9~&oj}x{;#$YQQtX?qz3mq6^l`i+up^oq2DOg?H44+q%US)O^kim z>Ljf8+wB*TaCH6mUP&v(rvT29mUvu!=NWMoNs60dMTO|6a|m~s-ULO7WRnd^$>jx zHYg7I2>s3tI;79PFL3f5E}y&op>cn-c7o1w4%>Tq2jTj_m=`e-311Oyo62JvP<6Rw zZi$~+4kK_|$RJ2tm-o+4UCZ{@fA;)gV!Yx-3+!UFpnS20p0WMxtZS7$3g^C^eJAE@3^0xmayE&%KP`^bUGQuYPiCtF5 z*eSxBd2xq;Cl&De1g@@0=>k|#pP{`&GG#HX^4*p9HCmFOTW*h^0}Sk4s5}Z@6a~!S zwoHjYUYR!*=da*1cs*YWvNG{4g4EvE#{g~e>8b>r_&`z8a~xEr_dh(7&L^AW@+pZ{ zg>%!ldG?%A!q6D#apho`otj6+{uJ3$j-?|CUiLZo)`cB4M;kcfMsDiZMla>i{>%QZe< z#NfM#eWT%dD-58 z{dn`TdxqxB`i+v?B_CViJf9bx$O6D#MXjE>LaXFh|MI>1uMe@Ic*1G63JKu<#zAPbgx;SUw zNuqFyQ!85_kh(~v9X|DNdL`b6$`_d?j~}aSfTd*Zl8~W zLEsRSw@rAxF`X|JZLgc6oqi)}`SV59yF(t?h4v@4;==b)D9+Jv={hLbgu7(b@EhCx zkCxscdo1(Xc)}Jg5Fv`AR-k^8x{ud7Ph`5Q-r56TcT^{A?!lqT_r`Xm+1!~&~ zbI9cY9DpIVqT(rZZc{;e?oTC>k6@(bsB*|Ks&YSsk38A59;NOC%RBg14)a(GXr-)~ zmLUOn)4{vW5#Mq1EJktvJpEICi@bwY6LIwqqaSM%tIO#I`1<5}x^y8Z#84sj)UT@} zX3|#u2I&e_DP*{1QPxn;PD92&fG?tp{T$vEu=m?g7k&0XGo_lrF1Z?EZ>>IKSXo{R z9hEZnr5g>(wK~}RY#7NwBZ;R~34iAib@%hwqeOJuIOnMywtZcG>!Gs3D~6CFHt~a? z1P3y}?TwF?71cLF59d~=OPP|AUS)YKX+i0ZF_+yNB8NFtc!SANPCr3u@B7Ki;e}PU zSDGqRf2SC(D0i_PW|6Iwv;%cx10ij;B&_h$(G z3T}~u0`jn1as~q?;Wrcibe_pr7u!Wy6UIXtlf}cHbFFy+nJHMK{e+f+MtC96Q~Nhl zY{5fduDpbtw09!5;Znj#=sx|VHmTZ;U5${HE%&6C$*V?PI#2l@aMHY%iJ3GrM&!NF z$w<+NJr%0nnV5k2wrnh)p+4qd?xMeAUp-O`t+y0nHUGV-0UQ^1r`_+hTT=tRJ~RTl zNxPya3l`bj%_gQk1y633O%)_T=oPiAjWFj4VhYFHQ`<)htN|&m%Y>}L+o&)LFc$KL}ICX7ql)T%%&cw{;y-9XAk^U2r9;HN;wJ@3x2^V1f$h( zM&UW9pW5&wr#Ew7TJX7-$2MG)Z=Le!90`qq|w?v!_{ueuDTG|{)52`sdo45lOUdj+HVP2wvpqw zsbAm)B>(4=dWTN6c&TGcQ@ZSz!>INf9TCTl(&>F$K2vOgvRO#?Z;cEO^AAsSsbQg# z@;uS@L-lFhIpsaCSh9zfx zruy&nHSVH5Hgy}^Iq;&@fgxV65B2axHV?PrIhFXjt0pa-fBn`!{sD4r6wqsz=>ojr zozQ&95v&GGine;OwWq2pl?OK|w95=e^fru!*VF!it2v=K^|FRb-xf!;5=1x}t^1;r z36XANTy|t$6mPBIFrs8~BJN0joka)QHa26#^K9dOp;%NHYX+JfUo0DB7V@U`LkX*R zgBNM4YP?ElPU=Hz7TY##?KeBuAJjJcy3Fm}KkbX?Bv$Cq@r9xrPOBz<1e*@VjzPi9 z$JMj6N&0Vq{aiU9aGg96R6Py-$n0y>7!^kd3!o8MuM~q^_FmI~H0U zS;QLOTct)ys01RcPc~4u6jo5V5fBvhfW_w(oNXNA-x zRpud>VxEj6wfUc4Pv)xk|G3ffYGZ$C%(h9<wrH$j&*T5sBh2I2j=nL)W>BP?mjBxjT8w;D? zaHaj;Hk5Mk90b%_i}Y;h#6fLKjyb+s!g>LBkK>0{Pe|t{@;Y5OTy$B}VI{H?x7Ep} zG1^12(EHKXQ8JR+%UgfEjm`t`KvWr{dN$;3^BcjE@R}4oT586>j4Bbj1TAW zQ)`uC7Kv1WTj=c^&Go^z6)Z zsa#x|lg~aBRaUufyVhAUe#w_#tw3udg*vYGP@c@cV^p66So`5iA;0gn_db%}GBawH zsx0HX`{t+Xaf)?a)Q@uzO@cb;`vDx6lzSeHB zdw*6WVPqFSXy`zEXm6>P_QA{sxonQ7bz4tAF2)LLxP}6hL+q6(q`DpnrM&al;F17% z1UHQeN4O7iEF|j!yxD?d&Q5BK6pnf^kt%$NX&byL>f!N@y z@1nln4ZKpdQ=|)FvHC}57)7nSDF4yN1?YFDHEVCDoA)K5t7|`M$c!BI>WHD)LeAND z#-)X$f4xMBeyNE!MAO-*y-fu^Z=l6{7{3jPKtktfm##(K{c+7Ydu?v5qK z7!=9M4i3gEmB|mV&48NC3dG?;;_gFboPlFvl}x|`eeY#gAMIA}K<{~5~$WM-4-olOROwt!!I!0;`{`ClV0FuMd1qo5LxY%od*ZHNh3gg^t(%&?8INV z*XJa(pHpj4@F!K(c1hqha_F6r+wTUyjP2yfpWzDZ(mDP3x539D$1uPN=;&9(b-{D9>p#f$b(dhZy z7w4kn3$vjg@Xr6uoj?@`&ZED6=ZfBGky~LuqnaT$NWoUkoF*&FBQky7;Z@#fLotvF ziD3Nbm1X5U%;x>Ur@i;9VJ7Yo2pHIpqv+L-efsl+_Nvud%7zA(Nhr8r0Q&K>^1kv=JGk#pmQcSUeAGhBrL36aJb0nE|j$*eB z6#a7xj=_T+_G1$|Iln6(pQUV-!i=XJ^7PqKAs+if!}!#O3({RoqKcmtkq4Fx7LMA#$KxNn z0dCBQO)IzE4OS)g=f6n$5#)Pg>tzTfgO@NL4+AZWsSHt~(p>}cIibjFX=i~YKNodj zs0112$=)*R`px{em1PrBwCR0&au!m^i~MrCB2E;IhPZOn{yG{7roLUMAMtfwbZA}< z^l(4uJ%t|3yF`B+cbqh(O(x6}bVz3TyQ1N$A|f=$=TEYE)LtT99Rh-m#4R|s+Z}5$ zo&Z&sR)0ic_t$O+l#hoBq)QS0)}zaBBKG!70l#c75i(`~lk7$$#y`I0W~PW~E>bQ39SU((tk{LG*$(AUX#wC{mDpa?oO`yd5t80> z(`J@U9ECB-CRbBO(=jy`Ab~w^&`4@_}M$Hhk|8`#AETaQb zS$dX!Hv?*U3$$^&Ty2A2|epdQ$zCFk~B=?jC25JK6r&LA`Dsr zGhgcZNvo;jplwhWetH0a=m0&f7X`FlkSeWHw&L@irY;a+^?2^Ofm+I50bHpRlX8Km z7d!c&Vg^Y5I@%ZTJhi>Kx(TgY1X#o7b<7BoY(4!5;LV7^!cX-}khn&+cCNKmIG`0- zsKe5M;n*@zXw}tZuZ9mHqCv)bbx!#xn4iWW(Pv@K`y{4!YJ)2*kCIU=6~@FWqLY$z z{_ItxB!R*JpC%2&htdhgw&g271%EY$8+>?2`Ld8GxbZ=?v6I?$9a+ z{6q@k=yJXq(g;U><;Rb9iq)-h@bt@yL;=`&WlhIuM9MSYSeiJ+K?*&C49Z6b4c@n& z$r_}uaGlXDx&{7dU=xQ;-QBX0NBjOk2^!OhE7%_(66B3cc59EG#Lpj7Y7ard>pDR3 zunvaM1C0$XTDtOF>BG!+cHsfn_}e!vx=}MCFxW(ir0bx$`M8B|B9LvRhIH|`+~Ri+ z&aN?hd6;)t@FTSATCzs)e)f)IjN3OjZUr_WJNGvcrPo6|EkuwFZjjb8v5x6a{^?*j z#3!)|vXf6sHCw3>GglY41?D8aB%3q3_8)GTK>AbpS)eq0;pvu9vE_KE@v-G1HFMja zv;aiNE}}g;dyx+tG*Y^X|HbceO6{Bp4jxx6oW8dG{=Wv7sVbYj5;t4W8Y8i&phwwG*KxlT6CnTGalxN zo?^_f)gYR+ONi2c@abTWg`$$USj2e@T8nkXHYqtssz-koApDRE@a637<|$Gn%O7xw z3hwTh#M+?FH73dXy0#oeIPzeL@$Ocb*Tm-;mg{Ah;bPmpt&r*&q5sw=rr_*LDADDM z25b4(E`vdauKd>D$NAbNRbD}?XB+j(C>JM(B5y6LyPZHGV>3_+Qcr&>y?J8mr`fWX z;DIP2(=S{rpBocb5@=RBBh2*QAzTt?gFCikC~~NT^EkZj^SqNF@t0hS$59EHKDp^r zt?&?9SjRiw1~m!`bc;9I9yB*|k_|>>~Ai+O&Z8l!yTSq@3y^=Xi*iIIL!+ztm zr{f2f&U-IL*kK|dI<9I1{F8F#We_D+(ZX(GYIO$b-!Jrz`yOzAe09!34lwWxMA)G& zbI3lzIaLJ^-Ir0JE zZvFH0LRL?Lw?%pj&z(%$uYVm9(V<9ltJXVWUC*_Yaf++?9(_yWj*7GoM;fyt|7tkh zHD4DD9vKnH;i7WQpf4GO9JJQkXHd_u3C#|i<&U^@BdjM(6nSg0bG zO8sM#CdIm_O%llMmVK#oWQ7f>c~u8o35&UW@5^bXv3UuoU)69bbp2ML^Z=CiC5Y{q11f09LV!-Y|iI(`JE$Q^u zU6@}{+zdn>_BcycPE%5jvZB3R2r+Q^ODKD;(yjtY1|MX!U8HROV{j-fytK9auF?_n zmCEpy_Sx0G^UYIhzK0c1%2Od|bGZk3jiOXbiqtvoSX_C|MU9Hm6^B^OSQhg~w1@DJ zKebQpvgVG5$OGJxI0TWYsI43)RJGj7?${i6=Q8%xUs5bCTGSYni)-uqzq|W`N)oi5 z#Uz0#mtm2K>X|ckYZ>0&x#tZ;{gf@nS0f?|Ec^sAFyI@~NPn^bAIRpncZcQZ9o- z+kzdmg$W$gD#|jjzm$?U*k|G9>sc>~Ac9QUh@xwT!-Z#IN zynVApI`aK&&#H-|BqduNG3#%FTt4qYGdz@p%ibcFJuQJ7bCOTRlgDzs&qtmPnyjcE zWev;R<7O#mhm<^DL>6DRj57(GZ`Z!h<^J0sqHv5WUp`E#GUVSqep98f)ph=gU9;U( zLXQ5FTc+ITB*^%Xm|8xx`ZX=Zd2;#Rm2+6Un9%Sv_NrA*#wBH~UkhP;IRuv{)jgt7 z=5S?Bd2oO~i3OrFU2>O5)x^2*xqs?E;$-PUHn^{dm#>Y@9$*6YGLW~h6XXk`F1>_u z7VscLAx_aw2SeIM7+hWn;J zW0S|fJfyeSwwbUs9yVni0x5lbv1mYZ?h+?mS|t zi!KGN#8_-ZAteB1Yy>lSBa6$S)%%_COxrs}wI7l6H%gkB@54I=Xkrs8v{R9^jDa?* z7(Sl+Hw;EKzS%vLhFu;Isi*J_(o+i$nX&e|<gwujzfJH zR_Vry{FIGcz*%$6$!h$3ZCsArKHyux-oP*UCf2QWQ(2onTo#-C*=KU~=;ipR zLJRbV8%xS{pS5(H9Z`Aa^G&?p1kA!2S$LxL2lqeei-$*x_*C}QgrHKS5B)rnP&B!j zRA^7R%IsKLUc5>qJgW@Y$1Ayk!C2_fj$lUAEbI#;?3C$28$#M_Fy*)aBUc`&tSf_vcV<( zp`Io$a_~sXyIPgI8HnurOHY_^ES&>NIe^usF=SbN6HD)>!34PYHdrG3R$y^pG=%xH zM5b>fA;5#+>J(|C93rI~2Ro>#XOIt73_y-s{T_dHBHlT5>{9-=xXO^HWgjc%o#7yPsz=8rs!IR0WC#$ZLFO; z-7$qDZZ&S|qJ|P7DVLgF2A@hSvr=~m=>oLND!dDlv_Bz+cl%&cKJMMArC7+K0s5F7 z9ltPlS#E7c6&6)TfWPShZ#Hg9u~!LLMVdDq9h5r{(+6DvBsyrJVkqbTV#Cb0h$B{2lmHA2iLY_-%|3{330QjYknzHam&pFd(Q zbryTZXs7tXijaQqb?g=@0xL#Pi$~3xarDJTd4TBadZnUW)y2b;N}o<5fHdPY&E)$x zNj!}2ArYu3A8@(-m+vJb+uEB&&o5M$s;IYrBvfAu;WS4yOC1U^O5L?MG{6GiC{s)G z7iz^Cmq0$r(-4?bTclw=;40co$D|{^o^pBh+nO2ng-iDLUZKulbsWMC0NA1(Vo3q% z-<^Sd)#4q^xtYKVVyCkMhLmn;!vJHx`d*2Dk`N<^5FwyGZ?;?^!ep%52=g4gt>CYv zp6Rub|NEtVb09{L&N++e~Vyi z*F)ArF};~y-7ri=U|5vA;dh`lv}~MCKbWTfhDQ;2Plo4YnEn+Nn|9Z%^9u255hgl- z9GL$UGrc^}b{|NrTZ0vpt`R=HTmj=cfZ?xZTDg2N0-$iB?b$nh+W}J7xX``3{D|pf zZ(;1?8de>Haklcqi7_Tq`9|Q8b2?X;>>SMoLBZe8-|imqI!IR{8l@up#*#4lKK2fy z&Gu%xIy;JPYx1YDf^o5{&Cl($TU1SW^ae|^?qTM^DSw-Gzw*`cP(n=~u^;rpX7knd zrPN>?fUZWErem5Yo(R~WwvUy8cYi;}OBrw>&a?98ij}FWo_1KUawE*bf2iJkUx!glld?8uCGoqtVa|MdC|GF5UE zcr6o;qNZ!Px z&3ss?Y>nSNg6G?H~bGfJp9{bGw5feRuy6rq8fJ0)Tkb26&SRUZ$O00iFp^7 zMI2Fm1h?E&-q{2-=B~C^keeIXjz8Jb%jBAe9=|ssp2fq=2xabQmV+?eia+Xk(-u6M ztGI;WmYmG}oKBdZmm@zdn(Kyit%FR;u~yfIv2<42;}@P_+eji7(?sj&nGOcI{SgEM zJ9YPJc`Owv5mJ^Wp%$C$f|qS{%1m=xs%;Hw!ywhi8l0x%abnpTa6^h=gjnoF0V6a8 z)yts*HNT~meb?2ocH6GfPHRSvEFeAqTC8{?x)4EEG{1B-A^UdtND^609Ozvz!OV$z z!hiA5-iwJ5=W2eZRj=74Nb>5sc!NR-8sbYUABs}Ij-g^`GLi$LUU_$31;cq@6wb~`@mWhzpy(@sysxgcM0pPi+53`;S~QIa<7r7KcA#1;w8=~QL=sX%rtJ9l|xi@D(Z?KZi7dE1S2gQskbmL z1m(Z@k>?m+-;V{gqy{%8f%3lNRG_ATuAHaU15RC))_f}db{-FFup9Yjl(%YZtWvVbT=OvUoL5%nels0?t zMWNyJooB71KbnDZ$VaUdH<@tmRR$#Pz`148bNk~s+-NoqD|)=3Ywx(}PB|n@W$xwt zJPj`vKEu$`F{&T(G*l-Ui(KW!nz-ztuqiyF2j}L}5#HlM@A4m|31aX7_|^98c>6E? zIQymkGpVxwd{;Q1H%Z4;>sN~!C`Mmsy>*?BsRi>9yx?l=(<0u>*Qb>tD8q$g=i!IT z^qVw0@DTmFK4i+I6q8R|bv~j**I!dT@ElX>lCuA#P*wCRLx8Rd!DaiOsA;V(y53I( z^c>_W+yg`*?85Q(z-YMl!siJT<6Pd(!HH(c=7X*Rw#^`=L z@0T9}zf#FIXC13+T-=9ej984}(d2h?Q5wOVKF3IvU1PCd2f7)80=8<-Ua{jFx-I{W z(3tuJ5^>Nv3NmO*(LM{e)ZVwedx!TZC;3eiL_hAR@J_-o1h<k3i(iE`k>-$SrD)1g&^@{Uw_s4G3a@~$ zmju2th!5^K=3iPUg{7Y9PU%$)S+?o@5FV|6vaDP~hIshN8)tczmXtGaR1=r8G;CBo zfLwq*s2wb<7B0Zv&&Y#xx3J`DY*{uy1`q46wL|Ku(;Iex(1Z#J?<;_Oe3H>+iXLD{O|RJ4P7TMwT!sj!d1&|5=oO~n70>E4=Mw)QvF7DQ zt6bE?ua?FJ6HQ^O7}~k2fEJy;usaM~P#Y`NuNJdXzu^bj(SUlA=Z`&7nH>~%J`w4kNT+Y_86xUGvXf?F|=}Wsz6`qkMm#L-K zgf7K3T6{$foz8w$c!bFAuWGs9W6P8BBSAhygFa%EuLBbQ*2QQRa3Ts6sEz_v1VB-x zys|dBFtLz?rz8KNU0#Clq(OKrSfbxp%OaC1j`K^J*&nAQ*l)$;WerSxe^mDxq&>sa zu5kh+^%vC5iwmaT&(HyYa&YC1J7{C_4M3bqwDjMaP#=d3WhRHr5kEO(j5EUo^!p=IoEy8xzGE2CwXz;U=iuwYb-j)XDWW>jGNfvf=n;XqwO$W zMt3tO4H-x(EB!uZsZz^M!w!9!wnt`{MhnOE0So$JP*ey102V58Zq@zA?~_r%V=2pQ z&To2RkT^Si(G~s8tdE;MTtaUx-$sN9I$FaaO+ArCH&U-0geUA*>Y&`VL99y}!jj}Y zw&GSz&U=OmJqKd3zGiO-lC08Kgn;I=2XG$p>GNW%IwFylv$6a%auyauZF0J zGXJug!RCr3FJ$lFd8XQsv>t4%J4L;!@r1m9aBFssiEV36g>RlgEYv~^!akV~j(b<= zwj;cl3Ml}+E#T?yD2r{CJJpDp5q+OM{o2uvYrPcAAid@Iiyf@a+X>lVVVW* z7?GilbS7MyS^5YMF8(NL6RUe~L^iTB4QCW(YqdotR#;7OC}jP9-l8z~qnQbE`@+Sk zIB;(KyS3l>Y4xTjA2-!x;NoJ_nxgP5&;4$$fBGbOH_S8gNK4a;N%G1z%(Jf-57fB8^4@(cM%cS(~?r#{L$C4tKU;lG9C^VdW2pc z=X&Zn7MIH-8`uT)-}0VKm!m5`cP--Ir=Ls+j9XYX-as3YNi~5F!lQj{$osoc)z?O@ zAgdQ6x+tqKzhRnrn!~OA(X9BJDC7pv<&7rHT?%U#i_3ah)3VCcya!m9AJ)F&m55es z=_$f0Q{oHV_`zzBuqu_A=X=TRK?ZH5QmG(Q7I!E@xd+gEd0*gi15%>AXCY6J3#!7* zE_<9=>-_Lh=-V z&M~}IYz>Y2^&z(~dHNYQhBVUn0h;Z4R_cvlB zs&q;XX@{W@h)?AR;P80s@=&p0jE z063v}1qv}#m`kGYaI2(T)az#V4AkJ~6&{9#Mc}cn8Kz)v4|2Y2oz%C_!`AnMt4QaW z50~~@&cjz~)UD&w^;u&33qB@fe1n2CnlrxD`{%B_CN;SX@%+q$t zc{ikl4ncHoM9*`CrN1xqxWLsjK!bzRon{k)cbV7o9Ji*IN>d#{TG?>{r?I;yw=yjXgd+v&hm8b?At=U(SuZR9$Jha05Q zu!;@mIyX2fOXSgPBX+~=}b+2k8bZQ?J zPHjA|Q)S=jT{>#Ejc|T>#u-n!-T~*xys`?e) zLwnPiP#jiAd=nDJ^2oT}B2+c_&bs!N`Dokc6_Ivqzy+KcJW*TG6Q|Med@Ret)wfX+;xU4|K*}+*F6jSx-558S2iuRs*%I|f-KQ2iS)7UfQ^Lc*6x}jS*iVpQo+Bn8!iHA0yWB(s_Z;rH^rF2 zIQR1i<}~@*CA0Z4osqZJ3B^o&U_iQ>ElE*c3#%r6&hQdn5;R(4IayQz_p0O7Ehwi8 zVi6{z)>zoV&aeGQ0+RM{F!jN&Z;oTL9-ER*i(NY#PH6#ihHL1aM)Y@da=2>O3iN|3 z+m^b=(%!Wg`SH_+A!N%)+(Wq+1jjQYqQkcXNSwCKo|=T3v=%@6ds|qX$m-9&utaW3 zRR~#bD1a0i*3wIq4!X#YTp|xS4xVD>Xr;O3$m}5(pot67tHFk8&Lb+!M>2hO6-~c> z9`7j?fW-!IxbBK=%P%7Eg^~F7me2rX#Wjz_TzhjWv+F)bS6oQV91J~k^rcDIWv%{b z>Q$*Rk8_dEEa;ZaONQ% z&|jwahS7_RhOKGtfTk!%BpT%b_)YbMu8tR}?PKBAh=Cc4@n;ZbdLzUI|&7%y`} z3?r6y;d}sJ`jUuLK!Lc%u0=WLeOW7>qLY$Gh>W@|)leMcwa;``N^pPvFn&M3w_Ex( zz$%qCQDrV>oe4D{l){m+9DSlj-Kh^R^{{yx+tQAi8GPytj=8+Z*0+!1R}Po2*KmWW zq!JC39o<2$lIf;J-Wf!(zE_0|ff1BXW9k8dEH^n$!UDHgU7F+WjxW4t#+j6p6RDM^ zspg-#e9HJ_ow*DxGHLwRGm@%7O-Yog{Q9m&QSmMo_T%LurP{QwMuqACxe01$!Bs{& zd)m$HF1`sJcGzk&{Q^$+i&3XIUTLnSsI9Ew6?V+)1fdf7+kTLZ-ub6eyp$*?@wW_h z+wgTwo+v#+f~9!SJ$&INEqw7)aeYOtm(!a?_eIP5}f4gAkG|dkIAN zXL;j#9#?JkjQ1|(E7%jcGkMSekJ?D7T>JBbSC~bPvcZ@j1)_&CrYAr-?ySuezf5)D z+fo@!>m5dy8t5+V2&HyjO+eiaR|v9`GT9~FGAe4FT+Sz>%I*QNC6}Q$1F*mB-$^-! zlwauS8z=`&N&Q**sgZxXOv_u9mrw03P>);GbN$s@>`WqUi~Mh%h_KYFW0#H(Yyv4c zHO7=N(#25pbOw{QX54U($U-Zdd3$Q>cmR(@QFNWjg1f9^m$GwmKzd@`>yN$`U;e%BL~087d!GE^ohOQ3W_YpcICHF)%2Ckr>=CQ!lOTcB)O~O)+uE4{s?ve$xt& zmK%`vXM3NjO=cAq`S`4@_ksX+f^nF0y7n1QWfcTh4XS|s5G_z1bwc&r9>dCjb!T+D z(?agQn>=w`X_Ga2_PXIyf*rDhE`{!4>9(`Z3xUoPC628xnSo&fKq@@` zxv;U8*dL^#1nxyAr*28K>>P60Y>-peKfzwa|51heNi(o-d+wP!k(y+`N+paBMqFQX$ke>|=kpN<)cdDakFWu$+ z82+~Z1mv9)r@@!dQ1j`>$VJPLx-elXop_Q*NuM9P&Q1Qd$gMl@(am1zBzoYiD3Qkh z_Y9k7I0kFf*!c`5xPbQW+V8hALweHw7`ns>$>wWoY>pA-7xd*n35wJGXB$Df^v9uY zN_$_frgPx_EGv^$7t9FagA?l!2lD~tAb4zAH}mDLXTN5b3;_Q%K@;qlB6_r_=RCm@jUK-?SZ zmTP_{!Vnx{hd_c;JEE3VFxS7AkQjip46sGb@3^P+bNKJ!vG&8|LbRRK+ziUlyw1G9 z^XrG1D_E@)j0Oq_YY60OoNnLfZ5wW0WWvzzPf7RDD^P zF4WO~8|2glvw%PCA`YY~menHO%vCYaXng6X_)n_@24b}S4=||H-J8XlYb)D3IsCN(2I+tiju3?$n&rWs6n3cPRadX-%SML@)35 yhBw=ymNf*nZilV+@u&ESJ_Zc)|Myk#IgaXV_igN6&8emVK9>!V1~2uUWBv!%GJyvG From 575676debff08b420cdeaaa6ecf3774491ccf73a Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:14:06 +0530 Subject: [PATCH 036/115] add back the deleted logo --- registry/azure-cosmos/logo.png | Bin 0 -> 38264 bytes registry/registry-automation-test/logo.png | Bin 0 -> 38264 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 registry/azure-cosmos/logo.png create mode 100644 registry/registry-automation-test/logo.png diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..001667d864a9bb07f7389f2534dec3a2514e86eb GIT binary patch literal 38264 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 literal 0 HcmV?d00001 diff --git a/registry/registry-automation-test/logo.png b/registry/registry-automation-test/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..001667d864a9bb07f7389f2534dec3a2514e86eb GIT binary patch literal 38264 zcmb?iWmjBHkjCAe;O?Ff+}+*X2@>2TxVw9BcXt?MaDvMK!3pjVB(TG~XaB)|m~+p$ zx2L=Msj4pRC>14XRHRQx5D*ZkvN95C5D-x85D<_?2yoyxIY%_B;0L0UjIJvL1Tyx= z4-z6fmjD8S970w?RKqLxtk=88K-#_*cf> z9Dzsw4Wjwu0g+#vvhZ*s!Z@M{#U`B{#X}n z;;bpsnS(#AXZAnr)HcxuT-_)EVvB;R+9s)#&HN-OAE-XV7X)3q!D4dD&x=LN(Kj>> z{kLR!!UrYZ9yS%IFwsarPe$VZ$R-1?$Tw4MG{zjd_bD^a?Z)w5oAQH1U=%)kete3Y zs{ng>ejLIi9*e1BgxC$3AmxG`*x2%+3J5y!UB(_uE-UNp;rP(~4;=f3z+g+SbwyBw z;>Ro-S15($BC)Oc)IZ;wd`yY`-{&kY0A^k`IvEg{No*&n4vEmMLV6Mk%O$O9FsL&0>A+O7^M>}wm%|1ykay7Wdc-_~U?q>BdE zg==CAr%G5zb-UzLYfPL4ed^=y{!z07Uh6ZEi{h-9%`Ae|0%A_SZgZ94l*(CY@Z$2o4h2MB#oN}TsG z38B8H?YB*XEyP#t)CVi+RC{tiH&9m3Tnxbn>z=Qeu6^_XOc#sxR*7FDue5({Y?kQ< z0sakillf)Z1-e8lxK$Z`h?^TeST+@M6n#IZknAeLyb6-wut7joV+i&6A=Y1K{WqJ> z6(PZF%W9W&g!GY98p37fg_-+;m>0_59DnJ*nqv?U;6U>hS^8p6!Q>(@rlNW`EioBZLYJyAeAsd`v=;3^Lq* z+WzXeLubGk<_P>x)|MBzND|70>8%a7emKE4$hABks-{U!8PW&Vn!kc(zBKiNIR4Y? z)(=>sYr8*x@nL35{eh00y95A1x1i$2BW&o5-R^wf0x0`)kAg9_LIW><0+v@29hBJx zobT8NVkQCY=GiDnjDS6Q@SRWvkTYAZ@B#5W2Wz ziWCpZh7R*hoPghDqjbj#Tkz2_z7nV!`c^y~z!4r}Yh^o7qmo%FX@$woPtRFRj}pU< zOn^xM0jDueQSu{kV&h98c_RF%CNByx6dKeE4jTDc`GEST2IElw{WamFT|%_0npq2< zt~h*lX%@!vbDFQh76_RI!T6O8n%fqsxC18bRQ7ZSu~QU5@IN*O6!#{kgRbse&51i~ zQO(KM57-5zi9la?&RHyuaK~+v>=}n_ASQ9OpsJ}&cqi0CRZY?X7?wf7$;nM3st9FV zgM9*bdJsre`5jFO3plrF`D3-0pI8v1(H-fXosvmg!7B?~u6 zXb(VC^+Ih&DYd{Z2?RuXy&Dr0a9-d|zVwL9&l*<+nNAyMv~5l@j^D6`x(2PK8Xc*~ z_y3wl;w4{*$q;!&V#En@Hc?1L#Jv#_mCMTUM_M_!ecf|s+AqA2IyrXGVD-uj+9hb7 zXTZZ~(l9MW&{tWesKK>NN8%02WjyYCr%;{PAclG<-Y^QiEZR^A@+I@hrF(U%E!Vtz zgdf2+2levhFc)B&5=HlaRmo8?h5GyYR_;Bkm~$Y~4z?~J=&i?WNVJ3l8F)gqV`4Q0 zienr#1yvOJ%l@A#A|V2NNzx$#Pf=6~I6%TN(w*=99t3syswtIU&*!GrDbkayToH0G z^0lWc2B1tDE+r?ZRlUSQjUm6<1?9cabu9h98R9aGuR@=j8)%ETU!wFYEmxo6iV*ic zC|zMq(eEOWk?*wk%+@{T9S{SU2sL0>AOf&bM-I*<2Z$x$RX7oB$)T~JAS==~Qz%tn zSRnT3u@UyjBSZ>By>YyVcT}UFosQWO3P;Mvlm$k_p_Q-GruRq$(NR^sNAhAz;B-h} zYBX2LofrX#P?IWfT_mP#MSxIxPe@~CoDPn_P|$0r$*jf|lvQ}+x#>Ugpac*8_+r?w z7*E!;?{56@4CFnw+UYd6aP*v^q1B=Z(B47-#$T}Xu9#V{C?RDcVo``GnJYXgnG7W| zy8B}=PCs8)BTn`P1P5x#`z4ScIWS3gkAdjd{WF9)22ARrmZ!ZI(oHB405R1z`W^%x zG}EwDPA2HL2=Utr_Mn@Ff$1>H0%Y31$1`69_KwoMvqz9K2}j!^?!=(pYVjTGc=j;S zaBh0`bC~vln`osBZ5MLa!C|+EYoT~wGe#yF>4A{060w&dV+7K!#@M(_t!>jyhxEF3 zVl4Lt7b#*1){bgn<}Kuo;DkJPfK~% zfp&N>SV4jVHFuP1O?YYeb?)H@^`_r`gFWJPNEgrUEmz zhv2f?9o6(3)1R0imdF}RHyn0Orn!WGUN$IOi(h8RoNOl57;)*9Pty627w`c}jep-& zo>&82UpLVbTy_MRQQ%i%CButLIAX|6)K@YM$MxqNAiH(I1qx~h0uQO>@|=gIittZBa~0S!5)@pHlOgBV z?Fu(Yvy_HiXrXYiWtd@J`9T?lyL2HSYmQIvv)xU|^&lib{MJ0+4-;sQSHAkY@Ur@t zqCWO`VF5UY)Xw`V5#WWGwKzh5L}d@7OJ2mFU-OwsV}q?t{+ardGOD|v`#83=rgWiH zzI0kFCG0P{@T0>~EqekIoiaUq{5e$gdH!r;f46_MOj)emc5o8B+0VIUVuN(#~wti;_f=D4<|Shr7Zm7*jDP&hb%JrT=O(r~Ld7e9g<{VIdVhN61y z3zpgvUuD%N#tH2hK>hP!J_}ig16r5~cHt}Sm6{1`6)z&=I(0sctyD{-uk;XGSUft# z8uxTGVQVwTTwd9)BzAhV*pizVt%TV6Rd#;jtQ^Ji`Q4*|yHBOEea1p=k-`@RWTg2X zA09SqeTRB;7Nk<@k9GzF%F-O*J+5BY(*}MttkBC@-o~8zt@g=vnISJ8OV5uVzhMLo zO`L79>i9usF?b6TG+Mdh@^w79?s^3wvRxDOh4e;c&Z^j$?Dw2p;q((IWur%IM2s~X z0_7bhBikbM^ZfvSTD30C!FcDt#ito#|2|L<1UuHBfgY%BhNFlGfee6{XS1}q`TEw= zFS7*(&B5I-yDRH7{9;-TIEqGqC7mpYT*hV!_sAuk_(d0` z3-|s?qEo|1lRv3$;o@ty1iCx!R_7EP$rU7*C$8Oa!#2Yxzju1@w%?CfgBDy~Bj&gm zjIJYDWtjR25iT`#mQ#l0N{wwi@pq^q(5~b9bmVuNHf;~lYM}g~uZYNVrV%@3Z}lk6 zXuF;b{2P;_(&Ekc?@GD@Z zIiNQZ?`$G`$ER8O7wLs}P(K9gFn8{C(k!?wh+j{Y(gm~6@^cc3!r@4Am_exs zKqK4I(ZpQaQPS0?c>CG4&}|-9*1ee}jai+2Nx}3yz4M92&bky% zO6?8n%#jiYC*UWxfzPy@cL!+4i!b8+mv`BSt*^U@YP2w}7u|$Y`>x84t)|fHuOYvl zqm`%*`$uxurvA7webIdU$g*rqRx^6MavNK*2I|?YsPt8_F^4byCx)CPn>B&QZbMA* zu>cDWE?EkyqGDut+T}c+`iA}0q?&>=kRT4u&cc)PR^TS%+RC|?K;9rS!R*~y;Z9rg zlVWOr%DkaBzf|XM9|*70nbMnDr8Ys^EzeU7(W_6?9byv7oDuHHVKMw5tl1WYhlvs| zP+Xmg3r8MXqEv`HYZ8|KN&ZjdX+vj=3%k^`N;(Ui%w`KG`_1uN-5wtv61ZL}3k`ZG z*r1|dIoa~c;Ar;32`&U>=m?njpRr7l2tkaxp_nETsl1FR&{_Gpk8q_5u{XcL(GB{; zYXX6?{6}n!W#n9L#U=jAeU+pXO%V1Hb5&;@IN~no>wQP#%UQD{0kwr_k1SzLgNVPv zuIkcO+Gx`V8^fZN+y{ZxPmp_GcJrmk9ab){$i`bjhZ-R}^eonUDao}zsZAD(^U&fq zdk!P3{#QG{>GaOQn$9dYecI=A+KQtf#4zU|ssTvNd`T}nFQ@|s6EZ+RP>3XtOwiCL zc2+%+$UpX}n;I1$qRSWX# zK1OfKj~#A>U%gN=H?oE0r#dx;M}CUI8)6l08193p@)&RS*8f+!lmDdlO;WQmT&-M5 zAViHxv1@m%#R-*TiO8sm&Z3Db>vbLb=uq1sJ7vNmvQ3!d zcvBm1N125mi5+aW7VOKE^PS(4E*07*;TF1l0w4$B$27!~c0iT^NXMJciI_&5Z=`6-@uJ|k*MDm$73mh|$a$p2yi*i}6T*_JMf<)8;Qw2zd> zP7%CYWy#;zfl2-2_6>Od>uuAwh9kTR-$xc`iwM>qS3{Itjc-n>eiaqEJ6J@HO|Jx! z9D!}KGFj%*H~68x%E|sN%DJg_vJH;x%2F&#T!a)0Hlp29Vzjn8vOznYYmJKKYyu5V zOJknu3{TFaj%dIR|D#W91x^+Iv(*f!X+*ExKrKO@_)x zA8Jag!Riy*4E+~tVjhq0?LZ=5-q&%i>haYKme8Aj>=KzzxrF-Lj(EK$<$V6u2!^E7K>O+i-#SArOW^{w44U6 z7EUpEzNGT=285stJCH#9_-v@Hg1KNZ>QVP_TWkDJ=g34CCe$PF4t9sc@0&QrUCs9~ zstWdg4KMkfJqZS!#wk5qVJ|#-JKZgfpeuyRWPU z6&~T~e<~c?cdMwy@pvC4zuG6<_o1vel-Uyl8{*B|8%gpsPp4)+bEtk*O9v|i3cBXR zZdTg9Pa}#F1Gc)vy-~EmU=n=aG|-6mPzahULHm5kvN91p>Pjj#$fHHIFAo5`@XM~g zSY_Tjw;5U>@q-&(z^r@1X@~l~=q0RPFrQ~7yyAX+1NMF4wEK_|g~(uUumLil@`M*JsGkW9QPEH8og4@JKZ0v8Ge;L5ZwLNe4}SW4$u>OA`W5tJ#w(3 z90>3&aN0!jws{xYDxaX!;F*u-mOz9t>NCsqKEJv={z&5S4K1ljJoOA%0G}_J=#6dV z6{c_MjG4{GgZnAAm7z_A7Wv92TxI@9Oc#dAkwh(5{?_HDGT6xTQ;gLJ5B=nJWfnu) zz8{JB!-dH4sP$ZrnN>9Lm(-a~HsJz~M_vtfGc|3HxpMX)NzJ#VORTbAJOizIe>c$!1Y)!DR>&if<2Ax6&I zZ1#`q6~4`@f{HRYG(z8r`tO$!rR0iAq8M+KUHgp8cRAfAdKcv65_=_pFQx3T3a+4d zWKWvNdoq&;o9*30F2hEHQU0c9Xg}_OF^JMERRP0E>DWwaRsrn!DFatKr5=j?DvwR6 zO;P^tD%zE>R33!a8b3AP@5A-M^)UR~^v1uF-c>rDHoj%eWP#e3nP!C9C3_w{aLbL$*qmuARd?&ddo__*N4`aB z-!j%74qxO%pkNMQE#?dMq1y}0LfMPgz$j%L4Yl|=5VO?sH#aQ>2yXsYX5oGPoIvka zpOl9*LiyU?3-48h?FT3g zBBrbbn|9f)fmzZ)R$hYzRJnC0u4V{becVOzx5HMrBtbvHzs> z(^zL8bdUX*zHD4egh7WB$PrsLnmJ8JIdgA&4L8$=do?612?(eEA#dxa75N5KdFl6w zkLxNke(5L{8}-{Pa?iV;TBbVc_d`K@ks%sAjew}iK^$UpSvqGsOeU%A@Age_o|Zy` zFos0~7gYe{P6kZ=K3yLs5RD4y6{f;BLI*Q{oJsgpLBVn>@R%_4Mi^>m^=A$HiMvke zzwpdRxA?iUCl`)jd>^il`WdQ z9{lnPi60JnfK_03WC)`s%N_ zNmmznqLD=#u~%L(y>Kx0Hl@nSo*yMNXEf47?h4`0C07Hj?}LJQQ8vBm_uD9jXIBrwhU9`C$EcQU-+ z^P5dxV&5*dI%DC3$XW;Q;o44Pg*>IP-@@+Pa)|-~kg5TOD>9vF@}<9moI)Rsec%}0 zI7HHUMq=)fiKMO7eOPDWYcA@Yo5hE}6)UyTCQr*?vEt6{PP9bsnZCresM^t8H=QsD znDxa5idry@ZwXnoXF4Mj%3^TF*C2VsKG+!tz^_tP-F(t80z#-kqLhcNbtXQELn23r z;h|=bf**%yp;HrZ`}1N1tCZn1KgsqcR&sS6JftY2Z$fSuyJ~NdVrG05eYIZi-SRcs zp|6O;3>aZa=Rm4PSr$crS$>SDtDu4cgy$%TwOo3m$e4_d+BrhnwNEb&zBPPH4#asD zEYCKZRS7o#syesn6P{g{nmxXba@(`xHk;MOcd6B~q6tT@jvR&){1lIL)US${QK~G+iNVIvd1}Y zw4@`l_~=jQo4*?W*9+htEN*)7%g<$CQ0wW=4IS)L85Zj7Yf~->QAMjHQhK%uMm}zK z5z6|@r7BKG;xjPCR)}y+C_rvw@GbcdM=+c{6a`FWOZA^s*rjI)6&*}RrAtsy-9IP+ zFip1H*DcGeymf0LmyueY10@AimYBZSQii8<*iTELQm8Yii|0flG=j{LE0D}03*_#T z48}NI#gq(ktxivvfiucn*{EY_BXZ{R5Sps4USi&NB0Efay8~&Neh;molEDK|S`*5Wp!AcE9b*IX_1^JqX%5qdH*(S=;`s|#K z(h_UF6p=b#lEK`H;{*;v*FdxQ<@`DA_5h3XlQ)*PUUfBQ5Va+yx~;vIlGiu~uTiHE zFe+wYiVR8q>vT3{kO(Wyz8WAm=*J#j$y3~3xYvz}=-cghR0 zmGR%o=aHD^x;*!&w9b)uLm-}v6~D7_{ByV}Grzebzl1!O|E0$BQD&Xf8UF3SWY#DB zoMExH;n*y~C@WWDv9j!)N=uJ3(^5TdAOtChqK zF8t_y%oJCGvQXrW zno|Z@pMYxCvSy<)2NI!)G!~RX#6xne4=|XP9<1BJsJupxJ)-ehDU_Q#ntCu6)Y!Ss zuQ!9j{nr`j|HkDL^tsK$rA9dwN=$o}^w{asfky)V;POR&9Xlp_`rQGw6LrBiprLI$ zd}6l&)D{KCsDv!huza()f`&iMR00PI5fVO^v*~KaM2e)mOB?MQW7fY;LpID)A)lnK zhkUuiA!bcbU%FA$Oq?@}t>f@8f&}d>!A`Wfj%@4QA+Mcg{BM5S#06~&%C-8L;=$a( ztHgZIz#$UT^b@Cpe z#LZ9cFg{@eBGn`E1{xjB^mWzQCu=!HLo5a;s>$RA$+Um79flvHikXerE8PiVyUM(x zW?hr2;v*G*)!KIuYo{>ir4gs?RU;7B=GX4;6i#dq6;hjlxhy#ZS-&YTmXj|$P-E~5 zyVvxG)gemw_rQP8ERTI&D|NH^T+k8f$7fm`h^>v2^{RWFT5HYVHBU&=nl zwm3YO>Q=)jo+jg>w}yW@FA8!TQTI;T6-Nv4op|j8&P4TL9sVPD6fHCQy{@)>aD@Z5 zlU#n!OU=CB4cm@}<--)lZqi)U$X@0QmA_wjFfY)c@|NCXI|9`OR=ySFUwmYBn82Rz zDDBN_2%ufV3(gc}har@WL|_WPLr*W|&>x&BDVYbs@|LPuM8{F9V)Yi4$LCENOY}(a zgKU5dGfG^vLNznp`A&$jT}$S;5eZFXFOJg>B*oCqzbU$WGQOQ+^0FXbj&dzKy+J+auIo9ywmIZy?!ygL- zr#6D#o@?;@u?`=+7vaZ{_{F78!A0 z88&^5lJW+bv>LjePL4SEr}y=|*BC-XZQ+n4s z%{tOW1XtUiMD@FkZZpLz-TS?Yga#|6XeK2xt0$X&3!|bEXgp?Oq__QNP`=*QxlUOy zT#dHFlcr3<@0Kz}I|XmPcrZh=fG>_Dlxfe%m_`J+GTtcRy;qMFPIKg8c9|0`hVcUm|{wvp+;%9;#ll;+ophgf!`kHa6wJO3H~XR7k2EC*0*${4a?jmiVqW%%?MVOPD5Osa8rw%zaAFGyyTi+ z))%@ggJj(N@v3Xb0G+r7VP=ZTrjO|70;E2L}xW(;K(vPDRR`znvxL|gquScMgX})R5o~LCs4IT zZMN1hbw0V-=6$9E#Nf@SyUj>Us&tSxE{7F|{LbtCLwAj^$Y^3;ZLl#Wf-~>|edTx7 zxd$`qTAe6{6C?YETsxxx(?oCW-SIK25cFOa@6>po!gedpc0= z-ES_k*t;W^);`T);v;Ndya(@i}ittJNdm-o!i_-u7d|gyhgqKUnWNf zX<6W@v5DZx8`BFi@tZkz$OsNs>&-xX>$>B4?h-a9R4AlD2gl^bVAj91Owul&g;T1DcqC$t zlT&N0`1@nq9!8dpNUVB3C1M#t;na)oST(axP<;i99da_U}V z5ke(rdsU9ohD$W?UxwDmYrrkyvsz^lnv0vNZe_VKG{+g@#jN4+AM!SZs+AVqWAQd~ zCf%}12$%s`#AtDh+PH^oF8=)G16S^vy{LO`UOa`neu5fTne_mlQn~cbwYM9KT%@c2 zfn)rF;nU;q;Sn?NGsu+V={9(!^R8<}LpZc;tCemMs;XG6m0oGt-A#tByOL8KU_Vq0 z_+Zy=8`YSd*S+CK+4x@Er)Xf=>Yr?{(Kp@EZS=}`{4Hx)z-}!`#=*EYcOB7H@j31@ zMlDY^GLN}tHfism8-HSX3-dXmj=stScq|S>P$?c zgwS37;2K4Kw;^SxnEGrNeUd(UyUrYe?&ygPsLmh1&U8Yo2c1huIMl}2IsuwB&Ne$Z zBlJ2@C4o_#B|_S|9pW$Gs{=JIsvxHR7A3T))uzR9?6RVQ*E?QW@CTOz@7S>3@I~Xf z_+Qn$&l7Y=s;U#dL^yqOA7Kb)gnhWprnlAVp^n6CbSS>g8lrq~QdNT|#ixt!q>wEd zq2Pn+?zI&NhB4i1X*a9Q4}lY-JshgYLEC|yOsG1OPqUX>W+6ZeC0Ay)^HP&T#clxutlew*-a=-xvF5c*D#?;bS>92=?V0)2zN&gO%Op~dNV%tWXcCgqyUNi$oIVAbMbGb}z zA$(E2l1La5fKFE#RFr@ApOigdolBd{uLj9_=7+D3tJYrNF}#1daMyTJr$E`S=zgY; z+EH-2h+@-q<-7`s=k75KVF$v}+ktkBc0eluv&KS#>R|h%{OxwSd8@0@3q#`Edx4` z;APyDv=>0;m3XHb-1waS@^A<9ws3k(7Oq{3>s9-+kbe>jmtxdWemC_%v}hoT zKC6PD0*8nafQM05;6-bGvRk_7O^0Hq`KkvrRhp_@ZamQ(5f8Q*ytAbL5y|efIH*e6 zS~+YGgFR_{t~1p&%ApG+j#{damw-u|ka7ixtY3%oeo{pZ=NueyT}JVAG9*YFB(8^2 za_Bso?}~c&JUa6Jxzs1v8v^!D14KoPLz zz7`;OP1$x81(JdZwu_Gu@6dn|G3d}C#0F(ddUBx`$G=#`sfuD_%5VrT8)U88+2%o4 zZ=FH187XjrlYz~ZD-OT=da3>a!X6vIwOC1g;WW`uXvx2P;O6T8NO*_weGWlC)1~|K zC1}jq#7*jf&7oVIYglS~J%I(q-q|b)Q9Fx5VQPkpffWlB4b;BYtW^&%0~&#hnIe&k zqdmK8!n6FF`iZGc&6|uV8<&O`4ILe;oqZv`yi1)hW;IYN9HJsMy8?0{O{w)KT0$Xl zqMfMgi3zk1Q4s2dDPqb;y@I;mZ!2HhnwO_H7cSb2{zdlT|CPyE4(NOWhhZ=0tv6mo ze!f01!ci*=WEJ_!P0A4YC%GuWju%ODRoXp>oF zLv*jXq5@JizEAI2=xJ0{JEx3PHDE@LApN9h@wIs3lN`66YQ2c%95_U_h8*6&j;X zJsR`L?19n4td!Bd>e`OF&N~E&5I3^vyeX{h029!4LgYh~Kl!fN*md2E3fX3f60&)k} zJ9I1PPZbzZNW}bYKCb3xUfEb|;T_c(?#`A521O%yaCK-vA?0auy_{yXc1UxUOamk( zJv^5=XWQi|)Um$@`s?982VYG)Er9vJ_kZ)#$of9;N8m1w?8M0*OSO0UqG{#G4SRIu zV-ozYzCOrcbJja;<3ly}R5v9Z7A`K_h$0OL7&3Ptn`@&a#2<=~@c;bv>*zVqo?o{| zqTZ${ES@FzWRr;@-J$Wb?47s&pqlbzg(;40qu+Ejfk)b3sGvAxF;-rR=|jnBbZqZ3 zpa>t2=bnw10E^+OlI4>cD})i#dK;6;`}w-^%`NxS!yN&*uI7`&&I4~z`D7ll_FDqi6zr!I-<-alP*OaEx-Jv;E>v0i}<_)=~5K?{_gK2W2&+{R?64(3u`zh_Q384eZvIO_d z3;`WKHSj(|iA?aXI~a&b&EG_rhymg%;x;jJrrmtXo*uB@@;tb9sTnDY>h?(d_ny9J z%15j=G?Ua~u`Q*!p!NqX7S%3$M(58D39VT9QMQg;$_3Q4nwwcl`Nn%p19y{tOwLYS zJ+s&z`drV$ekPEc95H@h>n&z+ZZ`~ZOaBUKEiD{WE1qWeqo8f5z5MHksX*sCg(W9q zO7TpAk#7~J8K-50nyLxeDJy(GNng9B1$WkYlHtl~W%*AAoxIVG$jjHsH4Pho)+2r? znl(6@k!Uo7nnIS8kmn%j=h?p3pC{&Gy8@KP?2GYQO>gWp|2WOG!aEFZcYy=wOM-5} zo&busP{277?;_fJ{?@QH7>IGp?ggxHHb|?r?lUxjwq~;hn|=!Fs?stHEbFDrUjvRz zYL1Q_{&ZXE$3$T70Y_7E`1oQ&G2XT#&Y${ZD$nk~Y~e^xQ}P2elskfYkJ zBx9RuqiJrI#EzJzJplm7V_RqX(<(B$NY9(z>EtHSGcU{ZIx>T`Hwdm1r(W-Clg*ok zp#5fP8W?FG_C%+2qA8yUsu!lC=eiov^52w$^{02dO9Sm%+TEXsjavZB0d zL+!JF$s2WR`4l0$9_cdC2vudn@^*D{oZlp1W84)URFT|K&E(&5fT#_YwgW^;3LMGz zyQLXpWx?k3aQZ(Y%GCmA;M#un#Bl%9S)TX1WD~x%bNn6=sQi78i#vm%R*lkgFZm1OGbPQp{(q$>7Y9-LY*6KPfIobzHWGSBj%0CCi*2 zHf>VF&I==Q21(;xqeHd{9I-fgXWjPcSNwG4{)eUTh`*d1l~`$?zKT-nKmKU|z~gea zQM6zI483>MzvfXrwYBaX>wcV?q?gYll-o5EWohVNiHT7bRn8l^X~`?vXYOd6rhBeKS#oCHAEG0^AMAfd4)66k z)(q#|LGHhfiAYy2oB6n;l{b_FYvd^Zu2l%YOieHhMwu17MIE2q5?XTSF<~k zK*YgHP1A}FYP>5rI?Ag(&|pQ=C>3GqkOa(c5KNBZ(WLP>aHLba6nUt=1?@0q>suO6!O6_~!yk=DtSX_%u6|iJa+!`~ws!wGyIS>So z+?j!3<0Bltekb3y1cvYXp>-T#Cb|vqg4(}--!MM=r7~}Tmb-PB*%x3Fd)W%^4!Ya} z8}RmylX7{Hc8JCq0xTE=Eoq|0YBmx3cbz3HhniSP`*!i%j@{N0wcY*SGQP6ABhlqs zG)qgI&4w!+L`5Sw%ysU@P*F;MzwB|G4?)Zb(VEa1PoEbTG>Mw<8s=tnsb99-7v4sJTw4J~~AFwrEepgg=K zE;GIX@?^q+6P~LE-h-{emgkFcj9J#j{H}mg{w8eq>?n`nd!|)gB(C^X z425CEe`gAQW94rf1Sn)*An8VLE8>pnWP38rDrkd=0V6Gy(RjP}o8{~-xvubXL(&1e zj_(|a=|=@!j*j-4TeZG!US2=?@w_x&=|oReyoz-8p??cVk=lXf@9iT`bBUqEENY?H zQv8+An)r7-A|Xzz=kk+Y>xgpe;z4&jzq$goO|6YJ875tuu{?w>a5tL9)=M__JR70W zPo~MKP*0jTcoa*-oiu2GfeA|3xm_6%TK5Z|jD=t(_&O*TU(Q#CS3J4Zw$U(WOrd{g zFv8#UiT?LK@#W7QpI?%7hG{c8QC2L;Ho1f{c=Ybgh*oXIH!_+0<`)@bb$3adGC1jXc}`QY5T!-o z&a^z0TEl~RZESJfl8-7NCOtC$TAM`W;0Roh{`(zUd6pb27fXazPsVTIkHtBf&|Ete zc9MzC<|z(2V%!>_d~Sn){{_5UlQ8QKMxa@Q1}+U+&KRytdLE%Gi##?iD{i1@tC1!j zO|)>c{Tj3B$eB-la(M=#gg7Q|ZA)p>IfWnx!V|wHUVE$QP7>7XQ@hqUm4gFt!Sk<0 zUHR7zd(TgmiV(R9Uo#eMxn0z->Dwy#aAhQZQuDT$J2PZO)`y*bHnuZ1G+zpVc1vHM7i`7C2-m9qZFE{Fc{? ztqml-rERpH>!0f&QlxLAyI5ygD*~__W@EEGY-Cn-a2)|Nouy&a{-G%F{ZNcKF)%tj zMs8w=&(i64Q%~I4E6QD%X~WS7yTspNd;OIJ3&31%7jmFhA!lq#4wV|OQ(|7?OP6tKvA5D<44dWz zpC#qFnk5Y4Ngg_FqrtZ8MsQ8%XD!pKD0PkPc}8&eyOp?zD2wEH_1QOdTh4q z+8;?;^6bD9JzLn>z+i#S=d$t8tzy^lGBOXYdHzJm#HUj*1Ui#q9{u8iouu45bREKb(80m_5R( zg2$XwlAO1?m+ZW@oAT69Q`dptSthbW6id0zB}G~xfNz4l1u^(3k-?m5ssoquwUI6W zzoFvl1eZAn>%B3$}WRK%2cQLUYU+s}KMsQ(4-6XB~Uhaqvy^TT|0a41bmwMd}|vNnQLnE{fjrhq_! zh|9kr+DZHtFQdG+{E4ek#t&=FHD5b*@@}%1^r9Q*yty#&)DO0^_%RbN8-d5B>=&^^?_$~g)FKxQ#N(;&Kjc#Aj`B5wIL zg9pnQ0^uce8gW@I!qvaZH+w$lK^-_frp!8+#z!%CH3;O@nE72TP^C}9Y@)5tyR7}W zQLA0ELw={#Qw1{_xsy8$y#JtyoaXyJx)Xv7qYm-A5081YC#_aFv_1};bvtR4iB&NQcmhZKZgL(|UWqZI-`hi37&F5(%aBnczW(s!G2GiMm z`)}y_BOIlMj`msCm74_lfu}h`P+$aMIM=bKj}=(#>y{{-(*rrdQO zhtcG8j})eh{fE~wrn1Pi4L|ic=rrD!7M*!jX@Nlhw71t0Y<5A>LFa*yw2T3dy?>HX zePCJ_ouLZ5aU&ZfzcYp1a(}Ng`KUkSI7PpmhbHY0Y#4r$4%7qeM0$0QS2R?=i~jhj zvhE(&;O`(ZIaUlmJNkt};4Q!)Ng1k(Z5TqGQ?I&4qKx1sak^~3W&A_H#wN<5Ui@s; zXe*P8mX-!9#qafJ-OwN9Ke1?`wrRyenskZ&s-l9Xr##15ogc+KR{8du=9V`xB#mF- zOdkGBc3;zMcY85#pO8&*E(Eb=e!%TsygT0>ajHrE<=`~MWA0rENK1{~y2YfZ3+9+Rw0Up5SeEfeo!4C-h1>89YU^78Q1A}G_n z-=64fh&IK(rF3*$Cs)~jc$Lg@in9`!DW?|QO%qSV-1u+sqx9RP;(uNmddo0RiE#K= zr28-0pEGfZM?+7$I^eMhnV@;5YMSq5ZXFlOD#Y28iFmO{idpMfP;z)s5d)1OG8*2mOnG z7;zJO9dI=@V?MQVTjU1RCvAG{Y2;d2^zrM7SoP$!f3hvzsd#Z(4%={|*wohYh* zoyMtmu-84gNrNaj|G|G*qAbpPl49Oz1xVJ zjL=j<88tmL2@)7@vAmg?%>yTb3UJ=%ZkaZ6*|EX*Uv%+)e4h%dfhFEi!XX{&?oDx? z%nt9cNW-&>`Tv}EBMHw>NtHVj%{te~y4tT^EI&KGKv?UlnN)Y+Nr0n=Ue=fi=AGtv z3nDy2@4vnN)%fTehXKQmh8#4?9UnN#Z@Mc({J38$++M6lm)n{8vsH!#!;?N`tTz!^ zOn*|!gNyW4Br$ZIu*;NRDU)KlsAPPW+;DWW6YWnQtP`1KhSJ28Urcsw4DLJWaO48T zSKaXbYc-bGuU1Z?iFf|2YbSn+;iR~QwsB%DwK9y;4_e95|H&9W3L79!eauyH$Ei^i zl$fbz2Tk_zxyc6+W89}M7!3VrI?zGb( z8jp7#OeF)^~X!@oAuq^^KE< zt*&CW_FDO}amuKqcQTVkOX5h(!AxEkZ@+Hkdb*ZMBtb>I=WxmJWw+?=1fx~o==#-8 zklv+D=hCns$4`{a_tp0cpL~kV{{LZfRQvDG%e`8zr@O!Y@P4Qz4&#m$MsrZFS1PMK zm&#OCz3=fKN$k{V{nz#IO>`U<8FJm?iLK5^)as>{5F^hzwaMxKe1vRV!0@etc%rjo z_%iIiHW6m6C>PK4%*wh8_f5*Pq}I0I*Uw~gRw>lZyc-C2=f{lEfi5)T|IvUfA2sko zq4Tf@%dRKZ8=T+Df0`BM`crBH?BaVCW3ZG->rcA%)4n%QFyK7L+GYtKu3|$&ja;j z2PZk{GSMT#UI9_(_uoCgTFajUov61HdHMAzy0>rq7>>AZONPb8ji83BRkyl{8SSe>n~$#lcYZ1vQrOWN_w#M~M7}MSNaKUg z>5{Ympw1Uz^9O5YLHa%q@e)?SRdp3zI!sJO>GIc+5U`BPh-BiD^c^ZuXho%O6VJW5UPfJ*5l#su+i`UZeN zT%>%V1HRpg*-8;|A9tv)M+W4Y>;0N3$)S1S)E|5^qrZ?Z5h{(&e zKaYB+tzPB6kmM6_Tpm-3)t>hleR=AQ<3EAw{8zFFdRhbRiJh>#xA6!o-I6eibyA2+ z4M)h@sQTI`lilhr=|)V6Nf(zA`1;Hj|6;J*Oc75Kg5RF&h6302wGSQAkfW&c1(LR# z02M`tqtD)nMjMwzUN6t(wBdJ3WCzBx6e{R28zbKSrddJK`}#xWl}2Kg1QHgUrUg5v zf97_fs4=e-YRZ+PnHak*mdi9PrR&&47KDYU>Jr$q=!Rb;|TVwO$zDS*v zKZ4X-i>|c?ctmv2g)5#1Uvd^YsW+TQ1KS%=S0D{sJ8JEaC|NLWZg(NT4z6+O-5>8 zpFtn>etU7ixK7YHxt%&afmGHz87nC}Jv&;>wKp%rUkMHam5xZ(zMamP7GVjA<0s*8 zQlnkNWapjdgxlM}sr`EWA3xvH{fDF3qBEiI9!EKchmSWkc@b!RB@CZM z=ug$|?Y0O>)!rJomUAr7v797d#)}zktfR3VGl4TB?2&l(30TQ=s--z}p}Hz1Z+5#Z zC7B7VR+Q-)lrw_BC*AN)>|WBEe+TmXE#IO;s=B>gUCze)Gk+}oeLqy{aQkIpvY;&N z!+A1@)H>(2pcc^~qVQhzeUawAXYGnMREX=jG;yF^+kRA%@zfVnkqrY!O#;+KQ=xF%(I_bugFqjdGM{h`RG^kyf-)p~ZAFTjd^&dCrVmqMQGDSa(hpXQ0(ZH( zbS6i0b#z1M^F5aCyv1ZZKWgKkIi+HswHq>avnWX+#;B(*cBPJTt{KMP7*^2GAzdmq zOGOzId6hl9P zj^zHvimf5uwT@A+Tl|WMhxia{vOyL3R)zz#{7_S)Pr>rjWL~(+Y_lB^s@|v7p+rQ- zq(TH$WNFk(kI1UV`;S|ew6VA?rbE>2PJeR`Lk|AN3aRiU)+L}o`2cYd{j6b$01Nca zdqQn~eIJoi=6+BJ20dGxuAJ($v7p}4DyB@BL-h|UXx(^Nv{vKoznMJ!kQxhIvcynI zy~ZmHKT5&g$QLt#I3v3Bgd(&JPAO;soHVNQC<`zSNip-*cnB`PAB13PqwiBpq`KCCcorqLRz2;G zLGk72LMPw3N4{5qU)NsOLT7eb$drNh9}oGi*d;2%IEZxT5K87pA=o?oV%Gmep>M8^ z&?E3f*zOVqkwA=rfccP%g>CP7uqW(xd=Mx;3yKbVZdX05Cl(QB+jGzSNaT$C1NN#` z=FY>O@yQtb0H2KUk_?LE3I`v85@ZJ$=B!E2cg=K@);NR1CIj|19@DWz=^0?{eDbu(6?|!lh}_jW$;(64AKb96keF{ zsd1Ahpb$)YxjzvFRWSsG3T*v5s#5Km5Fe`S@MJR##(}LTB8W@wJW&7HwQkThvP3K*L;M8JSBF51Pr^X^5%gS*BEf0B`XdOQ0^s zb^We;V3h*(FEJI>K0Go~GZNwHmDAP~qisyi+bGOt2{U0%UV3z8L1!|WMDcfx7VVBP z_mWtUkLGFO{kz-h`X8rU@-;p=up@qXf|t?w=U1eFqSbH=_~C}c>-F&A2m{lVUYFCc@))#=Ylb80E3)bB(?sbZ(_Xk`J?0g@O49r zA;wQ14~fYR*+`;;2-2o1Zhav4L^r(}g`nwG2fPm~PzC;3enhhRklxf@T=WwPc0_k!fcwPVK{&I z=cn4c2%-Q|ur{eLjzm8Ed8bp6;F)sgY17{p|3MiHcRIxls?o;gj#+=TZY&Lq0{&+`@D!xo@k}K8*Qyu{jlczb%Ds6aBAaUGSMZR*AC;o z%aGdeN*$prJo!hvUYw#Yj=+Z*qV$?r=S??3*n%h5mn#-wU^Bg%6sl9P_di>NOF6Uo z?&EWXnz2s~IBaeaa3f~YR-5stpN;kB( zi69g?d_{Z$^~reL^`94X?)b@fuWLPL`2Wyku=f{eKqlmd(wl`;azb6tqBvYx`bN7pBjI|$C zr#J1fAT7=vUb+-B`99Bjqu}$@ zKiHmOlUG|A5?V4qA^3vyU~C3g5lEkxYtPd~1T$)BxIwtlpL>ppK31X6&C_l^pQoGl z?4NgcLW@)|r|+&gm)$K8{>we zni;t0ampV&`|;rE|2C_kyXsS|c501CgT$`u0F6uUZ*lk7RcSuDh%B4E^?W>A=8o8$ zzCg}y9gSEtNbnII@ld#NOItM<_bJ!^wP{k$f75DfuZVxw=b>TXao^_cr2Gbz1r^>A zw(3HI^GYKLh4-iKuCZhSgk;$r!avnbQEmLpO0@F8m9eP(4QJWn+NSfxWy72VxToMU za!sCzddBtx{`+#Le_OKKPIz_dXet)^zuHxZic#X$ZZ=Jj(}YQ`JJ?5-(_S|LZ}u5f zC?BqcgP)o|-`S{*0wklS#>3)uRKwrsOkzScbQ{`G?i51Ty^fd*2=ge zfP_;C$+b2nOv#CMn&bnyH%c_k(=UciXta#{ZZkG4VIvx9wQz4g107nNN6N9o!# z!2(fqGi?K3VZeK?i;(1PjmEIJHS^0oK~ib90~^WgAFv07HS3dF3FMkg5|_1Wp`{3| zjjXVt>}C){KVsv@`IITAo0`ji0UEl9U62z^N8}d$oGdS(R)pb0un7CgVnS?;`d~hB5Jqotnt$OKuF!z0N;DM8U^i~C>c zeJ$1&;K?OQoukadZ8wf*xUVB`C_tJ}?oi42<98bqt5!u3Z;iq=HGp9kRPsE~e5YU( zVV5j)Gg>|9r$D*-g5RV*>TYYOwO?3$9l%9KRaz!atx^oH_c z?GM3=@oi@_Ecx9~&oj}x{;#$YQQtX?qz3mq6^l`i+up^oq2DOg?H44+q%US)O^kim z>Ljf8+wB*TaCH6mUP&v(rvT29mUvu!=NWMoNs60dMTO|6a|m~s-ULO7WRnd^$>jx zHYg7I2>s3tI;79PFL3f5E}y&op>cn-c7o1w4%>Tq2jTj_m=`e-311Oyo62JvP<6Rw zZi$~+4kK_|$RJ2tm-o+4UCZ{@fA;)gV!Yx-3+!UFpnS20p0WMxtZS7$3g^C^eJAE@3^0xmayE&%KP`^bUGQuYPiCtF5 z*eSxBd2xq;Cl&De1g@@0=>k|#pP{`&GG#HX^4*p9HCmFOTW*h^0}Sk4s5}Z@6a~!S zwoHjYUYR!*=da*1cs*YWvNG{4g4EvE#{g~e>8b>r_&`z8a~xEr_dh(7&L^AW@+pZ{ zg>%!ldG?%A!q6D#apho`otj6+{uJ3$j-?|CUiLZo)`cB4M;kcfMsDiZMla>i{>%QZe< z#NfM#eWT%dD-58 z{dn`TdxqxB`i+v?B_CViJf9bx$O6D#MXjE>LaXFh|MI>1uMe@Ic*1G63JKu<#zAPbgx;SUw zNuqFyQ!85_kh(~v9X|DNdL`b6$`_d?j~}aSfTd*Zl8~W zLEsRSw@rAxF`X|JZLgc6oqi)}`SV59yF(t?h4v@4;==b)D9+Jv={hLbgu7(b@EhCx zkCxscdo1(Xc)}Jg5Fv`AR-k^8x{ud7Ph`5Q-r56TcT^{A?!lqT_r`Xm+1!~&~ zbI9cY9DpIVqT(rZZc{;e?oTC>k6@(bsB*|Ks&YSsk38A59;NOC%RBg14)a(GXr-)~ zmLUOn)4{vW5#Mq1EJktvJpEICi@bwY6LIwqqaSM%tIO#I`1<5}x^y8Z#84sj)UT@} zX3|#u2I&e_DP*{1QPxn;PD92&fG?tp{T$vEu=m?g7k&0XGo_lrF1Z?EZ>>IKSXo{R z9hEZnr5g>(wK~}RY#7NwBZ;R~34iAib@%hwqeOJuIOnMywtZcG>!Gs3D~6CFHt~a? z1P3y}?TwF?71cLF59d~=OPP|AUS)YKX+i0ZF_+yNB8NFtc!SANPCr3u@B7Ki;e}PU zSDGqRf2SC(D0i_PW|6Iwv;%cx10ij;B&_h$(G z3T}~u0`jn1as~q?;Wrcibe_pr7u!Wy6UIXtlf}cHbFFy+nJHMK{e+f+MtC96Q~Nhl zY{5fduDpbtw09!5;Znj#=sx|VHmTZ;U5${HE%&6C$*V?PI#2l@aMHY%iJ3GrM&!NF z$w<+NJr%0nnV5k2wrnh)p+4qd?xMeAUp-O`t+y0nHUGV-0UQ^1r`_+hTT=tRJ~RTl zNxPya3l`bj%_gQk1y633O%)_T=oPiAjWFj4VhYFHQ`<)htN|&m%Y>}L+o&)LFc$KL}ICX7ql)T%%&cw{;y-9XAk^U2r9;HN;wJ@3x2^V1f$h( zM&UW9pW5&wr#Ew7TJX7-$2MG)Z=Le!90`qq|w?v!_{ueuDTG|{)52`sdo45lOUdj+HVP2wvpqw zsbAm)B>(4=dWTN6c&TGcQ@ZSz!>INf9TCTl(&>F$K2vOgvRO#?Z;cEO^AAsSsbQg# z@;uS@L-lFhIpsaCSh9zfx zruy&nHSVH5Hgy}^Iq;&@fgxV65B2axHV?PrIhFXjt0pa-fBn`!{sD4r6wqsz=>ojr zozQ&95v&GGine;OwWq2pl?OK|w95=e^fru!*VF!it2v=K^|FRb-xf!;5=1x}t^1;r z36XANTy|t$6mPBIFrs8~BJN0joka)QHa26#^K9dOp;%NHYX+JfUo0DB7V@U`LkX*R zgBNM4YP?ElPU=Hz7TY##?KeBuAJjJcy3Fm}KkbX?Bv$Cq@r9xrPOBz<1e*@VjzPi9 z$JMj6N&0Vq{aiU9aGg96R6Py-$n0y>7!^kd3!o8MuM~q^_FmI~H0U zS;QLOTct)ys01RcPc~4u6jo5V5fBvhfW_w(oNXNA-x zRpud>VxEj6wfUc4Pv)xk|G3ffYGZ$C%(h9<wrH$j&*T5sBh2I2j=nL)W>BP?mjBxjT8w;D? zaHaj;Hk5Mk90b%_i}Y;h#6fLKjyb+s!g>LBkK>0{Pe|t{@;Y5OTy$B}VI{H?x7Ep} zG1^12(EHKXQ8JR+%UgfEjm`t`KvWr{dN$;3^BcjE@R}4oT586>j4Bbj1TAW zQ)`uC7Kv1WTj=c^&Go^z6)Z zsa#x|lg~aBRaUufyVhAUe#w_#tw3udg*vYGP@c@cV^p66So`5iA;0gn_db%}GBawH zsx0HX`{t+Xaf)?a)Q@uzO@cb;`vDx6lzSeHB zdw*6WVPqFSXy`zEXm6>P_QA{sxonQ7bz4tAF2)LLxP}6hL+q6(q`DpnrM&al;F17% z1UHQeN4O7iEF|j!yxD?d&Q5BK6pnf^kt%$NX&byL>f!N@y z@1nln4ZKpdQ=|)FvHC}57)7nSDF4yN1?YFDHEVCDoA)K5t7|`M$c!BI>WHD)LeAND z#-)X$f4xMBeyNE!MAO-*y-fu^Z=l6{7{3jPKtktfm##(K{c+7Ydu?v5qK z7!=9M4i3gEmB|mV&48NC3dG?;;_gFboPlFvl}x|`eeY#gAMIA}K<{~5~$WM-4-olOROwt!!I!0;`{`ClV0FuMd1qo5LxY%od*ZHNh3gg^t(%&?8INV z*XJa(pHpj4@F!K(c1hqha_F6r+wTUyjP2yfpWzDZ(mDP3x539D$1uPN=;&9(b-{D9>p#f$b(dhZy z7w4kn3$vjg@Xr6uoj?@`&ZED6=ZfBGky~LuqnaT$NWoUkoF*&FBQky7;Z@#fLotvF ziD3Nbm1X5U%;x>Ur@i;9VJ7Yo2pHIpqv+L-efsl+_Nvud%7zA(Nhr8r0Q&K>^1kv=JGk#pmQcSUeAGhBrL36aJb0nE|j$*eB z6#a7xj=_T+_G1$|Iln6(pQUV-!i=XJ^7PqKAs+if!}!#O3({RoqKcmtkq4Fx7LMA#$KxNn z0dCBQO)IzE4OS)g=f6n$5#)Pg>tzTfgO@NL4+AZWsSHt~(p>}cIibjFX=i~YKNodj zs0112$=)*R`px{em1PrBwCR0&au!m^i~MrCB2E;IhPZOn{yG{7roLUMAMtfwbZA}< z^l(4uJ%t|3yF`B+cbqh(O(x6}bVz3TyQ1N$A|f=$=TEYE)LtT99Rh-m#4R|s+Z}5$ zo&Z&sR)0ic_t$O+l#hoBq)QS0)}zaBBKG!70l#c75i(`~lk7$$#y`I0W~PW~E>bQ39SU((tk{LG*$(AUX#wC{mDpa?oO`yd5t80> z(`J@U9ECB-CRbBO(=jy`Ab~w^&`4@_}M$Hhk|8`#AETaQb zS$dX!Hv?*U3$$^&Ty2A2|epdQ$zCFk~B=?jC25JK6r&LA`Dsr zGhgcZNvo;jplwhWetH0a=m0&f7X`FlkSeWHw&L@irY;a+^?2^Ofm+I50bHpRlX8Km z7d!c&Vg^Y5I@%ZTJhi>Kx(TgY1X#o7b<7BoY(4!5;LV7^!cX-}khn&+cCNKmIG`0- zsKe5M;n*@zXw}tZuZ9mHqCv)bbx!#xn4iWW(Pv@K`y{4!YJ)2*kCIU=6~@FWqLY$z z{_ItxB!R*JpC%2&htdhgw&g271%EY$8+>?2`Ld8GxbZ=?v6I?$9a+ z{6q@k=yJXq(g;U><;Rb9iq)-h@bt@yL;=`&WlhIuM9MSYSeiJ+K?*&C49Z6b4c@n& z$r_}uaGlXDx&{7dU=xQ;-QBX0NBjOk2^!OhE7%_(66B3cc59EG#Lpj7Y7ard>pDR3 zunvaM1C0$XTDtOF>BG!+cHsfn_}e!vx=}MCFxW(ir0bx$`M8B|B9LvRhIH|`+~Ri+ z&aN?hd6;)t@FTSATCzs)e)f)IjN3OjZUr_WJNGvcrPo6|EkuwFZjjb8v5x6a{^?*j z#3!)|vXf6sHCw3>GglY41?D8aB%3q3_8)GTK>AbpS)eq0;pvu9vE_KE@v-G1HFMja zv;aiNE}}g;dyx+tG*Y^X|HbceO6{Bp4jxx6oW8dG{=Wv7sVbYj5;t4W8Y8i&phwwG*KxlT6CnTGalxN zo?^_f)gYR+ONi2c@abTWg`$$USj2e@T8nkXHYqtssz-koApDRE@a637<|$Gn%O7xw z3hwTh#M+?FH73dXy0#oeIPzeL@$Ocb*Tm-;mg{Ah;bPmpt&r*&q5sw=rr_*LDADDM z25b4(E`vdauKd>D$NAbNRbD}?XB+j(C>JM(B5y6LyPZHGV>3_+Qcr&>y?J8mr`fWX z;DIP2(=S{rpBocb5@=RBBh2*QAzTt?gFCikC~~NT^EkZj^SqNF@t0hS$59EHKDp^r zt?&?9SjRiw1~m!`bc;9I9yB*|k_|>>~Ai+O&Z8l!yTSq@3y^=Xi*iIIL!+ztm zr{f2f&U-IL*kK|dI<9I1{F8F#We_D+(ZX(GYIO$b-!Jrz`yOzAe09!34lwWxMA)G& zbI3lzIaLJ^-Ir0JE zZvFH0LRL?Lw?%pj&z(%$uYVm9(V<9ltJXVWUC*_Yaf++?9(_yWj*7GoM;fyt|7tkh zHD4DD9vKnH;i7WQpf4GO9JJQkXHd_u3C#|i<&U^@BdjM(6nSg0bG zO8sM#CdIm_O%llMmVK#oWQ7f>c~u8o35&UW@5^bXv3UuoU)69bbp2ML^Z=CiC5Y{q11f09LV!-Y|iI(`JE$Q^u zU6@}{+zdn>_BcycPE%5jvZB3R2r+Q^ODKD;(yjtY1|MX!U8HROV{j-fytK9auF?_n zmCEpy_Sx0G^UYIhzK0c1%2Od|bGZk3jiOXbiqtvoSX_C|MU9Hm6^B^OSQhg~w1@DJ zKebQpvgVG5$OGJxI0TWYsI43)RJGj7?${i6=Q8%xUs5bCTGSYni)-uqzq|W`N)oi5 z#Uz0#mtm2K>X|ckYZ>0&x#tZ;{gf@nS0f?|Ec^sAFyI@~NPn^bAIRpncZcQZ9o- z+kzdmg$W$gD#|jjzm$?U*k|G9>sc>~Ac9QUh@xwT!-Z#IN zynVApI`aK&&#H-|BqduNG3#%FTt4qYGdz@p%ibcFJuQJ7bCOTRlgDzs&qtmPnyjcE zWev;R<7O#mhm<^DL>6DRj57(GZ`Z!h<^J0sqHv5WUp`E#GUVSqep98f)ph=gU9;U( zLXQ5FTc+ITB*^%Xm|8xx`ZX=Zd2;#Rm2+6Un9%Sv_NrA*#wBH~UkhP;IRuv{)jgt7 z=5S?Bd2oO~i3OrFU2>O5)x^2*xqs?E;$-PUHn^{dm#>Y@9$*6YGLW~h6XXk`F1>_u z7VscLAx_aw2SeIM7+hWn;J zW0S|fJfyeSwwbUs9yVni0x5lbv1mYZ?h+?mS|t zi!KGN#8_-ZAteB1Yy>lSBa6$S)%%_COxrs}wI7l6H%gkB@54I=Xkrs8v{R9^jDa?* z7(Sl+Hw;EKzS%vLhFu;Isi*J_(o+i$nX&e|<gwujzfJH zR_Vry{FIGcz*%$6$!h$3ZCsArKHyux-oP*UCf2QWQ(2onTo#-C*=KU~=;ipR zLJRbV8%xS{pS5(H9Z`Aa^G&?p1kA!2S$LxL2lqeei-$*x_*C}QgrHKS5B)rnP&B!j zRA^7R%IsKLUc5>qJgW@Y$1Ayk!C2_fj$lUAEbI#;?3C$28$#M_Fy*)aBUc`&tSf_vcV<( zp`Io$a_~sXyIPgI8HnurOHY_^ES&>NIe^usF=SbN6HD)>!34PYHdrG3R$y^pG=%xH zM5b>fA;5#+>J(|C93rI~2Ro>#XOIt73_y-s{T_dHBHlT5>{9-=xXO^HWgjc%o#7yPsz=8rs!IR0WC#$ZLFO; z-7$qDZZ&S|qJ|P7DVLgF2A@hSvr=~m=>oLND!dDlv_Bz+cl%&cKJMMArC7+K0s5F7 z9ltPlS#E7c6&6)TfWPShZ#Hg9u~!LLMVdDq9h5r{(+6DvBsyrJVkqbTV#Cb0h$B{2lmHA2iLY_-%|3{330QjYknzHam&pFd(Q zbryTZXs7tXijaQqb?g=@0xL#Pi$~3xarDJTd4TBadZnUW)y2b;N}o<5fHdPY&E)$x zNj!}2ArYu3A8@(-m+vJb+uEB&&o5M$s;IYrBvfAu;WS4yOC1U^O5L?MG{6GiC{s)G z7iz^Cmq0$r(-4?bTclw=;40co$D|{^o^pBh+nO2ng-iDLUZKulbsWMC0NA1(Vo3q% z-<^Sd)#4q^xtYKVVyCkMhLmn;!vJHx`d*2Dk`N<^5FwyGZ?;?^!ep%52=g4gt>CYv zp6Rub|NEtVb09{L&N++e~Vyi z*F)ArF};~y-7ri=U|5vA;dh`lv}~MCKbWTfhDQ;2Plo4YnEn+Nn|9Z%^9u255hgl- z9GL$UGrc^}b{|NrTZ0vpt`R=HTmj=cfZ?xZTDg2N0-$iB?b$nh+W}J7xX``3{D|pf zZ(;1?8de>Haklcqi7_Tq`9|Q8b2?X;>>SMoLBZe8-|imqI!IR{8l@up#*#4lKK2fy z&Gu%xIy;JPYx1YDf^o5{&Cl($TU1SW^ae|^?qTM^DSw-Gzw*`cP(n=~u^;rpX7knd zrPN>?fUZWErem5Yo(R~WwvUy8cYi;}OBrw>&a?98ij}FWo_1KUawE*bf2iJkUx!glld?8uCGoqtVa|MdC|GF5UE zcr6o;qNZ!Px z&3ss?Y>nSNg6G?H~bGfJp9{bGw5feRuy6rq8fJ0)Tkb26&SRUZ$O00iFp^7 zMI2Fm1h?E&-q{2-=B~C^keeIXjz8Jb%jBAe9=|ssp2fq=2xabQmV+?eia+Xk(-u6M ztGI;WmYmG}oKBdZmm@zdn(Kyit%FR;u~yfIv2<42;}@P_+eji7(?sj&nGOcI{SgEM zJ9YPJc`Owv5mJ^Wp%$C$f|qS{%1m=xs%;Hw!ywhi8l0x%abnpTa6^h=gjnoF0V6a8 z)yts*HNT~meb?2ocH6GfPHRSvEFeAqTC8{?x)4EEG{1B-A^UdtND^609Ozvz!OV$z z!hiA5-iwJ5=W2eZRj=74Nb>5sc!NR-8sbYUABs}Ij-g^`GLi$LUU_$31;cq@6wb~`@mWhzpy(@sysxgcM0pPi+53`;S~QIa<7r7KcA#1;w8=~QL=sX%rtJ9l|xi@D(Z?KZi7dE1S2gQskbmL z1m(Z@k>?m+-;V{gqy{%8f%3lNRG_ATuAHaU15RC))_f}db{-FFup9Yjl(%YZtWvVbT=OvUoL5%nels0?t zMWNyJooB71KbnDZ$VaUdH<@tmRR$#Pz`148bNk~s+-NoqD|)=3Ywx(}PB|n@W$xwt zJPj`vKEu$`F{&T(G*l-Ui(KW!nz-ztuqiyF2j}L}5#HlM@A4m|31aX7_|^98c>6E? zIQymkGpVxwd{;Q1H%Z4;>sN~!C`Mmsy>*?BsRi>9yx?l=(<0u>*Qb>tD8q$g=i!IT z^qVw0@DTmFK4i+I6q8R|bv~j**I!dT@ElX>lCuA#P*wCRLx8Rd!DaiOsA;V(y53I( z^c>_W+yg`*?85Q(z-YMl!siJT<6Pd(!HH(c=7X*Rw#^`=L z@0T9}zf#FIXC13+T-=9ej984}(d2h?Q5wOVKF3IvU1PCd2f7)80=8<-Ua{jFx-I{W z(3tuJ5^>Nv3NmO*(LM{e)ZVwedx!TZC;3eiL_hAR@J_-o1h<k3i(iE`k>-$SrD)1g&^@{Uw_s4G3a@~$ zmju2th!5^K=3iPUg{7Y9PU%$)S+?o@5FV|6vaDP~hIshN8)tczmXtGaR1=r8G;CBo zfLwq*s2wb<7B0Zv&&Y#xx3J`DY*{uy1`q46wL|Ku(;Iex(1Z#J?<;_Oe3H>+iXLD{O|RJ4P7TMwT!sj!d1&|5=oO~n70>E4=Mw)QvF7DQ zt6bE?ua?FJ6HQ^O7}~k2fEJy;usaM~P#Y`NuNJdXzu^bj(SUlA=Z`&7nH>~%J`w4kNT+Y_86xUGvXf?F|=}Wsz6`qkMm#L-K zgf7K3T6{$foz8w$c!bFAuWGs9W6P8BBSAhygFa%EuLBbQ*2QQRa3Ts6sEz_v1VB-x zys|dBFtLz?rz8KNU0#Clq(OKrSfbxp%OaC1j`K^J*&nAQ*l)$;WerSxe^mDxq&>sa zu5kh+^%vC5iwmaT&(HyYa&YC1J7{C_4M3bqwDjMaP#=d3WhRHr5kEO(j5EUo^!p=IoEy8xzGE2CwXz;U=iuwYb-j)XDWW>jGNfvf=n;XqwO$W zMt3tO4H-x(EB!uZsZz^M!w!9!wnt`{MhnOE0So$JP*ey102V58Zq@zA?~_r%V=2pQ z&To2RkT^Si(G~s8tdE;MTtaUx-$sN9I$FaaO+ArCH&U-0geUA*>Y&`VL99y}!jj}Y zw&GSz&U=OmJqKd3zGiO-lC08Kgn;I=2XG$p>GNW%IwFylv$6a%auyauZF0J zGXJug!RCr3FJ$lFd8XQsv>t4%J4L;!@r1m9aBFssiEV36g>RlgEYv~^!akV~j(b<= zwj;cl3Ml}+E#T?yD2r{CJJpDp5q+OM{o2uvYrPcAAid@Iiyf@a+X>lVVVW* z7?GilbS7MyS^5YMF8(NL6RUe~L^iTB4QCW(YqdotR#;7OC}jP9-l8z~qnQbE`@+Sk zIB;(KyS3l>Y4xTjA2-!x;NoJ_nxgP5&;4$$fBGbOH_S8gNK4a;N%G1z%(Jf-57fB8^4@(cM%cS(~?r#{L$C4tKU;lG9C^VdW2pc z=X&Zn7MIH-8`uT)-}0VKm!m5`cP--Ir=Ls+j9XYX-as3YNi~5F!lQj{$osoc)z?O@ zAgdQ6x+tqKzhRnrn!~OA(X9BJDC7pv<&7rHT?%U#i_3ah)3VCcya!m9AJ)F&m55es z=_$f0Q{oHV_`zzBuqu_A=X=TRK?ZH5QmG(Q7I!E@xd+gEd0*gi15%>AXCY6J3#!7* zE_<9=>-_Lh=-V z&M~}IYz>Y2^&z(~dHNYQhBVUn0h;Z4R_cvlB zs&q;XX@{W@h)?AR;P80s@=&p0jE z063v}1qv}#m`kGYaI2(T)az#V4AkJ~6&{9#Mc}cn8Kz)v4|2Y2oz%C_!`AnMt4QaW z50~~@&cjz~)UD&w^;u&33qB@fe1n2CnlrxD`{%B_CN;SX@%+q$t zc{ikl4ncHoM9*`CrN1xqxWLsjK!bzRon{k)cbV7o9Ji*IN>d#{TG?>{r?I;yw=yjXgd+v&hm8b?At=U(SuZR9$Jha05Q zu!;@mIyX2fOXSgPBX+~=}b+2k8bZQ?J zPHjA|Q)S=jT{>#Ejc|T>#u-n!-T~*xys`?e) zLwnPiP#jiAd=nDJ^2oT}B2+c_&bs!N`Dokc6_Ivqzy+KcJW*TG6Q|Med@Ret)wfX+;xU4|K*}+*F6jSx-558S2iuRs*%I|f-KQ2iS)7UfQ^Lc*6x}jS*iVpQo+Bn8!iHA0yWB(s_Z;rH^rF2 zIQR1i<}~@*CA0Z4osqZJ3B^o&U_iQ>ElE*c3#%r6&hQdn5;R(4IayQz_p0O7Ehwi8 zVi6{z)>zoV&aeGQ0+RM{F!jN&Z;oTL9-ER*i(NY#PH6#ihHL1aM)Y@da=2>O3iN|3 z+m^b=(%!Wg`SH_+A!N%)+(Wq+1jjQYqQkcXNSwCKo|=T3v=%@6ds|qX$m-9&utaW3 zRR~#bD1a0i*3wIq4!X#YTp|xS4xVD>Xr;O3$m}5(pot67tHFk8&Lb+!M>2hO6-~c> z9`7j?fW-!IxbBK=%P%7Eg^~F7me2rX#Wjz_TzhjWv+F)bS6oQV91J~k^rcDIWv%{b z>Q$*Rk8_dEEa;ZaONQ% z&|jwahS7_RhOKGtfTk!%BpT%b_)YbMu8tR}?PKBAh=Cc4@n;ZbdLzUI|&7%y`} z3?r6y;d}sJ`jUuLK!Lc%u0=WLeOW7>qLY$Gh>W@|)leMcwa;``N^pPvFn&M3w_Ex( zz$%qCQDrV>oe4D{l){m+9DSlj-Kh^R^{{yx+tQAi8GPytj=8+Z*0+!1R}Po2*KmWW zq!JC39o<2$lIf;J-Wf!(zE_0|ff1BXW9k8dEH^n$!UDHgU7F+WjxW4t#+j6p6RDM^ zspg-#e9HJ_ow*DxGHLwRGm@%7O-Yog{Q9m&QSmMo_T%LurP{QwMuqACxe01$!Bs{& zd)m$HF1`sJcGzk&{Q^$+i&3XIUTLnSsI9Ew6?V+)1fdf7+kTLZ-ub6eyp$*?@wW_h z+wgTwo+v#+f~9!SJ$&INEqw7)aeYOtm(!a?_eIP5}f4gAkG|dkIAN zXL;j#9#?JkjQ1|(E7%jcGkMSekJ?D7T>JBbSC~bPvcZ@j1)_&CrYAr-?ySuezf5)D z+fo@!>m5dy8t5+V2&HyjO+eiaR|v9`GT9~FGAe4FT+Sz>%I*QNC6}Q$1F*mB-$^-! zlwauS8z=`&N&Q**sgZxXOv_u9mrw03P>);GbN$s@>`WqUi~Mh%h_KYFW0#H(Yyv4c zHO7=N(#25pbOw{QX54U($U-Zdd3$Q>cmR(@QFNWjg1f9^m$GwmKzd@`>yN$`U;e%BL~087d!GE^ohOQ3W_YpcICHF)%2Ckr>=CQ!lOTcB)O~O)+uE4{s?ve$xt& zmK%`vXM3NjO=cAq`S`4@_ksX+f^nF0y7n1QWfcTh4XS|s5G_z1bwc&r9>dCjb!T+D z(?agQn>=w`X_Ga2_PXIyf*rDhE`{!4>9(`Z3xUoPC628xnSo&fKq@@` zxv;U8*dL^#1nxyAr*28K>>P60Y>-peKfzwa|51heNi(o-d+wP!k(y+`N+paBMqFQX$ke>|=kpN<)cdDakFWu$+ z82+~Z1mv9)r@@!dQ1j`>$VJPLx-elXop_Q*NuM9P&Q1Qd$gMl@(am1zBzoYiD3Qkh z_Y9k7I0kFf*!c`5xPbQW+V8hALweHw7`ns>$>wWoY>pA-7xd*n35wJGXB$Df^v9uY zN_$_frgPx_EGv^$7t9FagA?l!2lD~tAb4zAH}mDLXTN5b3;_Q%K@;qlB6_r_=RCm@jUK-?SZ zmTP_{!Vnx{hd_c;JEE3VFxS7AkQjip46sGb@3^P+bNKJ!vG&8|LbRRK+ziUlyw1G9 z^XrG1D_E@)j0Oq_YY60OoNnLfZ5wW0WWvzzPf7RDD^P zF4WO~8|2glvw%PCA`YY~menHO%vCYaXng6X_)n_@24b}S4=||H-J8XlYb)D3IsCN(2I+tiju3?$n&rWs6n3cPRadX-%SML@)35 yhBw=ymNf*nZilV+@u&ESJ_Zc)|Myk#IgaXV_igN6&8emVK9>!V1~2uUWBv!%GJyvG literal 0 HcmV?d00001 From 11333b45164fc596ddc39bb78aad53fd8610253e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:17:26 +0530 Subject: [PATCH 037/115] construct JSON object --- .github/workflows/registry-updates.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 1abf1377..26acd1e3 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -27,7 +27,7 @@ jobs: id: changed-files uses: tj-actions/changed-files@v44 with: - separator: "\n" + json: true files: | registry/** @@ -42,6 +42,7 @@ jobs: echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" echo "deleted files are $DELETED_FILES" + jq -n '{added: $ADDED_FILES, modified: $MODIFIED_FILES, deleted: $DELETED_FILES}' # - name: List changed files From 5162914f941ffba4bb8566f28b93c4220a2a1e6a Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:20:20 +0530 Subject: [PATCH 038/115] modify the jq command --- .github/workflows/registry-updates.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 26acd1e3..c82ec7a9 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -42,7 +42,11 @@ jobs: echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" echo "deleted files are $DELETED_FILES" - jq -n '{added: $ADDED_FILES, modified: $MODIFIED_FILES, deleted: $DELETED_FILES}' + jq -n + --arg added "$ADDED_FILES" \ + --arg modified "$MODIFIED_FILES" \ + --arg deleted "$DELETED_FILES" \ + '{added: $added, modified: $modified, deleted: $deleted}' # - name: List changed files From c409d7d9a6edf73e0fe43bec9c00683bd8c3580b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:23:53 +0530 Subject: [PATCH 039/115] another way of doing jq things --- .github/workflows/registry-updates.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index c82ec7a9..4533103d 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -42,11 +42,7 @@ jobs: echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" echo "deleted files are $DELETED_FILES" - jq -n - --arg added "$ADDED_FILES" \ - --arg modified "$MODIFIED_FILES" \ - --arg deleted "$DELETED_FILES" \ - '{added: $added, modified: $modified, deleted: $deleted}' + echo '{"added": "$ADDED_FILES", "modified": "$MODIFIED_FILES", "deleted": "$DELETED_FILES"}' | envsubst | jq . # - name: List changed files From 0c0fa054df7a87f492f9235b02f2d19a2d15d05c Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:25:30 +0530 Subject: [PATCH 040/115] try printing the output --- .github/workflows/registry-updates.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 4533103d..b7911723 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,11 +37,13 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} + OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" echo "added files are $ADDED_FILES" echo "modified files are $MODIFIED_FILES" echo "deleted files are $DELETED_FILES" + echo "OUPTUT is $OUTPUT" echo '{"added": "$ADDED_FILES", "modified": "$MODIFIED_FILES", "deleted": "$DELETED_FILES"}' | envsubst | jq . From 8ea30f4f66882b5a7f6604a175d291dc16b8b839 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:28:01 +0530 Subject: [PATCH 041/115] unstringify json --- .github/workflows/registry-updates.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index b7911723..5090be6f 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -40,11 +40,7 @@ jobs: OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "added files are $ADDED_FILES" - echo "modified files are $MODIFIED_FILES" - echo "deleted files are $DELETED_FILES" - echo "OUPTUT is $OUTPUT" - echo '{"added": "$ADDED_FILES", "modified": "$MODIFIED_FILES", "deleted": "$DELETED_FILES"}' | envsubst | jq . + echo "$OUTPUT" | jq -R 'fromjson' # - name: List changed files From 85b9a0d3a82567d01a3464e50d9f5e9e4a48c15f Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:28:40 +0530 Subject: [PATCH 042/115] vanilla jq --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 5090be6f..c32f7079 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -40,7 +40,7 @@ jobs: OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "$OUTPUT" | jq -R 'fromjson' + echo "$OUTPUT" | jq . # - name: List changed files From 87663776bc631d90c024989469f2d71610ba075b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 11 Jul 2024 16:30:53 +0530 Subject: [PATCH 043/115] recursively unstrigify object and array JSON --- .github/workflows/registry-updates.yaml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index c32f7079..dbf180e7 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -40,7 +40,18 @@ jobs: OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "$OUTPUT" | jq . + echo "$OUTPUT" | jq -R ' + def recurse_fromjson: + fromjson? // . | + if type == "object" then + map_values(recurse_fromjson) + elif type == "array" then + map(recurse_fromjson) + else + . + end; + recurse_fromjson + ' # - name: List changed files From 87a7267669f7f75ce3a719ea09a990d36aaa401c Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:05:55 +0530 Subject: [PATCH 044/115] echo all the added, modified and deleted files --- .github/workflows/registry-updates.yaml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index dbf180e7..4dda4a52 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -40,18 +40,14 @@ jobs: OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "$OUTPUT" | jq -R ' - def recurse_fromjson: - fromjson? // . | - if type == "object" then - map_values(recurse_fromjson) - elif type == "array" then - map(recurse_fromjson) - else - . - end; - recurse_fromjson - ' + echo "$ADDED_FILES" | jq . + echo "**************" + echo $MODIFIED_FILES" | jq . + echo "**************" + echo "$DELETED_FILES" | jq . + echo "**************" + + # - name: List changed files From 51c35b42639cc6a7c7b5ee54bd3a7189ee4caa4e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:07:06 +0530 Subject: [PATCH 045/115] remove redundant double quotes --- .github/workflows/registry-updates.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 4dda4a52..dc94617f 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -40,11 +40,11 @@ jobs: OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo "**************" - echo "$ADDED_FILES" | jq . + echo $ADDED_FILES | jq . echo "**************" - echo $MODIFIED_FILES" | jq . + echo $MODIFIED_FILES | jq . echo "**************" - echo "$DELETED_FILES" | jq . + echo $DELETED_FILES | jq . echo "**************" From 059c76603042a262386079b9630d5503bb31ee2d Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:09:08 +0530 Subject: [PATCH 046/115] write changed files output to a file --- .github/workflows/registry-updates.yaml | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index dc94617f..6a84dd12 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -39,27 +39,15 @@ jobs: DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | - echo "**************" - echo $ADDED_FILES | jq . - echo "**************" - echo $MODIFIED_FILES | jq . - echo "**************" - echo $DELETED_FILES | jq . - echo "**************" + echo $OUTPUT > changed_files.txt - # - name: List changed files - # id: list_files - # run: | - # if [ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]; then - # git diff --name-only ${{ github.sha }} > changed_files.txt - # else - # git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt - # fi - - # cat changed_files.txt + - name: List changed files + id: list_files + run: | + cat changed_files.txt # - name: Get the actual changes in the files # run: | From 92942bfba68bd3bcd4710636b1378d5671f825ca Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:11:19 +0530 Subject: [PATCH 047/115] try removing toJson --- .github/workflows/registry-updates.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 6a84dd12..8c2a70a4 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,13 +37,11 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} - OUTPUT: ${{ toJson(steps.changed-files.outputs) }} + OUTPUT: ${{ steps.changed-files.outputs }} run: | echo $OUTPUT > changed_files.txt - - - name: List changed files id: list_files run: | From 67202ff67d9f15aed17ba98142961ed08ce17974 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:13:09 +0530 Subject: [PATCH 048/115] try fromJSON --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 8c2a70a4..dca9ffdb 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,7 +37,7 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} - OUTPUT: ${{ steps.changed-files.outputs }} + OUTPUT: ${{ fromJSON(steps.changed-files.outputs) }} run: | echo $OUTPUT > changed_files.txt From b3521ad843b17f639fbca996d39e07c7738ca838 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:14:09 +0530 Subject: [PATCH 049/115] use string instead of toJson --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index dca9ffdb..b48b14f9 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,7 +37,7 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} - OUTPUT: ${{ fromJSON(steps.changed-files.outputs) }} + OUTPUT: ${{ string(steps.changed-files.outputs) }} run: | echo $OUTPUT > changed_files.txt From b069959c352c31e0167acbc25c0c7855d0765c58 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:15:42 +0530 Subject: [PATCH 050/115] use toJson only --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index b48b14f9..820b5a17 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,7 +37,7 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} - OUTPUT: ${{ string(steps.changed-files.outputs) }} + OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | echo $OUTPUT > changed_files.txt From 75a623976c70be8d9fa64cb8999e3b2421219ac9 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:19:54 +0530 Subject: [PATCH 051/115] create a JSON object --- .github/workflows/registry-updates.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 820b5a17..e1f4e13f 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -37,15 +37,13 @@ jobs: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} - OUTPUT: ${{ toJson(steps.changed-files.outputs) }} run: | - echo $OUTPUT > changed_files.txt - + echo "{\"added_files\": \"$ADDED_FILES\", \"modified_files\": \"$MODIFIED_FILES\", \"deleted_files\": \"$DELETED_FILES\"}" > changed_files.txt - name: List changed files id: list_files run: | - cat changed_files.txt + cat changed_files.txt > jq . # - name: Get the actual changes in the files # run: | From da932a72b312401de39983ad3f657b80d08df34e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:20:58 +0530 Subject: [PATCH 052/115] print the content of the changed files --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index e1f4e13f..980d3731 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -43,7 +43,7 @@ jobs: - name: List changed files id: list_files run: | - cat changed_files.txt > jq . + cat changed_files.txt | jq . # - name: Get the actual changes in the files # run: | From bb0a9393dc6530a33986da59a1ee28372044aa50 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:22:43 +0530 Subject: [PATCH 053/115] remove double quotes from the array values --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 980d3731..e92ea661 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -38,7 +38,7 @@ jobs: MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} run: | - echo "{\"added_files\": \"$ADDED_FILES\", \"modified_files\": \"$MODIFIED_FILES\", \"deleted_files\": \"$DELETED_FILES\"}" > changed_files.txt + echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.txt - name: List changed files id: list_files From 9fd2eb07fb538aa9a1b5865eeda6675cc1eecfaf Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 15:25:08 +0530 Subject: [PATCH 054/115] remove jq --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index e92ea661..dc259063 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -43,7 +43,7 @@ jobs: - name: List changed files id: list_files run: | - cat changed_files.txt | jq . + cat changed_files.txt # - name: Get the actual changes in the files # run: | From 42d9c9c58947cbb29a75a2292bde791992f13b4c Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:21:49 +0530 Subject: [PATCH 055/115] Parse the changed files JSON file --- .github/workflows/registry-updates.yaml | 53 +++++++++----------- registry-automation/cmd/ci.go | 66 ++++++++++++++++++------- 2 files changed, 70 insertions(+), 49 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index dc259063..720e346e 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -45,36 +45,27 @@ jobs: run: | cat changed_files.txt - # - name: Get the actual changes in the files - # run: | - # echo "Fetching actual changes ..." - # while read -r FILE; do - # echo "Changes in $FILE: " - # git diff $BASE_SHA $HEAD_SHA -- "$FILE" - # done < changed_files.txt - # env: - # BASE_SHA: ${{ steps.list_files.outputs.base }} - # HEAD_SHA: ${{ steps.list_files.outputs.head }} - - # - name: Pseudocode for Next steps - # id: next_steps - # run: | - # echo 'Detect status - added/modified/removed files' - # echo 'for each removed connector, remove from registry db' - # echo 'for each added connector, create a stub in the registry db' - # echo 'for each modified connector:' - # echo ' * Download tgz' - # echo ' * Re-upload tgz' - # echo ' * Extract' - # echo ' * Build payload for API' - # echo ' * PUT to API (gql)' + - name: Pseudocode for Next steps + id: next_steps + run: | + echo 'Detect status - added/modified/removed files' + echo 'for each removed connector, remove from registry db' + echo 'for each added connector, create a stub in the registry db' + echo 'for each modified connector:' + echo ' * Download tgz' + echo ' * Re-upload tgz' + echo ' * Extract' + echo ' * Build payload for API' + echo ' * PUT to API (gql)' - # - name: Setup Go - # uses: actions/setup-go@v4 - # with: - # go-version: 1.21.x + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: 1.21.x - # - name: Run registry automaion program - # run: | - # cd registry-automation - # go run main.go ci + - name: Run registry automation program + env: + CHANGED_FILES_PATH: "changed_files.txt" + run: | + cd registry-automation + go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 6b7b21d3..bbad5fce 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -4,7 +4,6 @@ Copyright © 2024 Hasura package cmd import ( - "bufio" "context" "encoding/json" "fmt" @@ -30,13 +29,19 @@ var ciCmd = &cobra.Command{ Run: runCI, } +type ChangedFiles struct { + Added []string `json:"added_files"` + Modified []string `json:"modified_files"` + Deleted []string `json:"deleted_files"` +} + func init() { rootCmd.AddCommand(ciCmd) // Path for the changed files in the PR - var cfpE = os.Getenv(`CHANGED_FILES_PATH`) - ciCmd.PersistentFlags().String("changed-files-path", cfpE, "path to a line-separated list of changed files in the PR") - if cfpE == "" { + var changedFilesPathEnv = os.Getenv(`CHANGED_FILES_PATH`) + ciCmd.PersistentFlags().String("changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") + if changedFilesPathEnv == "" { ciCmd.MarkPersistentFlagRequired("changed-files-path") } @@ -55,28 +60,53 @@ func runCI(cmd *cobra.Command, args []string) { // For each connector where a change is detected... - var changed_files = map[string]bool{} + // var changed_files = map[string]bool{} + // var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() + // file, err := os.Open(changed_files_path) + // if err != nil { + // log.Fatal(err) + // } + // defer file.Close() + + // scanner := bufio.NewScanner(file) + // for scanner.Scan() { + // changed_files[filepath.Dir(scanner.Text())] = true // Just assume we'll treat each connector as if everything has changed. + // } + + // if err := scanner.Err(); err != nil { + // panic(err) + // } + + // var hub_directory = cmd.PersistentFlags().Lookup("connector-hub-directory").Value.String() + + // for k := range changed_files { + // respondToChangedConnector(path.Join(hub_directory, k)) + // } + var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() - file, err := os.Open(changed_files_path) - if err != nil { - log.Fatal(err) + changedFilesContent, err := os.Open(changed_files_path) + + if err!= nil { + log.Fatalf("Failed to open the file: %v, err: %v", changed_files_path, err) } - defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - changed_files[filepath.Dir(scanner.Text())] = true // Just assume we'll treat each connector as if everything has changed. + defer changedFilesContent.Close() + + // Read the file's contents + changedFilesByteValue, err := ioutil.ReadAll(changedFilesContent) + if err != nil { + log.Fatalf("Failed to read JSON file: %v", err) } - if err := scanner.Err(); err != nil { - panic(err) + var changedFiles ChangedFiles + err = json.Unmarshal(changedFilesByteValue, &changedFiles) + if err != nil { + log.Fatalf("Failed to unmarshal JSON: %v", err) } - var hub_directory = cmd.PersistentFlags().Lookup("connector-hub-directory").Value.String() + fmt.Printf("Parsed JSON: \n%+v\n", changedFiles) + - for k := range changed_files { - respondToChangedConnector(path.Join(hub_directory, k)) - } } From 332366f0424dd7157593c64f595008ecbdaac574 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:27:38 +0530 Subject: [PATCH 056/115] remove the CONNECTOR_HUB_DIRECTORY flag --- .github/workflows/registry-updates.yaml | 6 +++--- registry-automation/cmd/ci.go | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 720e346e..67c84505 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -38,12 +38,12 @@ jobs: MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} run: | - echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.txt + echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.json - name: List changed files id: list_files run: | - cat changed_files.txt + cat changed_files.json - name: Pseudocode for Next steps id: next_steps @@ -65,7 +65,7 @@ jobs: - name: Run registry automation program env: - CHANGED_FILES_PATH: "changed_files.txt" + CHANGED_FILES_PATH: "changed_files.json" run: | cd registry-automation go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index bbad5fce..68fca62f 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -46,11 +46,11 @@ func init() { } // Location of the registry files - var rfpE = os.Getenv(`CONNECTOR_HUB_DIRECTORY`) - ciCmd.PersistentFlags().String("connector-hub-directory", rfpE, "path to the connector hub checkout directory") - if rfpE == "" { - ciCmd.MarkPersistentFlagRequired("connector-hub-directory") - } + // var rfpE = os.Getenv(`CONNECTOR_HUB_DIRECTORY`) + // ciCmd.PersistentFlags().String("connector-hub-directory", rfpE, "path to the connector hub checkout directory") + // if rfpE == "" { + // ciCmd.MarkPersistentFlagRequired("connector-hub-directory") + // } // TODO: Check rand.Seed(time.Now().UnixNano()) From 92619ff2a8a1e9e5f0a77cd644c125133a83c322 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:33:31 +0530 Subject: [PATCH 057/115] move the file to registry-automation first --- .github/workflows/registry-updates.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 67c84505..9dab4d23 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -67,5 +67,6 @@ jobs: env: CHANGED_FILES_PATH: "changed_files.json" run: | + mv changed_files.json registry-automation/changed_files.json cd registry-automation go run main.go ci From dffcf74a46ffbe144527f9845f8bf480c7376b3e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:40:03 +0530 Subject: [PATCH 058/115] use io.ReadAll --- registry-automation/cmd/ci.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 68fca62f..fc832ca6 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -93,11 +93,13 @@ func runCI(cmd *cobra.Command, args []string) { defer changedFilesContent.Close() // Read the file's contents - changedFilesByteValue, err := ioutil.ReadAll(changedFilesContent) + changedFilesByteValue, err := io.ReadAll(changedFilesContent) if err != nil { log.Fatalf("Failed to read JSON file: %v", err) } + + var changedFiles ChangedFiles err = json.Unmarshal(changedFilesByteValue, &changedFiles) if err != nil { From 2fbb3ba7efa2fe678af81cd4058fddbdd2e9186b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:41:43 +0530 Subject: [PATCH 059/115] print out the byte value --- registry-automation/cmd/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index fc832ca6..d35a1520 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -98,7 +98,7 @@ func runCI(cmd *cobra.Command, args []string) { log.Fatalf("Failed to read JSON file: %v", err) } - + fmt.Printf("Changed files byt value %v", changedFilesByteValue) var changedFiles ChangedFiles err = json.Unmarshal(changedFilesByteValue, &changedFiles) From 4a3eb7559c9c00ce658aa82f5116ca0c43bc48ac Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:48:00 +0530 Subject: [PATCH 060/115] convert into string first --- .github/workflows/registry-updates.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 9dab4d23..8af2b198 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -34,9 +34,9 @@ jobs: - name: Print out all the changed files env: - ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} - MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} - DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} + ADDED_FILES: ${{ string(steps.changed-files.outputs.added_files) }} + MODIFIED_FILES: ${{ string(steps.changed-files.outputs.modified_files) }} + DELETED_FILES: ${{ string(steps.changed-files.outputs.deleted_files) }} run: | echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.json From 47d937ad09a84c619826a4ad283ae6320028b717 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 16:50:10 +0530 Subject: [PATCH 061/115] don't escape json --- .github/workflows/registry-updates.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 8af2b198..aa57a863 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -28,15 +28,16 @@ jobs: uses: tj-actions/changed-files@v44 with: json: true + escape_json: false files: | registry/** - name: Print out all the changed files env: - ADDED_FILES: ${{ string(steps.changed-files.outputs.added_files) }} - MODIFIED_FILES: ${{ string(steps.changed-files.outputs.modified_files) }} - DELETED_FILES: ${{ string(steps.changed-files.outputs.deleted_files) }} + ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} + MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} + DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} run: | echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.json From 0ed25e5a00b522b9594f60286d69aca126fef343 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 17:04:46 +0530 Subject: [PATCH 062/115] delete azure cosmos logo --- registry/azure-cosmos/logo.png | Bin 38264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 registry/azure-cosmos/logo.png diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png deleted file mode 100644 index 001667d864a9bb07f7389f2534dec3a2514e86eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38264 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 From 968ce1a7def9657ad6b03dd17d40e9645cef8cd5 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 16 Jul 2024 17:06:21 +0530 Subject: [PATCH 063/115] remove logo from registry-automation-test --- registry/registry-automation-test/logo.png | Bin 38264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 registry/registry-automation-test/logo.png diff --git a/registry/registry-automation-test/logo.png b/registry/registry-automation-test/logo.png deleted file mode 100644 index 001667d864a9bb07f7389f2534dec3a2514e86eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38264 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 From 76370c3058b00e54f698ffa6b164160c2de572f2 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 17:38:19 +0530 Subject: [PATCH 064/115] modify the registry-updates workflow --- .github/workflows/registry-updates.yaml | 56 +++++++++---------- registry-automation/cmd/ci.go | 1 + registry/mongodb/releases/v0.0.1/package.json | 11 ++++ registry/mongodb/releases/v0.0.2/package.json | 11 ++++ registry/mongodb/releases/v0.0.3/package.json | 11 ++++ registry/mongodb/releases/v0.0.4/package.json | 11 ++++ registry/mongodb/releases/v0.0.5/package.json | 11 ++++ registry/mongodb/releases/v0.0.6/package.json | 11 ++++ registry/mongodb/releases/v0.1.0/package.json | 11 ++++ registry/mongodb/releases/v1.0.0/package.json | 11 ++++ 10 files changed, 117 insertions(+), 28 deletions(-) create mode 100644 registry/mongodb/releases/v0.0.1/package.json create mode 100644 registry/mongodb/releases/v0.0.2/package.json create mode 100644 registry/mongodb/releases/v0.0.3/package.json create mode 100644 registry/mongodb/releases/v0.0.4/package.json create mode 100644 registry/mongodb/releases/v0.0.5/package.json create mode 100644 registry/mongodb/releases/v0.0.6/package.json create mode 100644 registry/mongodb/releases/v0.1.0/package.json create mode 100644 registry/mongodb/releases/v1.0.0/package.json diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index aa57a863..a8063126 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -23,51 +23,51 @@ jobs: with: fetch_depth: 1 - - name: Get all changed files and use a comma separator in the output + - name: Get all connector version package changes id: changed-files uses: tj-actions/changed-files@v44 with: json: true escape_json: false files: | - registry/** + registry/**/releases/**/package.json - - name: Print out all the changed files + - name: Print out all the changed filse env: ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} run: | - echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.json + echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > connector_version_changes.json - name: List changed files id: list_files run: | - cat changed_files.json + cat connector_version_changes.json - - name: Pseudocode for Next steps - id: next_steps - run: | - echo 'Detect status - added/modified/removed files' - echo 'for each removed connector, remove from registry db' - echo 'for each added connector, create a stub in the registry db' - echo 'for each modified connector:' - echo ' * Download tgz' - echo ' * Re-upload tgz' - echo ' * Extract' - echo ' * Build payload for API' - echo ' * PUT to API (gql)' + # - name: Pseudocode for Next steps + # id: next_steps + # run: | + # echo 'Detect status - added/modified/removed files' + # echo 'for each removed connector, remove from registry db' + # echo 'for each added connector, create a stub in the registry db' + # echo 'for each modified connector:' + # echo ' * Download tgz' + # echo ' * Re-upload tgz' + # echo ' * Extract' + # echo ' * Build payload for API' + # echo ' * PUT to API (gql)' - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.x + # - name: Setup Go + # uses: actions/setup-go@v4 + # with: + # go-version: 1.21.x - - name: Run registry automation program - env: - CHANGED_FILES_PATH: "changed_files.json" - run: | - mv changed_files.json registry-automation/changed_files.json - cd registry-automation - go run main.go ci + # - name: Run registry automation program + # env: + # CHANGED_FILES_PATH: "changed_files.json" + # run: | + # mv changed_files.json registry-automation/changed_files.json + # cd registry-automation + # go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index d35a1520..7fe58168 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -18,6 +18,7 @@ import ( "path/filepath" "time" + "github.com/machinebox/graphql" "github.com/spf13/cobra" ) diff --git a/registry/mongodb/releases/v0.0.1/package.json b/registry/mongodb/releases/v0.0.1/package.json new file mode 100644 index 00000000..13d2851d --- /dev/null +++ b/registry/mongodb/releases/v0.0.1/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" + }, + "source": { + "hash": "c32adbde478147518f65ff465c40a0703239288a" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.2/package.json b/registry/mongodb/releases/v0.0.2/package.json new file mode 100644 index 00000000..e6561cd6 --- /dev/null +++ b/registry/mongodb/releases/v0.0.2/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.2", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" + }, + "source": { + "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.3/package.json b/registry/mongodb/releases/v0.0.3/package.json new file mode 100644 index 00000000..02812b53 --- /dev/null +++ b/registry/mongodb/releases/v0.0.3/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.3", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" + }, + "source": { + "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.4/package.json b/registry/mongodb/releases/v0.0.4/package.json new file mode 100644 index 00000000..d145fd13 --- /dev/null +++ b/registry/mongodb/releases/v0.0.4/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.4", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" + }, + "source": { + "hash": "38a4a56134a909001b645c659062ae393c2cebe0" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.5/package.json b/registry/mongodb/releases/v0.0.5/package.json new file mode 100644 index 00000000..9c7bcefe --- /dev/null +++ b/registry/mongodb/releases/v0.0.5/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.5", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" + }, + "source": { + "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.6/package.json b/registry/mongodb/releases/v0.0.6/package.json new file mode 100644 index 00000000..890a2f58 --- /dev/null +++ b/registry/mongodb/releases/v0.0.6/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.6", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" + }, + "source": { + "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.1.0/package.json b/registry/mongodb/releases/v0.1.0/package.json new file mode 100644 index 00000000..dc640be8 --- /dev/null +++ b/registry/mongodb/releases/v0.1.0/package.json @@ -0,0 +1,11 @@ +{ + "version": "0.1.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" + }, + "source": { + "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" + } +} \ No newline at end of file diff --git a/registry/mongodb/releases/v1.0.0/package.json b/registry/mongodb/releases/v1.0.0/package.json new file mode 100644 index 00000000..67035c87 --- /dev/null +++ b/registry/mongodb/releases/v1.0.0/package.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" + }, + "source": { + "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" + } +} \ No newline at end of file From 35866dd580beba921806b01e784d1b461fbe1570 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 17:40:06 +0530 Subject: [PATCH 065/115] use jq to print out stuff --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index a8063126..d9f3eeb0 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -44,7 +44,7 @@ jobs: - name: List changed files id: list_files run: | - cat connector_version_changes.json + jq . connector_version_changes.json # - name: Pseudocode for Next steps # id: next_steps From 4482ed329abd6adac019aecaea79279ef2cb3acf Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 17:44:05 +0530 Subject: [PATCH 066/115] separate out connector version changes from metadata changes --- .github/workflows/registry-updates.yaml | 35 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index d9f3eeb0..5a364ead 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -24,7 +24,7 @@ jobs: fetch_depth: 1 - name: Get all connector version package changes - id: changed-files + id: connector-version-changed-files uses: tj-actions/changed-files@v44 with: json: true @@ -35,9 +35,9 @@ jobs: - name: Print out all the changed filse env: - ADDED_FILES: ${{ steps.changed-files.outputs.added_files }} - MODIFIED_FILES: ${{ steps.changed-files.outputs.modified_files }} - DELETED_FILES: ${{ steps.changed-files.outputs.deleted_files }} + ADDED_FILES: ${{ steps.connector-version-changed-files.outputs.added_files }} + MODIFIED_FILES: ${{ steps.connector-version-changed-files.outputs.modified_files }} + DELETED_FILES: ${{ steps.connector-version-changed-files.outputs.deleted_files }} run: | echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > connector_version_changes.json @@ -46,6 +46,33 @@ jobs: run: | jq . connector_version_changes.json + - name: Get all connector metadata changes + id: connector-metadata-changed-files + uses: tj-actions/changed-files@v44 + with: + json: true + escape_json: false + files: | + registry: + - 'logo.png' + - 'logo.svg' + - 'README.md' + - 'metadata.json' + + - name: Print out all the changed filse + env: + ADDED_FILES: ${{ steps.connector-metadata-changed-files.outputs.added_files }} + MODIFIED_FILES: ${{ steps.connector-metadata-changed-files.outputs.modified_files }} + DELETED_FILES: ${{ steps.connector-metadata-changed-files.outputs.deleted_files }} + run: | + echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > connector_metadata_changes.json + + - name: List changed files + id: list_files_1 + run: | + jq . connector_metadata_changes.json + + # - name: Pseudocode for Next steps # id: next_steps # run: | From baf9bd898b6a73c8e2724cff7eb015a188ca84af Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 17:53:01 +0530 Subject: [PATCH 067/115] pattern match on the registry metadata files --- .github/workflows/registry-updates.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 5a364ead..d6e30043 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -53,11 +53,10 @@ jobs: json: true escape_json: false files: | - registry: - - 'logo.png' - - 'logo.svg' - - 'README.md' - - 'metadata.json' + registry/**/logo.png + registry/**/logo.svg + registry/**/README.md + registry/**/metadata.json - name: Print out all the changed filse env: From 4116d6e08411cfa99dd4fcd963cc706656c1c5e6 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 18:04:59 +0530 Subject: [PATCH 068/115] use files_yaml instead of files --- .github/workflows/registry-updates.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index d6e30043..a795b6af 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -52,11 +52,12 @@ jobs: with: json: true escape_json: false - files: | - registry/**/logo.png - registry/**/logo.svg - registry/**/README.md - registry/**/metadata.json + files_yaml: | + registry: + - registry/**/logo.png + - registry/**/logo.svg + - registry/**/README.md + - registry/**/metadata.json - name: Print out all the changed filse env: From cfd304358576834d17ab46ec9e173a394fa42840 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 17 Jul 2024 18:06:57 +0530 Subject: [PATCH 069/115] use cat instead of jq --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index a795b6af..6d058f7f 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -44,7 +44,7 @@ jobs: - name: List changed files id: list_files run: | - jq . connector_version_changes.json + cat connector_version_changes.json - name: Get all connector metadata changes id: connector-metadata-changed-files From fcb1ca8e84b28ccfd240e87696cf6df491aba91d Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 18 Jul 2024 13:30:56 +0530 Subject: [PATCH 070/115] rename files according to new format --- .github/workflows/registry-updates.yaml | 55 ++---- registry-automation/cmd/ci.go | 31 +++- registry/mongodb/metadata.json | 170 ++---------------- ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 ...{package.json => connector-packaging.json} | 0 10 files changed, 59 insertions(+), 197 deletions(-) rename registry/mongodb/releases/v0.0.1/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.0.2/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.0.3/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.0.4/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.0.5/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.0.6/{package.json => connector-packaging.json} (100%) rename registry/mongodb/releases/v0.1.0/{package.json => connector-packaging.json} (100%) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 6d058f7f..3ca2cd31 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -29,8 +29,6 @@ jobs: with: json: true escape_json: false - files: | - registry/**/releases/**/package.json - name: Print out all the changed filse @@ -39,39 +37,12 @@ jobs: MODIFIED_FILES: ${{ steps.connector-version-changed-files.outputs.modified_files }} DELETED_FILES: ${{ steps.connector-version-changed-files.outputs.deleted_files }} run: | - echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > connector_version_changes.json + echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > changed_files.json - name: List changed files id: list_files run: | - cat connector_version_changes.json - - - name: Get all connector metadata changes - id: connector-metadata-changed-files - uses: tj-actions/changed-files@v44 - with: - json: true - escape_json: false - files_yaml: | - registry: - - registry/**/logo.png - - registry/**/logo.svg - - registry/**/README.md - - registry/**/metadata.json - - - name: Print out all the changed filse - env: - ADDED_FILES: ${{ steps.connector-metadata-changed-files.outputs.added_files }} - MODIFIED_FILES: ${{ steps.connector-metadata-changed-files.outputs.modified_files }} - DELETED_FILES: ${{ steps.connector-metadata-changed-files.outputs.deleted_files }} - run: | - echo "{\"added_files\": $ADDED_FILES, \"modified_files\": $MODIFIED_FILES, \"deleted_files\": $DELETED_FILES}" > connector_metadata_changes.json - - - name: List changed files - id: list_files_1 - run: | - jq . connector_metadata_changes.json - + cat changed_files.json # - name: Pseudocode for Next steps # id: next_steps @@ -86,15 +57,15 @@ jobs: # echo ' * Build payload for API' # echo ' * PUT to API (gql)' - # - name: Setup Go - # uses: actions/setup-go@v4 - # with: - # go-version: 1.21.x + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: 1.21.x - # - name: Run registry automation program - # env: - # CHANGED_FILES_PATH: "changed_files.json" - # run: | - # mv changed_files.json registry-automation/changed_files.json - # cd registry-automation - # go run main.go ci + - name: Run registry automation program + env: + CHANGED_FILES_PATH: "changed_files.json" + run: | + mv changed_files.json registry-automation/changed_files.json + cd registry-automation + go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 7fe58168..df61b9cf 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -8,7 +8,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" "math/rand" "net/http" @@ -16,9 +15,9 @@ import ( "os/exec" "path" "path/filepath" + "regexp" "time" - "github.com/machinebox/graphql" "github.com/spf13/cobra" ) @@ -36,6 +35,17 @@ type ChangedFiles struct { Deleted []string `json:"deleted_files"` } +type ReleasePackageChecksum struct { + Type string `json:"type"` + Value string `json:"value"` +} + +type ReleasePackage struct { + Version string `json: "version"` + Uri string `json: "uri"` + Checksum ReleasePackageChecksum `json:"checksum"` +} + func init() { rootCmd.AddCommand(ciCmd) @@ -107,6 +117,19 @@ func runCI(cmd *cobra.Command, args []string) { log.Fatalf("Failed to unmarshal JSON: %v", err) } + const connectorVersionPackageRegex = `^registry/([^/]+)/([^/]+)/releases/connector-packaging\.json$` + + re := regexp.MustCompile(connectorVersionPackageRegex); + + for _, addedFile := range changedFiles.Added { + + matches := re.FindStringSubmatch(addedFile); + + if len(matches) == 3 { + fmt.Printf("regex matches are %+v", matches) + } + } + fmt.Printf("Parsed JSON: \n%+v\n", changedFiles) @@ -115,7 +138,6 @@ func runCI(cmd *cobra.Command, args []string) { func respondToChangedConnector(changed_connector_path string) { // Detect status - added/modified/removed files - // for each removed connector, remove from registry db // for each added connector, create a stub in the registry db // for each modified connector: // * Download tgz @@ -233,9 +255,10 @@ func downloadFile(sourceURL, destination string, headers map[string]string) erro return nil } + func readJSONFile(location string) map[string]interface{} { // Read the file - fileBytes, err := ioutil.ReadFile(location) + fileBytes, err := os.ReadFile(location) if err != nil { panic(fmt.Errorf("error reading file: %v", err)) } diff --git a/registry/mongodb/metadata.json b/registry/mongodb/metadata.json index 53e9e124..f0219847 100644 --- a/registry/mongodb/metadata.json +++ b/registry/mongodb/metadata.json @@ -1,155 +1,23 @@ { - "overview": { - "namespace": "hasura", - "description": "Connect to a MongoDB database and expose it to Hasura v3 Project", - "title": "MongoDB Connector", - "logo": "logo.png", - "tags": [ - "database" - ], - "latest_version": "v1.0.0" - }, - "author": { - "support_email": "support@hasura.io", - "homepage": "https://hasura.io", - "name": "Hasura" - }, - "is_verified": true, - "is_hosted_by_hasura": false, - "packages": [ - { - "version": "1.0.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" - }, - "source": { - "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" - } + "overview": { + "namespace": "hasura", + "description": "Connect to a MongoDB database and expose it to Hasura v3 Project", + "title": "MongoDB Connector", + "logo": "logo.png", + "tags": [ + "database" + ], + "latest_version": "v1.0.0" }, - { - "version": "0.1.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" - }, - "source": { - "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" - } + "author": { + "support_email": "support@hasura.io", + "homepage": "https://hasura.io", + "name": "Hasura" }, - { - "version": "0.0.6", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" - }, - "source": { - "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" - } - }, - { - "version": "0.0.5", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" - }, - "source": { - "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" - } - }, - { - "version": "0.0.4", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" - }, - "source": { - "hash": "38a4a56134a909001b645c659062ae393c2cebe0" - } - }, - { - "version": "0.0.3", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" - }, - "source": { - "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" - } - }, - { - "version": "0.0.2", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" - }, - "source": { - "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" - } - }, - { - "version": "0.0.1", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" - }, - "source": { - "hash": "c32adbde478147518f65ff465c40a0703239288a" - } + "is_verified": true, + "is_hosted_by_hasura": false, + "source_code": { + "is_open_source": true, + "repository": "https://github.com/hasura/ndc-mongodb/" } - ], - "source_code": { - "is_open_source": true, - "repository": "https://github.com/hasura/ndc-mongodb/", - "version": [ - { - "tag": "v1.0.0", - "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147", - "is_verified": true - }, - { - "tag": "v0.1.0", - "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1", - "is_verified": true - }, - { - "tag": "v0.0.6", - "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03", - "is_verified": true - }, - { - "tag": "v0.0.5", - "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6", - "is_verified": true - }, - { - "tag": "v0.0.4", - "hash": "38a4a56134a909001b645c659062ae393c2cebe0", - "is_verified": true - }, - { - "tag": "v0.0.3", - "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5", - "is_verified": true - }, - { - "tag": "v0.0.2", - "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0", - "is_verified": true - }, - { - "tag": "v0.0.1", - "hash": "c32adbde478147518f65ff465c40a0703239288a", - "is_verified": true - } - ] - } -} +} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.1/package.json b/registry/mongodb/releases/v0.0.1/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.1/package.json rename to registry/mongodb/releases/v0.0.1/connector-packaging.json diff --git a/registry/mongodb/releases/v0.0.2/package.json b/registry/mongodb/releases/v0.0.2/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.2/package.json rename to registry/mongodb/releases/v0.0.2/connector-packaging.json diff --git a/registry/mongodb/releases/v0.0.3/package.json b/registry/mongodb/releases/v0.0.3/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.3/package.json rename to registry/mongodb/releases/v0.0.3/connector-packaging.json diff --git a/registry/mongodb/releases/v0.0.4/package.json b/registry/mongodb/releases/v0.0.4/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.4/package.json rename to registry/mongodb/releases/v0.0.4/connector-packaging.json diff --git a/registry/mongodb/releases/v0.0.5/package.json b/registry/mongodb/releases/v0.0.5/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.5/package.json rename to registry/mongodb/releases/v0.0.5/connector-packaging.json diff --git a/registry/mongodb/releases/v0.0.6/package.json b/registry/mongodb/releases/v0.0.6/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.0.6/package.json rename to registry/mongodb/releases/v0.0.6/connector-packaging.json diff --git a/registry/mongodb/releases/v0.1.0/package.json b/registry/mongodb/releases/v0.1.0/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v0.1.0/package.json rename to registry/mongodb/releases/v0.1.0/connector-packaging.json From 6d709e143e71b10bac55f1c507c2f76783f3ccfe Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 18 Jul 2024 13:38:44 +0530 Subject: [PATCH 071/115] modify the regex --- registry-automation/cmd/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index df61b9cf..c1ca26bb 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -117,7 +117,7 @@ func runCI(cmd *cobra.Command, args []string) { log.Fatalf("Failed to unmarshal JSON: %v", err) } - const connectorVersionPackageRegex = `^registry/([^/]+)/([^/]+)/releases/connector-packaging\.json$` + const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)//connector-packaging\.json$` re := regexp.MustCompile(connectorVersionPackageRegex); From b2461cea1b1ac1475f0029c4a18da711b3ae2a37 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 18 Jul 2024 13:42:25 +0530 Subject: [PATCH 072/115] fix the regex --- .github/workflows/registry-updates.yaml | 2 ++ registry-automation/cmd/ci.go | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 3ca2cd31..ff198639 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -29,6 +29,8 @@ jobs: with: json: true escape_json: false + files: | + registry/** - name: Print out all the changed filse diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index c1ca26bb..97be9af3 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -109,15 +109,13 @@ func runCI(cmd *cobra.Command, args []string) { log.Fatalf("Failed to read JSON file: %v", err) } - fmt.Printf("Changed files byt value %v", changedFilesByteValue) - var changedFiles ChangedFiles err = json.Unmarshal(changedFilesByteValue, &changedFiles) if err != nil { log.Fatalf("Failed to unmarshal JSON: %v", err) } - const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)//connector-packaging\.json$` + const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` re := regexp.MustCompile(connectorVersionPackageRegex); From 6cc7dd11ecd5dc9d2152d37e24be8e260a4e3a79 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 25 Jul 2024 12:34:45 +0530 Subject: [PATCH 073/115] WIP commit to build the registry payload --- .gitignore | 1 + registry-automation/.vscode/settings.json | 3 + registry-automation/cmd/ci.go | 432 +++++++++++++++------- registry-automation/cmd/ci_test.go | 101 +++++ registry-automation/cmd/utils.go | 5 + registry-automation/go.mod | 37 +- registry-automation/go.sum | 160 ++++++++ registry/mongodb/metadata.json | 2 +- 8 files changed, 600 insertions(+), 141 deletions(-) create mode 100644 registry-automation/.vscode/settings.json create mode 100644 registry-automation/cmd/ci_test.go create mode 100644 registry-automation/cmd/utils.go diff --git a/.gitignore b/.gitignore index e15b2a27..0d856277 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ # testing /tmp/empty +registry-automation/extracted_tgz diff --git a/registry-automation/.vscode/settings.json b/registry-automation/.vscode/settings.json new file mode 100644 index 00000000..2c52e891 --- /dev/null +++ b/registry-automation/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "github.copilot.advanced": {} +} \ No newline at end of file diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 97be9af3..163bdaa3 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -13,13 +13,14 @@ import ( "net/http" "os" "os/exec" - "path" "path/filepath" "regexp" - "time" + "cloud.google.com/go/storage" "github.com/machinebox/graphql" "github.com/spf13/cobra" + "google.golang.org/api/option" + "gopkg.in/yaml.v2" ) // ciCmd represents the ci command @@ -30,161 +31,300 @@ var ciCmd = &cobra.Command{ } type ChangedFiles struct { - Added []string `json:"added_files"` + Added []string `json:"added_files"` Modified []string `json:"modified_files"` - Deleted []string `json:"deleted_files"` + Deleted []string `json:"deleted_files"` } -type ReleasePackageChecksum struct { - Type string `json:"type"` - Value string `json:"value"` +// ConnectorVersion represents a version of a connector, this type is +// used to insert a new version of a connector in the registry. +type ConnectorVersion struct { + // Namespace of the connector, e.g. "hasura" + Namespace string `graphql:"namespace"` + // Name of the connector + Name string `graphql:"name"` + // Semantic version of the connector + Version string `graphql:"version"` + // Docker image of the connector version + Image string `graphql:"image"` + // URL to the connector's metadata + PackageDefinitionURL string `graphql:"package_definition_url"` + // Is the connector version multitenant? + IsMultitenant bool `graphql:"is_multitenant"` + // Type of the connector packaing `PreBuiltDockerImage`/`ManagedDockerBuild` + Type string `graphql:"type"` } -type ReleasePackage struct { - Version string `json: "version"` - Uri string `json: "uri"` - Checksum ReleasePackageChecksum `json:"checksum"` +type ConnectionVersionMetadata struct { + Type string `yaml:"type"` + Image string `yaml: "image", omitempty` } +const ( + ManagedDockerBuild = "ManagedDockerBuild" + PrebuiltDockerImage = "PrebuiltDockerImage" +) + func init() { rootCmd.AddCommand(ciCmd) // Path for the changed files in the PR - var changedFilesPathEnv = os.Getenv(`CHANGED_FILES_PATH`) + var changedFilesPathEnv = os.Getenv("CHANGED_FILES_PATH") ciCmd.PersistentFlags().String("changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") if changedFilesPathEnv == "" { ciCmd.MarkPersistentFlagRequired("changed-files-path") } - // Location of the registry files - // var rfpE = os.Getenv(`CONNECTOR_HUB_DIRECTORY`) - // ciCmd.PersistentFlags().String("connector-hub-directory", rfpE, "path to the connector hub checkout directory") - // if rfpE == "" { - // ciCmd.MarkPersistentFlagRequired("connector-hub-directory") - // } - - // TODO: Check - rand.Seed(time.Now().UnixNano()) + // Publication environment + var publicationEnv = os.Getenv("PUBLICATION_ENV") + ciCmd.PersistentFlags().String("publication-env", publicationEnv, "publication environment (staging/prod). Default: staging") + // default publicationEnv to "staging" + if publicationEnv == "" { + ciCmd.PersistentFlags().Set("publication-env", "staging") + } } -func runCI(cmd *cobra.Command, args []string) { - - // For each connector where a change is detected... - - // var changed_files = map[string]bool{} - // var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() - // file, err := os.Open(changed_files_path) - // if err != nil { - // log.Fatal(err) - // } - // defer file.Close() - - // scanner := bufio.NewScanner(file) - // for scanner.Scan() { - // changed_files[filepath.Dir(scanner.Text())] = true // Just assume we'll treat each connector as if everything has changed. - // } +// processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version +func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConnectorVersions map[string]map[string]string, re *regexp.Regexp) { + for _, file := range files { + matches := re.FindStringSubmatch(file) + if len(matches) == 3 { + connectorName := matches[1] + connectorVersion := matches[2] - // if err := scanner.Err(); err != nil { - // panic(err) - // } + if _, exists := addedOrModifiedConnectorVersions[connectorName]; !exists { + addedOrModifiedConnectorVersions[connectorName] = make(map[string]string) + } - // var hub_directory = cmd.PersistentFlags().Lookup("connector-hub-directory").Value.String() + addedOrModifiedConnectorVersions[connectorName][connectorVersion] = file + } + } - // for k := range changed_files { - // respondToChangedConnector(path.Join(hub_directory, k)) - // } +} +// runCI is the main function that runs the CI workflow +func runCI(cmd *cobra.Command, args []string) { var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() changedFilesContent, err := os.Open(changed_files_path) - if err!= nil { + if err != nil { log.Fatalf("Failed to open the file: %v, err: %v", changed_files_path, err) } defer changedFilesContent.Close() - // Read the file's contents + // Read the changed file's contents. This file contains all the changed files in the PR changedFilesByteValue, err := io.ReadAll(changedFilesContent) if err != nil { - log.Fatalf("Failed to read JSON file: %v", err) + log.Fatalf("Failed to read the changed files JSON file: %v", err) } var changedFiles ChangedFiles err = json.Unmarshal(changedFilesByteValue, &changedFiles) if err != nil { - log.Fatalf("Failed to unmarshal JSON: %v", err) + log.Fatalf("Failed to unmarshal the changed files content: %v", err) + } + log.Printf("Changed files: %+v", changedFiles) + + // Collect the added or modified connectors + addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) + + for connectorName, versions := range addedOrModifiedConnectorVersions { + for version, connectorVersionPath := range versions { + err := respondToAddedOrModifiedConnectorVersion(connectorName, version, connectorVersionPath) + if err != nil { + log.Fatalf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) + } + } + } + + fmt.Printf("new connector versions: \n%+v\n", addedOrModifiedConnectorVersions) + +} + +func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[string]string { const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` + re := regexp.MustCompile(connectorVersionPackageRegex) // - re := regexp.MustCompile(connectorVersionPackageRegex); + addedOrModifiedConnectorVersions := make(map[string]map[string]string) - for _, addedFile := range changedFiles.Added { + processAddedOrModifiedConnectorVersions(changedFiles.Added, addedOrModifiedConnectorVersions, re) + processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions, re) - matches := re.FindStringSubmatch(addedFile); + return addedOrModifiedConnectorVersions +} - if len(matches) == 3 { - fmt.Printf("regex matches are %+v", matches) - } +func respondToAddedOrModifiedConnectorVersion(connectorName string, connectorVersion string, changedConnectorVersionPath string) error { + // // Detect status - added/modified/removed files + // // for each added connector, create a stub in the registry db + // // for each modified connector: + // // * Download tgz + // // * Re-upload tgz + // // * Extract + // // * Build payload for API + // // * PUT to API (gql) + + // Read the connector packaging file + ctx := context.Background() + + // connector's `metadata.json`, `registry/mongodb/metadata.json` + connectorMetadata, err := readJSONFile[map[string]interface{}](fmt.Sprintf("registry/%s/metadata.json", connectorName)) + if err != nil { + return fmt.Errorf("failed to read the connector metadata file: %v", err) + } + + // connector version's metadata, `registry/mongodb/releases/v1.0.0/connector-packaging.json` + connectorVersionPackagingInfo, err := readJSONFile[map[string]interface{}](changedConnectorVersionPath) // Read metadata file + if err != nil { + return fmt.Errorf("failed to read the connector packaging file: %v", err) } - fmt.Printf("Parsed JSON: \n%+v\n", changedFiles) + // Fetch, parse, and reupload the TGZ + tgzUrl, ok := connectorVersionPackagingInfo["uri"].(string) + // Check if the TGZ URL is valid + if !ok || tgzUrl == "" { + return fmt.Errorf("invalid or undefined TGZ URL: %v", tgzUrl) + } + connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(err, tgzUrl, connectorName, connectorVersion) + if err != nil { + return fmt.Errorf("failed to get connector version metadata: %v", err) + } + + uploadedTgzUrl, err := uploadConnectorVersionDefinition(ctx, connectorName, connectorVersion, connectorMetadataTgzPath) + if err != nil { + return fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, connectorVersion, err) + } + connectorMetadataType, ok := connectorVersionMetadata["type"].(string) + if !ok && (connectorMetadataType == ManagedDockerBuild || connectorMetadataType == PrebuiltDockerImage) { + return fmt.Errorf("invalid or undefined connector type: %v", connectorMetadataType) + } + + // // Build payload for registry upsert + // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? + registryPayload, err := buildRegistryPayload(connectorName, connectorVersion, connectorMetadataType, connectorMetadata, uploadedTgzUrl) + + if err != nil { + return fmt.Errorf("failed to build registry payload : %v", err) + } + + fmt.Printf("\n\n ************************ Registry payload: %+v", registryPayload) + + // // Upsert + // updateRegistryGQL(registry_payload) + return nil } -func respondToChangedConnector(changed_connector_path string) { - // Detect status - added/modified/removed files - // for each added connector, create a stub in the registry db - // for each modified connector: - // * Download tgz - // * Re-upload tgz - // * Extract - // * Build payload for API - // * PUT to API (gql) +func uploadConnectorVersionDefinition(ctx context.Context, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { + client, err := storage.NewClient(ctx, option.WithCredentialsFile("gcp-service-account-detail.json")) + if err != nil { - const logo_file = "logo.png" - const metadata_file = "metadata.json" - const readme_file = "README.md" + return "", fmt.Errorf("failed to create client: %v", err) + } + defer client.Close() - var logo_path = path.Join(changed_connector_path, logo_file) - var metadata_path = path.Join(changed_connector_path, metadata_file) - var readme_path = path.Join(changed_connector_path, readme_file) + bucketName := "dev-connector-platform-registry" - fmt.Println(changed_connector_path) - fmt.Println(logo_path) - fmt.Println(metadata_path) - fmt.Println(readme_path) + var uploadedTgzUrl string - // Read the metadata - var metadata_info = readJSONFile(metadata_path) // Read metadata file + objectName := fmt.Sprintf("packages/%s/%s/package.tgz", connectorName, connectorVersion) + uploadedTgzUrl, err = uploadFile(ctx, client, bucketName, objectName, connectorMetadataTgzPath) - // Fetch, parse, and reupload the TGZ - tgz_url := getStringFromPath([]string{"foo", "bar", "baz"}, metadata_info) // TODO // Get the url for the TGZ - tgz_path := getTempFilePath("/tmp") - downloadFile(tgz_url, tgz_path, map[string]string{}) // TODO: Auth headers - extracted_tgz_path := "path/to/extract/directory" // TODO - err := extractTarGz(tgz_path, extracted_tgz_path) if err != nil { - fmt.Println("Error:", err) - return + log.Fatalf("Failed to upload file: %v", err) + } else { + fmt.Println("Uploaded file to GCS:", uploadedTgzUrl) + } + return uploadedTgzUrl, nil +} - var tgz_info = readJSONFile(path.Join(extracted_tgz_path, "metadata.json")) // TODO: Check - var tgz_new_url = "https://todo.com" - uploadFile(tgz_path, tgz_new_url, map[string]string{}) +// Downloads the TGZ File from the URL specified by `tgzUrl`, extracts the TGZ file and returns the content of the +// connector-definition.yaml present in the .hasura-connector folder. +func getConnectorVersionMetadata(err error, tgzUrl string, connectorName string, connectorVersion string) (map[string]interface{}, string, error) { + var connectorVersionMetadata map[string]interface{} + tgzPath := getTempFilePath("extracted_tgz", ".tgz") - // Build payload for registry upsert - // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? - var registry_payload = buildRegistryPayload(metadata_info, tgz_info, tgz_new_url) + err = downloadFile(tgzUrl, tgzPath, map[string]string{}) + if err != nil { + return connectorVersionMetadata, "", fmt.Errorf("failed to download the connector version metadata file from the URL: %v - err: %v", tgzUrl, err) + } + + extractedTgzFolderPath := "extracted_tgz" + + if _, err := os.Stat(extractedTgzFolderPath); os.IsNotExist(err) { + err := os.Mkdir(extractedTgzFolderPath, 0755) + if err != nil { + return connectorVersionMetadata, "", fmt.Errorf("failed to read the connector version metadata file: %v", err) + } + } + + connectorVersionMetadataYamlFilePath, err := extractTarGz(tgzPath, extractedTgzFolderPath+"/"+connectorName+"/"+connectorVersion) + if err != nil { + return connectorVersionMetadata, "", fmt.Errorf("failed to read the connector version metadata file: %v", err) + } else { + fmt.Println("Extracted metadata file at :", connectorVersionMetadataYamlFilePath) + } - // Upsert - updateRegistryGQL(registry_payload) + connectorVersionMetadata, err = readYAMLFile(connectorVersionMetadataYamlFilePath) + if err != nil { + return connectorVersionMetadata, "", fmt.Errorf("failed to read the connector version metadata file: %v", err) + } + return connectorVersionMetadata, tgzPath, nil } -func buildRegistryPayload(metadata_info map[string]interface{}, tgz_info map[string]interface{}, tgz_url string) map[string]interface{} { - return map[string]interface{}{} // TODO +// Write a function that accepts a file path to a YAML file and returns +// the contents of the file as a map[string]interface{}. +// readYAMLFile accepts a file path to a YAML file and returns the contents of the file as a map[string]interface{}. +func readYAMLFile(filePath string) (map[string]interface{}, error) { + // Open the file + file, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + + // Read the file contents + data, err := io.ReadAll(file) + if err != nil { + return nil, fmt.Errorf("failed to read file: %w", err) + } + + // Unmarshal the YAML contents into a map + var result map[string]interface{} + err = yaml.Unmarshal(data, &result) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal YAML: %w", err) + } + + return result, nil +} + +func buildRegistryPayload( + connectorName string, + version string, + packagingType string, + connectorMetadata map[string]interface{}, + uploadedConnectorDefinitionTgzUrl string, +) (ConnectorVersion, error) { + var connectorVersion ConnectorVersion + connectorOverview, ok := connectorMetadata["overview"].(map[string]interface{}) + if !ok { + return connectorVersion, fmt.Errorf("Could not find connector overview in the connector's metadata") + } + connectorNamespace, ok := connectorOverview["namespace"].(string) + if !ok { + return connectorVersion, fmt.Errorf("Could not find the 'namespace' of the connector in the connector's overview in the connector's metadata.json") + } + connectorVersion.Namespace = connectorNamespace + connectorVersion.Name = connectorName + connectorVersion.Version = version + + return connectorVersion, nil } func updateRegistryGQL(payload map[string]interface{}) { @@ -205,6 +345,8 @@ func updateRegistryGQL(payload map[string]interface{}) { req.Var("key", "value") + // add a new key value to req + var respData map[string]interface{} if err := client.Run(ctx, req, &respData); err != nil { @@ -213,8 +355,6 @@ func updateRegistryGQL(payload map[string]interface{}) { } -// Helper functions - func downloadFile(sourceURL, destination string, headers map[string]string) error { // Create a new HTTP client client := &http.Client{} @@ -253,21 +393,32 @@ func downloadFile(sourceURL, destination string, headers map[string]string) erro return nil } +// parseJSON accepts a JSON byte slice and returns the parsed value as the specified type. +func parseJSON[T any](data []byte) (T, error) { + var result T + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return result, nil +} -func readJSONFile(location string) map[string]interface{} { +// Reads a JSON file and attempts to parse the content of the file +// into the type T. +// Note: The location is relative to the root of the repository +func readJSONFile[T any](location string) (T, error) { // Read the file - fileBytes, err := os.ReadFile(location) + var result T + fileBytes, err := os.ReadFile("../" + location) if err != nil { - panic(fmt.Errorf("error reading file: %v", err)) + return result, fmt.Errorf("error reading file at location: %s %v", location, err) } - // Parse JSON - var data map[string]interface{} - if err := json.Unmarshal(fileBytes, &data); err != nil { - panic(fmt.Errorf("error parsing JSON: %v", err)) + if err := json.Unmarshal(fileBytes, &result); err != nil { + return result, fmt.Errorf("error parsing JSON: %v", err) } - return data + return result, nil } func getStringFromPath(path []string, m map[string]interface{}) string { @@ -299,16 +450,16 @@ func getStringFromPath(path []string, m map[string]interface{}) string { const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // generateRandomFileName generates a random file name based on the current time. -func generateRandomFileName() string { +func generateRandomFileName(fileExtension string) string { b := make([]byte, 10) for i := range b { b[i] = letterBytes[rand.Intn(len(letterBytes))] } - return string(b) + return string(b) + fileExtension } // getTempFilePath generates a random file name in the specified directory. -func getTempFilePath(directory string) string { +func getTempFilePath(directory string, fileExtension string) string { // Ensure the directory exists err := os.MkdirAll(directory, os.ModePerm) if err != nil { @@ -316,7 +467,7 @@ func getTempFilePath(directory string) string { } // Generate a random file name - fileName := generateRandomFileName() + fileName := generateRandomFileName(fileExtension) // Create the file path filePath := filepath.Join(directory, fileName) @@ -325,56 +476,59 @@ func getTempFilePath(directory string) string { _, err = os.Stat(filePath) if !os.IsNotExist(err) { // File exists, generate a new name - fileName = generateRandomFileName() + fileName = generateRandomFileName(fileExtension) filePath = filepath.Join(directory, fileName) } return filePath + } -func uploadFile(sourceFilePath, destinationURL string, headers map[string]string) { - // Open the file - file, err := os.Open(sourceFilePath) +// uploadFile uploads a file to Google Cloud Storage +// document this function with comments +func uploadFile(ctx context.Context, client *storage.Client, bucketName, objectName, filePath string) (string, error) { + bucket := client.Bucket(bucketName) + object := bucket.Object(objectName) + wc := object.NewWriter(ctx) + + file, err := os.Open(filePath) if err != nil { - panic(fmt.Errorf("error opening file: %v", err)) + return "", fmt.Errorf("failed to open file: %v", err) } defer file.Close() - // Create a new HTTP request with a POST method - req, err := http.NewRequest("POST", destinationURL, file) - if err != nil { - panic(fmt.Errorf("error creating request: %v", err)) + if _, err := io.Copy(wc, file); err != nil { + return "", fmt.Errorf("failed to upload file: %w", err) } - - // Add headers to the request - for key, value := range headers { - req.Header.Set(key, value) + if err := wc.Close(); err != nil { + return "", fmt.Errorf("failed to close writer: %w", err) } - // Create an HTTP client - client := &http.Client{} + // Return the public URL of the uploaded object. + publicURL := fmt.Sprintf("https://storage.googleapis.com/%s/%s", bucketName, objectName) - // Send the request - resp, err := client.Do(req) - if err != nil { - panic(fmt.Errorf("error sending request: %v", err)) - } - defer resp.Body.Close() - - // Check the response status code - if resp.StatusCode != http.StatusOK { - panic(fmt.Errorf("upload failed with status code: %d", resp.StatusCode)) - } + fmt.Printf("File %s uploaded to bucket %s as %s and is available at %s.\n", filePath, bucketName, objectName, publicURL) + return publicURL, nil } -func extractTarGz(src, dest string) error { - // Run the tar command with the -xzf options - cmd := exec.Command("tar", "-xzf", src, "-C", dest) +func extractTarGz(src, dest string) (string, error) { + // Create the destination directory + // Get the present working directory + pwd := os.Getenv("PWD") + filepath := pwd + "/" + dest + + if err := os.MkdirAll(filepath, 0755); err != nil { + return "", fmt.Errorf("error creating destination directory: %v", err) + } + // Run the tar command with the -xvzf options + cmd := exec.Command("tar", "-xvzf", src, "-C", dest) // Execute the command if err := cmd.Run(); err != nil { - return fmt.Errorf("error extracting tar.gz file: %v", err) + return "", fmt.Errorf("error extracting tar.gz file: %v", err) } - return nil + log.Println("***** File path: ", filepath) + + return fmt.Sprintf("%s/.hasura-connector/connector-metadata.yaml", filepath), nil } diff --git a/registry-automation/cmd/ci_test.go b/registry-automation/cmd/ci_test.go new file mode 100644 index 00000000..b1ccc4a6 --- /dev/null +++ b/registry-automation/cmd/ci_test.go @@ -0,0 +1,101 @@ +package cmd + +import ( + "regexp" + "testing" +) + +func TestProcessAddedOrModifiedConnectorVersions(t *testing.T) { + // Define test cases + testCases := []struct { + name string + files []string + expectedAddedOrModifiedConnectors map[string]map[string]string + }{ + { + name: "Test case 1", + files: []string{ + "registry/hasura/releases/v1.0.0/connector-packaging.json", + "registry/hasura/releases/v2.0.0/connector-packaging.json", + "registry/other/releases/v1.0.0/connector-packaging.json", + }, + expectedAddedOrModifiedConnectors: map[string]map[string]string{ + "hasura": { + "v1.0.0": "registry/hasura/releases/v1.0.0/connector-packaging.json", + "v2.0.0": "registry/hasura/releases/v2.0.0/connector-packaging.json", + }, + "other": { + "v1.0.0": "registry/other/releases/v1.0.0/connector-packaging.json", + }, + }, + }, + { + name: "Test case 2", + files: []string{ + "registry/hasura/releases/v1.0.0/connector-packaging.json", + "registry/hasura/releases/v1.0.0/other-file.json", + }, + expectedAddedOrModifiedConnectors: map[string]map[string]string{ + "hasura": { + "v1.0.0": "registry/hasura/releases/v1.0.0/connector-packaging.json", + }, + }, + }, + { + name: "Test case 3", + files: []string{ + "registry/hasura/releases/v1.0.0/other-file.json", + "registry/other/releases/v1.0.0/connector-packaging.json", + }, + expectedAddedOrModifiedConnectors: map[string]map[string]string{ + "other": { + "v1.0.0": "registry/other/releases/v1.0.0/connector-packaging.json", + }, + }, + }, + } + + // Define the regular expression pattern + connectorVersionPackageRegex := `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` + re := regexp.MustCompile(connectorVersionPackageRegex) + + // Run the test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Initialize the map to store the added or modified connectors + addedOrModifiedConnectorVersions := make(map[string]map[string]string) + + // Call the function under test + processAddedOrModifiedConnectorVersions(tc.files, addedOrModifiedConnectorVersions, re) + + // Compare the actual result with the expected result + if len(addedOrModifiedConnectorVersions) != len(tc.expectedAddedOrModifiedConnectors) { + t.Errorf("Unexpected number of connectors. Expected: %d, Got: %d", len(tc.expectedAddedOrModifiedConnectors), len(addedOrModifiedConnectorVersions)) + } + + for connectorName, versions := range addedOrModifiedConnectorVersions { + expectedVersions, ok := tc.expectedAddedOrModifiedConnectors[connectorName] + if !ok { + t.Errorf("Unexpected connector name: %s", connectorName) + continue + } + + if len(versions) != len(expectedVersions) { + t.Errorf("Unexpected number of versions for connector %s. Expected: %d, Got: %d", connectorName, len(expectedVersions), len(versions)) + } + + for version, connectorVersionPath := range versions { + expectedPath, ok := expectedVersions[version] + if !ok { + t.Errorf("Unexpected version for connector %s: %s", connectorName, version) + continue + } + + if connectorVersionPath != expectedPath { + t.Errorf("Unexpected connector version path for connector %s, version %s. Expected: %s, Got: %s", connectorName, version, expectedPath, connectorVersionPath) + } + } + } + }) + } +} diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go new file mode 100644 index 00000000..b167d71c --- /dev/null +++ b/registry-automation/cmd/utils.go @@ -0,0 +1,5 @@ +package cmd + +func getFilePathRelativeToRepository(filePath string) string { + return "../../" + filePath +} diff --git a/registry-automation/go.mod b/registry-automation/go.mod index b471be51..59b7ef16 100644 --- a/registry-automation/go.mod +++ b/registry-automation/go.mod @@ -5,8 +5,23 @@ go 1.21.4 require github.com/spf13/cobra v1.8.0 require ( + cloud.google.com/go v0.115.0 // indirect + cloud.google.com/go/auth v0.7.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/iam v1.1.11 // indirect + cloud.google.com/go/storage v1.43.0 // indirect github.com/andybalholm/brotli v1.0.1 // indirect - github.com/golang/snappy v0.0.2 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/machinebox/graphql v0.2.2 // indirect @@ -15,4 +30,24 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/ulikunitz/xz v0.5.9 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.188.0 // indirect + google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/registry-automation/go.sum b/registry-automation/go.sum index eb4b546b..5d0aac40 100644 --- a/registry-automation/go.sum +++ b/registry-automation/go.sum @@ -1,12 +1,75 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go/auth v0.7.1 h1:Iv1bbpzJ2OIg16m94XI9/tlzZZl3cdeR3nGVGj78N7s= +cloud.google.com/go/auth v0.7.1/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= +cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= +cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw= +cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -29,16 +92,113 @@ github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw= +google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d h1:/hmn0Ku5kWij/kjGsrcJeC1T/MrJi2iNWwgAqrihFwc= +google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= +google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= +google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/registry/mongodb/metadata.json b/registry/mongodb/metadata.json index f0219847..b3cebab8 100644 --- a/registry/mongodb/metadata.json +++ b/registry/mongodb/metadata.json @@ -20,4 +20,4 @@ "is_open_source": true, "repository": "https://github.com/hasura/ndc-mongodb/" } -} \ No newline at end of file +} From 71717ab2926e1ac58fb2bd9c1e8068fd772e7cc6 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 25 Jul 2024 13:12:29 +0530 Subject: [PATCH 074/115] Build out the registry payload --- registry-automation/cmd/ci.go | 54 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 163bdaa3..cc721f3b 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -199,14 +199,9 @@ func respondToAddedOrModifiedConnectorVersion(connectorName string, connectorVer return fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, connectorVersion, err) } - connectorMetadataType, ok := connectorVersionMetadata["type"].(string) - if !ok && (connectorMetadataType == ManagedDockerBuild || connectorMetadataType == PrebuiltDockerImage) { - return fmt.Errorf("invalid or undefined connector type: %v", connectorMetadataType) - } - // // Build payload for registry upsert // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? - registryPayload, err := buildRegistryPayload(connectorName, connectorVersion, connectorMetadataType, connectorMetadata, uploadedTgzUrl) + registryPayload, err := buildRegistryPayload(connectorName, connectorVersion, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) if err != nil { return fmt.Errorf("failed to build registry payload : %v", err) @@ -307,22 +302,45 @@ func readYAMLFile(filePath string) (map[string]interface{}, error) { func buildRegistryPayload( connectorName string, version string, - packagingType string, + connectorVersionMetadata map[string]interface{}, connectorMetadata map[string]interface{}, uploadedConnectorDefinitionTgzUrl string, ) (ConnectorVersion, error) { var connectorVersion ConnectorVersion + var connectorVersionDockerImage string + connectorOverview, ok := connectorMetadata["overview"].(map[string]interface{}) if !ok { - return connectorVersion, fmt.Errorf("Could not find connector overview in the connector's metadata") + return connectorVersion, fmt.Errorf("could not find connector overview in the connector's metadata") } connectorNamespace, ok := connectorOverview["namespace"].(string) if !ok { - return connectorVersion, fmt.Errorf("Could not find the 'namespace' of the connector in the connector's overview in the connector's metadata.json") + return connectorVersion, fmt.Errorf("could not find the 'namespace' of the connector in the connector's overview in the connector's metadata.json") + } + + connectorVersionPackagingDefinition, ok := connectorVersionMetadata["packagingDefinition"].(map[interface{}]interface{}) + if !ok { + return connectorVersion, fmt.Errorf("could not find the 'packagingDefinition' of the connector %s version %s in the connector's metadata", connectorName, version) + } + connectorVersionPackagingType, ok := connectorVersionPackagingDefinition["type"].(string) + if !ok && (connectorVersionPackagingType == ManagedDockerBuild || connectorVersionPackagingType == PrebuiltDockerImage) { + return connectorVersion, fmt.Errorf("invalid or undefined connector type: %v", connectorVersionPackagingDefinition) + } else if connectorVersionPackagingType == PrebuiltDockerImage { + connectorVersionDockerImage, ok = connectorVersionPackagingDefinition["dockerImage"].(string) + if !ok { + return connectorVersion, fmt.Errorf("could not find the 'dockerImage' of the PrebuiltDockerImage connector %s version %s in the connector's metadata", connectorName, version) + } + } + + connectorVersion = ConnectorVersion{ + Namespace: connectorNamespace, + Name: connectorName, + Version: version, + Image: connectorVersionDockerImage, + PackageDefinitionURL: uploadedConnectorDefinitionTgzUrl, + IsMultitenant: false, // TODO(KC): Figure this out. + Type: connectorVersionPackagingType, } - connectorVersion.Namespace = connectorNamespace - connectorVersion.Name = connectorName - connectorVersion.Version = version return connectorVersion, nil } @@ -393,16 +411,6 @@ func downloadFile(sourceURL, destination string, headers map[string]string) erro return nil } -// parseJSON accepts a JSON byte slice and returns the parsed value as the specified type. -func parseJSON[T any](data []byte) (T, error) { - var result T - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return result, nil -} - // Reads a JSON file and attempts to parse the content of the file // into the type T. // Note: The location is relative to the root of the repository @@ -528,7 +536,5 @@ func extractTarGz(src, dest string) (string, error) { return "", fmt.Errorf("error extracting tar.gz file: %v", err) } - log.Println("***** File path: ", filepath) - return fmt.Sprintf("%s/.hasura-connector/connector-metadata.yaml", filepath), nil } From d795855378932b74bf51b6b612a3cf1661d092a0 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 29 Jul 2024 13:38:42 +0530 Subject: [PATCH 075/115] collect all the processed connectors --- registry-automation/cmd/ci.go | 166 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 84 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index cc721f3b..2fb8fc8c 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -40,13 +40,13 @@ type ChangedFiles struct { // used to insert a new version of a connector in the registry. type ConnectorVersion struct { // Namespace of the connector, e.g. "hasura" - Namespace string `graphql:"namespace"` + Namespace string `json:"namespace"` // Name of the connector - Name string `graphql:"name"` + Name string `json:"name"` // Semantic version of the connector - Version string `graphql:"version"` + Version string `json:"version"` // Docker image of the connector version - Image string `graphql:"image"` + Image *string `json:"image,omitempty"` // URL to the connector's metadata PackageDefinitionURL string `graphql:"package_definition_url"` // Is the connector version multitenant? @@ -55,9 +55,12 @@ type ConnectorVersion struct { Type string `graphql:"type"` } +// Create a struct with the following fields: +// type string +// image *string (optional) type ConnectionVersionMetadata struct { - Type string `yaml:"type"` - Image string `yaml: "image", omitempty` + Type string `yaml:"type"` + Image *string `yaml:"image,omitempty"` } const ( @@ -87,6 +90,8 @@ func init() { // processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConnectorVersions map[string]map[string]string, re *regexp.Regexp) { for _, file := range files { + // Extract the connector name and version from the file path + matches := re.FindStringSubmatch(file) if len(matches) == 3 { connectorName := matches[1] @@ -104,6 +109,7 @@ func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConn // runCI is the main function that runs the CI workflow func runCI(cmd *cobra.Command, args []string) { + ctx := context.Background() var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() changedFilesContent, err := os.Open(changed_files_path) @@ -113,6 +119,12 @@ func runCI(cmd *cobra.Command, args []string) { defer changedFilesContent.Close() + client, err := storage.NewClient(ctx, option.WithCredentialsFile("gcp-service-account-detail.json")) + if err != nil { + log.Fatalf("Failed to create Google bucket client: %v", err) + } + defer client.Close() + // Read the changed file's contents. This file contains all the changed files in the PR changedFilesByteValue, err := io.ReadAll(changedFilesContent) if err != nil { @@ -126,21 +138,33 @@ func runCI(cmd *cobra.Command, args []string) { } - log.Printf("Changed files: %+v", changedFiles) - // Collect the added or modified connectors addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) + // iterate over the addedOrModifiedConnectorVersions and respond to each connector + // by traversing the map and calling the respondToAddedOrModifiedConnectorVersion function + // for each connector, collect the result of respondToAddedOrModifiedConnectorVersion in an array + // and return the array of results + + var connectorVersions []ConnectorVersion for connectorName, versions := range addedOrModifiedConnectorVersions { for version, connectorVersionPath := range versions { - err := respondToAddedOrModifiedConnectorVersion(connectorName, version, connectorVersionPath) + connectorVersion, err := respondToAddedOrModifiedConnectorVersion(client, connectorName, version, connectorVersionPath) if err != nil { log.Fatalf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) } + connectorVersions = append(connectorVersions, connectorVersion) } } - fmt.Printf("new connector versions: \n%+v\n", addedOrModifiedConnectorVersions) + // Serialize connectorVersions to JSON and the + // print the JSON to the console + connectorVersionsJSON, err := json.Marshal(connectorVersions) + if err != nil { + log.Fatalf("Failed to marshal the connector versions: %v", err) + } else { + fmt.Printf("Connector Versions: %s", connectorVersionsJSON) + } } @@ -156,7 +180,7 @@ func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[ return addedOrModifiedConnectorVersions } -func respondToAddedOrModifiedConnectorVersion(connectorName string, connectorVersion string, changedConnectorVersionPath string) error { +func respondToAddedOrModifiedConnectorVersion(client *storage.Client, connectorName string, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { // // Detect status - added/modified/removed files // // for each added connector, create a stub in the registry db // // for each modified connector: @@ -167,73 +191,59 @@ func respondToAddedOrModifiedConnectorVersion(connectorName string, connectorVer // // * PUT to API (gql) // Read the connector packaging file - ctx := context.Background() + var connectorVersion ConnectorVersion // connector's `metadata.json`, `registry/mongodb/metadata.json` connectorMetadata, err := readJSONFile[map[string]interface{}](fmt.Sprintf("registry/%s/metadata.json", connectorName)) if err != nil { - return fmt.Errorf("failed to read the connector metadata file: %v", err) + return connectorVersion, fmt.Errorf("failed to read the connector metadata file: %v", err) } // connector version's metadata, `registry/mongodb/releases/v1.0.0/connector-packaging.json` connectorVersionPackagingInfo, err := readJSONFile[map[string]interface{}](changedConnectorVersionPath) // Read metadata file if err != nil { - return fmt.Errorf("failed to read the connector packaging file: %v", err) + return connectorVersion, fmt.Errorf("failed to read the connector packaging file: %v", err) } - // Fetch, parse, and reupload the TGZ tgzUrl, ok := connectorVersionPackagingInfo["uri"].(string) // Check if the TGZ URL is valid if !ok || tgzUrl == "" { - return fmt.Errorf("invalid or undefined TGZ URL: %v", tgzUrl) + return connectorVersion, fmt.Errorf("invalid or undefined TGZ URL: %v", tgzUrl) } - connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(err, tgzUrl, connectorName, connectorVersion) + connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(err, tgzUrl, connectorName, version) if err != nil { - return fmt.Errorf("failed to get connector version metadata: %v", err) + return connectorVersion, fmt.Errorf("failed to get connector version metadata: %v", err) } - uploadedTgzUrl, err := uploadConnectorVersionDefinition(ctx, connectorName, connectorVersion, connectorMetadataTgzPath) + uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connectorName, version, connectorMetadataTgzPath) if err != nil { - return fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, connectorVersion, err) + return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, version, err) } // // Build payload for registry upsert // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? - registryPayload, err := buildRegistryPayload(connectorName, connectorVersion, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) - - if err != nil { - return fmt.Errorf("failed to build registry payload : %v", err) - } - - fmt.Printf("\n\n ************************ Registry payload: %+v", registryPayload) + return buildRegistryPayload(connectorName, version, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) // // Upsert - // updateRegistryGQL(registry_payload) - return nil + // success, err := updateRegistryGQL(registryPayload) + // if err != nil { + // return connectorVersion, fmt.Errorf("failed to update the registry: %v", err) + // } else { + // fmt.Printf("Successfully updated the registry: %v", success) + + // } + // return nil } -func uploadConnectorVersionDefinition(ctx context.Context, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { - client, err := storage.NewClient(ctx, option.WithCredentialsFile("gcp-service-account-detail.json")) - if err != nil { - - return "", fmt.Errorf("failed to create client: %v", err) - } - defer client.Close() - +func uploadConnectorVersionDefinition(client *storage.Client, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { bucketName := "dev-connector-platform-registry" - - var uploadedTgzUrl string - objectName := fmt.Sprintf("packages/%s/%s/package.tgz", connectorName, connectorVersion) - uploadedTgzUrl, err = uploadFile(ctx, client, bucketName, objectName, connectorMetadataTgzPath) + uploadedTgzUrl, err := uploadFile(client, bucketName, objectName, connectorMetadataTgzPath) if err != nil { - log.Fatalf("Failed to upload file: %v", err) - } else { - fmt.Println("Uploaded file to GCS:", uploadedTgzUrl) - + return "", err } return uploadedTgzUrl, nil } @@ -299,6 +309,7 @@ func readYAMLFile(filePath string) (map[string]interface{}, error) { return result, nil } +// buildRegistryPayload builds the payload for the registry upsert API func buildRegistryPayload( connectorName string, version string, @@ -336,7 +347,7 @@ func buildRegistryPayload( Namespace: connectorNamespace, Name: connectorName, Version: version, - Image: connectorVersionDockerImage, + Image: &connectorVersionDockerImage, PackageDefinitionURL: uploadedConnectorDefinitionTgzUrl, IsMultitenant: false, // TODO(KC): Figure this out. Type: connectorVersionPackagingType, @@ -345,32 +356,44 @@ func buildRegistryPayload( return connectorVersion, nil } -func updateRegistryGQL(payload map[string]interface{}) { +func updateRegistryGQL(payload []ConnectorVersion) (bool, error) { // Example: https://stackoverflow.com/questions/66931228/http-requests-golang-with-graphql - client := graphql.NewClient("https://") + client := graphql.NewClient("https://conn-deploy-stg.hasura.app/v1/graphql") ctx := context.Background() req := graphql.NewRequest(` - query ($key: String!) { - items (id:$key) { - field1 - field2 - field3 - } +mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_version_insert_input!]!) { + insert_hub_registry_connector_version(objects: $connectorVersion, on_conflict: {constraint: connector_version_namespace_name_version_key, update_columns: [image, package_definition_url]})) { + affected_rows + returning { + image + namespace + is_multitenant + package_definition_url } + } +} `) - req.Var("key", "value") + req.Var("connectorVersion", interface{}(payload)) // add a new key value to req var respData map[string]interface{} + req.Header.Set("x-connector-publication-key", "") // TODO: The value of the header should be fetched from the environment variable CONNECTOR_PUBLICATION_KEY + + // Execute the GraphQL query and check the response. if err := client.Run(ctx, req, &respData); err != nil { - panic(err) + return false, err } + // print the respData + fmt.Println("Response from the API: ", respData) + + return true, nil + } func downloadFile(sourceURL, destination string, headers map[string]string) error { @@ -429,32 +452,6 @@ func readJSONFile[T any](location string) (T, error) { return result, nil } -func getStringFromPath(path []string, m map[string]interface{}) string { - var current interface{} = m - - // Traverse the path - for _, key := range path { - // Check if current element is a map - if currentMap, ok := current.(map[string]interface{}); ok { - // Check if key exists in the current map - if val, found := currentMap[key]; found { - current = val - } else { - return "" // Key not found, return empty string - } - } else { - return "" // Current element is not a map, return empty string - } - } - - // Check if the final value is a string - if value, ok := current.(string); ok { - return value - } - - return "" // Final value is not a string, return empty string -} - const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // generateRandomFileName generates a random file name based on the current time. @@ -494,10 +491,11 @@ func getTempFilePath(directory string, fileExtension string) string { // uploadFile uploads a file to Google Cloud Storage // document this function with comments -func uploadFile(ctx context.Context, client *storage.Client, bucketName, objectName, filePath string) (string, error) { +func uploadFile(client *storage.Client, bucketName, objectName, filePath string) (string, error) { bucket := client.Bucket(bucketName) object := bucket.Object(objectName) - wc := object.NewWriter(ctx) + newCtx := context.Background() + wc := object.NewWriter(newCtx) file, err := os.Open(filePath) if err != nil { From 8882013d91568eae5b8df532fc27988070232260 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 30 Jul 2024 15:26:36 +0530 Subject: [PATCH 076/115] no-op refactors --- registry-automation/cmd/ci.go | 129 +++++++++++------------------ registry-automation/cmd/ci_test.go | 7 +- 2 files changed, 50 insertions(+), 86 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 2fb8fc8c..032133ad 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -48,11 +48,11 @@ type ConnectorVersion struct { // Docker image of the connector version Image *string `json:"image,omitempty"` // URL to the connector's metadata - PackageDefinitionURL string `graphql:"package_definition_url"` + PackageDefinitionURL string `json:"package_definition_url"` // Is the connector version multitenant? - IsMultitenant bool `graphql:"is_multitenant"` + IsMultitenant bool `json:"is_multitenant"` // Type of the connector packaing `PreBuiltDockerImage`/`ManagedDockerBuild` - Type string `graphql:"type"` + Type string `json:"type"` } // Create a struct with the following fields: @@ -88,7 +88,10 @@ func init() { } // processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version -func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConnectorVersions map[string]map[string]string, re *regexp.Regexp) { +func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConnectorVersions map[string]map[string]string) { + const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` + re := regexp.MustCompile(connectorVersionPackageRegex) + for _, file := range files { // Extract the connector name and version from the file path @@ -141,58 +144,60 @@ func runCI(cmd *cobra.Command, args []string) { // Collect the added or modified connectors addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) - // iterate over the addedOrModifiedConnectorVersions and respond to each connector - // by traversing the map and calling the respondToAddedOrModifiedConnectorVersion function - // for each connector, collect the result of respondToAddedOrModifiedConnectorVersion in an array - // and return the array of results - var connectorVersions []ConnectorVersion + var uploadConnectorVersionErr error + encounteredError := false for connectorName, versions := range addedOrModifiedConnectorVersions { for version, connectorVersionPath := range versions { - connectorVersion, err := respondToAddedOrModifiedConnectorVersion(client, connectorName, version, connectorVersionPath) + var connectorVersion ConnectorVersion + connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) if err != nil { - log.Fatalf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) + fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) + encounteredError = true + break } connectorVersions = append(connectorVersions, connectorVersion) } + if encounteredError { + break + } } - // Serialize connectorVersions to JSON and the - // print the JSON to the console - connectorVersionsJSON, err := json.Marshal(connectorVersions) - if err != nil { - log.Fatalf("Failed to marshal the connector versions: %v", err) + if encounteredError { + // delete the uploaded connector versions from the registry + log.Fatalf("Failed to upload the connector version: %v", uploadConnectorVersionErr) + // TODO: Delete the uploaded connector versions from the registry + } else { - fmt.Printf("Connector Versions: %s", connectorVersionsJSON) + fmt.Println("Successfully uploaded the connector versions to the registry") + + err = updateRegistryGQL(connectorVersions) + if err != nil { + log.Fatalf("Failed to update the registry: %v", err) + } + } } +// collectAddedOrModifiedConnectors collects the added or modified connectors from the changed files func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[string]string { - const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` - re := regexp.MustCompile(connectorVersionPackageRegex) // addedOrModifiedConnectorVersions := make(map[string]map[string]string) - processAddedOrModifiedConnectorVersions(changedFiles.Added, addedOrModifiedConnectorVersions, re) - processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions, re) + processAddedOrModifiedConnectorVersions(changedFiles.Added, addedOrModifiedConnectorVersions) + processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions) return addedOrModifiedConnectorVersions } -func respondToAddedOrModifiedConnectorVersion(client *storage.Client, connectorName string, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { - // // Detect status - added/modified/removed files - // // for each added connector, create a stub in the registry db - // // for each modified connector: - // // * Download tgz - // // * Re-upload tgz - // // * Extract - // // * Build payload for API - // // * PUT to API (gql) - - // Read the connector packaging file +// uploadConnectorVersionPackage uploads the connector version package to the registry +func uploadConnectorVersionPackage(client *storage.Client, connectorName string, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { + var connectorVersion ConnectorVersion + // Read the connector's metadata and the connector version's metadata + // connector's `metadata.json`, `registry/mongodb/metadata.json` connectorMetadata, err := readJSONFile[map[string]interface{}](fmt.Sprintf("registry/%s/metadata.json", connectorName)) if err != nil { @@ -222,19 +227,9 @@ func respondToAddedOrModifiedConnectorVersion(client *storage.Client, connectorN return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, version, err) } - // // Build payload for registry upsert - // var logo_new_url = reuploadLogo(logo_path) // Is the logo hosted somewhere? + // Build payload for registry upsert return buildRegistryPayload(connectorName, version, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) - // // Upsert - // success, err := updateRegistryGQL(registryPayload) - // if err != nil { - // return connectorVersion, fmt.Errorf("failed to update the registry: %v", err) - // } else { - // fmt.Printf("Successfully updated the registry: %v", success) - - // } - // return nil } func uploadConnectorVersionDefinition(client *storage.Client, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { @@ -356,17 +351,18 @@ func buildRegistryPayload( return connectorVersion, nil } -func updateRegistryGQL(payload []ConnectorVersion) (bool, error) { +func updateRegistryGQL(payload []ConnectorVersion) error { // Example: https://stackoverflow.com/questions/66931228/http-requests-golang-with-graphql - client := graphql.NewClient("https://conn-deploy-stg.hasura.app/v1/graphql") + client := graphql.NewClient("http://localhost:8081/v1/graphql") ctx := context.Background() req := graphql.NewRequest(` mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_version_insert_input!]!) { - insert_hub_registry_connector_version(objects: $connectorVersion, on_conflict: {constraint: connector_version_namespace_name_version_key, update_columns: [image, package_definition_url]})) { + insert_hub_registry_connector_version(objects: $connectorVersion, on_conflict: {constraint: connector_version_namespace_name_version_key, update_columns: [image, package_definition_url]}) { affected_rows returning { + id image namespace is_multitenant @@ -375,24 +371,26 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi } } `) - - req.Var("connectorVersion", interface{}(payload)) + // add the payload to the request + req.Var("connectorVersion", payload) // add a new key value to req var respData map[string]interface{} - req.Header.Set("x-connector-publication-key", "") // TODO: The value of the header should be fetched from the environment variable CONNECTOR_PUBLICATION_KEY + req.Header.Set("x-hasura-admin-secret", "myadminsecretkey") + req.Header.Set("x-hasura-role", "connector_publishing_automation") + req.Header.Set("x-connector-publication-key", "usnEu*pYp8wiUjbzv3g4iruemTzDgfi@") // TODO: The value of the header should be fetched from the environment variable CONNECTOR_PUBLICATION_KEY // Execute the GraphQL query and check the response. if err := client.Run(ctx, req, &respData); err != nil { - return false, err + return err } // print the respData fmt.Println("Response from the API: ", respData) - return true, nil + return nil } @@ -484,39 +482,10 @@ func getTempFilePath(directory string, fileExtension string) string { fileName = generateRandomFileName(fileExtension) filePath = filepath.Join(directory, fileName) } - return filePath } -// uploadFile uploads a file to Google Cloud Storage -// document this function with comments -func uploadFile(client *storage.Client, bucketName, objectName, filePath string) (string, error) { - bucket := client.Bucket(bucketName) - object := bucket.Object(objectName) - newCtx := context.Background() - wc := object.NewWriter(newCtx) - - file, err := os.Open(filePath) - if err != nil { - return "", fmt.Errorf("failed to open file: %v", err) - } - defer file.Close() - - if _, err := io.Copy(wc, file); err != nil { - return "", fmt.Errorf("failed to upload file: %w", err) - } - if err := wc.Close(); err != nil { - return "", fmt.Errorf("failed to close writer: %w", err) - } - - // Return the public URL of the uploaded object. - publicURL := fmt.Sprintf("https://storage.googleapis.com/%s/%s", bucketName, objectName) - - fmt.Printf("File %s uploaded to bucket %s as %s and is available at %s.\n", filePath, bucketName, objectName, publicURL) - return publicURL, nil -} - func extractTarGz(src, dest string) (string, error) { // Create the destination directory // Get the present working directory diff --git a/registry-automation/cmd/ci_test.go b/registry-automation/cmd/ci_test.go index b1ccc4a6..7646e084 100644 --- a/registry-automation/cmd/ci_test.go +++ b/registry-automation/cmd/ci_test.go @@ -1,7 +1,6 @@ package cmd import ( - "regexp" "testing" ) @@ -55,10 +54,6 @@ func TestProcessAddedOrModifiedConnectorVersions(t *testing.T) { }, } - // Define the regular expression pattern - connectorVersionPackageRegex := `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` - re := regexp.MustCompile(connectorVersionPackageRegex) - // Run the test cases for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -66,7 +61,7 @@ func TestProcessAddedOrModifiedConnectorVersions(t *testing.T) { addedOrModifiedConnectorVersions := make(map[string]map[string]string) // Call the function under test - processAddedOrModifiedConnectorVersions(tc.files, addedOrModifiedConnectorVersions, re) + processAddedOrModifiedConnectorVersions(tc.files, addedOrModifiedConnectorVersions) // Compare the actual result with the expected result if len(addedOrModifiedConnectorVersions) != len(tc.expectedAddedOrModifiedConnectors) { From fd32b0ca77d8b997283d995fd7aaa50cd21029bc Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 30 Jul 2024 16:16:46 +0530 Subject: [PATCH 077/115] remove redundant fields --- registry-automation/cmd/ci.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 032133ad..23949424 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -177,7 +177,6 @@ func runCI(cmd *cobra.Command, args []string) { } } - } // collectAddedOrModifiedConnectors collects the added or modified connectors from the changed files @@ -329,6 +328,7 @@ func buildRegistryPayload( return connectorVersion, fmt.Errorf("could not find the 'packagingDefinition' of the connector %s version %s in the connector's metadata", connectorName, version) } connectorVersionPackagingType, ok := connectorVersionPackagingDefinition["type"].(string) + if !ok && (connectorVersionPackagingType == ManagedDockerBuild || connectorVersionPackagingType == PrebuiltDockerImage) { return connectorVersion, fmt.Errorf("invalid or undefined connector type: %v", connectorVersionPackagingDefinition) } else if connectorVersionPackagingType == PrebuiltDockerImage { @@ -363,10 +363,6 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi affected_rows returning { id - image - namespace - is_multitenant - package_definition_url } } } From 1ce8713508bae882ebe6a1b56f65f5b9d5d97466 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 12:32:34 +0530 Subject: [PATCH 078/115] minor no-op --- registry-automation/cmd/ci.go | 40 +++++++++++++++++++++++++------- registry-automation/cmd/utils.go | 6 +++-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 23949424..b3cc6cec 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -147,6 +147,7 @@ func runCI(cmd *cobra.Command, args []string) { var connectorVersions []ConnectorVersion var uploadConnectorVersionErr error encounteredError := false + for connectorName, versions := range addedOrModifiedConnectorVersions { for version, connectorVersionPath := range versions { var connectorVersion ConnectorVersion @@ -164,19 +165,36 @@ func runCI(cmd *cobra.Command, args []string) { } if encounteredError { + // attempt to cleanup the uploaded connector versions + _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up // delete the uploaded connector versions from the registry log.Fatalf("Failed to upload the connector version: %v", uploadConnectorVersionErr) // TODO: Delete the uploaded connector versions from the registry } else { fmt.Println("Successfully uploaded the connector versions to the registry") - err = updateRegistryGQL(connectorVersions) if err != nil { + // attempt to cleanup the uploaded connector versions + _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up + log.Fatalf("Failed to update the registry: %v", err) } + } +} + +func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions []ConnectorVersion) error { + // Iterate over the connector versions and delete the uploaded files + // from the google bucket + for _, connectorVersion := range connectorVersions { + objectName := generateGCPObjectName(connectorVersion.Name, connectorVersion.Version) + err := deleteFile(client, "dev-connector-platform-registry", objectName) + if err != nil { + return err + } } + return nil } // collectAddedOrModifiedConnectors collects the added or modified connectors from the changed files @@ -185,7 +203,11 @@ func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[ addedOrModifiedConnectorVersions := make(map[string]map[string]string) processAddedOrModifiedConnectorVersions(changedFiles.Added, addedOrModifiedConnectorVersions) - processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions) + + // Not sure if we need to process the modified files as well, because it is very unlikely + // that an existing connector version will be modified. + + // processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions) return addedOrModifiedConnectorVersions } @@ -224,16 +246,18 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connectorName, version, connectorMetadataTgzPath) if err != nil { return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, version, err) + } else { + // print success message with the name of the connector and the version + fmt.Printf("Successfully uploaded the connector version definition in google cloud registry for the connector: %v version: %v\n", connectorName, version) } // Build payload for registry upsert return buildRegistryPayload(connectorName, version, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) - } func uploadConnectorVersionDefinition(client *storage.Client, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { bucketName := "dev-connector-platform-registry" - objectName := fmt.Sprintf("packages/%s/%s/package.tgz", connectorName, connectorVersion) + objectName := generateGCPObjectName(connectorName, connectorVersion) uploadedTgzUrl, err := uploadFile(client, bucketName, objectName, connectorMetadataTgzPath) if err != nil { @@ -338,6 +362,9 @@ func buildRegistryPayload( } } + // TODO: Make a query to the registry to check if the connector already exists, + // if not, insert the connector first and then insert the connector version. + // Also, fetch the is_multitenant value from the registry. connectorVersion = ConnectorVersion{ Namespace: connectorNamespace, Name: connectorName, @@ -352,8 +379,6 @@ func buildRegistryPayload( } func updateRegistryGQL(payload []ConnectorVersion) error { - // Example: https://stackoverflow.com/questions/66931228/http-requests-golang-with-graphql - client := graphql.NewClient("http://localhost:8081/v1/graphql") ctx := context.Background() @@ -365,8 +390,7 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi id } } -} - `) +}`) // add the payload to the request req.Var("connectorVersion", payload) diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index b167d71c..70a8b4e1 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -1,5 +1,7 @@ package cmd -func getFilePathRelativeToRepository(filePath string) string { - return "../../" + filePath +import "fmt" + +func generateGCPObjectName(connectorName, version string) string { + return fmt.Sprintf("packages/%s/%s/package.tgz", connectorName, version) } From f2928f6f37d0cf2659e64a52682baa019da6902f Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 14:04:26 +0530 Subject: [PATCH 079/115] WIP: gather CLI args in a struct --- registry-automation/cmd/ci.go | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index b3cc6cec..f678657b 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -68,23 +68,64 @@ const ( PrebuiltDockerImage = "PrebuiltDockerImage" ) +// Make a struct with the fields expected in the command line arguments +type ConnectorRegistryArgs struct { + ChangedFilesPath string + PublicationEnv string + ConnectorRegistryGQL string + ConnectorPublicationKey string + GCPServiceAccountDetails string + GCPBucketName string +} + +var cmdArgs ConnectorRegistryArgs + func init() { rootCmd.AddCommand(ciCmd) // Path for the changed files in the PR var changedFilesPathEnv = os.Getenv("CHANGED_FILES_PATH") - ciCmd.PersistentFlags().String("changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") + ciCmd.PersistentFlags().StringVar(&cmdArgs.ChangedFilesPath, "changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") if changedFilesPathEnv == "" { ciCmd.MarkPersistentFlagRequired("changed-files-path") } // Publication environment var publicationEnv = os.Getenv("PUBLICATION_ENV") - ciCmd.PersistentFlags().String("publication-env", publicationEnv, "publication environment (staging/prod). Default: staging") + ciCmd.PersistentFlags().StringVar(&cmdArgs.PublicationEnv, "publication-env", publicationEnv, "publication environment (staging/prod). Default: staging") // default publicationEnv to "staging" if publicationEnv == "" { ciCmd.PersistentFlags().Set("publication-env", "staging") } + + // Connector registry Hasura GraphQL URL + registryGQLURL := os.Getenv("CONNECTOR_REGISTRY_GQL_URL") + ciCmd.PersistentFlags().StringVar(&cmdArgs.ConnectorRegistryGQL, "connector-registry-gql-url", registryGQLURL, "Hasura GraphQL URL for the connector registry") + if registryGQLURL == "" { + ciCmd.MarkPersistentFlagRequired("connector-registry-gql-url") + } + + // Connector publication key + connectorPublicationKey := os.Getenv("CONNECTOR_PUBLICATION_KEY") + ciCmd.PersistentFlags().StringVar(&cmdArgs.ConnectorPublicationKey, "connector-publication-key", connectorPublicationKey, "Connector publication key used for authentication with the registry GraphQL API") + if connectorPublicationKey == "" { + ciCmd.MarkPersistentFlagRequired("connector-publication-key") + } + + // GCP service account details + gcpServiceAccountDetails := os.Getenv("GCP_SERVICE_ACCOUNT_DETAILS") + ciCmd.PersistentFlags().StringVar(&cmdArgs.GCPServiceAccountDetails, "gcp-service-account-details", gcpServiceAccountDetails, "GCP service account details file path") + if gcpServiceAccountDetails == "" { + ciCmd.MarkPersistentFlagRequired("gcp-service-account-details") + } + + // GCP bucket name + gcpBucketName := os.Getenv("GCP_BUCKET_NAME") + ciCmd.PersistentFlags().StringVar(&cmdArgs.GCPBucketName, "gcp-bucket-name", gcpBucketName, "GCP bucket name") + if gcpBucketName == "" { + ciCmd.MarkPersistentFlagRequired("gcp-bucket-name") + } + } // processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version @@ -113,11 +154,10 @@ func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConn // runCI is the main function that runs the CI workflow func runCI(cmd *cobra.Command, args []string) { ctx := context.Background() - var changed_files_path = cmd.PersistentFlags().Lookup("changed-files-path").Value.String() - changedFilesContent, err := os.Open(changed_files_path) + changedFilesContent, err := os.Open(cmdArgs.ChangedFilesPath) if err != nil { - log.Fatalf("Failed to open the file: %v, err: %v", changed_files_path, err) + log.Fatalf("Failed to open the file: %v, err: %v", cmdArgs.ChangedFilesPath, err) } defer changedFilesContent.Close() @@ -398,7 +438,6 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi var respData map[string]interface{} - req.Header.Set("x-hasura-admin-secret", "myadminsecretkey") req.Header.Set("x-hasura-role", "connector_publishing_automation") req.Header.Set("x-connector-publication-key", "usnEu*pYp8wiUjbzv3g4iruemTzDgfi@") // TODO: The value of the header should be fetched from the environment variable CONNECTOR_PUBLICATION_KEY From 15537e9de60fedd475f5a7b340aa9a8f953d1e0d Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 14:31:09 +0530 Subject: [PATCH 080/115] include connector's namespace in the registry path --- registry-automation/cmd/ci.go | 45 ++++++++++++++++++-------------- registry-automation/cmd/utils.go | 4 +-- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index f678657b..5f3565c1 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -228,8 +228,8 @@ func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions // from the google bucket for _, connectorVersion := range connectorVersions { - objectName := generateGCPObjectName(connectorVersion.Name, connectorVersion.Version) - err := deleteFile(client, "dev-connector-platform-registry", objectName) + objectName := generateGCPObjectName(connectorVersion.Namespace, connectorVersion.Name, connectorVersion.Version) + err := deleteFile(client, cmdArgs.GCPBucketName, objectName) if err != nil { return err } @@ -280,10 +280,15 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(err, tgzUrl, connectorName, version) if err != nil { - return connectorVersion, fmt.Errorf("failed to get connector version metadata: %v", err) + return connectorVersion, err } - uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connectorName, version, connectorMetadataTgzPath) + connectorNamespace, err := getConnectorNamespace(connectorMetadata) + if err != nil { + return connectorVersion, fmt.Errorf("failed to get the connector namespace: %v", err) + } + + uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connectorNamespace, connectorName, version, connectorMetadataTgzPath) if err != nil { return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, version, err) } else { @@ -292,12 +297,12 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, } // Build payload for registry upsert - return buildRegistryPayload(connectorName, version, connectorVersionMetadata, connectorMetadata, uploadedTgzUrl) + return buildRegistryPayload(connectorNamespace, connectorName, version, connectorVersionMetadata, uploadedTgzUrl) } -func uploadConnectorVersionDefinition(client *storage.Client, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { - bucketName := "dev-connector-platform-registry" - objectName := generateGCPObjectName(connectorName, connectorVersion) +func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { + bucketName := cmdArgs.GCPBucketName + objectName := generateGCPObjectName(connectorNamespace, connectorName, connectorVersion) uploadedTgzUrl, err := uploadFile(client, bucketName, objectName, connectorMetadataTgzPath) if err != nil { @@ -367,26 +372,28 @@ func readYAMLFile(filePath string) (map[string]interface{}, error) { return result, nil } +func getConnectorNamespace(connectorMetadata map[string]interface{}) (string, error) { + connectorOverview, ok := connectorMetadata["overview"].(map[string]interface{}) + if !ok { + return "", fmt.Errorf("could not find connector overview in the connector's metadata") + } + connectorNamespace, ok := connectorOverview["namespace"].(string) + if !ok { + return "", fmt.Errorf("could not find the 'namespace' of the connector in the connector's overview in the connector's metadata.json") + } + return connectorNamespace, nil +} + // buildRegistryPayload builds the payload for the registry upsert API func buildRegistryPayload( + connectorNamespace string, connectorName string, version string, connectorVersionMetadata map[string]interface{}, - connectorMetadata map[string]interface{}, uploadedConnectorDefinitionTgzUrl string, ) (ConnectorVersion, error) { var connectorVersion ConnectorVersion var connectorVersionDockerImage string - - connectorOverview, ok := connectorMetadata["overview"].(map[string]interface{}) - if !ok { - return connectorVersion, fmt.Errorf("could not find connector overview in the connector's metadata") - } - connectorNamespace, ok := connectorOverview["namespace"].(string) - if !ok { - return connectorVersion, fmt.Errorf("could not find the 'namespace' of the connector in the connector's overview in the connector's metadata.json") - } - connectorVersionPackagingDefinition, ok := connectorVersionMetadata["packagingDefinition"].(map[interface{}]interface{}) if !ok { return connectorVersion, fmt.Errorf("could not find the 'packagingDefinition' of the connector %s version %s in the connector's metadata", connectorName, version) diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index 70a8b4e1..9d1d9890 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -2,6 +2,6 @@ package cmd import "fmt" -func generateGCPObjectName(connectorName, version string) string { - return fmt.Sprintf("packages/%s/%s/package.tgz", connectorName, version) +func generateGCPObjectName(namespace, connectorName, version string) string { + return fmt.Sprintf("packages/%s/%s/%s/package.tgz", namespace, connectorName, version) } From e368a050ef6beae28a19ca3e9822b32e05eafb90 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 14:35:04 +0530 Subject: [PATCH 081/115] add a debug log in cleaning uploaded connector versions --- registry-automation/cmd/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 5f3565c1..bc9760f5 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -217,7 +217,6 @@ func runCI(cmd *cobra.Command, args []string) { if err != nil { // attempt to cleanup the uploaded connector versions _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up - log.Fatalf("Failed to update the registry: %v", err) } } @@ -226,6 +225,7 @@ func runCI(cmd *cobra.Command, args []string) { func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions []ConnectorVersion) error { // Iterate over the connector versions and delete the uploaded files // from the google bucket + fmt.Println("Cleaning up the uploaded connector versions") for _, connectorVersion := range connectorVersions { objectName := generateGCPObjectName(connectorVersion.Namespace, connectorVersion.Name, connectorVersion.Version) From bf22df2e840202673fe3fd72c432f1019cc97b83 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 14:35:41 +0530 Subject: [PATCH 082/115] remove stray comment --- registry-automation/cmd/ci.go | 1 - 1 file changed, 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index bc9760f5..1584af04 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -209,7 +209,6 @@ func runCI(cmd *cobra.Command, args []string) { _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up // delete the uploaded connector versions from the registry log.Fatalf("Failed to upload the connector version: %v", uploadConnectorVersionErr) - // TODO: Delete the uploaded connector versions from the registry } else { fmt.Println("Successfully uploaded the connector versions to the registry") From 359f4730948ce1e21c085f444727e57b75c2a111 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 14:54:30 +0530 Subject: [PATCH 083/115] use the GCP_SERVICE_ACCOUNT_DETAILS from the env --- registry-automation/cmd/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 1584af04..b7014fb1 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -162,7 +162,7 @@ func runCI(cmd *cobra.Command, args []string) { defer changedFilesContent.Close() - client, err := storage.NewClient(ctx, option.WithCredentialsFile("gcp-service-account-detail.json")) + client, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(cmdArgs.GCPServiceAccountDetails))) if err != nil { log.Fatalf("Failed to create Google bucket client: %v", err) } From 1643bdc1d3a7b0f77b94a32afcf4429bfc61dac4 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 15:09:59 +0530 Subject: [PATCH 084/115] track cmd/gcp.go --- registry-automation/cmd/ci.go | 9 +++---- registry-automation/cmd/gcp.go | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 registry-automation/cmd/gcp.go diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index b7014fb1..a205d3ed 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -425,7 +425,8 @@ func buildRegistryPayload( } func updateRegistryGQL(payload []ConnectorVersion) error { - client := graphql.NewClient("http://localhost:8081/v1/graphql") + var respData map[string]interface{} + client := graphql.NewClient(cmdArgs.ConnectorRegistryGQL) ctx := context.Background() req := graphql.NewRequest(` @@ -440,12 +441,8 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi // add the payload to the request req.Var("connectorVersion", payload) - // add a new key value to req - - var respData map[string]interface{} - req.Header.Set("x-hasura-role", "connector_publishing_automation") - req.Header.Set("x-connector-publication-key", "usnEu*pYp8wiUjbzv3g4iruemTzDgfi@") // TODO: The value of the header should be fetched from the environment variable CONNECTOR_PUBLICATION_KEY + req.Header.Set("x-connector-publication-key", cmdArgs.ConnectorPublicationKey) // Execute the GraphQL query and check the response. if err := client.Run(ctx, req, &respData); err != nil { diff --git a/registry-automation/cmd/gcp.go b/registry-automation/cmd/gcp.go new file mode 100644 index 00000000..40d41d62 --- /dev/null +++ b/registry-automation/cmd/gcp.go @@ -0,0 +1,46 @@ +// Description: This file contains the functions to interact with Google Cloud Storage. +package cmd + +import ( + "cloud.google.com/go/storage" + "context" + "fmt" + "io" + "os" +) + +// deleteFile deletes a file from Google Cloud Storage +func deleteFile(client *storage.Client, bucketName, objectName string) error { + bucket := client.Bucket(bucketName) + object := bucket.Object(objectName) + + return object.Delete(context.Background()) +} + +// uploadFile uploads a file to Google Cloud Storage +// document this function with comments +func uploadFile(client *storage.Client, bucketName, objectName, filePath string) (string, error) { + bucket := client.Bucket(bucketName) + object := bucket.Object(objectName) + newCtx := context.Background() + wc := object.NewWriter(newCtx) + + file, err := os.Open(filePath) + if err != nil { + return "", fmt.Errorf("failed to open file: %v", err) + } + defer file.Close() + + if _, err := io.Copy(wc, file); err != nil { + return "", fmt.Errorf("failed to upload file: %w", err) + } + if err := wc.Close(); err != nil { + return "", fmt.Errorf("failed to close writer: %w", err) + } + + // Return the public URL of the uploaded object. + publicURL := fmt.Sprintf("https://storage.googleapis.com/%s/%s", bucketName, objectName) + + fmt.Printf("File %s uploaded to bucket %s as %s and is available at %s.\n", filePath, bucketName, objectName, publicURL) + return publicURL, nil +} From b499d2ce93c07f763fea3118c50791750f4b49cd Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 17:33:05 +0530 Subject: [PATCH 085/115] update the github action --- .github/workflows/registry-updates.yaml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index ff198639..01a87462 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -16,6 +16,7 @@ on: jobs: update_registry_db: runs-on: ubuntu-latest + environment: staging steps: - name: Checkout repository @@ -46,19 +47,6 @@ jobs: run: | cat changed_files.json - # - name: Pseudocode for Next steps - # id: next_steps - # run: | - # echo 'Detect status - added/modified/removed files' - # echo 'for each removed connector, remove from registry db' - # echo 'for each added connector, create a stub in the registry db' - # echo 'for each modified connector:' - # echo ' * Download tgz' - # echo ' * Re-upload tgz' - # echo ' * Extract' - # echo ' * Build payload for API' - # echo ' * PUT to API (gql)' - - name: Setup Go uses: actions/setup-go@v4 with: @@ -67,7 +55,13 @@ jobs: - name: Run registry automation program env: CHANGED_FILES_PATH: "changed_files.json" + PUBLICATION_ENV: "staging" + CONNECTOR_REGISTRY_GQL_URL: ${{ secrets.CONNECTOR_REGISTRY_GQL_URL }} + GCP_BUCKET_NAME: dev-connector-platform-registry + GCP_SERVICE_ACCOUNT_DETAILS: ${{ secrets.GCP_SERVICE_ACCOUNT_DETAILS }} + CONNECTOR_PUBICATION_KEY: ${{ secrets.CONNECTOR_PUBLICATION_KEY }} run: | + echo "connector registry GQL URL is $CONNECTOR_REGISTRY_GQL_URL" mv changed_files.json registry-automation/changed_files.json cd registry-automation go run main.go ci From a2b554b58c21d92032df8e76358884644b1e2e47 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 17:36:13 +0530 Subject: [PATCH 086/115] fix typo --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 01a87462..30f637b5 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -59,7 +59,7 @@ jobs: CONNECTOR_REGISTRY_GQL_URL: ${{ secrets.CONNECTOR_REGISTRY_GQL_URL }} GCP_BUCKET_NAME: dev-connector-platform-registry GCP_SERVICE_ACCOUNT_DETAILS: ${{ secrets.GCP_SERVICE_ACCOUNT_DETAILS }} - CONNECTOR_PUBICATION_KEY: ${{ secrets.CONNECTOR_PUBLICATION_KEY }} + CONNECTOR_PUBLICATION_KEY: ${{ secrets.CONNECTOR_PUBLICATION_KEY }} run: | echo "connector registry GQL URL is $CONNECTOR_REGISTRY_GQL_URL" mv changed_files.json registry-automation/changed_files.json From 9cb3e14d7a27c6a23c2c1d861742c76783f96918 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 17:39:38 +0530 Subject: [PATCH 087/115] pass connector-publication-key as argument --- .github/workflows/registry-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 30f637b5..998ace83 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -64,4 +64,4 @@ jobs: echo "connector registry GQL URL is $CONNECTOR_REGISTRY_GQL_URL" mv changed_files.json registry-automation/changed_files.json cd registry-automation - go run main.go ci + go run main.go ci --connector-publication-key $CONNECTOR_PUBLICATION_KEY From 41c35db5e827751811215c5d04e1cb437c4f7576 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 18:43:34 +0530 Subject: [PATCH 088/115] use env vars for sensitive stuff --- .github/workflows/registry-updates.yaml | 3 +-- registry-automation/cmd/ci.go | 29 +++++++++++++++---------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index 998ace83..acb9369b 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -61,7 +61,6 @@ jobs: GCP_SERVICE_ACCOUNT_DETAILS: ${{ secrets.GCP_SERVICE_ACCOUNT_DETAILS }} CONNECTOR_PUBLICATION_KEY: ${{ secrets.CONNECTOR_PUBLICATION_KEY }} run: | - echo "connector registry GQL URL is $CONNECTOR_REGISTRY_GQL_URL" mv changed_files.json registry-automation/changed_files.json cd registry-automation - go run main.go ci --connector-publication-key $CONNECTOR_PUBLICATION_KEY + go run main.go ci diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index a205d3ed..a35f93cc 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -72,7 +72,7 @@ const ( type ConnectorRegistryArgs struct { ChangedFilesPath string PublicationEnv string - ConnectorRegistryGQL string + ConnectorRegistryGQLUrl string ConnectorPublicationKey string GCPServiceAccountDetails string GCPBucketName string @@ -98,34 +98,40 @@ func init() { ciCmd.PersistentFlags().Set("publication-env", "staging") } +} + +func buildContext() { // Connector registry Hasura GraphQL URL registryGQLURL := os.Getenv("CONNECTOR_REGISTRY_GQL_URL") - ciCmd.PersistentFlags().StringVar(&cmdArgs.ConnectorRegistryGQL, "connector-registry-gql-url", registryGQLURL, "Hasura GraphQL URL for the connector registry") if registryGQLURL == "" { - ciCmd.MarkPersistentFlagRequired("connector-registry-gql-url") + log.Fatalf("CONNECTOR_REGISTRY_GQL_URL is not set") + } else { + cmdArgs.ConnectorRegistryGQLUrl = registryGQLURL } // Connector publication key connectorPublicationKey := os.Getenv("CONNECTOR_PUBLICATION_KEY") - ciCmd.PersistentFlags().StringVar(&cmdArgs.ConnectorPublicationKey, "connector-publication-key", connectorPublicationKey, "Connector publication key used for authentication with the registry GraphQL API") if connectorPublicationKey == "" { - ciCmd.MarkPersistentFlagRequired("connector-publication-key") + log.Fatalf("CONNECTOR_PUBLICATION_KEY is not set") + } else { + cmdArgs.ConnectorPublicationKey = connectorPublicationKey } // GCP service account details gcpServiceAccountDetails := os.Getenv("GCP_SERVICE_ACCOUNT_DETAILS") - ciCmd.PersistentFlags().StringVar(&cmdArgs.GCPServiceAccountDetails, "gcp-service-account-details", gcpServiceAccountDetails, "GCP service account details file path") if gcpServiceAccountDetails == "" { - ciCmd.MarkPersistentFlagRequired("gcp-service-account-details") + log.Fatalf("GCP_SERVICE_ACCOUNT_DETAILS is not set") + } else { + cmdArgs.GCPServiceAccountDetails = gcpServiceAccountDetails } // GCP bucket name gcpBucketName := os.Getenv("GCP_BUCKET_NAME") - ciCmd.PersistentFlags().StringVar(&cmdArgs.GCPBucketName, "gcp-bucket-name", gcpBucketName, "GCP bucket name") if gcpBucketName == "" { - ciCmd.MarkPersistentFlagRequired("gcp-bucket-name") + log.Fatalf("GCP_BUCKET_NAME is not set") + } else { + cmdArgs.GCPBucketName = gcpBucketName } - } // processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version @@ -154,6 +160,7 @@ func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConn // runCI is the main function that runs the CI workflow func runCI(cmd *cobra.Command, args []string) { ctx := context.Background() + buildContext() changedFilesContent, err := os.Open(cmdArgs.ChangedFilesPath) if err != nil { @@ -426,7 +433,7 @@ func buildRegistryPayload( func updateRegistryGQL(payload []ConnectorVersion) error { var respData map[string]interface{} - client := graphql.NewClient(cmdArgs.ConnectorRegistryGQL) + client := graphql.NewClient(cmdArgs.ConnectorRegistryGQLUrl) ctx := context.Background() req := graphql.NewRequest(` From 6e759aa167615244fd948897ae81c9e7a785f384 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 31 Jul 2024 18:48:45 +0530 Subject: [PATCH 089/115] no-op refactor --- registry-automation/cmd/ci.go | 116 ----------------------------- registry-automation/cmd/utils.go | 123 ++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 117 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index a35f93cc..245d4515 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -9,11 +9,7 @@ import ( "fmt" "io" "log" - "math/rand" - "net/http" "os" - "os/exec" - "path/filepath" "regexp" "cloud.google.com/go/storage" @@ -462,115 +458,3 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi return nil } - -func downloadFile(sourceURL, destination string, headers map[string]string) error { - // Create a new HTTP client - client := &http.Client{} - - // Create a new GET request - req, err := http.NewRequest("GET", sourceURL, nil) - if err != nil { - return fmt.Errorf("error creating request: %v", err) - } - - // Add headers - for key, value := range headers { - req.Header.Set(key, value) - } - - // Send the request - resp, err := client.Do(req) - if err != nil { - return fmt.Errorf("error sending request: %v", err) - } - defer resp.Body.Close() - - // Create the destination file - outFile, err := os.Create(destination) - if err != nil { - return fmt.Errorf("error creating destination file: %v", err) - } - defer outFile.Close() - - // Write the response body to the file - _, err = io.Copy(outFile, resp.Body) - if err != nil { - return fmt.Errorf("error writing to file: %v", err) - } - - return nil -} - -// Reads a JSON file and attempts to parse the content of the file -// into the type T. -// Note: The location is relative to the root of the repository -func readJSONFile[T any](location string) (T, error) { - // Read the file - var result T - fileBytes, err := os.ReadFile("../" + location) - if err != nil { - return result, fmt.Errorf("error reading file at location: %s %v", location, err) - } - - if err := json.Unmarshal(fileBytes, &result); err != nil { - return result, fmt.Errorf("error parsing JSON: %v", err) - } - - return result, nil -} - -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - -// generateRandomFileName generates a random file name based on the current time. -func generateRandomFileName(fileExtension string) string { - b := make([]byte, 10) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] - } - return string(b) + fileExtension -} - -// getTempFilePath generates a random file name in the specified directory. -func getTempFilePath(directory string, fileExtension string) string { - // Ensure the directory exists - err := os.MkdirAll(directory, os.ModePerm) - if err != nil { - panic(fmt.Errorf("error creating directory: %v", err)) - } - - // Generate a random file name - fileName := generateRandomFileName(fileExtension) - - // Create the file path - filePath := filepath.Join(directory, fileName) - - // Check if the file already exists - _, err = os.Stat(filePath) - if !os.IsNotExist(err) { - // File exists, generate a new name - fileName = generateRandomFileName(fileExtension) - filePath = filepath.Join(directory, fileName) - } - return filePath - -} - -func extractTarGz(src, dest string) (string, error) { - // Create the destination directory - // Get the present working directory - pwd := os.Getenv("PWD") - filepath := pwd + "/" + dest - - if err := os.MkdirAll(filepath, 0755); err != nil { - return "", fmt.Errorf("error creating destination directory: %v", err) - } - // Run the tar command with the -xvzf options - cmd := exec.Command("tar", "-xvzf", src, "-C", dest) - - // Execute the command - if err := cmd.Run(); err != nil { - return "", fmt.Errorf("error extracting tar.gz file: %v", err) - } - - return fmt.Sprintf("%s/.hasura-connector/connector-metadata.yaml", filepath), nil -} diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index 9d1d9890..591bc58f 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -1,7 +1,128 @@ package cmd -import "fmt" +import ( + "encoding/json" + "fmt" + "io" + "math/rand" + "net/http" + "os" + "os/exec" + "path/filepath" +) func generateGCPObjectName(namespace, connectorName, version string) string { return fmt.Sprintf("packages/%s/%s/%s/package.tgz", namespace, connectorName, version) } + +func downloadFile(sourceURL, destination string, headers map[string]string) error { + // Create a new HTTP client + client := &http.Client{} + + // Create a new GET request + req, err := http.NewRequest("GET", sourceURL, nil) + if err != nil { + return fmt.Errorf("error creating request: %v", err) + } + + // Add headers + for key, value := range headers { + req.Header.Set(key, value) + } + + // Send the request + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error sending request: %v", err) + } + defer resp.Body.Close() + + // Create the destination file + outFile, err := os.Create(destination) + if err != nil { + return fmt.Errorf("error creating destination file: %v", err) + } + defer outFile.Close() + + // Write the response body to the file + _, err = io.Copy(outFile, resp.Body) + if err != nil { + return fmt.Errorf("error writing to file: %v", err) + } + + return nil +} + +// Reads a JSON file and attempts to parse the content of the file +// into the type T. +// Note: The location is relative to the root of the repository +func readJSONFile[T any](location string) (T, error) { + // Read the file + var result T + fileBytes, err := os.ReadFile("../" + location) + if err != nil { + return result, fmt.Errorf("error reading file at location: %s %v", location, err) + } + + if err := json.Unmarshal(fileBytes, &result); err != nil { + return result, fmt.Errorf("error parsing JSON: %v", err) + } + + return result, nil +} + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +// generateRandomFileName generates a random file name based on the current time. +func generateRandomFileName(fileExtension string) string { + b := make([]byte, 10) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) + fileExtension +} + +// getTempFilePath generates a random file name in the specified directory. +func getTempFilePath(directory string, fileExtension string) string { + // Ensure the directory exists + err := os.MkdirAll(directory, os.ModePerm) + if err != nil { + panic(fmt.Errorf("error creating directory: %v", err)) + } + + // Generate a random file name + fileName := generateRandomFileName(fileExtension) + + // Create the file path + filePath := filepath.Join(directory, fileName) + + // Check if the file already exists + _, err = os.Stat(filePath) + if !os.IsNotExist(err) { + // File exists, generate a new name + fileName = generateRandomFileName(fileExtension) + filePath = filepath.Join(directory, fileName) + } + return filePath + +} + +func extractTarGz(src, dest string) (string, error) { + // Create the destination directory + // Get the present working directory + pwd := os.Getenv("PWD") + filepath := pwd + "/" + dest + + if err := os.MkdirAll(filepath, 0755); err != nil { + return "", fmt.Errorf("error creating destination directory: %v", err) + } + // Run the tar command with the -xvzf options + cmd := exec.Command("tar", "-xvzf", src, "-C", dest) + + // Execute the command + if err := cmd.Run(); err != nil { + return "", fmt.Errorf("error extracting tar.gz file: %v", err) + } + + return fmt.Sprintf("%s/.hasura-connector/connector-metadata.yaml", filepath), nil +} From ec62c9f0c687e879c7c7f6db56313e31d53b8ce4 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 1 Aug 2024 13:21:44 +0530 Subject: [PATCH 090/115] no-op refactor --- registry-automation/cmd/ci.go | 1 - 1 file changed, 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 245d4515..901f9174 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -456,5 +456,4 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi fmt.Println("Response from the API: ", respData) return nil - } From d5111d795aafd6689c12b41b28ef48fc7718a23f Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 1 Aug 2024 14:07:28 +0530 Subject: [PATCH 091/115] add a success log on completion --- registry-automation/cmd/ci.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 901f9174..7e72ed00 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -222,6 +222,8 @@ func runCI(cmd *cobra.Command, args []string) { log.Fatalf("Failed to update the registry: %v", err) } } + + fmt.Println("Successfully added connector versions to the registry.") } func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions []ConnectorVersion) error { @@ -452,8 +454,5 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi return err } - // print the respData - fmt.Println("Response from the API: ", respData) - return nil } From a9c0d3a03e247d70d900a7c2f89be293d1b516f8 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Thu, 1 Aug 2024 16:19:04 +0530 Subject: [PATCH 092/115] no-op refactors --- registry-automation/cmd/ci.go | 143 +++++++++++++++++++++++-------- registry-automation/cmd/utils.go | 10 +-- 2 files changed, 113 insertions(+), 40 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 7e72ed00..966ae8e2 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -37,17 +37,18 @@ type ChangedFiles struct { type ConnectorVersion struct { // Namespace of the connector, e.g. "hasura" Namespace string `json:"namespace"` - // Name of the connector + // Name of the connector, e.g. "mongodb" Name string `json:"name"` - // Semantic version of the connector + // Semantic version of the connector version, e.g. "v1.0.0" Version string `json:"version"` - // Docker image of the connector version + // Docker image of the connector version (optional) + // This field is only required if the connector version is of type `PrebuiltDockerImage` Image *string `json:"image,omitempty"` // URL to the connector's metadata PackageDefinitionURL string `json:"package_definition_url"` // Is the connector version multitenant? IsMultitenant bool `json:"is_multitenant"` - // Type of the connector packaing `PreBuiltDockerImage`/`ManagedDockerBuild` + // Type of the connector packaging `PreBuiltDockerImage`/`ManagedDockerBuild` Type string `json:"type"` } @@ -187,43 +188,51 @@ func runCI(cmd *cobra.Command, args []string) { // Collect the added or modified connectors addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) - var connectorVersions []ConnectorVersion - var uploadConnectorVersionErr error - encounteredError := false - - for connectorName, versions := range addedOrModifiedConnectorVersions { - for version, connectorVersionPath := range versions { - var connectorVersion ConnectorVersion - connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) - if err != nil { - fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) - encounteredError = true + // check if the map is empty + if len(addedOrModifiedConnectorVersions) == 0 { + fmt.Println("No connector versions found in the changed files.") + return + } else { + // Iterate over the added or modified connectors and upload the connector versions + var connectorVersions []ConnectorVersion + var uploadConnectorVersionErr error + encounteredError := false + + for connectorName, versions := range addedOrModifiedConnectorVersions { + for version, connectorVersionPath := range versions { + var connectorVersion ConnectorVersion + connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) + + if uploadConnectorVersionErr != nil { + fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) + encounteredError = true + break + } + connectorVersions = append(connectorVersions, connectorVersion) + } + if encounteredError { break } - connectorVersions = append(connectorVersions, connectorVersion) - } - if encounteredError { - break } - } - - if encounteredError { - // attempt to cleanup the uploaded connector versions - _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up - // delete the uploaded connector versions from the registry - log.Fatalf("Failed to upload the connector version: %v", uploadConnectorVersionErr) - } else { - fmt.Println("Successfully uploaded the connector versions to the registry") - err = updateRegistryGQL(connectorVersions) - if err != nil { + if encounteredError { // attempt to cleanup the uploaded connector versions _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up - log.Fatalf("Failed to update the registry: %v", err) + // delete the uploaded connector versions from the registry + log.Fatalf("Failed to upload the connector version: %v", uploadConnectorVersionErr) + + } else { + fmt.Printf("Connector versions to be added to the registry: %+v\n", connectorVersions) + err = updateRegistryGQL(connectorVersions) + if err != nil { + // attempt to cleanup the uploaded connector versions + _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up + log.Fatalf("Failed to update the registry: %v", err) + } } - } - fmt.Println("Successfully added connector versions to the registry.") + fmt.Println("Successfully added connector versions to the registry.") + } } func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions []ConnectorVersion) error { @@ -319,7 +328,7 @@ func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace // connector-definition.yaml present in the .hasura-connector folder. func getConnectorVersionMetadata(err error, tgzUrl string, connectorName string, connectorVersion string) (map[string]interface{}, string, error) { var connectorVersionMetadata map[string]interface{} - tgzPath := getTempFilePath("extracted_tgz", ".tgz") + tgzPath := getTempFilePath("extracted_tgz") err = downloadFile(tgzUrl, tgzPath, map[string]string{}) if err != nil { @@ -388,6 +397,48 @@ func getConnectorNamespace(connectorMetadata map[string]interface{}) (string, er return connectorNamespace, nil } +// struct to store the response of teh GetConnectorInfo query +type GetConnectorInfoResponse struct { + HubRegistryConnector []struct { + Name string `json:"name"` + MultitenantConnector *struct { + ID string `json:"id"` + } `json:"multitenant_connector"` + } `json:"hub_registry_connector"` +} + +func getConnectorInfoFromRegistry(connectorNamespace string, connectorName string) (GetConnectorInfoResponse, error) { + var respData GetConnectorInfoResponse + client := graphql.NewClient(cmdArgs.ConnectorRegistryGQLUrl) + ctx := context.Background() + + req := graphql.NewRequest(` +query GetConnectorInfo ($name: String!, $namespace: String!) { + hub_registry_connector(where: {_and: [{name: {_eq: $name}}, {namespace: {_eq: $namespace}}]}) { + name + multitenant_connector { + id + } + } +}`) + req.Var("name", connectorName) + req.Var("namespace", connectorNamespace) + + req.Header.Set("x-hasura-role", "connector_publishing_automation") + req.Header.Set("x-connector-publication-key", cmdArgs.ConnectorPublicationKey) + + // Execute the GraphQL query and check the response. + if err := client.Run(ctx, req, &respData); err != nil { + return respData, err + } else { + if len(respData.HubRegistryConnector) == 0 { + return respData, nil + } + } + + return respData, nil +} + // buildRegistryPayload builds the payload for the registry upsert API func buildRegistryPayload( connectorNamespace string, @@ -411,18 +462,40 @@ func buildRegistryPayload( if !ok { return connectorVersion, fmt.Errorf("could not find the 'dockerImage' of the PrebuiltDockerImage connector %s version %s in the connector's metadata", connectorName, version) } + } // TODO: Make a query to the registry to check if the connector already exists, // if not, insert the connector first and then insert the connector version. // Also, fetch the is_multitenant value from the registry. + + // query GetConnectorInfo ($name: String!, $namespace: String!) { + // hub_registry_connector(where: {_and: [{name: {_eq: $name}}, {namespace: {_eq: $namespace}}]}) { + // name + // multitenant_connector { + // id + // } + // } + // } + + connectorInfo, err := getConnectorInfoFromRegistry(connectorNamespace, connectorName) + + if err != nil { + return connectorVersion, err + } + + // Check if the connector exists in the registry first + if len(connectorInfo.HubRegistryConnector) == 0 { + return connectorVersion, fmt.Errorf("Inserting a new connector is not supported yet") + } + connectorVersion = ConnectorVersion{ Namespace: connectorNamespace, Name: connectorName, Version: version, Image: &connectorVersionDockerImage, PackageDefinitionURL: uploadedConnectorDefinitionTgzUrl, - IsMultitenant: false, // TODO(KC): Figure this out. + IsMultitenant: connectorInfo.HubRegistryConnector[0].MultitenantConnector != nil, Type: connectorVersionPackagingType, } diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index 591bc58f..b08b766a 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -74,16 +74,16 @@ func readJSONFile[T any](location string) (T, error) { const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // generateRandomFileName generates a random file name based on the current time. -func generateRandomFileName(fileExtension string) string { +func generateRandomFileName() string { b := make([]byte, 10) for i := range b { b[i] = letterBytes[rand.Intn(len(letterBytes))] } - return string(b) + fileExtension + return string(b) + ".tar.gz" } // getTempFilePath generates a random file name in the specified directory. -func getTempFilePath(directory string, fileExtension string) string { +func getTempFilePath(directory string) string { // Ensure the directory exists err := os.MkdirAll(directory, os.ModePerm) if err != nil { @@ -91,7 +91,7 @@ func getTempFilePath(directory string, fileExtension string) string { } // Generate a random file name - fileName := generateRandomFileName(fileExtension) + fileName := generateRandomFileName() // Create the file path filePath := filepath.Join(directory, fileName) @@ -100,7 +100,7 @@ func getTempFilePath(directory string, fileExtension string) string { _, err = os.Stat(filePath) if !os.IsNotExist(err) { // File exists, generate a new name - fileName = generateRandomFileName(fileExtension) + fileName = generateRandomFileName() filePath = filepath.Join(directory, fileName) } return filePath From c62a2551422af42873ef4f764c2fdb9ec96ded17 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 12:54:57 +0530 Subject: [PATCH 093/115] no-op change --- registry-automation/cmd/utils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index b08b766a..3c286413 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -49,7 +49,6 @@ func downloadFile(sourceURL, destination string, headers map[string]string) erro if err != nil { return fmt.Errorf("error writing to file: %v", err) } - return nil } From c7f189109a80d409ca834eff4affe42187c81772 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 12:57:25 +0530 Subject: [PATCH 094/115] remove stray comment --- registry-automation/cmd/ci.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 966ae8e2..4df3c1f9 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -465,19 +465,6 @@ func buildRegistryPayload( } - // TODO: Make a query to the registry to check if the connector already exists, - // if not, insert the connector first and then insert the connector version. - // Also, fetch the is_multitenant value from the registry. - - // query GetConnectorInfo ($name: String!, $namespace: String!) { - // hub_registry_connector(where: {_and: [{name: {_eq: $name}}, {namespace: {_eq: $namespace}}]}) { - // name - // multitenant_connector { - // id - // } - // } - // } - connectorInfo, err := getConnectorInfoFromRegistry(connectorNamespace, connectorName) if err != nil { From 55784d26fcbe81e48652b1f0239fb2a2294ebe3e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 13:46:30 +0530 Subject: [PATCH 095/115] update the registry-updates GH workflow --- .github/workflows/registry-updates.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index acb9369b..b1e8d9f4 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -7,12 +7,6 @@ on: paths: - registry/** - - pull_request: - types: [opened, synchronize, reopened, closed] - paths: - - registry/** - jobs: update_registry_db: runs-on: ubuntu-latest From ee69f668478bb0b170fe5af8e95252b6abab3cd6 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 13:49:03 +0530 Subject: [PATCH 096/115] run registry-updates only against the main branch --- .github/workflows/registry-updates.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/registry-updates.yaml b/.github/workflows/registry-updates.yaml index b1e8d9f4..56a6af14 100644 --- a/.github/workflows/registry-updates.yaml +++ b/.github/workflows/registry-updates.yaml @@ -1,9 +1,10 @@ name: Update Hub DB from GH Registry on: - push: + pull_request: branches: - - lyndon/registry-automation # TODO: Remove the branch response + - main + types: [opened, synchronize, reopened] paths: - registry/** From fa58cc5653e342201b843151506ffad3a437221e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 13:55:23 +0530 Subject: [PATCH 097/115] restore stuff from main --- LICENSE | 201 ------------------ registry-automation/.vscode/settings.json | 3 - registry/azure-cosmos/logo.png | Bin 0 -> 38264 bytes registry/azure-cosmos/metadata.json | 11 - registry/registry-automation-test/README.md | 171 --------------- .../registry-automation-test/metadata.json | 68 ------ 6 files changed, 454 deletions(-) delete mode 100644 LICENSE delete mode 100644 registry-automation/.vscode/settings.json create mode 100644 registry/azure-cosmos/logo.png delete mode 100644 registry/registry-automation-test/README.md delete mode 100644 registry/registry-automation-test/metadata.json diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/registry-automation/.vscode/settings.json b/registry-automation/.vscode/settings.json deleted file mode 100644 index 2c52e891..00000000 --- a/registry-automation/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "github.copilot.advanced": {} -} \ No newline at end of file diff --git a/registry/azure-cosmos/logo.png b/registry/azure-cosmos/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..001667d864a9bb07f7389f2534dec3a2514e86eb GIT binary patch literal 38264 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 literal 0 HcmV?d00001 diff --git a/registry/azure-cosmos/metadata.json b/registry/azure-cosmos/metadata.json index f78f8c5e..46b72c45 100644 --- a/registry/azure-cosmos/metadata.json +++ b/registry/azure-cosmos/metadata.json @@ -15,17 +15,6 @@ "is_verified": true, "is_hosted_by_hasura": true, "packages": [ - { - "version": "test", - "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/test/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" - }, - "source": { - "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" - } - }, { "version": "0.1.3", "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.3/connector-definition.tgz", diff --git a/registry/registry-automation-test/README.md b/registry/registry-automation-test/README.md deleted file mode 100644 index 70df2d45..00000000 --- a/registry/registry-automation-test/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# Azure Cosmos DB for NoSQL Connector - -[![Docs](https://img.shields.io/badge/docs-v3.x-brightgreen.svg?style=flat)](https://hasura.io/docs/3.0/latest/connectors/azure-cosmos/) -[![ndc-hub](https://img.shields.io/badge/ndc--hub-azure--cosmos-blue.svg?style=flat)](https://hasura.io/connectors/azure-cosmos) -[![License](https://img.shields.io/badge/license-Apache--2.0-purple.svg?style=flat)](LICENSE.txt) -[![Status](https://img.shields.io/badge/status-alpha-yellow.svg?style=flat)](./readme.md) - -With this connector, Hasura allows you to instantly create a real-time GraphQL API on top of your data models in Azure Cosmos DB for NoSQL Database containers. This connector supports Azure Cosmos DB for NoSQL's functionalities listed in the table below, allowing for efficient and scalable data operations. - -This connector is built using the [TypeScript Data Connector SDK](https://github.com/hasura/ndc-sdk-typescript) and implements the [Data Connector Spec](https://github.com/hasura/ndc-spec). - -- [Connector information in the Hasura Hub](https://hasura.io/connectors/azure-cosmos) -- [Hasura V3 Documentation](https://hasura.io/docs/3.0) - -## Features - -Below, you'll find a matrix of all supported features for the Azure Cosmos DB for NoSQL connector: - -| Feature | Supported | Notes | -| ------------------------------- | --------- | ----- | -| Native Queries + Logical Models | ✅ | | -| Simple Object Query | ✅ | | -| Filter / Search | ✅ | | -| Simple Aggregation | ✅ | | -| Sort | ✅ | | -| Paginate | ✅ | | -| Nested Objects | ✅ | | -| Nested Arrays | ✅ | | -| Nested Filtering | ❌ | | -| Nested Sorting | ❌ | | -| Nested Relationships | ❌ | | - - -## Before you get Started - -1. Create a [Hasura Cloud account](https://console.hasura.io) -2. Install the [CLI](https://hasura.io/docs/3.0/cli/installation/) -3. Install the [Hasura VS Code extension](https://marketplace.visualstudio.com/items?itemName=HasuraHQ.hasura) -4. [Create a supergraph](https://hasura.io/docs/3.0/getting-started/init-supergraph) -5. [Create a subgraph](https://hasura.io/docs/3.0/getting-started/init-subgraph) - -## Using the connector - -To use the Azure Cosmos DB for NoSQL connector, follow these steps in a Hasura project: -(Note: for more information on the following steps, please refer to the Postgres connector documentation [here](https://hasura.io/docs/3.0/getting-started/connect-to-data/connect-a-source)) - - -### 1. Init the connector -(Note: here and following we are naming the subgraph "my_subgraph" and the connector "my_azure_cosmos") - - ```bash - ddn connector init my_azure_cosmos --subgraph my_subgraph --hub-connector hasura/azure-cosmos - ``` - -### 2. Add your Azure Cosmos DB for NoSQL credentials - -Add you credentials to `my_subgraph/connector/my_azure_cosmos/.env.local` - -```env title="my_subgraph/connector/my_azure_cosmos/.env.local" -OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://local.hasura.dev:4317 -OTEL_SERVICE_NAME=my_subgraph_my_azure_cosmos -AZURE_COSMOS_DB_NAME= -AZURE_COSMOS_ENDPOINT= -AZURE_COSMOS_KEY= -AZURE_COSMOS_NO_OF_ROWS_TO_FETCH= -``` - -Note: `AZURE_COSMOS_CONNECTOR_NO_OF_ROWS_TO_FETCH` is an optional field, with 100 rows to be fetched by default. - -### 3. Introspect your indices - -From the root of your project run: - -```bash title="From the root of your project run:" -ddn connector introspect --connector my_subgraph/connector/my_azure_cosmos/connector.yaml -``` - -If you look at the `config.json` for your connector, you'll see metadata describing your Azure Cosmos DB for NoSQL mappings. - -### 4. Create the Hasura metadata - -Run the following from the root of your project: - -```bash title="Run the following from the root of your project:" -ddn connector-link add my_azure_cosmos --subgraph my_subgraph -``` - -The generated file has two environment variables — one for reads and one for writes — that you'll need to add to your -subgraph's `.env.my_subgraph` file. Each key is prefixed by the subgraph name, an underscore, and the name of the -connector. Ensure the port value matches what is published in your connector's docker compose file. - -```env title="my_subgraph/.env.my_subgraph" -MY_SUBGRAPH_MY_AZURE_COSMOS_READ_URL=http://local.hasura.dev:8081 -MY_SUBGRAPH_MY_AZURE_COSMOS_WRITE_URL=http://local.hasura.dev:8081 -``` - -### 5. Start the connector's docker compose - -Let's start our connector's docker compose file. Run the following from the connector's subdirectory inside a subgraph: - -```bash title="Run the following from the connector's subdirectory inside a subgraph:" -docker compose -f docker-compose.my_azure_cosmos.yaml up -``` - -This starts our Azure Cosmos DB for NoSQL connector on the specified port. We can navigate to the following address, with the port -modified, to see the schema of our Azure Cosmos DB for NoSQL source: - -```bash -http://localhost:8081/schema -``` - -### 6. Include the connector in your docker compose - -Kill the connector by pressing `CTRL+C` in the terminal tab in which the connector is running. - -Then, add the following inclusion to the docker compose `docker-compose.hasura.yaml` in your project's root directory, taking care to modify the -subgraph's name. - -```yaml title="docker-compose.hasura.yaml" -include: - - path: my_subgraph/connector/my_azure_cosmos/docker-compose.my_azure_cosmos.yaml -``` - -Now, whenever running the following, you'll bring up the GraphQL engine, observability tools, and any connectors you've -included. From the root of your project, run: - -```bash title="From the root of your project, run:" -HASURA_DDN_PAT=$(ddn auth print-pat) docker compose -f docker-compose.hasura.yaml watch -``` - -### 7. Update the new DataConnectorLink object - -Finally, now that our `DataConnectorLink` has the correct environment variables configured for the Azure Cosmos DB for NoSQL connector, -we can run the update command to have the CLI look at the configuration JSON and transform it to reflect our database's -schema in `hml` format. In a new terminal tab from the root of your project, run: - -```bash title="From the root of your project, run:" -ddn connector-link update my_azure_cosmos --subgraph my_subgraph -``` - -After this command runs, you can open your `my_subgraph/metadata/my_azure_cosmos.hml` file and see your metadata completely -scaffolded out for you 🎉 - -### 8. Import _all_ your indices - -You can do this in one convenience command. From the root of your project, run: - -```bash title="From the root of your project, run:" -ddn connector-link update my_azure_cosmos --subgraph my_subgraph --add-all-resources -``` - -### 9. Create a supergraph build - -Pass the `local` subcommand along with specifying the output directory as `./engine` in the root of the project. This -directory is used by the docker-compose file to serve the engine locally. From the root of your project, run: - -```bash title="From the root of your project, run:" -ddn supergraph build local --output-dir ./engine -``` - -You can now navigate to -[`https://console.hasura.io/local/graphql?url=http://localhost:3000`](https://console.hasura.io/local/graphql?url=http://localhost:3000) -and interact with your API using the Hasura Console. - -## Contributing - -We're happy to receive any contributions from the community. Please refer to our [development guide](https://github.com/hasura/ndc-azure-cosmos-connector/blob/main/docs/development.md). - -## License - -The Hasura Azure Cosmos DB for NoSQL connector is available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/registry/registry-automation-test/metadata.json b/registry/registry-automation-test/metadata.json deleted file mode 100644 index f78f8c5e..00000000 --- a/registry/registry-automation-test/metadata.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "overview": { - "namespace": "hasura", - "description": "Connect to a Azure Cosmos DB for NoSQL and expose it to Hasura v3 Project", - "title": "Azure Cosmos DB for NoSQL Connector", - "logo": "logo.png", - "tags": [], - "latest_version": "v0.1.3" - }, - "author": { - "support_email": "support@hasura.io", - "homepage": "https://hasura.io", - "name": "Hasura" - }, - "is_verified": true, - "is_hosted_by_hasura": true, - "packages": [ - { - "version": "test", - "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/test/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" - }, - "source": { - "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" - } - }, - { - "version": "0.1.3", - "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.3/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "34655ff615be0d5738ffe1811972776808e9880a6fa3ec673123844c648154d7" - }, - "source": { - "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905" - } - }, - { - "version": "0.1.2", - "uri": "https://github.com/hasura/ndc-azure-cosmos-connector/releases/download/v0.1.2/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "09ce246a9039d2aaf799a7e0402b243fb3763ba802535348a9fee243de1bf1b7" - }, - "source": { - "hash": "f67b2f80d64175a055a9489d4e59f30d5d3870a0" - } - } - ], - "source_code": { - "is_open_source": true, - "repository": "https://github.com/hasura/ndc-azure-cosmos-connector/", - "version": [ - { - "tag": "v0.1.3", - "hash": "97032d1a41fd932d637b5ba24ca6611d9e1f4905", - "is_verified": true - }, - { - "tag": "v0.1.2", - "hash": "f67b2f80d64175a055a9489d4e59f30d5d3870a0", - "is_verified": true - } - ] - } - } From 9ede410bae0c4d3ece0099ef20ac7fc1f851231a Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Fri, 2 Aug 2024 17:11:47 +0530 Subject: [PATCH 098/115] Add WIP RFC about the connector automation --- rfcs/0006-connector-publishing-automation.md | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 rfcs/0006-connector-publishing-automation.md diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md new file mode 100644 index 00000000..0b3e533a --- /dev/null +++ b/rfcs/0006-connector-publishing-automation.md @@ -0,0 +1,62 @@ +# Connector registry Github packaging + +This is a Work-In-Progress document. Please provide any feedback you wish to contribute via Github comments and suggestions. + +## Introduction + +This RFC proposes how a new connector version should be added to the `registry` folder to automatically be published. Publishing here +means that the connector version will be available for use in Hasura's DDN. + +## Directory structure + +The following directory structure for connector versions is proposed: + +``` +registry/ +├── logo.png +├── metadata.json +├── README.md +└── releases + ├── v0.0.1 + │ └── connector-packaging.json + ├── v0.0.2 + │ └── connector-packaging.json + ├── v0.0.3 + │ └── connector-packaging.json + ├── v0.0.4 + │ └── connector-packaging.json + ├── v0.0.5 + │ └── connector-packaging.json + ├── v0.0.6 + │ └── connector-packaging.json + ├── v0.1.0 + │ └── connector-packaging.json + └── v1.0.0 + └── connector-packaging.json +``` + +### `connector-packaging.json` + +Every connector version has a package defintion, as specified here(TODO: Link to the packaging RFC). The `connector-packaging.json` +file should contain the relevant information to access the package definition. + +```json +{ + "version": "0.0.1", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" + }, + "source": { + "hash": "c32adbde478147518f65ff465c40a0703239288a" + } +} +``` + +The following fields are required: + +- `version`: The version of the connector. +- `uri`: The URI to download the connector package. The package should be a tarball containing the connector package definition and the URL should be accessible without any authentication. +- `checksum`: The checksum of the connector package. The checksum should be calculated using the `sha256` algorithm. +- `source`: The source of the connector package. The `hash` field should contain the commit hash of the source code that was used to build the connector package. From f1966e8f82c3407b89bd70e080d08f9a12379251 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 5 Aug 2024 13:12:28 +0530 Subject: [PATCH 099/115] update RFC --- rfcs/0006-connector-publishing-automation.md | 46 +++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 0b3e533a..ac47f297 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -7,7 +7,17 @@ This is a Work-In-Progress document. Please provide any feedback you wish to con This RFC proposes how a new connector version should be added to the `registry` folder to automatically be published. Publishing here means that the connector version will be available for use in Hasura's DDN. -## Directory structure +This RFC builds on top of the [Connector Package Distribution RFC](0002-distribution-gh.md). + +## Changes to the existing `metadata.json` file + +The `packages` field will be removed from the `metadata.json` file. The `packages` field will be replaced by a `releases` folder in the connector directory. + +The `releases` folder will contain a folder for each version of the connector. Each version folder will contain a `connector-packaging.json` file. + +The `connector-packaging.json` file will contain the relevant information to access the package definition. + +## Directory structure of the connectors `registry` The following directory structure for connector versions is proposed: @@ -35,9 +45,17 @@ registry/ └── connector-packaging.json ``` +The `registry` folder will contain a folder for each connector. Each connector folder will contain the following files: + +- `logo.png`: The logo of the connector. The logo should be in PNG format. +- `metadata.json`: The metadata of the connector. (TODO: Link to the metadata RFC) +- `README.md`: The README file of the connector. The README file should contain information about the connector, how to use it, and any other relevant information. The contents of the README file would be displayed in the landing page of the connector in the Hasura. +- `releases`: The releases folder will contain a folder for each version of the connector. Each version folder will contain a `connector-packaging.json` file. More details about the `connector-packaging.json` file are provided below. + + ### `connector-packaging.json` -Every connector version has a package defintion, as specified here(TODO: Link to the packaging RFC). The `connector-packaging.json` +Every connector version should have a package definition, as specified here(TODO: Link to the packaging RFC). The `connector-packaging.json` file should contain the relevant information to access the package definition. ```json @@ -60,3 +78,27 @@ The following fields are required: - `uri`: The URI to download the connector package. The package should be a tarball containing the connector package definition and the URL should be accessible without any authentication. - `checksum`: The checksum of the connector package. The checksum should be calculated using the `sha256` algorithm. - `source`: The source of the connector package. The `hash` field should contain the commit hash of the source code that was used to build the connector package. + + +## Publishing a new connector version + +To publish a new connector version, follow these steps: + +1. Create a new folder with the version number in the `releases` folder of the connector. +2. Create a `connector-packaging.json` file in the new folder with the relevant information. +3. Open a PR against the `main` branch of the repository. +4. You should see the `registry-update` workflow run on the PR. This workflow will validate the connector-packaging.json file and publish the new version to the registry if the validation is successful. +5. Once the workflow is successful, the new version of the connector will be available in the **Staging** Hasura DDN. Every new commit will overwrite the previous version of that connector in the staging DDN. So, feel free to push new commits to the PR to update the connector version in the staging DDN. +6. Once the PR is merged, the new version of the connector will be available in the **Production** Hasura DDN. + + +P.S: Multiple connector versions can be published in the same PR. The `registry-update` workflow will publish all the versions in the PR to the registry. + + +## Updates to logo and README + +If you want to update the logo or README of the connector, you can do so by opening a PR against the `main` branch of the repository. + +The `registry-update` workflow will run on the PR and update the logo and README in the staging DDN. + +Once the PR is merged, the logo and README will be updated in the production DDN. From 65191b5cb5752195cc5c21bd7f69bd3fd3483d33 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 5 Aug 2024 13:16:14 +0530 Subject: [PATCH 100/115] rename legacy `package.json` file --- .../releases/v1.0.0/{package.json => connector-packaging.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename registry/mongodb/releases/v1.0.0/{package.json => connector-packaging.json} (100%) diff --git a/registry/mongodb/releases/v1.0.0/package.json b/registry/mongodb/releases/v1.0.0/connector-packaging.json similarity index 100% rename from registry/mongodb/releases/v1.0.0/package.json rename to registry/mongodb/releases/v1.0.0/connector-packaging.json From 4a881c21bc713ad4964708bc8d65974641013cad Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 5 Aug 2024 13:33:05 +0530 Subject: [PATCH 101/115] remove copyright template --- registry-automation/main.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/registry-automation/main.go b/registry-automation/main.go index 8c2d80b2..4f168b4b 100644 --- a/registry-automation/main.go +++ b/registry-automation/main.go @@ -1,7 +1,3 @@ -/* -Copyright © 2024 NAME HERE - -*/ package main import "github.com/hasura/ndc-hub/registry-automation/cmd" From 479f0c5e41aa0a3dc30232b2223fdee8f12832aa Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 5 Aug 2024 14:24:06 +0530 Subject: [PATCH 102/115] remove Copyright templates --- registry-automation/cmd/ci.go | 3 --- registry-automation/cmd/root.go | 3 --- 2 files changed, 6 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 4df3c1f9..09967a23 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -1,6 +1,3 @@ -/* -Copyright © 2024 Hasura -*/ package cmd import ( diff --git a/registry-automation/cmd/root.go b/registry-automation/cmd/root.go index d3a23760..85f354f5 100644 --- a/registry-automation/cmd/root.go +++ b/registry-automation/cmd/root.go @@ -1,6 +1,3 @@ -/* -Copyright © 2024 Hasura -*/ package cmd import ( From 128a2a0190cf50fcf96cd7c79fe0b485883eac5b Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 6 Aug 2024 12:11:23 +0530 Subject: [PATCH 103/115] address review comments --- registry-automation/LICENSE | 0 registry-automation/cmd/ci.go | 43 +++++++++++++++------------------ registry-automation/cmd/root.go | 5 ---- 3 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 registry-automation/LICENSE diff --git a/registry-automation/LICENSE b/registry-automation/LICENSE deleted file mode 100644 index e69de29b..00000000 diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 09967a23..f169b8c6 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -72,21 +72,21 @@ type ConnectorRegistryArgs struct { GCPBucketName string } -var cmdArgs ConnectorRegistryArgs +var ciCmdArgs ConnectorRegistryArgs func init() { rootCmd.AddCommand(ciCmd) // Path for the changed files in the PR var changedFilesPathEnv = os.Getenv("CHANGED_FILES_PATH") - ciCmd.PersistentFlags().StringVar(&cmdArgs.ChangedFilesPath, "changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") + ciCmd.PersistentFlags().StringVar(&ciCmdArgs.ChangedFilesPath, "changed-files-path", changedFilesPathEnv, "path to a line-separated list of changed files in the PR") if changedFilesPathEnv == "" { ciCmd.MarkPersistentFlagRequired("changed-files-path") } // Publication environment var publicationEnv = os.Getenv("PUBLICATION_ENV") - ciCmd.PersistentFlags().StringVar(&cmdArgs.PublicationEnv, "publication-env", publicationEnv, "publication environment (staging/prod). Default: staging") + ciCmd.PersistentFlags().StringVar(&ciCmdArgs.PublicationEnv, "publication-env", publicationEnv, "publication environment (staging/prod). Default: staging") // default publicationEnv to "staging" if publicationEnv == "" { ciCmd.PersistentFlags().Set("publication-env", "staging") @@ -100,7 +100,7 @@ func buildContext() { if registryGQLURL == "" { log.Fatalf("CONNECTOR_REGISTRY_GQL_URL is not set") } else { - cmdArgs.ConnectorRegistryGQLUrl = registryGQLURL + ciCmdArgs.ConnectorRegistryGQLUrl = registryGQLURL } // Connector publication key @@ -108,7 +108,7 @@ func buildContext() { if connectorPublicationKey == "" { log.Fatalf("CONNECTOR_PUBLICATION_KEY is not set") } else { - cmdArgs.ConnectorPublicationKey = connectorPublicationKey + ciCmdArgs.ConnectorPublicationKey = connectorPublicationKey } // GCP service account details @@ -116,7 +116,7 @@ func buildContext() { if gcpServiceAccountDetails == "" { log.Fatalf("GCP_SERVICE_ACCOUNT_DETAILS is not set") } else { - cmdArgs.GCPServiceAccountDetails = gcpServiceAccountDetails + ciCmdArgs.GCPServiceAccountDetails = gcpServiceAccountDetails } // GCP bucket name @@ -124,7 +124,7 @@ func buildContext() { if gcpBucketName == "" { log.Fatalf("GCP_BUCKET_NAME is not set") } else { - cmdArgs.GCPBucketName = gcpBucketName + ciCmdArgs.GCPBucketName = gcpBucketName } } @@ -153,17 +153,14 @@ func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConn // runCI is the main function that runs the CI workflow func runCI(cmd *cobra.Command, args []string) { - ctx := context.Background() buildContext() - changedFilesContent, err := os.Open(cmdArgs.ChangedFilesPath) - + changedFilesContent, err := os.Open(ciCmdArgs.ChangedFilesPath) if err != nil { - log.Fatalf("Failed to open the file: %v, err: %v", cmdArgs.ChangedFilesPath, err) + log.Fatalf("Failed to open the file: %v, err: %v", ciCmdArgs.ChangedFilesPath, err) } - defer changedFilesContent.Close() - client, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(cmdArgs.GCPServiceAccountDetails))) + client, err := storage.NewClient(context.Background(), option.WithCredentialsJSON([]byte(ciCmdArgs.GCPServiceAccountDetails))) if err != nil { log.Fatalf("Failed to create Google bucket client: %v", err) } @@ -184,7 +181,6 @@ func runCI(cmd *cobra.Command, args []string) { // Collect the added or modified connectors addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) - // check if the map is empty if len(addedOrModifiedConnectorVersions) == 0 { fmt.Println("No connector versions found in the changed files.") @@ -239,7 +235,7 @@ func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions for _, connectorVersion := range connectorVersions { objectName := generateGCPObjectName(connectorVersion.Namespace, connectorVersion.Name, connectorVersion.Version) - err := deleteFile(client, cmdArgs.GCPBucketName, objectName) + err := deleteFile(client, ciCmdArgs.GCPBucketName, objectName) if err != nil { return err } @@ -266,7 +262,6 @@ func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { var connectorVersion ConnectorVersion - // Read the connector's metadata and the connector version's metadata // connector's `metadata.json`, `registry/mongodb/metadata.json` @@ -288,7 +283,7 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, return connectorVersion, fmt.Errorf("invalid or undefined TGZ URL: %v", tgzUrl) } - connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(err, tgzUrl, connectorName, version) + connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(tgzUrl, connectorName, version) if err != nil { return connectorVersion, err } @@ -311,7 +306,7 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, } func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { - bucketName := cmdArgs.GCPBucketName + bucketName := ciCmdArgs.GCPBucketName objectName := generateGCPObjectName(connectorNamespace, connectorName, connectorVersion) uploadedTgzUrl, err := uploadFile(client, bucketName, objectName, connectorMetadataTgzPath) @@ -323,11 +318,11 @@ func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace // Downloads the TGZ File from the URL specified by `tgzUrl`, extracts the TGZ file and returns the content of the // connector-definition.yaml present in the .hasura-connector folder. -func getConnectorVersionMetadata(err error, tgzUrl string, connectorName string, connectorVersion string) (map[string]interface{}, string, error) { +func getConnectorVersionMetadata(tgzUrl string, connectorName string, connectorVersion string) (map[string]interface{}, string, error) { var connectorVersionMetadata map[string]interface{} tgzPath := getTempFilePath("extracted_tgz") - err = downloadFile(tgzUrl, tgzPath, map[string]string{}) + err := downloadFile(tgzUrl, tgzPath, map[string]string{}) if err != nil { return connectorVersionMetadata, "", fmt.Errorf("failed to download the connector version metadata file from the URL: %v - err: %v", tgzUrl, err) } @@ -406,7 +401,7 @@ type GetConnectorInfoResponse struct { func getConnectorInfoFromRegistry(connectorNamespace string, connectorName string) (GetConnectorInfoResponse, error) { var respData GetConnectorInfoResponse - client := graphql.NewClient(cmdArgs.ConnectorRegistryGQLUrl) + client := graphql.NewClient(ciCmdArgs.ConnectorRegistryGQLUrl) ctx := context.Background() req := graphql.NewRequest(` @@ -422,7 +417,7 @@ query GetConnectorInfo ($name: String!, $namespace: String!) { req.Var("namespace", connectorNamespace) req.Header.Set("x-hasura-role", "connector_publishing_automation") - req.Header.Set("x-connector-publication-key", cmdArgs.ConnectorPublicationKey) + req.Header.Set("x-connector-publication-key", ciCmdArgs.ConnectorPublicationKey) // Execute the GraphQL query and check the response. if err := client.Run(ctx, req, &respData); err != nil { @@ -488,7 +483,7 @@ func buildRegistryPayload( func updateRegistryGQL(payload []ConnectorVersion) error { var respData map[string]interface{} - client := graphql.NewClient(cmdArgs.ConnectorRegistryGQLUrl) + client := graphql.NewClient(ciCmdArgs.ConnectorRegistryGQLUrl) ctx := context.Background() req := graphql.NewRequest(` @@ -504,7 +499,7 @@ mutation InsertConnectorVersion($connectorVersion: [hub_registry_connector_versi req.Var("connectorVersion", payload) req.Header.Set("x-hasura-role", "connector_publishing_automation") - req.Header.Set("x-connector-publication-key", cmdArgs.ConnectorPublicationKey) + req.Header.Set("x-connector-publication-key", ciCmdArgs.ConnectorPublicationKey) // Execute the GraphQL query and check the response. if err := client.Run(ctx, req, &respData); err != nil { diff --git a/registry-automation/cmd/root.go b/registry-automation/cmd/root.go index 85f354f5..9cf49a5d 100644 --- a/registry-automation/cmd/root.go +++ b/registry-automation/cmd/root.go @@ -26,9 +26,4 @@ func init() { // Cobra supports persistent flags, which, if defined here, // will be global for your application. - // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.registry-automation.yaml)") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } From 12ec04352dd565856a4f121f03438a9c75a50324 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 6 Aug 2024 12:29:30 +0530 Subject: [PATCH 104/115] update comment --- registry-automation/cmd/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index f169b8c6..3adbb0e1 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -45,7 +45,7 @@ type ConnectorVersion struct { PackageDefinitionURL string `json:"package_definition_url"` // Is the connector version multitenant? IsMultitenant bool `json:"is_multitenant"` - // Type of the connector packaging `PreBuiltDockerImage`/`ManagedDockerBuild` + // Type of the connector packaging `PrebuiltDockerImage`/`ManagedDockerBuild` Type string `json:"type"` } From 5d5c7a87f75c4a827dac413b9df165cf25491c58 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Wed, 7 Aug 2024 17:32:02 +0530 Subject: [PATCH 105/115] make changes according to the new registry folder structure --- registry-automation/cmd/ci.go | 133 +++++++++++++++-------------- registry-automation/cmd/ci_test.go | 96 --------------------- 2 files changed, 69 insertions(+), 160 deletions(-) delete mode 100644 registry-automation/cmd/ci_test.go diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 3adbb0e1..ec5a0cb5 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -128,27 +128,47 @@ func buildContext() { } } -// processAddedOrModifiedConnectorVersions processes the files in the PR and extracts the connector name and version -func processAddedOrModifiedConnectorVersions(files []string, addedOrModifiedConnectorVersions map[string]map[string]string) { - const connectorVersionPackageRegex = `^registry/([^/]+)/releases/([^/]+)/connector-packaging\.json$` - re := regexp.MustCompile(connectorVersionPackageRegex) +// processChangedFiles processes the files in the PR and extracts the connector name and version +// This function checks for the following things: +// 1. If a new connector version is added, it adds the connector version to the `newlyAddedConnectorVersions` map. +// 2. If the logo file is modified, it adds the connector name and the path to the modified logo to the `modifiedLogos` map. +// 3. If the README file is modified, it adds the connector name and the path to the modified README to the `modifiedReadmes` map. +func processChangedFiles(changedFiles ChangedFiles) NewConnectorVersions { + + newlyAddedConnectorVersions := make(map[Connector]map[string]string) + + var connectorVersionPackageRegex = regexp.MustCompile(`^registry/([^/]+)/([^/]+)/releases/([^/]+)/connector-packaging\.json$`) + + files := append(changedFiles.Added, changedFiles.Modified...) for _, file := range files { // Extract the connector name and version from the file path + if connectorVersionPackageRegex.MatchString(file) { + + matches := connectorVersionPackageRegex.FindStringSubmatch(file) + if len(matches) == 4 { + connectorNamespace := matches[1] + connectorName := matches[2] + connectorVersion := matches[3] - matches := re.FindStringSubmatch(file) - if len(matches) == 3 { - connectorName := matches[1] - connectorVersion := matches[2] + connector := Connector{ + Name: connectorName, + Namespace: connectorNamespace, + } + + if _, exists := newlyAddedConnectorVersions[connector]; !exists { + newlyAddedConnectorVersions[connector] = make(map[string]string) + } - if _, exists := addedOrModifiedConnectorVersions[connectorName]; !exists { - addedOrModifiedConnectorVersions[connectorName] = make(map[string]string) + newlyAddedConnectorVersions[connector][connectorVersion] = file } - addedOrModifiedConnectorVersions[connectorName][connectorVersion] = file + } else { + fmt.Println("Skipping file: ", file) } } + return newlyAddedConnectorVersions } // runCI is the main function that runs the CI workflow @@ -180,32 +200,36 @@ func runCI(cmd *cobra.Command, args []string) { } // Collect the added or modified connectors - addedOrModifiedConnectorVersions := collectAddedOrModifiedConnectors(changedFiles) + addedOrModifiedConnectorVersions := processChangedFiles(changedFiles) // check if the map is empty if len(addedOrModifiedConnectorVersions) == 0 { fmt.Println("No connector versions found in the changed files.") return } else { - // Iterate over the added or modified connectors and upload the connector versions - var connectorVersions []ConnectorVersion - var uploadConnectorVersionErr error - encounteredError := false - - for connectorName, versions := range addedOrModifiedConnectorVersions { - for version, connectorVersionPath := range versions { - var connectorVersion ConnectorVersion - connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) - - if uploadConnectorVersionErr != nil { - fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, err) - encounteredError = true - break - } - connectorVersions = append(connectorVersions, connectorVersion) - } - if encounteredError { + processNewlyAddedConnectorVersions(client, addedOrModifiedConnectorVersions) + } +} + +func processNewlyAddedConnectorVersions(client *storage.Client, newlyAddedConnectorVersions NewConnectorVersions) { + // Iterate over the added or modified connectors and upload the connector versions + var connectorVersions []ConnectorVersion + var uploadConnectorVersionErr error + encounteredError := false + + for connectorName, versions := range newlyAddedConnectorVersions { + for version, connectorVersionPath := range versions { + var connectorVersion ConnectorVersion + connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) + + if uploadConnectorVersionErr != nil { + fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, uploadConnectorVersionErr) + encounteredError = true + break + } else { + connectorVersions = append(connectorVersions, connectorVersion) } + } if encounteredError { @@ -216,7 +240,7 @@ func runCI(cmd *cobra.Command, args []string) { } else { fmt.Printf("Connector versions to be added to the registry: %+v\n", connectorVersions) - err = updateRegistryGQL(connectorVersions) + err := updateRegistryGQL(connectorVersions) if err != nil { // attempt to cleanup the uploaded connector versions _ = cleanupUploadedConnectorVersions(client, connectorVersions) // ignore errors while cleaning up @@ -243,32 +267,18 @@ func cleanupUploadedConnectorVersions(client *storage.Client, connectorVersions return nil } -// collectAddedOrModifiedConnectors collects the added or modified connectors from the changed files -func collectAddedOrModifiedConnectors(changedFiles ChangedFiles) map[string]map[string]string { - - addedOrModifiedConnectorVersions := make(map[string]map[string]string) - - processAddedOrModifiedConnectorVersions(changedFiles.Added, addedOrModifiedConnectorVersions) - - // Not sure if we need to process the modified files as well, because it is very unlikely - // that an existing connector version will be modified. - - // processAddedOrModifiedConnectorVersions(changedFiles.Modified, addedOrModifiedConnectorVersions) - - return addedOrModifiedConnectorVersions +// Type that uniquely identifies a connector +type Connector struct { + Name string `json:"name"` + Namespace string `json:"namespace"` } +type NewConnectorVersions map[Connector]map[string]string + // uploadConnectorVersionPackage uploads the connector version package to the registry -func uploadConnectorVersionPackage(client *storage.Client, connectorName string, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { +func uploadConnectorVersionPackage(client *storage.Client, connector Connector, version string, changedConnectorVersionPath string) (ConnectorVersion, error) { var connectorVersion ConnectorVersion - // Read the connector's metadata and the connector version's metadata - - // connector's `metadata.json`, `registry/mongodb/metadata.json` - connectorMetadata, err := readJSONFile[map[string]interface{}](fmt.Sprintf("registry/%s/metadata.json", connectorName)) - if err != nil { - return connectorVersion, fmt.Errorf("failed to read the connector metadata file: %v", err) - } // connector version's metadata, `registry/mongodb/releases/v1.0.0/connector-packaging.json` connectorVersionPackagingInfo, err := readJSONFile[map[string]interface{}](changedConnectorVersionPath) // Read metadata file @@ -283,26 +293,21 @@ func uploadConnectorVersionPackage(client *storage.Client, connectorName string, return connectorVersion, fmt.Errorf("invalid or undefined TGZ URL: %v", tgzUrl) } - connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(tgzUrl, connectorName, version) + connectorVersionMetadata, connectorMetadataTgzPath, err := getConnectorVersionMetadata(tgzUrl, connector, version) if err != nil { return connectorVersion, err } - connectorNamespace, err := getConnectorNamespace(connectorMetadata) - if err != nil { - return connectorVersion, fmt.Errorf("failed to get the connector namespace: %v", err) - } - - uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connectorNamespace, connectorName, version, connectorMetadataTgzPath) + uploadedTgzUrl, err := uploadConnectorVersionDefinition(client, connector.Name, connector.Namespace, version, connectorMetadataTgzPath) if err != nil { - return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connectorName, version, err) + return connectorVersion, fmt.Errorf("failed to upload the connector version definition - connector: %v version:%v - err: %v", connector.Name, version, err) } else { // print success message with the name of the connector and the version - fmt.Printf("Successfully uploaded the connector version definition in google cloud registry for the connector: %v version: %v\n", connectorName, version) + fmt.Printf("Successfully uploaded the connector version definition in google cloud registry for the connector: %v version: %v\n", connector.Name, version) } // Build payload for registry upsert - return buildRegistryPayload(connectorNamespace, connectorName, version, connectorVersionMetadata, uploadedTgzUrl) + return buildRegistryPayload(connector.Namespace, connector.Name, version, connectorVersionMetadata, uploadedTgzUrl) } func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace, connectorName string, connectorVersion string, connectorMetadataTgzPath string) (string, error) { @@ -318,7 +323,7 @@ func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace // Downloads the TGZ File from the URL specified by `tgzUrl`, extracts the TGZ file and returns the content of the // connector-definition.yaml present in the .hasura-connector folder. -func getConnectorVersionMetadata(tgzUrl string, connectorName string, connectorVersion string) (map[string]interface{}, string, error) { +func getConnectorVersionMetadata(tgzUrl string, connector Connector, connectorVersion string) (map[string]interface{}, string, error) { var connectorVersionMetadata map[string]interface{} tgzPath := getTempFilePath("extracted_tgz") @@ -336,7 +341,7 @@ func getConnectorVersionMetadata(tgzUrl string, connectorName string, connectorV } } - connectorVersionMetadataYamlFilePath, err := extractTarGz(tgzPath, extractedTgzFolderPath+"/"+connectorName+"/"+connectorVersion) + connectorVersionMetadataYamlFilePath, err := extractTarGz(tgzPath, extractedTgzFolderPath+"/"+connector.Namespace+"/"+connector.Name+"/"+connectorVersion) if err != nil { return connectorVersionMetadata, "", fmt.Errorf("failed to read the connector version metadata file: %v", err) } else { diff --git a/registry-automation/cmd/ci_test.go b/registry-automation/cmd/ci_test.go deleted file mode 100644 index 7646e084..00000000 --- a/registry-automation/cmd/ci_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package cmd - -import ( - "testing" -) - -func TestProcessAddedOrModifiedConnectorVersions(t *testing.T) { - // Define test cases - testCases := []struct { - name string - files []string - expectedAddedOrModifiedConnectors map[string]map[string]string - }{ - { - name: "Test case 1", - files: []string{ - "registry/hasura/releases/v1.0.0/connector-packaging.json", - "registry/hasura/releases/v2.0.0/connector-packaging.json", - "registry/other/releases/v1.0.0/connector-packaging.json", - }, - expectedAddedOrModifiedConnectors: map[string]map[string]string{ - "hasura": { - "v1.0.0": "registry/hasura/releases/v1.0.0/connector-packaging.json", - "v2.0.0": "registry/hasura/releases/v2.0.0/connector-packaging.json", - }, - "other": { - "v1.0.0": "registry/other/releases/v1.0.0/connector-packaging.json", - }, - }, - }, - { - name: "Test case 2", - files: []string{ - "registry/hasura/releases/v1.0.0/connector-packaging.json", - "registry/hasura/releases/v1.0.0/other-file.json", - }, - expectedAddedOrModifiedConnectors: map[string]map[string]string{ - "hasura": { - "v1.0.0": "registry/hasura/releases/v1.0.0/connector-packaging.json", - }, - }, - }, - { - name: "Test case 3", - files: []string{ - "registry/hasura/releases/v1.0.0/other-file.json", - "registry/other/releases/v1.0.0/connector-packaging.json", - }, - expectedAddedOrModifiedConnectors: map[string]map[string]string{ - "other": { - "v1.0.0": "registry/other/releases/v1.0.0/connector-packaging.json", - }, - }, - }, - } - - // Run the test cases - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - // Initialize the map to store the added or modified connectors - addedOrModifiedConnectorVersions := make(map[string]map[string]string) - - // Call the function under test - processAddedOrModifiedConnectorVersions(tc.files, addedOrModifiedConnectorVersions) - - // Compare the actual result with the expected result - if len(addedOrModifiedConnectorVersions) != len(tc.expectedAddedOrModifiedConnectors) { - t.Errorf("Unexpected number of connectors. Expected: %d, Got: %d", len(tc.expectedAddedOrModifiedConnectors), len(addedOrModifiedConnectorVersions)) - } - - for connectorName, versions := range addedOrModifiedConnectorVersions { - expectedVersions, ok := tc.expectedAddedOrModifiedConnectors[connectorName] - if !ok { - t.Errorf("Unexpected connector name: %s", connectorName) - continue - } - - if len(versions) != len(expectedVersions) { - t.Errorf("Unexpected number of versions for connector %s. Expected: %d, Got: %d", connectorName, len(expectedVersions), len(versions)) - } - - for version, connectorVersionPath := range versions { - expectedPath, ok := expectedVersions[version] - if !ok { - t.Errorf("Unexpected version for connector %s: %s", connectorName, version) - continue - } - - if connectorVersionPath != expectedPath { - t.Errorf("Unexpected connector version path for connector %s, version %s. Expected: %s, Got: %s", connectorName, version, expectedPath, connectorVersionPath) - } - } - } - }) - } -} From c8cc3eeb39fd95cbe144d4baaa26a7de4a400539 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 14:16:14 +0530 Subject: [PATCH 106/115] add connector namespace --- registry-automation/cmd/ci.go | 8 +++-- registry-automation/cmd/utils.go | 33 +++++--------------- rfcs/0006-connector-publishing-automation.md | 2 +- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index ec5a0cb5..18375dee 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -325,9 +325,11 @@ func uploadConnectorVersionDefinition(client *storage.Client, connectorNamespace // connector-definition.yaml present in the .hasura-connector folder. func getConnectorVersionMetadata(tgzUrl string, connector Connector, connectorVersion string) (map[string]interface{}, string, error) { var connectorVersionMetadata map[string]interface{} - tgzPath := getTempFilePath("extracted_tgz") - - err := downloadFile(tgzUrl, tgzPath, map[string]string{}) + tgzPath, err := getTempFilePath("extracted_tgz") + if err != nil { + return connectorVersionMetadata, "", fmt.Errorf("failed to get the temp file path: %v", err) + } + err = downloadFile(tgzUrl, tgzPath, map[string]string{}) if err != nil { return connectorVersionMetadata, "", fmt.Errorf("failed to download the connector version metadata file from the URL: %v - err: %v", tgzUrl, err) } diff --git a/registry-automation/cmd/utils.go b/registry-automation/cmd/utils.go index 3c286413..15357b07 100644 --- a/registry-automation/cmd/utils.go +++ b/registry-automation/cmd/utils.go @@ -4,11 +4,9 @@ import ( "encoding/json" "fmt" "io" - "math/rand" "net/http" "os" "os/exec" - "path/filepath" ) func generateGCPObjectName(namespace, connectorName, version string) string { @@ -70,19 +68,8 @@ func readJSONFile[T any](location string) (T, error) { return result, nil } -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - -// generateRandomFileName generates a random file name based on the current time. -func generateRandomFileName() string { - b := make([]byte, 10) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] - } - return string(b) + ".tar.gz" -} - // getTempFilePath generates a random file name in the specified directory. -func getTempFilePath(directory string) string { +func getTempFilePath(directory string) (string, error) { // Ensure the directory exists err := os.MkdirAll(directory, os.ModePerm) if err != nil { @@ -90,19 +77,13 @@ func getTempFilePath(directory string) string { } // Generate a random file name - fileName := generateRandomFileName() - - // Create the file path - filePath := filepath.Join(directory, fileName) - - // Check if the file already exists - _, err = os.Stat(filePath) - if !os.IsNotExist(err) { - // File exists, generate a new name - fileName = generateRandomFileName() - filePath = filepath.Join(directory, fileName) + tempFile, err := os.CreateTemp(directory, "connector-*.tar.gz") + if err != nil { + return "", fmt.Errorf("error creating temp file: %v", err) } - return filePath + defer tempFile.Close() + + return tempFile.Name(), nil } diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index ac47f297..89e735b9 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -22,7 +22,7 @@ The `connector-packaging.json` file will contain the relevant information to acc The following directory structure for connector versions is proposed: ``` -registry/ +registry// ├── logo.png ├── metadata.json ├── README.md From a0ba7fc1b558ea3960e74c95f041fa3653963b66 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 15:02:24 +0530 Subject: [PATCH 107/115] Manually set `PreBuiltDockerImage as package version type --- registry-automation/cmd/ci.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index 18375dee..c3364777 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -222,9 +222,7 @@ func processNewlyAddedConnectorVersions(client *storage.Client, newlyAddedConnec connectorVersion, uploadConnectorVersionErr = uploadConnectorVersionPackage(client, connectorName, version, connectorVersionPath) if uploadConnectorVersionErr != nil { - fmt.Printf("Error while processing version and connector: %s - %s, Error: %v", version, connectorName, uploadConnectorVersionErr) encounteredError = true - break } else { connectorVersions = append(connectorVersions, connectorVersion) @@ -475,6 +473,15 @@ func buildRegistryPayload( return connectorVersion, fmt.Errorf("Inserting a new connector is not supported yet") } + var connectorVersionType string + + if connectorVersionPackagingType == PrebuiltDockerImage { + // Note: The connector version type is set to `PreBuiltDockerImage` if the connector version is of type `PrebuiltDockerImage`, this is a HACK because this value might be removed in the future and we might not even need to insert new connector versions in the `hub_registry_connector_version` table. + connectorVersionType = "PreBuiltDockerImage" + } else { + connectorVersionType = ManagedDockerBuild + } + connectorVersion = ConnectorVersion{ Namespace: connectorNamespace, Name: connectorName, @@ -482,7 +489,7 @@ func buildRegistryPayload( Image: &connectorVersionDockerImage, PackageDefinitionURL: uploadedConnectorDefinitionTgzUrl, IsMultitenant: connectorInfo.HubRegistryConnector[0].MultitenantConnector != nil, - Type: connectorVersionPackagingType, + Type: connectorVersionType, } return connectorVersion, nil From bfd4909d7e25d9231f34dbae7451219e19fea3e1 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 15:33:58 +0530 Subject: [PATCH 108/115] add test connector-packages back --- .../mongodb/releases/v0.0.1/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.0.2/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.0.3/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.0.4/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.0.5/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.0.6/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v0.1.0/connector-packaging.json | 11 +++++++++++ .../mongodb/releases/v1.0.0/connector-packaging.json | 11 +++++++++++ 8 files changed, 88 insertions(+) create mode 100644 registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json create mode 100644 registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json diff --git a/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json new file mode 100644 index 00000000..13d2851d --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" + }, + "source": { + "hash": "c32adbde478147518f65ff465c40a0703239288a" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json new file mode 100644 index 00000000..e6561cd6 --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.2", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" + }, + "source": { + "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json new file mode 100644 index 00000000..02812b53 --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.3", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" + }, + "source": { + "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json new file mode 100644 index 00000000..d145fd13 --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.4", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" + }, + "source": { + "hash": "38a4a56134a909001b645c659062ae393c2cebe0" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json new file mode 100644 index 00000000..9c7bcefe --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.5", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" + }, + "source": { + "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json new file mode 100644 index 00000000..890a2f58 --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.6", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" + }, + "source": { + "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json b/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json new file mode 100644 index 00000000..dc640be8 --- /dev/null +++ b/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "0.1.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" + }, + "source": { + "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" + } +} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json b/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json new file mode 100644 index 00000000..67035c87 --- /dev/null +++ b/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" + }, + "source": { + "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" + } +} \ No newline at end of file From e47e759dbd46a41bd491739be25724793ce38a2e Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 15:43:08 +0530 Subject: [PATCH 109/115] Add relevant links in the RFCs --- rfcs/0002-distribution-gh.md | 6 +++++- rfcs/0006-connector-publishing-automation.md | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/rfcs/0002-distribution-gh.md b/rfcs/0002-distribution-gh.md index e1b39817..2933022a 100644 --- a/rfcs/0002-distribution-gh.md +++ b/rfcs/0002-distribution-gh.md @@ -1,8 +1,13 @@ # Connector Package Distribution RFC - Milestone 1 +> [!NOTE] +> This RFC has since been extended by the [Connector publishing automation](./0006-connectors-publishing-automation.md) + This is a Work-In-Progress document. Please provide any feedback you wish to contribute via Github comments and suggestions. + + ## Purpose Connector API, definition and packaging are specified respectively by: @@ -271,4 +276,3 @@ Any publicly accessible APIs with publication capabilities have the potential to * Recycling of content * Unintentional mistakes * Spam / Reflection - diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 89e735b9..2c3690be 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -1,6 +1,7 @@ # Connector registry Github packaging -This is a Work-In-Progress document. Please provide any feedback you wish to contribute via Github comments and suggestions. +> [!NOTE] +> This RFC is an update on the [Connector Package Distribution RFC](0002-distribution-gh.md). ## Introduction From 7af83a0bf20a8ea90097603cfd93d6d4e53b87e4 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 15:45:53 +0530 Subject: [PATCH 110/115] update the RFC --- rfcs/0006-connector-publishing-automation.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 2c3690be..1eb633bc 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -8,15 +8,13 @@ This RFC proposes how a new connector version should be added to the `registry` folder to automatically be published. Publishing here means that the connector version will be available for use in Hasura's DDN. -This RFC builds on top of the [Connector Package Distribution RFC](0002-distribution-gh.md). +## File structure of the connectors `registry` -## Changes to the existing `metadata.json` file +The packages field in the `metadata.json` file will be removed and replaced by a releases folder within the connector directory. -The `packages` field will be removed from the `metadata.json` file. The `packages` field will be replaced by a `releases` folder in the connector directory. +The releases folder will house a separate folder for each version of the connector, with each version folder containing a `connector-packaging.json` file. -The `releases` folder will contain a folder for each version of the connector. Each version folder will contain a `connector-packaging.json` file. - -The `connector-packaging.json` file will contain the relevant information to access the package definition. +This `connector-packaging.json` file will include all the necessary information to access the package definition. ## Directory structure of the connectors `registry` From 25fa3fe24f9f9e69a8a72f167c636d2380c45863 Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 15:55:56 +0530 Subject: [PATCH 111/115] fix TODOs --- rfcs/0006-connector-publishing-automation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 1eb633bc..05383885 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -47,14 +47,14 @@ registry// The `registry` folder will contain a folder for each connector. Each connector folder will contain the following files: - `logo.png`: The logo of the connector. The logo should be in PNG format. -- `metadata.json`: The metadata of the connector. (TODO: Link to the metadata RFC) +- `metadata.json`: The metadata of the connector. Metadata format is described in the [Github Distribution RFC](./0002-distribution-gh.md). - `README.md`: The README file of the connector. The README file should contain information about the connector, how to use it, and any other relevant information. The contents of the README file would be displayed in the landing page of the connector in the Hasura. - `releases`: The releases folder will contain a folder for each version of the connector. Each version folder will contain a `connector-packaging.json` file. More details about the `connector-packaging.json` file are provided below. ### `connector-packaging.json` -Every connector version should have a package definition, as specified here(TODO: Link to the packaging RFC). The `connector-packaging.json` +Every connector version should have a package definition. The `connector-packaging.json` file should contain the relevant information to access the package definition. ```json From d53f63fb16eba7480524e79a4cb5ae6485bc06bc Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Mon, 12 Aug 2024 23:22:12 +0530 Subject: [PATCH 112/115] minor changes --- registry-automation/cmd/ci.go | 1 + rfcs/0006-connector-publishing-automation.md | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/registry-automation/cmd/ci.go b/registry-automation/cmd/ci.go index c3364777..5f701888 100644 --- a/registry-automation/cmd/ci.go +++ b/registry-automation/cmd/ci.go @@ -224,6 +224,7 @@ func processNewlyAddedConnectorVersions(client *storage.Client, newlyAddedConnec if uploadConnectorVersionErr != nil { encounteredError = true break + } else { connectorVersions = append(connectorVersions, connectorVersion) } diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 05383885..71ab6f55 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -5,8 +5,7 @@ ## Introduction -This RFC proposes how a new connector version should be added to the `registry` folder to automatically be published. Publishing here -means that the connector version will be available for use in Hasura's DDN. +This RFC proposes how a new connector version should be added to the `registry` folder to automatically be published. Publishing in this context means that the connector version will be available for public use in Hasura's DDN. ## File structure of the connectors `registry` @@ -16,8 +15,6 @@ The releases folder will house a separate folder for each version of the connect This `connector-packaging.json` file will include all the necessary information to access the package definition. -## Directory structure of the connectors `registry` - The following directory structure for connector versions is proposed: ``` @@ -51,6 +48,8 @@ The `registry` folder will contain a folder for each connector. Each connector f - `README.md`: The README file of the connector. The README file should contain information about the connector, how to use it, and any other relevant information. The contents of the README file would be displayed in the landing page of the connector in the Hasura. - `releases`: The releases folder will contain a folder for each version of the connector. Each version folder will contain a `connector-packaging.json` file. More details about the `connector-packaging.json` file are provided below. +NOTE: The `releases` folder should only be added for Hub connectors. +For example, `postgres-azure` connector should not have a `releases` folder as it is not a Hub connector. ### `connector-packaging.json` From 10141a04aedf8b1f3e94b867248ac4df9e020b9a Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 13 Aug 2024 12:25:58 +0530 Subject: [PATCH 113/115] add notes in the RFC --- rfcs/0006-connector-publishing-automation.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rfcs/0006-connector-publishing-automation.md b/rfcs/0006-connector-publishing-automation.md index 71ab6f55..ef4081ea 100644 --- a/rfcs/0006-connector-publishing-automation.md +++ b/rfcs/0006-connector-publishing-automation.md @@ -89,8 +89,11 @@ To publish a new connector version, follow these steps: 5. Once the workflow is successful, the new version of the connector will be available in the **Staging** Hasura DDN. Every new commit will overwrite the previous version of that connector in the staging DDN. So, feel free to push new commits to the PR to update the connector version in the staging DDN. 6. Once the PR is merged, the new version of the connector will be available in the **Production** Hasura DDN. +> [!NOTE] +> The `registry-update` workflow will only run on the PRs against the `main` branch of the repository. -P.S: Multiple connector versions can be published in the same PR. The `registry-update` workflow will publish all the versions in the PR to the registry. +> [!NOTE] +> Multiple connector versions can be published in the same PR. The `registry-update` workflow will publish all the versions in the PR to the registry. ## Updates to logo and README From 6377629cf8bfbe9a0edf26ce40e5c61e668ed1eb Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 13 Aug 2024 12:46:31 +0530 Subject: [PATCH 114/115] final cleanup --- registry/hasura/aurora/metadata.json | 7 +- registry/hasura/citus/metadata.json | 7 +- registry/hasura/cockroach/metadata.json | 7 +- registry/hasura/elasticsearch/metadata.json | 18 +- registry/hasura/mongodb/metadata.json | 168 ++++++++++++++++-- registry/hasura/neon/metadata.json | 7 +- .../hasura/postgres-alloydb/metadata.json | 7 +- registry/hasura/postgres-azure/metadata.json | 7 +- registry/hasura/postgres-cosmos/metadata.json | 7 +- registry/hasura/postgres-gcp/metadata.json | 7 +- .../hasura/postgres-timescaledb/metadata.json | 7 +- registry/hasura/postgres/metadata.json | 7 +- .../releases/v0.0.1/connector-packaging.json | 11 -- .../releases/v0.0.2/connector-packaging.json | 11 -- .../releases/v0.0.3/connector-packaging.json | 11 -- .../releases/v0.0.4/connector-packaging.json | 11 -- .../releases/v0.0.5/connector-packaging.json | 11 -- .../releases/v0.0.6/connector-packaging.json | 11 -- .../releases/v0.1.0/connector-packaging.json | 11 -- .../releases/v1.0.0/connector-packaging.json | 11 -- 20 files changed, 227 insertions(+), 117 deletions(-) delete mode 100644 registry/mongodb/releases/v0.0.1/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.0.2/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.0.3/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.0.4/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.0.5/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.0.6/connector-packaging.json delete mode 100644 registry/mongodb/releases/v0.1.0/connector-packaging.json delete mode 100644 registry/mongodb/releases/v1.0.0/connector-packaging.json diff --git a/registry/hasura/aurora/metadata.json b/registry/hasura/aurora/metadata.json index c00ff339..fd1f453b 100644 --- a/registry/hasura/aurora/metadata.json +++ b/registry/hasura/aurora/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/citus/metadata.json b/registry/hasura/citus/metadata.json index 1f4af8a0..76480564 100644 --- a/registry/hasura/citus/metadata.json +++ b/registry/hasura/citus/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/cockroach/metadata.json b/registry/hasura/cockroach/metadata.json index 88569e24..f4115c5d 100644 --- a/registry/hasura/cockroach/metadata.json +++ b/registry/hasura/cockroach/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/elasticsearch/metadata.json b/registry/hasura/elasticsearch/metadata.json index 1bc665e1..75b74dcb 100644 --- a/registry/hasura/elasticsearch/metadata.json +++ b/registry/hasura/elasticsearch/metadata.json @@ -7,7 +7,7 @@ "tags": [ "search" ], - "latest_version": "v1.0.0" + "latest_version": "v1.0.1" }, "author": { "support_email": "support@hasura.io", @@ -60,6 +60,17 @@ "source": { "hash": "9f1f508f551b4a9dec02c49e3312f38c24bb16c4" } + }, + { + "version": "1.0.1", + "uri": "https://github.com/hasura/ndc-elasticsearch/releases/download/v1.0.1/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "83b0b4f5b1f60a50e303f6354c4d48d397fc7d0a361eb8a14d8fe11b63fe6abd" + }, + "source": { + "hash": "72fad205f57e88781da6acafe1e03a7d220467c7" + } } ], "source_code": { @@ -85,6 +96,11 @@ "tag": "v1.0.0", "hash": "9f1f508f551b4a9dec02c49e3312f38c24bb16c4", "is_verified": true + }, + { + "tag": "v1.0.1", + "hash": "72fad205f57e88781da6acafe1e03a7d220467c7", + "is_verified": true } ] } diff --git a/registry/hasura/mongodb/metadata.json b/registry/hasura/mongodb/metadata.json index b3cebab8..53e9e124 100644 --- a/registry/hasura/mongodb/metadata.json +++ b/registry/hasura/mongodb/metadata.json @@ -1,23 +1,155 @@ { - "overview": { - "namespace": "hasura", - "description": "Connect to a MongoDB database and expose it to Hasura v3 Project", - "title": "MongoDB Connector", - "logo": "logo.png", - "tags": [ - "database" - ], - "latest_version": "v1.0.0" + "overview": { + "namespace": "hasura", + "description": "Connect to a MongoDB database and expose it to Hasura v3 Project", + "title": "MongoDB Connector", + "logo": "logo.png", + "tags": [ + "database" + ], + "latest_version": "v1.0.0" + }, + "author": { + "support_email": "support@hasura.io", + "homepage": "https://hasura.io", + "name": "Hasura" + }, + "is_verified": true, + "is_hosted_by_hasura": false, + "packages": [ + { + "version": "1.0.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" + }, + "source": { + "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" + } }, - "author": { - "support_email": "support@hasura.io", - "homepage": "https://hasura.io", - "name": "Hasura" + { + "version": "0.1.0", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" + }, + "source": { + "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" + } }, - "is_verified": true, - "is_hosted_by_hasura": false, - "source_code": { - "is_open_source": true, - "repository": "https://github.com/hasura/ndc-mongodb/" + { + "version": "0.0.6", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" + }, + "source": { + "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" + } + }, + { + "version": "0.0.5", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" + }, + "source": { + "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" + } + }, + { + "version": "0.0.4", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" + }, + "source": { + "hash": "38a4a56134a909001b645c659062ae393c2cebe0" + } + }, + { + "version": "0.0.3", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" + }, + "source": { + "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" + } + }, + { + "version": "0.0.2", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" + }, + "source": { + "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" + } + }, + { + "version": "0.0.1", + "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", + "checksum": { + "type": "sha256", + "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" + }, + "source": { + "hash": "c32adbde478147518f65ff465c40a0703239288a" + } } + ], + "source_code": { + "is_open_source": true, + "repository": "https://github.com/hasura/ndc-mongodb/", + "version": [ + { + "tag": "v1.0.0", + "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147", + "is_verified": true + }, + { + "tag": "v0.1.0", + "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1", + "is_verified": true + }, + { + "tag": "v0.0.6", + "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03", + "is_verified": true + }, + { + "tag": "v0.0.5", + "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6", + "is_verified": true + }, + { + "tag": "v0.0.4", + "hash": "38a4a56134a909001b645c659062ae393c2cebe0", + "is_verified": true + }, + { + "tag": "v0.0.3", + "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5", + "is_verified": true + }, + { + "tag": "v0.0.2", + "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0", + "is_verified": true + }, + { + "tag": "v0.0.1", + "hash": "c32adbde478147518f65ff465c40a0703239288a", + "is_verified": true + } + ] + } } diff --git a/registry/hasura/neon/metadata.json b/registry/hasura/neon/metadata.json index 2abe04b7..ca88bf34 100644 --- a/registry/hasura/neon/metadata.json +++ b/registry/hasura/neon/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres-alloydb/metadata.json b/registry/hasura/postgres-alloydb/metadata.json index 28e968ca..7c9faa60 100644 --- a/registry/hasura/postgres-alloydb/metadata.json +++ b/registry/hasura/postgres-alloydb/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres-azure/metadata.json b/registry/hasura/postgres-azure/metadata.json index 4e85da7d..4abff6a4 100644 --- a/registry/hasura/postgres-azure/metadata.json +++ b/registry/hasura/postgres-azure/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres-cosmos/metadata.json b/registry/hasura/postgres-cosmos/metadata.json index 66d97b3e..8c2bb20e 100644 --- a/registry/hasura/postgres-cosmos/metadata.json +++ b/registry/hasura/postgres-cosmos/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres-gcp/metadata.json b/registry/hasura/postgres-gcp/metadata.json index 691bdfda..33c4a3db 100644 --- a/registry/hasura/postgres-gcp/metadata.json +++ b/registry/hasura/postgres-gcp/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres-timescaledb/metadata.json b/registry/hasura/postgres-timescaledb/metadata.json index d014e1fe..201e71b3 100644 --- a/registry/hasura/postgres-timescaledb/metadata.json +++ b/registry/hasura/postgres-timescaledb/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/hasura/postgres/metadata.json b/registry/hasura/postgres/metadata.json index af1333d7..501c2b73 100644 --- a/registry/hasura/postgres/metadata.json +++ b/registry/hasura/postgres/metadata.json @@ -7,7 +7,7 @@ "tags": [ "database" ], - "latest_version": "v1.0.1" + "latest_version": "v1.0.2" }, "author": { "support_email": "support@hasura.io", @@ -54,6 +54,11 @@ "tag": "v1.0.1", "hash": "e2fd651", "is_verified": true + }, + { + "tag": "v1.0.2", + "hash": "1378805", + "is_verified": true } ] } diff --git a/registry/mongodb/releases/v0.0.1/connector-packaging.json b/registry/mongodb/releases/v0.0.1/connector-packaging.json deleted file mode 100644 index 13d2851d..00000000 --- a/registry/mongodb/releases/v0.0.1/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.1", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" - }, - "source": { - "hash": "c32adbde478147518f65ff465c40a0703239288a" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.2/connector-packaging.json b/registry/mongodb/releases/v0.0.2/connector-packaging.json deleted file mode 100644 index e6561cd6..00000000 --- a/registry/mongodb/releases/v0.0.2/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.2", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" - }, - "source": { - "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.3/connector-packaging.json b/registry/mongodb/releases/v0.0.3/connector-packaging.json deleted file mode 100644 index 02812b53..00000000 --- a/registry/mongodb/releases/v0.0.3/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.3", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" - }, - "source": { - "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.4/connector-packaging.json b/registry/mongodb/releases/v0.0.4/connector-packaging.json deleted file mode 100644 index d145fd13..00000000 --- a/registry/mongodb/releases/v0.0.4/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.4", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" - }, - "source": { - "hash": "38a4a56134a909001b645c659062ae393c2cebe0" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.5/connector-packaging.json b/registry/mongodb/releases/v0.0.5/connector-packaging.json deleted file mode 100644 index 9c7bcefe..00000000 --- a/registry/mongodb/releases/v0.0.5/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.5", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" - }, - "source": { - "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.0.6/connector-packaging.json b/registry/mongodb/releases/v0.0.6/connector-packaging.json deleted file mode 100644 index 890a2f58..00000000 --- a/registry/mongodb/releases/v0.0.6/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.6", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" - }, - "source": { - "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v0.1.0/connector-packaging.json b/registry/mongodb/releases/v0.1.0/connector-packaging.json deleted file mode 100644 index dc640be8..00000000 --- a/registry/mongodb/releases/v0.1.0/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.1.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" - }, - "source": { - "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" - } -} \ No newline at end of file diff --git a/registry/mongodb/releases/v1.0.0/connector-packaging.json b/registry/mongodb/releases/v1.0.0/connector-packaging.json deleted file mode 100644 index 67035c87..00000000 --- a/registry/mongodb/releases/v1.0.0/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "1.0.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" - }, - "source": { - "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" - } -} \ No newline at end of file From 25c4816b871894826809a83a7e281af88d2e06ae Mon Sep 17 00:00:00 2001 From: Karthikeyan C Date: Tue, 13 Aug 2024 12:49:05 +0530 Subject: [PATCH 115/115] final cleanup --- .../mongodb/releases/v0.0.1/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.0.2/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.0.3/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.0.4/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.0.5/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.0.6/connector-packaging.json | 11 ----------- .../mongodb/releases/v0.1.0/connector-packaging.json | 11 ----------- .../mongodb/releases/v1.0.0/connector-packaging.json | 11 ----------- 8 files changed, 88 deletions(-) delete mode 100644 registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json delete mode 100644 registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json diff --git a/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json deleted file mode 100644 index 13d2851d..00000000 --- a/registry/hasura/mongodb/releases/v0.0.1/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.1", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.1/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2cd3584557be7e2870f3488a30cac6219924b3f7accd9f5f473285323843a0f4" - }, - "source": { - "hash": "c32adbde478147518f65ff465c40a0703239288a" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json deleted file mode 100644 index e6561cd6..00000000 --- a/registry/hasura/mongodb/releases/v0.0.2/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.2", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.2/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "f014459e9dbcce8bafe1c33c74b1fa1720d544bc283cc819c81d719028219846" - }, - "source": { - "hash": "90c336c4d1d949d62dd25b04742e650fb6d458e0" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json deleted file mode 100644 index 02812b53..00000000 --- a/registry/hasura/mongodb/releases/v0.0.3/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.3", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.3/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" - }, - "source": { - "hash": "b50094a368f8fbab7c37e4b83ef5dc1249a4a5d5" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json deleted file mode 100644 index d145fd13..00000000 --- a/registry/hasura/mongodb/releases/v0.0.4/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.4", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.4/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "7b826a79686b48e58819751091fac62071df75ca9fd617b80709fe098a054f26" - }, - "source": { - "hash": "38a4a56134a909001b645c659062ae393c2cebe0" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json deleted file mode 100644 index 9c7bcefe..00000000 --- a/registry/hasura/mongodb/releases/v0.0.5/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.5", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.5/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "2064a98d223240b912720f0528c6b9a7107a42e4452407c2b75e77dcfdbd4227" - }, - "source": { - "hash": "055154b5d84f05ff0049aa75a29b85caf89822f6" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json b/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json deleted file mode 100644 index 890a2f58..00000000 --- a/registry/hasura/mongodb/releases/v0.0.6/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.6", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.0.6/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "24370c44a8ff92dce488569717956069f2a50de7a8f54547b140d85a17b52875" - }, - "source": { - "hash": "6e842c308eeee38d3bc393e6b99157961ca3ed03" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json b/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json deleted file mode 100644 index dc640be8..00000000 --- a/registry/hasura/mongodb/releases/v0.1.0/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.1.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v0.1.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "adb5ce24e053117ba33c16ecf54bdc5a678790f3b31801645911fdf7091a58e0" - }, - "source": { - "hash": "175272912b86a11359a9b6b7fd72c7a6e2326bf1" - } -} \ No newline at end of file diff --git a/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json b/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json deleted file mode 100644 index 67035c87..00000000 --- a/registry/hasura/mongodb/releases/v1.0.0/connector-packaging.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "1.0.0", - "uri": "https://github.com/hasura/ndc-mongodb/releases/download/v1.0.0/connector-definition.tgz", - "checksum": { - "type": "sha256", - "value": "0dc038620f40911a2c5662b61d8e2ac9605876c80b3eb3cbae5cc1ebcd5b611f" - }, - "source": { - "hash": "4beb7ddabddc3035ca5cc7bd85493a71a2e34147" - } -} \ No newline at end of file