Skip to content

Commit 9f73b7b

Browse files
authored
Merge pull request #5 from loganintech/provider/bitbucket
Added bitbucket support
2 parents 195388a + 38462a9 commit 9f73b7b

File tree

9 files changed

+202
-23
lines changed

9 files changed

+202
-23
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
# Changelog
22

3+
## [0.3.0] - 2019-04-XX
4+
### Added
5+
6+
* Initial bitbucket support using app base64-encoded username:apppasword flow. [Read more about app passwords](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html)
7+
8+
### Changed
9+
10+
* Slightly changed helptext for github privacy flag.
11+
* Github parameters are no longer serialized if they're `None`.
12+
313
## [0.2.2] - 2019-04-14
414
### Added
515

616
* Custom --endpoint (-e) param allowing request redirection to enterprise providers
717

818
## [0.2.1] - 2019-04-14
919
### Changed
20+
1021
* Modified Cargo manifest entry for the license
1122

1223
## [0.2.0] - 2019-04-14

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gitpub"
3-
version = "0.2.2"
3+
version = "0.3.0"
44
authors = ["Logan Saso <[email protected]>"]
55
description = "A CLI app to create remote git repositories."
66
repository = "https://github.com/loganintech/gitpub"
@@ -13,8 +13,9 @@ license = "GPL-3.0"
1313
edition = "2018"
1414

1515
[dependencies]
16-
reqwest = "0.9.14"
16+
reqwest = "0.9.15"
1717
serde = { version = "1.0.90", features = [ "derive" ] }
1818
serde_json = "1.0.39"
1919
structopt = "0.2.15"
2020
clap = "2.33.0"
21+
base64 = "0.10.1"

README.md

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
A small program to create remote git repositories from the command line.
44

5+
_Note:_ Environment variables can also be passed directly via CLI parameters, therefore setting said variables are always optional.
6+
57
Usage:
68

79
```
8-
Git Publish 0.2.2
10+
Git Publish 0.3.0
911
Logan Saso <[email protected]>
1012
A small program to create remote git repositories from the command line.
1113
@@ -17,9 +19,10 @@ FLAGS:
1719
-V, --version Prints version information
1820
1921
SUBCOMMANDS:
20-
github Create a repo on github.
21-
gitlab Create a repo on gitlab.
22-
help Prints this message or the help of the given subcommand(s)
22+
bitbucket Create a repo on bitbucket.
23+
github Create a repo on github.
24+
gitlab Create a repo on gitlab.
25+
help Prints this message or the help of the given subcommand(s)
2326
```
2427

2528
## Github Setup
@@ -31,7 +34,7 @@ _Note:_ If you want to create org repositories the token also requires `org` sco
3134

3235
### Github
3336
```
34-
gitpub-github 0.2.2
37+
gitpub-github 0.3.0
3538
Logan Saso <[email protected]>
3639
Create a repo on github.
3740
@@ -61,10 +64,8 @@ OPTIONS:
6164
--org <org> Creates the repo under an organization. Requires you have CREATE REPO
6265
permissions in that org.
6366
-p, --private <private> Requires 'repo' scope on your personal access token
64-
--team <team_id> Id of the team that has access to this repo. Only valid when using
65-
--org.
66-
-t, --token <token> A personal access token. Alternatively read from GITHUB_REPO_TOKEN env
67-
variable [env: GITHUB_REPO_TOKEN=<YOUR_TOKEN>]
67+
--team <team_id> Id of the team that has access to this repo. Only valid when using --org.
68+
-t, --token <token> A personal access token. Alternatively read from GITHUB_REPO_TOKEN env variable [env: GITHUB_REPO_TOKEN=<YOUR_TOKEN>]
6869
```
6970

7071
## Gitlab Setup
@@ -77,7 +78,7 @@ _Note_: Optionally set the `GITLAB_USERNAME` environment variable to enable prin
7778

7879
### Gitlab
7980
```
80-
gitpub-gitlab 0.2.2
81+
gitpub-gitlab 0.3.0
8182
Logan Saso <[email protected]>
8283
Create a repo on gitlab.
8384
@@ -184,3 +185,37 @@ OPTIONS:
184185
Enables or disables wikis for this repo. Defaults to true.
185186
```
186187

