7 Commits

Author SHA1 Message Date
333636b524 Revise help text for CLI "--project" arg 2025-07-21 14:57:18 -05:00
e954a2b09a Drop notice about CLI not having "repo" & "owner" 2025-07-21 14:54:16 -05:00
da8f008f1a Use current-dir as final fallback repo name
It all falls into place! I had been dreading doing this bit, but after
updating the usage guide I realized the CLI args should be split, too.
Which finally means that I can just glue on the PWD name as a final
fallback for the repo name.

Try the args, then the config file(s), then PWD. If nothing works, the
user is in a world of hurt. Bail out.
2025-07-21 14:48:30 -05:00
7c0966be30 Split the owner and repo args apart in CLI parser 2025-07-21 14:21:13 -05:00
c1019afa7a Write configuration guide in the README 2025-07-21 14:04:04 -05:00
1a619d7bb4 Update CLI usage guide, add project lookup guide
There's a new inconsistency, however. The previous URL and FQRN
arguments are no longer mandatory but their description makes it seem
as though they are.
2025-07-21 14:04:01 -05:00
fc0d1b569c Add a project path CLI option 2025-07-21 11:56:20 -05:00
4 changed files with 102 additions and 27 deletions

View File

@@ -5,7 +5,7 @@ CLI tools for interacting with the Gitea API. Use interactively to talk to your
## Usage
```txt
Usage: gt-tools --url <GITEA_URL> --repo <REPO> <COMMAND>
Usage: gt-tool [OPTIONS] <COMMAND>
Commands:
list-releases
@@ -16,6 +16,7 @@ Commands:
Options:
-u, --url <GITEA_URL> [env: GTTOOL_GITEA_URL=]
-r, --repo <REPO> [env: GTTOOL_FQRN=]
-p, --project <PROJECT> Path to project (relative or absolute). Used to select configuration.
-h, --help Print help
-V, --version Print version
```
@@ -40,6 +41,12 @@ The repository name must be provided with `--repo` or `-u` on the command line,
E.g.: `--repo "go-gitea/gitea"` would name the Gitea repo belonging to the go-gitea organization.
### `<PROJECT>`
Override the default (current-directory) project name when searching through the config files for this project's settings.
See [configuration](#configuration) for details on format and file locations.
### `<COMMAND>`:
One of these, defaults to `help`:
@@ -51,3 +58,55 @@ One of these, defaults to `help`:
| upload-release | Uploads one-or-more files to an existing release, identified by it's tag name. |
| help | prints the help text (the usage summary above). |
## Configuration
Instead of specifying everything on the command line every single run, some TOML files can be used to persist project settings.
> Exporting some environment variables would be similar, but that would be *more* annoying when working on multiple projects. One would have to constantly re-export the settings or use two shells. But then there's the issue of losing track of which shell has which settings.
Settings are retrieved from a table named the same as the project's path on disk. For example, gt_tool itself could have an entry as follows:
```toml
["/home/robert/projects/gt-tool"]
gitea_url = "https://demo.gitea.com/"
owner = "dummy"
repo = "gt-tool"
token = "fake-token"
```
Some may apply to all projects. For this, one can use the special `[all]` table.
```toml
[all]
gitea_url = "https://demo.gitea.com/"
```
Since the more-specific settings are preferred, these can be combined to have an override effect.
```toml
[all]
gitea_url = "https://demo.gitea.com/"
owner = "robert"
# no `repo = ` section because that must be project specific.
token = "fake-token"
# Override Gitea target so I can test my uploads privately.
["/home/robert/projects/gt-tool"]
gitea_url = "http://localhost:3000"
repo = "gt-tool"
```
Similar to how unspecified project settings will fall back to those in the "`[all]`" table, whole files will fall back to other, lower priority files. First, each dir in `$XDG_CONFIG_DIRS` is scanned for a `gt-tool.toml` file. Then, `/etc/gt-tool.toml`.
> All config files **MUST** be named named `gt-tool.toml`.
### Recognized Keys
| Key | Description |
|-|-|
| gitea_url | URL of the Gitea server. Same as `-u`, `--url`, and `$GTTOOL_GITEA_URL`. |
| owner | Owner of the repository (individual, or organization). Combined with "repo" key to produce the fully-qualified-repo-name. Front-half of `-r`, `--repo`, and `$GTTOOL_FQRN` |
| repo | Name of the repository on the Gitea server. Combined with "owner" key to produce the fully-qualified-repo-name. Back-half of `-r`, `--repo`, and `$GTTOOL_FQRN` |
| token | Gitea auth token, exactly the same as `$RELEASE_KEY_GITEA` |
Additional keys are quietly ignored. The config loading is done by querying a HashMap, so anything not touched doesn't get inspected. The only requirements are that the file is valid TOML, and that these keys are all strings.h

View File

@@ -5,8 +5,16 @@ use clap::{Parser, Subcommand};
pub struct Args {
#[arg(short = 'u', long = "url", env = "GTTOOL_GITEA_URL")]
pub gitea_url: Option<String>,
#[arg(short = 'r', long = "repo", env = "GTTOOL_FQRN")]
#[arg(short = 'o', long = "owner", env = "GTTOOL_OWNER")]
pub owner: Option<String>,
#[arg(short = 'r', long = "repo", env = "GTTOOL_REPO")]
pub repo: Option<String>,
#[arg(
short = 'p',
long = "project",
help = "Path to project (relative or absolute). Used to override configuration selection."
)]
pub project: Option<String>,
#[command(subcommand)]
pub command: Commands,

