Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: PATCH request for repos/OWNER/REPO/properties/values broken #90

Open
1 task done
felixlut opened this issue Jul 15, 2024 · 5 comments
Open
1 task done
Labels
Status: Triage This is being looked at and prioritized Type: Bug Something isn't working as documented

Comments

@felixlut
Copy link

felixlut commented Jul 15, 2024

What happened?

I'm playing around with this sdk as a means of contributing to integrations/terraform-provider-github#1956, and as such my focus is on the endpoints related to repository custom properties.

The issue I'm facing occurs when calling octokitClient.Repos().ByOwnerId(owner).ByRepoId(repoName).Properties().Values().Patch(), which is mapped to the repos/OWNER/REPO/properties/values PATCH endpoint. I'll list the code I'm using further down in the message.

When running the code below I receive the following error:

  • error status code received from the API

I've ran the debugger and dug deeper into the call chain, and found that the error code is 400, but haven't been able to find an error message. Digging down all the way to the net/http layer and inspecting the request body being sent, it looks like this:

  • "{\"properties\":[{\"property_name\":\"text\",\"value\":\"test\"}]}"

Which isn't too dissimilar to what the API expects (example from the docs):

  • '{"properties":[{"property_name":"environment","value":"production"},{"property_name":"service","value":"web"},{"property_name":"team","value":"octocat"}]}'

After playing around with curl a bit, I've managed to receive a 400 error by using malformed JSON in the body (see example below). My guess is that this SDK somewhere along the line parses the custom property incorrectly, or that I'm passing the property_name and value incorrectly to it.

curl -L \
  -X PATCH \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $(gh auth token)" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/YesWeKanske/test-custom-properties/properties/values -d '"{"properties":[{"property_name":"text","value":"test"}]}"'
{
  "message": "Problems parsing JSON",
  "documentation_url": "https://docs.github.com/rest/repos/custom-properties#create-or-update-custom-property-values-for-a-repository",
  "status": "400"
}
package main

import (
	"context"
	"log"
	"os"
	"time"

	abs "github.com/microsoft/kiota-abstractions-go"
	"github.com/octokit/go-sdk/pkg"
	"github.com/octokit/go-sdk/pkg/github/models"
	"github.com/octokit/go-sdk/pkg/github/repos"
)

func main() {
	octokitClient, err := pkg.NewApiClient(
		pkg.WithUserAgent("my-user-agent"),
		pkg.WithRequestTimeout(60*time.Second),
		pkg.WithBaseUrl("https://api.github.com"),
		pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")),
	)
	ctx := context.Background()

	if err != nil {
		log.Fatalf("error creating client: %v", err)
	}

	owner := "YesWeKanske"
	repoName := "test-custom-properties"

	repoURL := octokitClient.Repos().ByOwnerId(owner).ByRepoId(repoName)
	propURL := repoURL.Properties().Values()

	headers := abs.NewRequestHeaders()
	_ = headers.TryAdd("Accept", "application/vnd.github.v3+json")
	_ = headers.TryAdd("X-GitHub-Api-Version", "2022-11-28")
	defaultRequestConfig := &abs.RequestConfiguration[abs.DefaultQueryParameters]{
		QueryParameters: &abs.DefaultQueryParameters{},
		Headers: headers,
	}

	propertyName := "text"
	propertyValue := "test"
	testProps := make(map[string]interface{})
	testProps[propertyName] = propertyValue

	testProperty := models.NewCustomPropertyValue()
	testProperty.SetPropertyName(&propertyName)

	propertyValueModel := models.NewCustomPropertyValue_CustomPropertyValue_value()
	propertyValueModel.SetString(&propertyValue)
	testProperty.SetValue(propertyValueModel)
	// testProperty.SetAdditionalData(testProps)
	
	patchBody := repos.NewItemItemPropertiesValuesPatchRequestBody()
	patchBody.SetProperties([]models.CustomPropertyValueable{
		testProperty,
	})
	// patchBody.SetAdditionalData(testProps)

	err = propURL.Patch(ctx, patchBody, defaultRequestConfig)
	if err != nil {
		panic(err)
	}
}

I've also explored the following:

  • The value attribute of an CustomPropertyValue should implement the CustomPropertyValue_CustomPropertyValue_valueable interface, which only have the two methods GetString() and SetString, which implies that the value of a custom property can only be a string. But it can be either a string or a list of string (multi_select custom property type). Due to this this SDK can only work with the other property types currently (except for the stuff mentioned above 😄). The curl call below is valid, but there is no way of replicating it with this SDK from what I can tell
curl -L \
  -X PATCH \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $(gh auth token)" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/YesWeKanske/test-custom-properties/properties/values -d '{"properties": [{"property_name": "multi-select","value": ["option1","option2"]}]}'
  • Both models.CustomPropertyValue and repos.ItemItemPropertiesValuesPatchRequestBody supports a function called SetAdditionalData(). I've tried playing around with those two, but they seem to mess up the json body that is being sent to the GitHub API by adding key value pairs to it (the two "test": "text" below):
{
  "properties": [
    {
      "property_name": "text",
      "value": "test",
      "text": "test"
    }
  ],
  "text": "test"
}

Versions

