Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Marek Czernek committed Aug 1, 2020
0 parents commit 4c686d8
Show file tree
Hide file tree
Showing 9 changed files with 662 additions and 0 deletions.
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
GOCMD=go
GOBUILD=$(GOCMD) build
GORUN=$(GOCMD) run
GOPKG=./main
GOARCH=amd64
BINARY_NAME=react-rm

.PHONY: build
build:
$(GOBUILD) -o bin/$(BINARY_NAME) -v $(GOPKG)

.PHONY: run
run:
$(GORUN) $(GOPKG)

.PHONY: build-all
build-all:
echo "Cross-compiling for macOS and Linux (amd64)"
GOOS=linux GOARCH=$(GOARCH) $(GOBUILD) -o bin/$(BINARY_NAME)_linux -v $(GOPKG)
GOOS=darwin GOARCH=$(GOARCH) $(GOBUILD) -o bin/$(BINARY_NAME)_darwin -v $(GOPKG)

.PHONY: all
all: build
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# react-rm

This program serves as a small command-line utility to remove all reactions
from any issue in a given repository.

## Prerequisites

### Github API Token

This program uses the Github personal access token for authorization and authentication.

To create a new Github Token, follow the [GitHub documentation](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token).

This application requires the `repo` access

![Image of repository settings](./docs/repo.png)

### Configuration file

The program expects a configuration file. See the example [github-cli](./docs/github-cli.yml).

Copy this configuration file into the default `~/.config` location:

```
cp docs/github-cli.yml ~/.config/
```

Alternatively, you can use any other location on the system. The program uses the `-c` flag for
passing a configuration file path, e.g.:

```
issue-rm -c github-cli
```

Edit the configuration file with your values.

## Building

To build the Go binary, execute:

```
make
```

To cross-compile for Linux and macOS, execute:

```
make build-all
```

Binaries are saved into the `bin` directory

## Executing

To execute the program, execute:

```
make run
```
Empty file added bin/.gitkeep
Empty file.
7 changes: 7 additions & 0 deletions docs/github-cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
auth:
personal_access_token: "access-token"
login: "github-username"

repo:
owner: "repository organization (owner)"
name: "repository name"
Binary file added docs/repo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/m-czernek/issue-rm

go 1.13

require (
github.com/google/go-github/v32 v32.1.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/yaml.v2 v2.3.0
sigs.k8s.io/controller-runtime v0.6.1
)
450 changes: 450 additions & 0 deletions go.sum

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions main/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"fmt"
"os"

"gopkg.in/yaml.v2"
)

type Config struct {
Auth `yaml:"auth"`
Repo `yaml:"repo"`
}

type Auth struct {
Token string `yaml:"personal_access_token"`
Login string `yaml:"login"`
}

type Repo struct {
Name string `yaml:"name"`
Owner string `yaml:"owner"`
}

func GetConfig(path string) (*Config, error) {
f, err := os.Open(path)
defer f.Close()
if err != nil {
return nil, err
}
var cfg Config
decoder := yaml.NewDecoder(f)
err = decoder.Decode(&cfg)
return &cfg, err
}

func (r Repo) String() string {
return fmt.Sprintf("%v/%v", r.Owner, r.Name)
}
74 changes: 74 additions & 0 deletions main/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package main

import (
"context"
"flag"
"fmt"
"os"
"path"
"sync"

"github.com/google/go-github/v32/github"
"golang.org/x/oauth2"
)

var configPath string
var removed int = 0

func main() {
parseCmdFlags()
cfg, err := GetConfig(configPath)
if err != nil {
fmt.Printf("Could not parse configuration yaml: %v\n", err)
os.Exit(1)
}

client := getGithubClient(cfg)

var wg sync.WaitGroup

issues, _, _ := client.Issues.ListByRepo(context.Background(), cfg.Repo.Owner, cfg.Repo.Name, nil)
wg.Add(len(issues))

for _, issue := range issues {
go deleteIssueReactions(&wg, client, cfg, *issue.Number)
}
wg.Wait()
fmt.Printf("Successfully removed %d issue reactions from repo %v\n", removed, cfg.Repo)
}

func deleteIssueReactions(wg *sync.WaitGroup, client *github.Client, cfg *Config, issueNumber int) {
defer wg.Done()
ctx := context.Background()
reactions, _, _ := client.Reactions.ListIssueReactions(ctx, cfg.Repo.Owner, cfg.Repo.Name, issueNumber, nil)
for _, reaction := range reactions {
if *reaction.User.Login == cfg.Auth.Login {
_, err := client.Reactions.DeleteIssueReaction(ctx, cfg.Repo.Owner, cfg.Repo.Name, issueNumber, *reaction.ID)
if err != nil {
fmt.Println("[ERR] Could not delete reaction ", reaction)
fmt.Println(err)
} else {
removed++
}
}
}
}

func getDefaultConfigPath() string {
home, _ := os.UserHomeDir()
return path.Join(home, ".config", "github-cli.yml")
}

func parseCmdFlags() {
flag.StringVar(&configPath, "c", getDefaultConfigPath(), "A path to the YAML configuration file (default: "+getDefaultConfigPath()+")")
flag.Parse()
}

func getGithubClient(cfg *Config) *github.Client {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: cfg.Auth.Token},
)
tc := oauth2.NewClient(ctx, ts)
return github.NewClient(tc)
}

0 comments on commit 4c686d8

Please sign in to comment.