-
Notifications
You must be signed in to change notification settings - Fork 773
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
feat: support repository level custom_property resource and custom_properties datasource #2316
feat: support repository level custom_property resource and custom_properties datasource #2316
Conversation
@felixlut It seems that v64 google/go-github#3240 added support for Multi select finally. Only issue is that the terraform provider codebase is still at v63 |
Seems like #2359 will deal with bumping the dep, so I'll revisit this once it's merged |
I started looking into this again over the weekend but hit a bottleneck again. I made a fix in google/go-github#3309, but that requires another bump of the The reason I'd rather use that than the |
@felixlut given that go-github has been updated to v66 are you now unblocked? |
Will take a look again in the coming week or so |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aight, long time coming but I finally think this PR is in a reviewable state! I've made some comments on certain parts where I'm not 100% sure on the design, I'd love to get some opinions on those! Of the bat these 2 things are noteworthy as well:
- I opted for a non-authoriative custom_propertY resource as opposed to an authoriative custom_propertIES resource. Reason being that fulfills the use-case I have. I think an authoriative resource should exist, as it has its uses similarily to github_repository_collaborators. Nothing stops later PR:s doing just that
- On a similar note I opted opted out of adding
custom_property
togithub_repository
, as proposed here for the same reason. Nothing stops future PR:s here either. Docs just needs to reflect that both shouldn't be used as the same time
- On a similar note I opted opted out of adding
- For the data_source I opted for custom_propertIES over reading each property individually. The reason for this is that the API endpoint for reading custom properties on a repo returns ALL properties. Filtering that full list and returning just 1 property seemed redundant to me. With that said creating a custom_propertY data source should be trivial with a future PR 😄
Also, thanks @ViktorLindgren95 for juggling some ideas regarding this PR with me, much appreciated!
"property_value": { | ||
Type: schema.TypeSet, | ||
MinItems: 1, | ||
Required: true, | ||
Description: "Value of the custom property.", | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
ForceNew: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value of a custom property can be either null
or string
or array
of strings
because of the multi_select
property type (docs). This is an interesting design choice in the API that poses some unintuitive challenges while interacting with it, namely how we design the Terraform resource for the property_value
?
- Have different fields for
property_value_string
andproperty_value_list
depending on the input type? - Treat everything as a list of strings (and
null
as[]
)? jsonencode
:ed values?- This thread discusses it a bit more
I opted for the "treat everything as an array of strings" solution, as that is how GitHub have solved the issue in their other API:s that deal with custom properties (eg the Organization Rulesets API, hidden deep in .conditions.repository_property_and_ref_name.repository_property.include.property_values
). Like with the other comments, I'm all ears for opinions here
"property_type": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Type of the custom property", | ||
ForceNew: true, | ||
ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{SINGLE_SELECT, MULTI_SELECT, STRING, TRUE_FALSE}, false), "property_type"), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the downsides of the limitations mentioned in the comment below (property_value
can be null
or string
or array
) is that we need to know which format the API expects when creating/updating the custom property. I.e., an array with 1 element can either represent a multi_select
property, and the API then expects that we send the full array, or it could be a single_select
(or any other type actually), where the API would then expect only a string in the call to it. Docs for the specific endpoint can be found here.
I had the following ideas as workarounds:
- User supplies the
custom_property_type
in the resource. More responsibility on the user, but it works... - Given the name of the custom property, read it on an org level and thereby derive the
value_type
. Downside of this is that the user/App running Terraform needs"Custom properties" organization permissions (read)
- One would imagine that there should be a corresponding repo-level endpoint where one could read the
value_type
, but I've not been able to find one. This is the closest I could find, but that just returns the name and value of an already set property, which is not enough for our problem - It's also possible to run a "greedy" attempt at creating/updating the custom property when the
array
is of length 1. First try running it with the singlestring
, and if that fails try again with thearray
instead. The error message is pretty helpful here (see below). This feels incredibly hacky though...
I opted for the user having to fill in custom_property_type
but I'd love to be convinced there is another way here
|
||
func TestAccGithubRepositoryCustomPropertiesDataSource(t *testing.T) { | ||
|
||
t.Skip("You need an org with custom properties already setup as described in the variables below") // TODO: at the time of writing org_custom_properties are not supported by this terraform provider, so cant be setup in the test itself for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've ran the tests locally and confirmed they work in my test org. Notably this should be updated once #2107 is merged (or another PR takes its place)
|
||
func TestAccGithubRepositoryCustomProperty(t *testing.T) { | ||
|
||
t.Skip("You need an org with custom properties already setup as described in the variables below") // TODO: at the time of writing org_custom_properties are not supported by this terraform provider, so cant be setup in the test itself for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've ran the tests locally and confirmed they work in my test org. Notably this should be updated once #2107 is merged (or another PR takes its place)
Description: "Name of the repository which the custom properties should be on.", | ||
}, | ||
"property": { | ||
Type: schema.TypeSet, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I see most people using this resource is to:
- Read the custom properties of a repo
- For each specific property do something based on it's value. Eg, do X to the repo if the
owner
property equals Y, do Z to the repo if theenvironment
property equals ...
This means that it should be as easy as possible to get the value of a specific property. IMO that would be best achieved by using a TypeMap
. Unfortunately that is not supported by v2 of the terraform-plugin-sdk (see thread).
The choice is then between TypeList
or TypeSet
. Reading the docs the latter sounds more correct to me, as the order of the custom properties does not matter. We've seen issues regarding this in this provider in the past, eg in #1950, that should be avoided by using TypeSet
.
It's worth noting that there are some other implications of using TypeSet
though, namely that they are non-indexable. This common pattern will for example not work, and throw the error below:
data "github_repository_custom_properties" "test" {
repository = "test-custom-properties"
}
locals {
# Assuming the repo have a property called "string" set already
test = data.github_repository_custom_properties.test.property[index(data.github_repository_custom_properties.test.property.*.property_name, "string")]
}
That does not mean that it's impossible to fetch the value of a custom property though. Either of the two snippets below does work, and are IMO more readable, but I think I'd be amiss if I didn't mention this.
data "github_repository_custom_properties" "test" {
repository = "test-custom-properties"
}
locals {
# Get single custom property
string_property = one([ for prop in data.github_repository_custom_properties.test.property: prop if prop.property_name == "string" ])
# Convert the output of the data_source to a map that can then be referenced by `local.property_map[<property_name>]`
property_map = { for prop in data.github_repository_custom_properties.test.property: prop.property_name => prop.property_value }
}
I personally lean towards using a TypeSet
to avoid possible weird diffs, but I don't feel strongly about it. If anyone have any opinions here I'm all ears 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixlut have you considered also adding a github_repository_custom_property
data source to access a singular property? It would allow for more direct access to properties at the cost of increased API usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 |
Any update on getting this PR merged? This would be a really useful enhancement to support custom properties! |
@hashildy it hasn't moved since my last message ^^ It is ready for review though (or at least it was 2m ago). |
@stevehipwell - is this PR able to be reviewed/merged? |
@hashildy I'm just a contributor, I have 9 PRs that have been ready to review merge in the last 3 months that haven't had a single comment by a maintainer. |
@kfcampbell - Any chance of getting a review / approval of this PR? |
Contributes to #1956
Custom properties are defined on an organizational level, and then applied on a repository level. This PR aims to solve the latter of those two, while the former already has a PR for it in #2107.
Edit: Leaving the original comment below. Update can be found below in #2316 (review)
This is a work in progress (WIP) since the underlying sdk:s are lacking for the REST endpoints pertaining to the repository level custom properties:
go-github
lacks support for themulti_select
custom property type, see Bug: Multi-select Custom Properties are not supported google/go-github#3198. There is a PR close to being merged for solving this feat!: Add support for multi-select Custom Properties google/go-github#3200go-github
has been released sincegithub_repository_custom_properties
datasource with it due to the lacking functionality ofgo-github
in this area currently. I'm currently trying to get it to write the custom properties, which I've been unsuccessful in so far. See [BUG]: PATCH request for repos/OWNER/REPO/properties/values broken octokit/go-sdk#90If there's any progress on either of these I'll update this PR
Before the change?
After the change?
Pull request checklist
Does this introduce a breaking change?
Please see our docs on breaking changes to help!