I've used the latest version of the provider at the time of writing this bug report (go get github.com/octokit/go-sdk@a74a3a2a13654bd84794fd91a6a0fbc96f883722, where a74a3a2a13654bd84794fd91a6a0fbc96f883722 is a commit to this repo). My go.mod file looks like so:

module example/hello

go 1.22.3

require (
	github.com/microsoft/kiota-abstractions-go v1.6.0
	github.com/octokit/go-sdk v0.0.21-0.20240709170617-a74a3a2a1365
)

require (
	github.com/cjlapao/common-go v0.0.39 // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/go-logr/logr v1.4.1 // indirect
	github.com/go-logr/stdr v1.2.2 // indirect
	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
	github.com/google/uuid v1.6.0 // indirect
	github.com/kfcampbell/ghinstallation v0.0.6 // indirect
	github.com/microsoft/kiota-http-go v1.3.3 // indirect
	github.com/microsoft/kiota-serialization-form-go v1.0.0 // indirect
	github.com/microsoft/kiota-serialization-json-go v1.0.7 // indirect
	github.com/microsoft/kiota-serialization-multipart-go v1.0.0 // indirect
	github.com/microsoft/kiota-serialization-text-go v1.0.0 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect
	github.com/stretchr/testify v1.9.0 // indirect
	go.opentelemetry.io/otel v1.24.0 // indirect
	go.opentelemetry.io/otel/metric v1.24.0 // indirect
	go.opentelemetry.io/otel/trace v1.24.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)

Code of Conduct

  • I agree to follow this project's Code of Conduct
@felixlut felixlut added Status: Triage This is being looked at and prioritized Type: Bug Something isn't working as documented labels Jul 15, 2024
Copy link

👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a process in place for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labeled with Status: Up for grabs. You & others like you are the reason all of this works! So thank you & happy coding! 🚀

@kfcampbell
Copy link
Member

I appreciate this super thoughtful bug report, and thank you for working to bring the new SDK into the Terraform provider. That's great!

I've reproduced what you've done here on a dummy repo (kfcampbell-terraform-provider/tf-acc-test-destroy-trfiz), and I agree there's something wonky going on in the generated code. I'm able to add custom properties successfully via the UI, and via a CURL request like the following:

curl -L   -X PATCH   -H "Accept: application/vnd.github+json"   -H "Authorization: Bearer $(gh auth token)"   -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/kfcampbell-terraform-provider/tf-acc-test-destroy-trfiz/properties/values -d '{"properties":[{"property_name":"environment","value":"test-from-curl"}]}'

When using the SDK, I'm using the following code (after creating the client as we do in the example token CLI):

	customPropertyValue := models.NewCustomPropertyValue()
	propertyName := "environment"
	propertyValue := "test-from-go-sdk"

	customPropertyValue.SetPropertyName(&propertyName)
	value := models.NewCustomPropertyValue_CustomPropertyValue_value()
	value.SetString(&propertyValue)
	customPropertyValue.SetValue(value)

	patchRequestBody := repos.NewItemItemPropertiesValuesPatchRequestBody()
	patchRequestBody.SetProperties([]models.CustomPropertyValueable{customPropertyValue})

	err = client.Repos().ByOwnerId("kfcampbell-terraform-provider").ByRepoId("tf-acc-test-destroy-trfiz").
		Properties().Values().Patch(context.Background(), patchRequestBody, nil)
	if err != nil {
		log.Fatalf("error setting custom properties: %v", err)
	}

This fails with a 400 Bad Request error, and I see the payload going out as:

"{\"properties\":[{\"property_name\":\"environment\",\"value\":\"test-from-go-sdk\"}]}"

When I attempt a curl request with that as the payload (as I'm somewhat suspicious of the backslashes), I get a 422, not a 400.

I think this is an error with Kiota, our generation engine, so I've filed microsoft/kiota#4995 and will do some investigation with them.

@kfcampbell
Copy link
Member

@felixlut this should be fixed as of v0.0.23!

@felixlut
Copy link
Author

Thanks! I'll take a stab after work today or tomorrow

@felixlut
Copy link
Author

felixlut commented Aug 1, 2024

@kfcampbell setting non-multi_select property values works now!

multi_select values are still broken though from what I can tell, for the reason I stated in the original issue:

  • The value attribute of an CustomPropertyValue should implement the CustomPropertyValue_CustomPropertyValue_valueable interface, which only have the two methods GetString() and SetString, which implies that the value of a custom property can only be a string. But it can be either a string or a list of string (multi_select custom property type). Due to this this SDK can only work with the other property types currently (except for the stuff mentioned above 😄). The curl call below is valid, but there is no way of replicating it with this SDK from what I can tell
curl -L \
  -X PATCH \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $(gh auth token)" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/YesWeKanske/test-custom-properties/properties/values -d '{"properties": [{"property_name": "multi-select","value": ["option1","option2"]}]}'

This might warrant its own issue though 😄

I'll also note that the Organization Ruleset API seems to handle the fact that a property value can be either a string or a list of strings in the way I proposed here, i.e., by just treating it as a list of strings at all times. It's pretty deeply nested, but Org Rulesets can target repos by custom properties, and this is where this occurs. .conditions.repository_property_and_ref_name.repository_property.include.property_values always takes a list of strings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Triage This is being looked at and prioritized Type: Bug Something isn't working as documented
Projects
Status: 🛑 Blocked/Awaiting Response
Development

No branches or pull requests

2 participants