188+
## BitBucket Setup
189+
190+
1. Create an app password with repo scope from https://bitbucket.org/account/user/<YOUR_USERNAME>/app-passwords
191+
2. Set the environment variable `BITBUCKET_REPO_TOKEN` to the generated personal access token.
192+
3. Set the environment variable `BITBUCKET_USERNAME` to your bitbucket username.
193+
194+
### Bitbucket
195+
196+
```
197+
gitpub-bitbucket 0.3.0
198+
Logan Saso <[email protected]>
199+
Create a repo on bitbucket.
200+
201+
USAGE:
202+
gitpub bitbucket [OPTIONS] --name <name> --token <token> --username <username>
203+
204+
FLAGS:
205+
-h, --help Prints help information
206+
-V, --version Prints version information
207+
208+
OPTIONS:
209+
-e, --endpoint <custom_endpoint> Allows redirection of requests to enterprise providers.
210+
-d, --description <description> A short description of the repository.
211+
--fork_policy <fork_policy> Allow public forking of this repo. [possible values: allow_forks, no_public_forks, no_forks]
212+
-i, --issues <has_issues> Enable or disable issues for this repo. Defaults to true.
213+
-w, --wiki <has_wiki> Enables or disables wikis for this repo. Defaults to true.
214+
-p, --private <is_private> Sets whether or not the repository is private.
215+
--language <language> Give bitbucket a hint about the programming language.
216+
-n, --name <name> The name of the new repository.
217+
--scm <scm> Control the underlying source control method. [possible values: hg, git]
218+
-t, --token <token> A personal access token. Alternatively read from BITBUCKET_REPO_TOKEN env variable [env: BITBUCKET_REPO_TOKEN=<YOUR_APP_PASSWORD>]
219+
--username <username> Your bitbucket username. Alternatively read from BITBUCKET_USERNAME env variable [env: BITBUCKET_USERNAME=<YOUR_USERNAME>]
220+
--homepage <website> A URL with more information about the repository.
221+
```

src/cli.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::provider::{github::GithubArgs, gitlab::GitlabArgs, Provider};
1+
use crate::provider::{bitbucket::BitbucketArgs, github::GithubArgs, gitlab::GitlabArgs, Provider};
22
use structopt::StructOpt;
33

44
#[derive(StructOpt)]
@@ -20,30 +20,38 @@ pub enum Gitpo {
2020
raw(setting = "structopt::clap::AppSettings::ColoredHelp")
2121
)]
2222
Gitlab(GitlabArgs),
23+
#[structopt(
24+
name = "bitbucket",
25+
about = "Create a repo on bitbucket.",
26+
raw(setting = "structopt::clap::AppSettings::ColoredHelp")
27+
)]
28+
BitBucket(BitbucketArgs),
2329
}
2430

2531
// You're probably looking at this and thinking, logan, what are you doing.
2632
// Well, the idea here is to allow the possibility for more complicated provider options in the future.
2733
// We may not want every subcommand to be a provider
2834
impl Provider for Gitpo {
29-
3035
fn payload(&self) -> String {
3136
match self {
3237
Gitpo::Github(config) => config.payload(),
3338
Gitpo::Gitlab(config) => config.payload(),
39+
Gitpo::BitBucket(config) => config.payload(),
3440
}
3541
}
3642

3743
fn endpoint(&self) -> String {
3844
match self {
3945
Gitpo::Github(config) => config.endpoint(),
4046
Gitpo::Gitlab(config) => config.endpoint(),
47+
Gitpo::BitBucket(config) => config.endpoint(),
4148
}
4249
}
4350
fn extract_url(&self, src: &reqwest::header::HeaderMap) -> String {
4451
match self {
4552
Gitpo::Github(config) => config.extract_url(src),
4653
Gitpo::Gitlab(config) => config.extract_url(src),
54+
Gitpo::BitBucket(config) => config.extract_url(src),
4755
}
4856
}
4957
}

src/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
2222
let request = match &config {
2323
Gitpo::Github(config) => request.header("Authorization", format!("token {}", config.token)),
2424
Gitpo::Gitlab(config) => request.header("Private-Token", config.token.to_string()),
25+
Gitpo::BitBucket(config) => request.header(
26+
"Authorization",
27+
format!(
28+
"Basic {}",
29+
base64::encode(&format!("{}:{}", &config.username, &config.token))
30+
),
31+
),
2532
};
2633