View File

@@ -23,6 +23,8 @@ pub enum Error {
Placeholder, // TODO: Enumerate error modes
MissingGiteaUrl, // the gitea URL wasn't specified on the CLI, env, or config file.
MissingRepoFRQN, // either the owner, repo, or both weren't specified in the loaded PartialConfig
MissingRepoOwner,
MissingRepoName,
WrappedConfigErr(config::Error),
WrappedReqwestErr(reqwest::Error),
MissingAuthToken,

View File

@@ -1,4 +1,4 @@
use std::path;
use std::path::{self, PathBuf};
use gt_tool::cli::Args;
use gt_tool::structs::release::{CreateReleaseOption, Release};
@@ -12,12 +12,15 @@ use reqwest::header::ACCEPT;
async fn main() -> Result<(), gt_tool::Error> {
let args = Args::parse();
// TODO: Heuristics to guess project path
// See issue #8: https://git.gelvin.dev/robert/gt-tool/issues/8
let pwd = std::env::current_dir()
.map_err(|_e| gt_tool::Error::WrappedConfigErr(gt_tool::config::Error::CouldntReadFile))?;
let project_path =
args.project
.map(PathBuf::from)
.unwrap_or(std::env::current_dir().map_err(|_e| {
gt_tool::Error::WrappedConfigErr(gt_tool::config::Error::CouldntReadFile)
})?);
let config = gt_tool::config::get_config(
pwd.to_str()
project_path
.to_str()
.expect("I assumed the path can be UTF-8, but that didn't work out..."),
gt_tool::config::default_paths(),
)?;
@@ -27,21 +30,17 @@ async fn main() -> Result<(), gt_tool::Error> {
.gitea_url
.or(config.gitea_url)
.ok_or(gt_tool::Error::MissingGiteaUrl)?;
// Config files split the repo FQRN into "owner" and "repo" (confusing naming, sorry)
// These must be merged back together and passed along.
let conf_fqrn = config
.owner
.ok_or(gt_tool::Error::MissingRepoFRQN)
.and_then(|mut own| {
let repo = config.repo.ok_or(gt_tool::Error::MissingRepoFRQN)?;
own.push('/');
own.push_str(&repo);
Ok(own)
});
let repo_fqrn = args
.repo
.ok_or(gt_tool::Error::MissingRepoFRQN)
.or(conf_fqrn)?;
let owner = args.owner
.or(config.owner)
.ok_or(gt_tool::Error::MissingRepoOwner)?;
let repo = args.repo
.or(config.repo)
.or_else(infer_repo)
.ok_or(gt_tool::Error::MissingRepoName)?;
let repo_fqrn = String::from(format!("{owner}/{repo}"));
let mut headers = reqwest::header::HeaderMap::new();
headers.append(ACCEPT, header::HeaderValue::from_static("application/json"));
@@ -171,3 +170,10 @@ fn match_release_by_tag(tag: &String, releases: Vec<Release>) -> Option<Release>
}
release
}
fn infer_repo() -> Option<String> {
let pwd = std::env::current_dir().ok()?;
let file_name = pwd.file_name()?;
let file_name_string = file_name.to_str()?;
Some(String::from(file_name_string))
}