6 Commits

Author SHA1 Message Date
ab8b21d01c Fix deserialization with some attributes
The "repository" field doesn't have a type right now, so I'm going to
skip deserializing it. The returned JSON has a value for this field, but
Serde will ignore it.

The `Packages.pkg_type` field is called "type" in the JSON string (and
Go code, as mentioned in the comment). Similarly, the PackageType enum
I have to represent this field in Rust has capital starting letters
where the JSON uses all lowercase. Both problems are solved with a Serde
rename attribute.
2025-09-12 13:00:11 -05:00
c6dd63143e Fix: Typo, missing 'a' in Package.created_at 2025-09-12 12:59:56 -05:00
94ec8cfd71 Add and connect "list-packages" subcommand
And with that I have the API call being made!... except it doesn't work
quite right.
2025-09-12 11:53:09 -05:00
55b992b5c4 Impl the list_packages API function 2025-09-12 09:29:33 -05:00
7b02063bb7 Add new structs for describing packages 2025-09-12 09:28:16 -05:00
59f67e1d4e Bump version to 4.0-dev 2025-09-12 09:24:29 -05:00
14 changed files with 155 additions and 298 deletions

View File

@@ -1,12 +1,7 @@
[package] [package]
name = "gt-tool" name = "gt-tool"
version = "3.0.1" version = "4.0.0-dev"
edition = "2024" edition = "2024"
license = "GPL-3.0-only"
description = "CLI tools for interacting with the Gitea API. Mainly for attaching files to releases."
# homepage = "" I have no website for a project home page :(
repository = "https://git.gelvin.dev/robert/gt-tool"
readme = "README.md"
[dependencies] [dependencies]
clap = { version = "4.5.23", features = ["derive", "env"] } clap = { version = "4.5.23", features = ["derive", "env"] }
@@ -16,3 +11,13 @@ reqwest = { version = "0.12.15", features = ["json", "stream", "multipart"] }
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
tokio = { version = "1.43.1", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.43.1", features = ["macros", "rt-multi-thread"] }
toml = "0.8.19" toml = "0.8.19"
# Packages available in Debian (Sid)
# clap = "4.5.23"
# reqwest = "0.12.15"
# tokio = "1.43.1"
# Debian (Bookworm)
# clap = "4.0.32"
# reqwest = "0.11.13"
# tokio = "1.24.2"

View File

@@ -1 +0,0 @@
{"package":"62e0ece55a4e0150ab3a3f7f5299e6eb113134975100cddde5a68dfcbb5e1a5c","files":{}}

144
debian/changelog vendored
View File

@@ -1,144 +0,0 @@
gt-tool (3.0.1-2) unstable; urgency=medium
* Fix: debian/copyright was using old package name.
* Add a cargo-checksum.json, remove its fake
* Remove bogus pre-step inserts
* Strip out all the imports and exports
* Drop a copyright notice (!)
* Adopt debian/control contents from debcargo output
* Adopt debcargo auto-gen'd testing stuff
-- Robert Garrett <robertgarrett404@gmail.com> Thu, 13 Nov 2025 22:07:35 -0600
gt-tool (3.0.1-1) unstable; urgency=medium
* Update dependency versions for Debian 13 "Trixie"
* Add metadata required for publishing to crates.io
* Remove the comments tracking Debian-specific deps
* Mark v3.0.1 patch
* Update gbp.conf debian-branch to "deb/trixie"
* Drop entirety of old patch set
-- Robert Garrett <robertgarrett404@gmail.com> Thu, 13 Nov 2025 17:12:26 -0600
gt-tool (3.0.0-1) unstable; urgency=medium
* Make the README title singular
* Add a Cargo.toml & Git tag version comparison
* Scaffold the new config module
* Add property-get utility function
* Add a get-table util function
* Util fn's can use anything that impl's ToString
* Util to get sometimes-empty config property
* Add partial- and whole- config structs
* Prototype load-config function
* Put the per-project test expects in for lconf()
* Finish `fn lconf()`. Project-specific vals load
* Create-and-assign struct to whole.all
* Use the get_table util to extract "[all]" table
* Extract PartCfg readers to a try_from impl
* Add a builder-pattern proj-path setter, for flavor
* Assert empty conf str is an error, TODO: semantics
* Rename the config-string-reading function
* Externalize the test table
* Remove some debug prints
* Signature & tests for fn load_from_file()
* Implement the load_from_file function
* "Merge" method on PartialConfig
* Complete the public `get_config()` function
* Pass in search files rather than generating them
* Make default search paths available as util fn
* Remove `WholeFile` struct & anything that uses it
* Autoformat
* Cargo clippy fixes
* Delete a now-solved FIXME comment
* Make the URL and Repo FQRN CLI args optional
* Wire in the conf file loading, assume PWD project
* Add more unit tests for the config loader
* Add test for skipping unavailable conf files
* Fix config unit tests: project path is set!
* Add docstring for PartialConfig::try_from()
* Fix: use empty PartialConfig if proj conf missing
* Fix: use default "[all]" if one isn't present
* Another autoformat
* Fix some clippy lints
* Mark pre-release 3.0.0-alpha.1
* Add a project path CLI option
* Update CLI usage guide, add project lookup guide
* Write configuration guide in the README
* Split the owner and repo args apart in CLI parser
* Use current-dir as final fallback repo name
* Drop notice about CLI not having "repo" & "owner"
* Revise help text for CLI "--project" arg
* Update usage printout
* Create a short, complete explanation of req. info.
* New 'authentication' section
* Delete the old CLI option sections
* Rename remaining CLI arg sections
* Revise explanation of `--project` option
* Drop the "no-repo" comment in TOML example
* Rephrase the all-projects setting introduction
* Mark the file-format and search-path conf sections
* Lint and format
* Bump crate version to v3.0.0
* Update automation workflow with new CLI args
* Add new upstream dependency to debian/control
* Rediff patches
-- Robert Garrett <robertgarrett404@gmail.com> Tue, 22 Jul 2025 09:54:28 -0500
gt-tool (2.2.0-2) unstable; urgency=medium
* Fix: "Source:" URL in debian/copyright
* Fix typo in copyright comment
-- Robert Garrett <robertgarrett404@gmail.com> Sun, 13 Jul 2025 16:59:25 -0500
gt-tool (2.2.0-1) unstable; urgency=medium
* Basic impl Display for the Release struct
* Print releases in reverse order for easier reading
* Colorize the output!
* Remove trailing newline in Release item printout
* Galaxy-brained newline intersperse function
* Change to free-fn intersperse for stdlib compat
* `Release.colorized()`, not std::fmt::Display
* Address most of the cargo-clippy lints
* Prefix unused variables to quiet the linter
* Autoformat
* Oops, missed one
* Bump to v2.2.0
* Lift the empty-body string outside the let-if
* Add the new dependencies to debian/control
-- Robert Garrett <robertgarrett404@gmail.com> Fri, 04 Jul 2025 10:10:54 -0500
gt-tool (2.1.0-1) unstable; urgency=medium
* Fix: incorrect field names for `Attachment`
-- Robert Garrett <robertgarrett404@gmail.com> Thu, 12 Jun 2025 17:51:12 -0500
gt-tool (2.0.0-1) unstable; urgency=medium
* Interrogate list_releases result more closely
* Interrogate create_release result more closely
* Drop unused imports
* "Fix" the test case
* Interrogate create_release_attachment result
* Fold client-error-decode into a util function
* Add `Attachment` struct, new iface for create-rel
* Update main.rs to use new attachment iface
* Delete the unit tests
* ... and the unit testing notes in README.md
* Drop unused import in api/release.rs
* Use pre Rust 1.81 compatible file-exists test
* Rediff patches
-- Robert Garrett <robertgarrett404@gmail.com> Thu, 12 Jun 2025 16:28:18 -0500
gt-tool (1.0.0-1) unstable; urgency=low
* Experimental release.
-- Robert Garrett <robertgarrett404@gmail.com> Sun, 1 Jun 2025 16:05:00 -0500

88
debian/control vendored
View File

@@ -1,88 +0,0 @@
Source: gt-tool
Maintainer: Robert Garrett <robertgarrett404@gmail.com>
Section: rust
Priority: optional
Standards-Version: 4.6.2
Build-Depends:
debhelper-compat (= 13),
dh-sequence-cargo
Build-Depends-Arch:
cargo:native,
rustc:native,
libstd-rust-dev,
librust-clap-4+default-dev (>= 4.5.23-~~),
librust-clap-4+derive-dev (>= 4.5.23-~~),
librust-clap-4+env-dev (>= 4.5.23-~~),
librust-colored-2+default-dev (>= 2.2.0-~~),
librust-itertools-0.13+default-dev,
librust-reqwest-0.12+default-dev (>= 0.12.15-~~),
librust-reqwest-0.12+json-dev (>= 0.12.15-~~),
librust-reqwest-0.12+multipart-dev (>= 0.12.15-~~),
librust-reqwest-0.12+stream-dev (>= 0.12.15-~~),
librust-serde-1+default-dev (>= 1.0.217-~~),
librust-serde-1+derive-dev (>= 1.0.217-~~),
librust-tokio-1+default-dev (>= 1.43.1-~~),
librust-tokio-1+macros-dev (>= 1.43.1-~~),
librust-tokio-1+rt-multi-thread-dev (>= 1.43.1-~~),
librust-toml-0.8+default-dev (>= 0.8.19-~~)
Homepage: https://git.gelvin.dev/robert/gt-tool
Vcs-Git: https://git.gelvin.dev/robert/gt-tool
Vcs-Browser: https://git.gelvin.dev/robert/gt-tool
Rules-Requires-Root: no
X-Cargo-Crate: gt-tool
Package: librust-gt-tool-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-clap-4+default-dev (>= 4.5.23-~~),
librust-clap-4+derive-dev (>= 4.5.23-~~),
librust-clap-4+env-dev (>= 4.5.23-~~),
librust-colored-2+default-dev (>= 2.2.0-~~),
librust-itertools-0.13+default-dev,
librust-reqwest-0.12+default-dev (>= 0.12.15-~~),
librust-reqwest-0.12+json-dev (>= 0.12.15-~~),
librust-reqwest-0.12+multipart-dev (>= 0.12.15-~~),
librust-reqwest-0.12+stream-dev (>= 0.12.15-~~),
librust-serde-1+default-dev (>= 1.0.217-~~),
librust-serde-1+derive-dev (>= 1.0.217-~~),
librust-tokio-1+default-dev (>= 1.43.1-~~),
librust-tokio-1+macros-dev (>= 1.43.1-~~),
librust-tokio-1+rt-multi-thread-dev (>= 1.43.1-~~),
librust-toml-0.8+default-dev (>= 0.8.19-~~)
Provides:
librust-gt-tool+default-dev (= ${binary:Version}),
librust-gt-tool-3-dev (= ${binary:Version}),
librust-gt-tool-3+default-dev (= ${binary:Version}),
librust-gt-tool-3.0-dev (= ${binary:Version}),
librust-gt-tool-3.0+default-dev (= ${binary:Version}),
librust-gt-tool-3.0.1-dev (= ${binary:Version}),
librust-gt-tool-3.0.1+default-dev (= ${binary:Version})
Description: CLI tools for interacting with the Gitea API - Rust source code
Mainly for attaching files to releases.
.
Source code for Debianized Rust crate "gt-tool"
Package: gt-tool
Architecture: any
Depends:
${misc:Depends},
${shlibs:Depends},
${cargo:Depends}
Recommends:
${cargo:Recommends}
Suggests:
${cargo:Suggests}
Provides:
${cargo:Provides}
Built-Using: ${cargo:Built-Using}
Static-Built-Using: ${cargo:Static-Built-Using}
Description: CLI tools for interacting with the Gitea API.
Use interactively to talk to your Gitea instance, or automatically via a CI/CD
pipeline. Currently supports:
.
- showing the Releases for a project
- creating a new Release for a project
- attaching files to a release

30
debian/copyright vendored
View File

@@ -1,30 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: gt-tool
Upstream-Contact: Robert Garrett <robertgarrett404@gmail.com>
Source: https://git.gelvin.dev/robert/gt-tool
Files: *
Copyright: 2025 Robert Garrett <robertgarrett404@gmail.com>
License: GPL-3+
Files: debian/*
Copyright: 2025 Robert Garrett <robertgarrett404@gmail.com>
License: GPL-3+
License: GPL-3+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
.
You should have received a copy of the GNU General Public License
along with it. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the full text of the GNU General Public License version 3
can be found in the file /usr/share/common-licenses/GPL-3.

6
debian/gbp.conf vendored
View File

@@ -1,6 +0,0 @@
[DEFAULT]
compression = xz
compression-level = 9
upstream-tag = v%(version)s
debian-branch = deb/trixie

7
debian/rules vendored
View File

@@ -1,7 +0,0 @@
#!/usr/bin/make -f
%:
dh $@ --buildsystem cargo
override_dh_auto_test:
dh_auto_test -- test --all

View File

@@ -1 +0,0 @@
3.0 (quilt)

14
debian/tests/control vendored
View File

@@ -1,14 +0,0 @@
Test-Command: /usr/share/cargo/bin/cargo-auto-test gt-tool 3.0.1 --all-targets --all-features
Features: test-name=rust-gt-tool:@
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
Test-Command: /usr/share/cargo/bin/cargo-auto-test gt-tool 3.0.1 --all-targets
Features: test-name=librust-gt-tool-dev:default
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
Test-Command: /usr/share/cargo/bin/cargo-auto-test gt-tool 3.0.1 --all-targets --no-default-features
Features: test-name=librust-gt-tool-dev:
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable

View File

@@ -1,4 +1,40 @@
pub fn list_packages() {} use crate::structs::package::{Package, PackageType};
/// Gets all packages of an owner
///
/// https://github.com/go-gitea/gitea/blob/main/routers/api/v1/packages/package.go#L22
///
/// Matches the route `GET /packages/{owner}`
pub async fn list_packages(
client: &reqwest::Client,
gitea_url: &str,
owner: &str,
pkg_type: Option<PackageType>,
) -> crate::Result<Vec<Package>> {
let request_url = format!("{gitea_url}/api/v1/packages/{owner}");
// add the query parameter only when a package type filter has been set.
let request_url = if let Some(pkg_type) = pkg_type {
let pkg_type = pkg_type.to_string();
format!("{request_url}?type={pkg_type}")
} else {
request_url
};
let req = client.get(request_url).send().await;
let response = req.map_err(crate::Error::WrappedReqwestErr)?;
if response.status().is_success() {
let release_list = response
.json::<Vec<Package>>()
.await
.map_err(crate::Error::WrappedReqwestErr)?;
return Ok(release_list);
} else if response.status().is_client_error() {
let mesg = crate::decode_client_error(response).await?;
return Err(crate::Error::ApiErrorMessage(mesg));
}
panic!("Reached the end of `api::list_packages()` without matching a return pathway.");
}
pub fn get_packages() {} pub fn get_packages() {}
pub fn delete_package() {} pub fn delete_package() {}
pub fn list_package_files() {} pub fn list_package_files() {}

View File

@@ -44,4 +44,5 @@ pub enum Commands {
#[arg()] #[arg()]
files: Vec<String>, files: Vec<String>,
}, },
ListPackages,
} }

View File

@@ -134,6 +134,16 @@ async fn main() -> Result<(), gt_tool::Error> {
return Err(gt_tool::Error::NoSuchRelease); return Err(gt_tool::Error::NoSuchRelease);
} }
} }
gt_tool::cli::Commands::ListPackages => {
let packages = gt_tool::api::packages::list_packages(&client, &gitea_url, &owner, None).await?;
itertools::Itertools::intersperse(
packages
.iter()
.rev()
.map(|pkg| pkg.colorized()),
String::from("")
).for_each(|package| println!("{package}"));
}
} }
Ok(()) Ok(())

View File

@@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod package;
pub mod release; pub mod release;
pub mod repo; pub mod repo;

95
src/structs/package.rs Normal file
View File

@@ -0,0 +1,95 @@
use colored::Colorize;
use serde::{Deserialize, Serialize};
use crate::structs::release::Author;
/// Represents the package as described by JSON
///
/// https://github.com/go-gitea/gitea/blob/main/modules/structs/package.go
#[derive(Debug, Deserialize, Serialize)]
pub struct Package {
created_at: String, // TODO: Datetime struct
creator: Author,
html_url: String,
id: u64,
name: String,
owner: Author,
#[serde(skip)]
repository: (), // TODO: Create a `struct Repository`
#[serde(rename = "type")] // field is "type" in JSON & Go, but that's a
pkg_type: PackageType, // keyword in Rust so we need to serde-rename it.
version: String,
}
impl Package {
pub fn colorized(&self) -> String {
let name = "Name:".green().bold();
let version = "Ver:".green();
let pkg_type = "Type:".white();
format!(
"{name} {}
{version} {}, {pkg_type} {}",
self.name,
self.version,
self.pkg_type.to_string(),
)
}
}
/// A marker for the kind of package being handled.
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PackageType {
Alpine,
Arch,
Cargo,
Chef,
Composer,
Conan,
Conda,
Container,
Cran,
Debian,
Generic,
Go,
Helm,
Maven,
Npm,
Nuget,
Pub,
PyPi,
Rpm,
RubyGems,
Swift,
Vagrant,
}
impl ToString for PackageType {
fn to_string(&self) -> String {
match self {
PackageType::Alpine => "alpine".into(),
PackageType::Arch => "arch".into(),
PackageType::Cargo => "cargo".into(),
PackageType::Chef => "chef".into(),
PackageType::Composer => "composer".into(),
PackageType::Conan => "conan".into(),
PackageType::Conda => "conda".into(),
PackageType::Container => "container".into(),
PackageType::Cran => "cran".into(),
PackageType::Debian => "debian".into(),
PackageType::Generic => "generic".into(),
PackageType::Go => "go".into(),
PackageType::Helm => "helm".into(),
PackageType::Maven => "maven".into(),
PackageType::Npm => "npm".into(),
PackageType::Nuget => "nuget".into(),
PackageType::Pub => "pub".into(),
PackageType::PyPi => "pypi".into(),
PackageType::Rpm => "rpm".into(),
PackageType::RubyGems => "rubygems".into(),
PackageType::Swift => "swift".into(),
PackageType::Vagrant => "vagrant".into(),
}
}
}