2734
let result = request.send()?;
2835
let status = result.status();
2936
let headers = result.headers();
3037
match status {
31-
StatusCode::CREATED => {
38+
StatusCode::OK | StatusCode::CREATED => {
3239
let apiloc = config.extract_url(&headers);
3340
println!("Repo created: {}", apiloc);
3441
}

src/provider/bitbucket.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use super::Provider;
2+
use serde::Serialize;
3+
use serde_json::to_string;
4+
use structopt::StructOpt;
5+
6+
#[derive(Serialize, StructOpt)]
7+
pub struct BitbucketArgs {
8+
#[structopt(short = "n", long = "name", help = "The name of the new repository.")]
9+
name: String,
10+
#[structopt(
11+
short = "t",
12+
long = "token",
13+
help = "A personal access token. Alternatively read from BITBUCKET_REPO_TOKEN env variable",
14+
env = "BITBUCKET_REPO_TOKEN"
15+
)]
16+
#[serde(skip_serializing)]
17+
pub token: String,
18+
#[structopt(
19+
long = "username",
20+
help = "Your bitbucket username. Alternatively read from BITBUCKET_USERNAME env variable",
21+
env = "BITBUCKET_USERNAME"
22+
)]
23+
#[serde(skip_serializing)]
24+
pub username: String,
25+
#[structopt(
26+
short = "d",
27+
long = "description",
28+
help = "A short description of the repository."
29+
)]
30+
#[serde(skip_serializing_if = "Option::is_none")]
31+
description: Option<String>,
32+
#[structopt(
33+
short = "p",
34+
long = "private",
35+
help = "Sets whether or not the repository is private."
36+
)]
37+
#[serde(skip_serializing_if = "Option::is_none")]
38+
is_private: Option<bool>,
39+
#[structopt(
40+
short = "w",
41+
long = "wiki",
42+
help = "Enables or disables wikis for this repo. Defaults to true."
43+
)]
44+
#[serde(skip_serializing_if = "Option::is_none")]
45+
has_wiki: Option<bool>,
46+
#[structopt(
47+
short = "i",
48+
long = "issues",
49+
help = "Enable or disable issues for this repo. Defaults to true."
50+
)]
51+
#[serde(skip_serializing_if = "Option::is_none")]
52+
has_issues: Option<bool>,
53+
#[structopt(
54+
long = "fork_policy",
55+
help = "Allow public forking of this repo.",
56+
possible_value = "allow_forks",
57+
possible_value = "no_public_forks",
58+
possible_value = "no_forks"
59+
)]
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
fork_policy: Option<String>,
62+
#[structopt(
63+
long = "scm",
64+
help = "Control the underlying source control method.",
65+
possible_value = "hg",
66+
possible_value = "git"
67+
)]
68+
#[serde(skip_serializing_if = "Option::is_none")]
69+
scm: Option<String>,
70+
#[structopt(
71+
long = "language",
72+
help = "Give bitbucket a hint about the programming language."
73+
)]
74+
language: Option<String>,
75+
#[serde(skip_serializing)]
76+
#[structopt(
77+
short = "e",
78+
long = "endpoint",
79+
help = "Allows redirection of requests to enterprise providers."
80+
)]
81+
custom_endpoint: Option<String>,
82+
}
83+
84+
const ENDPOINT: &str = "https://api.bitbucket.org/2.0/repositories/{username}/{slug}";
85+
86+
impl Provider for BitbucketArgs {
87+
fn payload(&self) -> String {
88+
to_string(&self).unwrap()
89+
}
90+
91+
fn endpoint(&self) -> String {
92+
if let Some(custom_endpoint) = &self.custom_endpoint {
93+
custom_endpoint.to_string()
94+
} else {
95+
ENDPOINT
96+
.replace("{username}", &self.username)
97+
.replace("{slug}", &self.name)
98+
}
99+
}
100+
101+
fn extract_url(&self, _: &reqwest::header::HeaderMap) -> String {
102+
format!("https://bitbucket.org/{}/{}", &self.username, &self.name)
103+
}
104+
}

0 commit comments

Comments
 (0)