Skip to content

Commit

Permalink
Merge pull request #64 from mattpolzin/allow-pat-in-config
Browse files Browse the repository at this point in the history
support adding a GitHUB PAT to config file rather than relying on an environment variable.
  • Loading branch information
mattpolzin authored Jul 23, 2022
2 parents 996743c + 1b53e5e commit 7bfa620
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 57 deletions.
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Building the latest commits of Harmony requires a HEAD build of the Idris 2 comp
Alternatively, you can build Harmony with Docker (see [Docker Build](#docker-build)).

## Installation
For any installation, you need to add a GitHub [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) to your environment as the `GITHUB_PAT` variable. It's easiest to `export` that variable from your shell resource file or profile.
For any installation, you need to have a GitHub [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token).

You can eiher add the PAT to your environment as the `GITHUB_PAT` variable (perhaps exporting it from your shell resource file or profile) or you can store your PAT in Harmony's config file. The first time you start Harmony, it will ask you to configure your PAT if you don't want to use the Environment variable. You only need one of (a) the ENV var and (b) the config property and the environment variable will take precedence if you have both set.

### NPM
You can install Harmony via npm directly by running `npm install -g @mattpolzin/harmony`.
Expand Down Expand Up @@ -59,13 +61,25 @@ eval "$(harmony --bash-completion-script)"
The first time you start Harmony in any particular folder, you will be asked to provide some information about the GitHub repository you are working with. This information is stored in a file named `harmony.json` in the current working directory.

Note that the GitHub organization and repository are both slugs, not names. These are the values you find in a GitHub URL pointing to your repository. Harmony does not work with personal repositories because they do not have teams or members.
```shell
$ harmony
```
$ harmony sync
Creating a new configuration (storing in harmony.json)...
Harmony uses a GitHub Personal Access Token (PAT) to communicate with GitHub.
You can set this via the $GITHUB_PAT environment variable or a config property.
If you don't set in your config now, you can set later with `harmony config githubPAT abcdefg`.
The ENV var will always take precedence over the config property.
What PAT would you like to set in the config file (ENTER for default: unset)?
What GitHub org would you like to use harmony for (ENTER for default: myorg)?
What repository would you like to use harmony for (ENTER for default: myrepo)?
diff-repo
What GitHub remote repo would you like to use harmony for (ENTER for default: origin)?
Would you like harmony to comment when it assigns reviewers? [Y/n]
Would you like harmony to assign teams in addition to individuals when it assigns reviewers? [Y/n]
Creating config...
```

Expand Down Expand Up @@ -148,6 +162,8 @@ Not all configuration properties can be read/set with this command.
#### Properties
- `assignTeams` -- When picking a reviewer from a team, assign the team as a reviewer as well.
- `commentOnAssign` -- When assigning a reviewer chosen by Harmony, comment on the pull request.
- `defaultRemote` -- When pushing new branches, what remote destination should be used.
- `githubPAT` -- If the `$GITHUB_PAT` environment variable is not set, this Personal Access Token is used to authenticate with GitHub.

### Sync
Running `harmony sync` will sync the locally configured team slugs and user logins that are used by auto-completion for Harmony. This sync is also performed automatically the first time you run Harmony after more than a day without the configuration being synced.
Expand Down
2 changes: 1 addition & 1 deletion harmony.ipkg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package harmony
version = 1.0.0
version = 1.1.0
authors = "Mathew Polzin"
license = "MIT"
-- brief =
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mattpolzin/harmony",
"version": "1.0.0",
"version": "1.1.0",
"publishConfig": {
"access": "public"
},
Expand Down
2 changes: 1 addition & 1 deletion src/AppVersion.idr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module AppVersion

export
appVersion : String
appVersion = "1.0.0"
appVersion = "1.1.0"

export
printVersion : HasIO io => io ()
Expand Down
36 changes: 29 additions & 7 deletions src/Config.idr
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ propSetters = [
("assignTeams" , update parseBool (\b => { assignTeams := b }))
, ("commentOnAssign", update parseBool (\b => { commentOnAssign := b }))
, ("defaultRemote" , update Just (\s => { defaultRemote := Just s }))
, ("githubPAT" , update Just (\s => { githubPAT := Just $ hide s }))
]
where
parseBool : String -> Maybe Bool
Expand Down Expand Up @@ -121,6 +122,7 @@ propGetters = [
("assignTeams" , show . assignTeams)
, ("commentOnAssign", show . commentOnAssign)
, ("defaultRemote" , maybe "Not set (defaults to \"origin\")" show . defaultRemote)
, ("githubPAT" , maybe "Not set (will use $GITHUB_PAT environment variable)" show . githubPAT)
]

namespace PropGettersProperties
Expand All @@ -143,13 +145,30 @@ preferOriginRemote names =
Just n => n
Nothing => fromMaybe "origin" (head' names)

createConfig : Git => Octokit =>
(terminalColors : Bool)
createConfig : Git =>
(envGithubPAT : Maybe String)
-> (terminalColors : Bool)
-> (editor : Maybe String)
-> Promise Config
createConfig terminalColors editor = do
createConfig envGithubPAT terminalColors editor = do
putStrLn "Creating a new configuration (storing in \{Config.filename})..."
putStrLn ""

let defaultPATString = enterForDefaultStr "unset"
putStr $ unlines [ "Harmony uses a GitHub Personal Access Token (PAT) to communicate with GitHub."
, "You can set this via the $GITHUB_PAT environment variable or a config property."
, "If you don't set in your config now, you can set later with `harmony config githubPAT abcdefg`."
, "The ENV var will always take precedence over the config property."
, ""
, "What PAT would you like to set in the config file\{defaultPATString}?"
]
configPAT <- (\case "" => Nothing; s => Just s) . trim <$> getLine

-- Personal access token either comes from the ENV or the config property
Just pat <- pure $ envGithubPAT <|> configPAT
| _ => reject $ "Either the GITHUB_PAT environment variable or githubPAT config "
++ "property must be set to a personal access token."

remoteGuess <- preferOriginRemote <$> listRemotes
defaultOrgAndRepo <- (parseGitHubURI <$> remoteURI remoteGuess) <|> pure Nothing

Expand All @@ -171,6 +190,7 @@ createConfig terminalColors editor = do
putStr "Would you like harmony to assign teams in addition to individuals when it assigns reviewers? [Y/n] "
assignTeams <- yesUnlessNo . trim <$> getLine

_ <- liftIO $ octokit pat
putStrLn "Creating config..."
mainBranch <- getRepoDefaultBranch org repo
updatedAt <- cast <$> time
Expand All @@ -191,6 +211,7 @@ createConfig terminalColors editor = do
, commentOnAssign
, teamSlugs
, orgMembers
, githubPAT = hide <$> configPAT
, ephemeral
}
ignore $ writeConfig config
Expand Down Expand Up @@ -250,13 +271,14 @@ loadConfig terminalColors editor = let (>>=) = (>>=) @{Monad.Compose} in

export
covering
loadOrCreateConfig : Git => Octokit =>
(terminalColors : Bool)
loadOrCreateConfig : Git =>
(envGithubPAT : Maybe String)
-> (terminalColors : Bool)
-> (editor : Maybe String)
-> Promise Config
loadOrCreateConfig terminalColors editor = do
loadOrCreateConfig envGithubPAT terminalColors editor = do
Right config <- loadConfig terminalColors editor
| Left (File FileNotFound) => createConfig terminalColors editor
| Left (File FileNotFound) => createConfig envGithubPAT terminalColors editor
| Left err => reject "Error loading \{Config.filename}: \{show err}."
pure config

31 changes: 30 additions & 1 deletion src/Data/Config.idr
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ record Ephemeral where
||| If set, a preferred editor to use for writing PR desriptions.
editor : Maybe String

export
data Hidden a = Hide a

export
hide : a -> Hidden a
hide = Hide

export
expose : Hidden a -> a
expose (Hide x) = x

export
Show (Hidden a) where
show _ = "xxxxxxxx (hidden)"

public export
record Config where
constructor MkConfig
Expand All @@ -45,6 +60,11 @@ record Config where
teamSlugs : List String
||| Local cache of GitHub members within the configured org.
orgMembers : List String
||| A GitHub Personal Access Token. This value is only used if
||| there is no $GITHUB_PAT environment variable set. One of
||| either the environment variable or this config property
||| must be set.
githubPAT : Maybe (Hidden String)
||| Configuration properties that are not written to a file.
ephemeral : Ephemeral -- not written out to file

Expand All @@ -56,6 +76,7 @@ settableProps = [
"assignTeams"
, "commentOnAssign"
, "defaultRemote"
, "githubPAT"
]

export
Expand All @@ -82,14 +103,18 @@ Show Config where
, "commentOnAssign: \{show config.commentOnAssign}"
, " teamSlugs: \{show config.teamSlugs}"
, " orgMembers: \{show config.orgMembers}"
, " githubPAT: \{personalAccessToken}"
]
where
defaultRemote : String
defaultRemote = maybe "Not set (defaults to \"origin\")" show config.defaultRemote

personalAccessToken : String
personalAccessToken = maybe "Not set (will use $GITHUB_PAT environment variable)" show config.githubPAT

export
json : Config -> JSON
json (MkConfig updatedAt org repo defaultRemote mainBranch assignTeams commentOnAssign teamSlugs orgMembers _) =
json (MkConfig updatedAt org repo defaultRemote mainBranch assignTeams commentOnAssign teamSlugs orgMembers githubPAT _) =
JObject [
("assignTeams" , JBoolean assignTeams)
, ("commentOnAssign", JBoolean commentOnAssign)
Expand All @@ -99,6 +124,7 @@ json (MkConfig updatedAt org repo defaultRemote mainBranch assignTeams commentOn
, ("mainBranch" , JString mainBranch)
, ("orgMembers" , JArray $ JString <$> sort orgMembers)
, ("teamSlugs" , JArray $ JString <$> sort teamSlugs)
, ("githubPAT" , maybe JNull (JString . expose) githubPAT)
, ("updatedAt" , JNumber $ cast updatedAt)
]

Expand Down Expand Up @@ -127,6 +153,7 @@ parseConfig ephemeral = (maybeToEither "Failed to parse JSON" . JSON.parse) >=>
, "orgMembers"
] config
let maybeDefaultRemote = lookup "defaultRemote" config
let maybeGithubPAT = lookup "githubPAT" config
ua <- cast <$> integer updatedAt
o <- string org
r <- string repo
Expand All @@ -136,6 +163,7 @@ parseConfig ephemeral = (maybeToEither "Failed to parse JSON" . JSON.parse) >=>
ca <- bool commentOnAssign
ts <- array string teamSlugs
om <- array string orgMembers
gp <- maybe (Right Nothing) (optional string) maybeGithubPAT
pure $ MkConfig {
updatedAt = ua
, org = o
Expand All @@ -146,6 +174,7 @@ parseConfig ephemeral = (maybeToEither "Failed to parse JSON" . JSON.parse) >=>
, teamSlugs = ts
, commentOnAssign = ca
, orgMembers = om
, githubPAT = (map Hide) gp
, ephemeral = ephemeral
}
parseConfigJson (JArray _) = Left "Expected config JSON to be an Object, not an array."
Expand Down
Loading

0 comments on commit 7bfa620

Please sign in to comment.