-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add go utility on generating git issues at provider repos
- Loading branch information
Showing
3 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# open_issues | ||
|
||
`open_issues` is a go utility intended to open git issues on provider repos. | ||
|
||
## Pre-requisites | ||
|
||
- Create a github token which has a access to the following scopes. And save it in your environment as `GITHUB_ISSUE_OPENER_TOKEN` | ||
- `repo:status` - Grants access to commit status on public and private repositories. | ||
- `repo_deployment` - Grants access to deployment statuses on public and private repositories. | ||
- `public_repo` - Grants access to public repositories | ||
- Decide upon the title of the issue to be opened. Update it in the utility. | ||
- Update the issue body | ||
|
||
## How to run the tool | ||
|
||
- From the root of the project Cluster API, run below to dry run the utility. | ||
|
||
```go | ||
make provider-issues-dry-run | ||
``` | ||
|
||
OR | ||
|
||
run below to create the issues at the provider repositories. | ||
|
||
```sh | ||
make provider-issues | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
//go:build tools | ||
// +build tools | ||
|
||
/* | ||
Copyright 2023 The Kubernetes Authors. | ||
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. | ||
*/ | ||
|
||
// main is the main package for the open issues utility. | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"os" | ||
"strings" | ||
) | ||
|
||
const ( | ||
baseURL = "https://api.github.com" | ||
issueTitle = "CAPI v1.x.0-beta.0 has been released and is ready for testing" | ||
) | ||
|
||
var ( | ||
repoList = []string{ | ||
"kubernetes-sigs/cluster-api-addon-provider-helm", | ||
"kubernetes-sigs/cluster-api-provider-aws", | ||
"kubernetes-sigs/cluster-api-provider-azure", | ||
"kubernetes-sigs/cluster-api-provider-cloudstack", | ||
"kubernetes-sigs/cluster-api-provider-digitalocean", | ||
"kubernetes-sigs/cluster-api-provider-gcp", | ||
"kubernetes-sigs/cluster-api-provider-kubemark", | ||
"kubernetes-sigs/cluster-api-provider-kubevirt", | ||
"kubernetes-sigs/cluster-api-provider-ibmcloud", | ||
"kubernetes-sigs/cluster-api-provider-nested", | ||
"oracle/cluster-api-provider-oci", | ||
"kubernetes-sigs/cluster-api-provider-openstack", | ||
"kubernetes-sigs/cluster-api-operator", | ||
"kubernetes-sigs/cluster-api-provider-packet", | ||
"kubernetes-sigs/cluster-api-provider-vsphere", | ||
} | ||
) | ||
|
||
// Issue is the struct for the issue. | ||
type Issue struct { | ||
// Title is the title of the issue. | ||
Title string `json:"title"` | ||
|
||
// Body is the body of the issue. | ||
Body string `json:"body"` | ||
} | ||
|
||
// IssueResponse is the struct for the issue response. | ||
type IssueResponse struct { | ||
// HTMLURL is the URL of the issue. | ||
HTMLURL string `json:"html_url"` | ||
} | ||
|
||
func main() { | ||
token := flag.String("token", "", "GitHub personal access token") | ||
dryRun := flag.Bool("dryRun", true, "Dry run") | ||
flag.Parse() | ||
|
||
if *token == "" { | ||
fmt.Println("GitHub personal access token is required.") | ||
os.Exit(1) | ||
} | ||
|
||
issueBody := ` | ||
<!-- body --> | ||
<!-- TODO: remove all TODOs before running this utility --> | ||
<!-- TODO: update CAPI release semver --> | ||
CAPI v1.x.0-beta.0 has been released and is ready for testing. | ||
Looking forward to your feedback before CAPI 1.x.0 release! | ||
## For quick reference | ||
<!-- body --> | ||
<!-- TODO: CAPI release notes --> | ||
- [CAPI v1.x.0-beta.0 release notes](https://github.com/kubernetes-sigs/cluster-api/releases/tag/v1.x.0-beta.0) | ||
- [Shortcut to CAPI git issues](https://github.com/kubernetes-sigs/cluster-api/issues) | ||
## Following are the planned dates for the upcoming releases | ||
<!-- TODO: update CAPI release timeline --> | ||
|Release|Expected Date| | ||
|-----|-----| | ||
|v1.5.0-beta.x | Tuesday 5th July 2023| | ||
|release-1.5 branch created (Begin [Code Freeze])|Tuesday 11th July 2023| | ||
|v1.5.0-rc.0 released|Tuesday 11th July 2023| | ||
| release-1.5 jobs created | Tuesday 11th July 2023 | | ||
| v1.5.0-rc.x released | Tuesday 18th July 2023 | | ||
| v1.5.0 released | Tuesday 25th July 2023 | | ||
<!-- body --> | ||
<!-- [List of CAPI providers](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#communicate-beta-to-providers) --> | ||
` | ||
|
||
if *dryRun { | ||
fmt.Printf("\n") | ||
fmt.Println("###############################################") | ||
fmt.Println("Dry run is enabled. No git issues will be created.") | ||
fmt.Println("###############################################") | ||
fmt.Printf("\n") | ||
} | ||
|
||
fmt.Println("\n\nCreating issues for the following repositories:") | ||
fmt.Println(strings.Join(repoList, "\n")) | ||
fmt.Printf("\n") | ||
|
||
if !*dryRun { | ||
fmt.Println("Continue to create issues? (y/n)") | ||
var response string | ||
_, err := fmt.Scanln(&response) | ||
if err != nil { | ||
fmt.Printf("Failed to read response: %s\n", err) | ||
os.Exit(1) | ||
} | ||
if response != "y" { | ||
fmt.Println("Aborting...") | ||
os.Exit(0) | ||
} | ||
} | ||
fmt.Printf("\n") | ||
|
||
for _, repo := range repoList { | ||
url := fmt.Sprintf("%s/repos/%s/issues", baseURL, repo) | ||
if *dryRun { | ||
fmt.Printf("Dry run: %s\n", url) | ||
continue | ||
} | ||
|
||
issue := Issue{ | ||
Title: issueTitle, | ||
Body: issueBody, | ||
} | ||
|
||
issueJSON, err := json.Marshal(issue) | ||
if err != nil { | ||
fmt.Printf("Failed to marshal issue: %s\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, url, bytes.NewBuffer(issueJSON)) | ||
if err != nil { | ||
fmt.Printf("Failed to create request: %s\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
req.Header.Set("Accept", "application/vnd.github+json") | ||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *token)) | ||
req.Header.Set("X-Github-Api-Version", "2022-11-28") | ||
req.Header.Set("User-Agent", "open_git_issues") | ||
req.Header.Set("Content-Type", "application/json") | ||
|
||
client := &http.Client{} | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
fmt.Printf("Failed to send request: %s\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
if resp.StatusCode != http.StatusCreated { | ||
fmt.Printf("Failed to create issue for repository '%s'\nStatus code: %d\nStatus:%s\n\n\n", repo, resp.StatusCode, resp.Status) | ||
} else { | ||
responseBody, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
fmt.Printf("Failed to read response body: %s\n", err) | ||
err := resp.Body.Close() | ||
if err != nil { | ||
fmt.Printf("Failed to close response body: %s\n", err) | ||
} | ||
os.Exit(1) | ||
} | ||
|
||
var issueResponse IssueResponse | ||
err = json.Unmarshal(responseBody, &issueResponse) | ||
if err != nil { | ||
fmt.Printf("Failed to unmarshal issue response: %s\n", err) | ||
err := resp.Body.Close() | ||
if err != nil { | ||
fmt.Printf("Failed to close response body: %s\n", err) | ||
} | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Printf("\nIssue created for repository '%s'\nURL: %s\n", repo, issueResponse.HTMLURL) | ||
} | ||
err = resp.Body.Close() | ||
if err != nil { | ||
fmt.Printf("Failed to close response body: %s\n", err) | ||
} | ||
} | ||
} |