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

feature: GitHub component #2

Merged
merged 11 commits into from
Oct 20, 2023
Merged

feature: GitHub component #2

merged 11 commits into from
Oct 20, 2023

Conversation

gberenice
Copy link
Member

Info

This adds a Github component. For now, we're able to manage repositories configuration.

@gberenice gberenice requested review from Gowiem and kevcube October 16, 2023 16:15
Copy link

@kevcube kevcube left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the dynamic "list of repos" approach but then our call to the underlying module is so much of this = each.this which seems like a waste of key presses (even if copilot does all the heavy lifting)

Also conglomerating every repo into one state file is probably harmless but large blast radius.. I dunno I think it is best for us to essentially call the mineiros repo (forked with SOPS mixin) many times instead of calling it in a loop

github/main.tf Outdated
source = "mineiros-io/repository/github"
version = "0.18.0"

for_each = var.repos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

Comment on lines 18 to 32
provider "github" {
base_url = var.gh_base_url
owner = var.gh_owner

token = local.gh_token_enabled ? local.gh_token : null

dynamic "app_auth" {
for_each = local.gh_app_auth_enabled ? ["app_auth"] : []
content {
id = var.gh_app_auth_id
installation_id = var.gh_app_auth_installation_id
pem_file = local.gh_app_auth_pem_file
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can all be handled in environment variables and that sort of configuration will remain consistent in Spacelift, then we don't have to do the auth method selection logic in locals, but there's also merits to it being explicit in code. Especially because we don't use a chamber sort of environment variable management in local dev loop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We rarely use env variables for this type of configuration, so I leaned towards the approach that keeps GH configuration in one place without a need to set up Spacelift stacks (in our case). With this implementation, a token can still be consumed as an env variable if not set via SOPS.
For app_auth we could work on more complex logic in the future if needed.

Comment on lines 34 to 84
variable "gh_app_auth_id" {
type = string
description = "The ID of the GitHub App."
default = ""
}

variable "gh_app_auth_installation_id" {
type = string
description = "The ID of the GitHub App installation"
default = ""
}

variable "gh_app_auth_pem_file_secret_name" {
type = string
description = <<-EOF
The name of the secret retrieved by secrets mixin that contains
the contents of the GitHub App private key PEM file.
EOF
default = null
}

variable "gh_base_url" {
type = string
description = <<-EOF
(Optional) This is the target GitHub base API endpoint.
Providing a value is a requirement when working with GitHub Enterprise.
It is optional to provide this value and it can also be sourced from the GITHUB_BASE_URL environment variable.
The value must end with a slash, for example: https://terraformtesting-ghe.westus.cloudapp.azure.com/
EOF
default = null
}

variable "gh_owner" {
type = string
description = <<-EOF
(Optional) This is the target GitHub organization or individual user account to manage.
For example, `torvalds` and `github` are valid owners. It is optional to provide this value
and it can also be sourced from the GITHUB_OWNER environment variable.
When not provided and a token is available, the individual user account owning the token will be used.
When not provided and no token is available, the provider may not function correctly.
EOF
default = null
}

variable "gh_token_secret_name" {
type = string
description = <<-EOF
The name of the secret retrieved by secrets mixin that contains the GitHub personal access token.
EOF
default = null
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer all variables being in variables.tf unless they're specific to a shared mixin

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of this as of future mixin, but it's not the case right now, so I've moved it to the variables.tf 👌

type = string
description = <<-EOF
The name of the secret retrieved by secrets mixin that contains the GitHub personal access token.
EOF
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This EOF (and others) should be spaced two forward because I think now the final rendered result will be two spaces forward, b/c this line is the one with least indentation

https://developer.hashicorp.com/terraform/language/expressions/strings#indented-heredocs

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it closer I might be wrong. If you have a sec to verify let me know

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Terraform analyses the lines in the sequence to find the one with the smallest number of leading spaces, and then trims that many spaces from the beginning of all of the lines.
Since there is no diff in space numbers for these vars, it renders fine. However I've updated the description format to use the expected number of spaces.

Copy link

@kevcube kevcube Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I wasn't sure if it would also analyze the spaces before your EOF marker

@@ -5,14 +5,16 @@
*.tfstate
*.tfstate.*

# Terraform lock files
.terraform.lock.hcl
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should include

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The components are intended to be used as child modules, and the root module should have it's own lock file anyway. What's the reason we might want to keep it here?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this component is already at root module level for a consumer. The most we would do is just copy it into sts-devops, no? to wrap it an additional time and write another variable = var.variable ... block seems like too much

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally I see no opinions online that lockfiles should not be included in child modules and don't see a reason not to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just not used by Terraform, no init is run on this level.

Copy link
Member Author

@gberenice gberenice Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this component is already at root module level for a consumer. The most we would do is just copy it into sts-devops, no? to wrap it an additional time and write another variable = var.variable ... block seems like too much

Not sure. Let's discuss on a call.

github/main.tf Outdated Show resolved Hide resolved
github/main.tf Outdated
deploy_keys = each.value.deploy_keys
deploy_keys_computed = each.value.deploy_keys_computed

# Branch Protections v3 Configuration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove V3 config so we can avoid potentially using it since it sounds like it's now legacy?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, especially considering it may conflict with v4 branch protections if used for the same branch. Removed.

Copy link
Member

@Gowiem Gowiem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gberenice I didn't check all those inputs as I imagine that's just a for_each over ALL of the vars in the child module, yeah? That seems great to me and this looks solid. One or two requests below and I'll approve when you get back to me on those!

@Gowiem
Copy link
Member

Gowiem commented Oct 16, 2023

@kevcube saw this comment and wanted to share thoughts:

Also conglomerating every repo into one state file is probably harmless but large blast radius.. I dunno I think it is best for us to essentially call the mineiros repo (forked with SOPS mixin) many times instead of calling it in a loop

This is a legit point of view and I could see going either way on it depending on size. Two size perspectives that are worth considering:

  1. In our-case at Masterpoint, we have 40 something repos in this org, which I think would be be painful: We'd have a lot of separate states that would need to be managed as separate plans / applies to review / approve / deal with. I'd find that tedious if we suddenly ended up with 40 new Stacks to manage in Spacelift (even though we're not running this in Spacelift). And if we had auto-approve apply on for all of them... then I think it'd be similar concerns as if they were all in one statefile.

  2. Our primary customer's use-case, I could see it working fine: Maybe we have ~10 separate states to manage? No big deal for now.

I'm a bit torn on it when typing it out. I think I gravitate towards the for_each pattern to help alleviate pain for issue 1, but I'm open to push back. @gberenice would definitely like your opinion.

@kevcube
Copy link

kevcube commented Oct 17, 2023

@Gowiem I see your point that "auto-approve vs. one mega-state file, both have issues" but I think I feel more comfortable with auto-approve. Frankly the risk with either is minimal, but if someone is making changes from local then auto-approve is irrelevant and the mega-state is still a risk.

Honestly I think auto-approve everywhere should be a goal of ours (maybe with plan outputs printed to PRs and reviewed as a part of PR)

@gberenice
Copy link
Member Author

@gberenice I didn't check all those inputs as I imagine that's just a for_each over ALL of the vars in the child module, yeah?

Yes (god bless copilot and chatgpt).

@gberenice
Copy link
Member Author

@Gowiem @kevcube to me, the main question is - what this component is about and how we're layering the resources.
If we think of this component as of a high-level abstraction that can be extended (for example, with terraform-github-team) then it's probably worth taking risks with megastate and avoiding pain with dealing with plenty of states.
If only repo management is expected here - then I we're choosing the path of smaller "fractions", that, in some cases, could cost us unpleasant work to manage it. Long chain of child modules is also a concern to me.

Forking the repo raises the question of sync between the projects. I bet we'll be lazy and have some changes pushed to our repo only (classic). The original repo doesn't seem to be active at the moment, but I've already noticed some minor issues worth contributing.

@gberenice gberenice merged commit d3132a4 into main Oct 20, 2023
2 checks passed
@gberenice gberenice deleted the feature/gh_component branch October 20, 2023 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants