This commit is contained in:
2025-08-13 12:09:11 +02:00
parent 15aeb136b2
commit 1501a09e62
17 changed files with 246 additions and 144 deletions

View File

@@ -88,27 +88,6 @@ fn do() ! {
herocmds.cmd_generator(mut cmd)
herocmds.cmd_docusaurus(mut cmd)
// herocmds.cmd_bootstrap(mut cmd)
// herocmds.cmd_init(mut cmd)
// herocmds.cmd_imagedownsize(mut cmd)
// herocmds.cmd_biztools(mut cmd)
// herocmds.cmd_gen(mut cmd)
// herocmds.cmd_sshagent(mut cmd)
// herocmds.cmd_installers(mut cmd)
// herocmds.cmd_configure(mut cmd)
// herocmds.cmd_postgres(mut cmd)
// Ensure the herocmds module is imported so the remaining commands are visible
// `cmd_mdbook` is not part of the current code base it has been removed.
// If you need markdownbook support, reintroduce the command implementation
// and uncomment the line below.
// herocmds.cmd_mdbook(mut cmd)
// herocmds.cmd_luadns(mut cmd)
// herocmds.cmd_caddy(mut cmd)
// herocmds.cmd_zola(mut cmd)
// herocmds.cmd_juggler(mut cmd)
// herocmds.cmd_starlight(mut cmd)
// herocmds.cmd_docsorter(mut cmd)
// cmd.add_command(publishing.cmd_publisher(pre_func))
cmd.setup()
cmd.parse(os.args)
}

View File

@@ -1,19 +1,40 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
#!/usr/bin/env -S v -n -w -g -cg -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.clients.gitea_client
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.clients.giteaclient
// Configure PostgreSQL client
heroscript := "
!!gitea_client.configure
url: 'https://gitea.example.com'
user: 'despiegk'
token: '0597b7c143953bc66b47268bfcdc324340b3f47d'
"
// heroscript := "
// !!giteaclient.configure
// url: 'git.ourworld.tf'
// user: 'despiegk'
// secret: ''
// "
// Process the heroscript configuration
gitea_client.play(heroscript: heroscript)!
// // Process the heroscript configuration
// playcmds.play(heroscript: heroscript, emptycheck: false)!
// Get the configured client
mut db_client := gitea_client.get()!
mut client := giteaclient.get()!
// Get the authenticated user
// user := client.get_current_user()!
// println('Authenticated as: ${user.login}')
// List repositories for the authenticated user
repos := client.user_list_repos()!
println('Found ${repos.len} repositories:')
for repo in repos {
println('- ${repo.full_name}')
}
// Get a specific repository's issues
owner := 'gitea'
repo_name := 'gitea'
println('\nFetching issues for ${owner}/${repo_name}...')
issues := client.list_repo_issues(owner, repo_name)!
println('Found ${issues.len} issues.')
for issue in issues {
println(' #${issue.number}: ${issue.title}')
}

View File

@@ -9,6 +9,6 @@ const spec_path = '${os.dir(@FILE)}/openapi.json'
mod := gen.generate_client_module(
api_name: 'Gitea'
)!
mod.write_v('${os.dir(@FILE)}/gitea_client',
mod.write_v('${os.dir(@FILE)}/giteaclient',
overwrite: true
)!

View File

@@ -1,17 +0,0 @@
example how to
```v
pub fn (mut self GiteaClient) list_classifiers() ![]Classifier {
req := httpconnection.Request{
method: .get
prefix: 'v1/classifiers'
}
//fetch the http client
mut httpclient := self.httpclient()!
response := httpclient.get(req)!
classifiers := json.decode([]Classifier, response)!
return classifiers
}
```

View File

@@ -1,6 +1,6 @@
!!hero_code.generate_client
name:'gitea_client'
name:'giteaclient'
classname:'GiteaClient'
singleton:0
default:1

View File

@@ -1,12 +1,12 @@
module gitea_client
module giteaclient
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.ui.console
__global (
gitea_client_global map[string]&GiteaClient
gitea_client_default string
giteaclient_global map[string]&GiteaClient
giteaclient_default string
)
/////////FACTORY
@@ -31,19 +31,19 @@ pub fn get(args_ ArgsGet) !&GiteaClient {
mut obj := GiteaClient{
name: args.name
}
if args.name !in gitea_client_global {
if args.name !in giteaclient_global {
if !exists(args)! {
set(obj)!
} else {
heroscript := context.hero_config_get('gitea_client', args.name)!
heroscript := context.hero_config_get('giteaclient', args.name)!
mut obj_ := heroscript_loads(heroscript)!
set_in_mem(obj_)!
}
}
return gitea_client_global[args.name] or {
println(gitea_client_global)
return giteaclient_global[args.name] or {
println(giteaclient_global)
// bug if we get here because should be in globals
panic('could not get config for gitea_client with name, is bug:${args.name}')
panic('could not get config for giteaclient with name, is bug:${args.name}')
}
}
@@ -52,34 +52,34 @@ pub fn set(o GiteaClient) ! {
set_in_mem(o)!
mut context := base.context()!
heroscript := heroscript_dumps(o)!
context.hero_config_set('gitea_client', o.name, heroscript)!
context.hero_config_set('giteaclient', o.name, heroscript)!
}
// does the config exists?
pub fn exists(args_ ArgsGet) !bool {
mut context := base.context()!
mut args := args_get(args_)
return context.hero_config_exists('gitea_client', args.name)
return context.hero_config_exists('giteaclient', args.name)
}
pub fn delete(args_ ArgsGet) ! {
mut args := args_get(args_)
mut context := base.context()!
context.hero_config_delete('gitea_client', args.name)!
if args.name in gitea_client_global {
// del gitea_client_global[args.name]
context.hero_config_delete('giteaclient', args.name)!
if args.name in giteaclient_global {
// del giteaclient_global[args.name]
}
}
// only sets in mem, does not set as config
fn set_in_mem(o GiteaClient) ! {
mut o2 := obj_init(o)!
gitea_client_global[o.name] = &o2
gitea_client_default = o.name
giteaclient_global[o.name] = &o2
giteaclient_default = o.name
}
pub fn play(mut plbook PlayBook) ! {
mut install_actions := plbook.find(filter: 'gitea_client.configure')!
mut install_actions := plbook.find(filter: 'giteaclient.configure')!
if install_actions.len > 0 {
for install_action in install_actions {
heroscript := install_action.heroscript()
@@ -89,9 +89,9 @@ pub fn play(mut plbook PlayBook) ! {
}
}
// switch instance to be used for gitea_client
// switch instance to be used for giteaclient
pub fn switch(name string) {
gitea_client_default = name
giteaclient_default = name
}
// helpers

View File

@@ -1,5 +1,5 @@
// File: lib/clients/gitea_client/gitea_client_model.v
module gitea_client
// File: lib/clients/giteaclient/giteaclient_model.v
module giteaclient
import freeflowuniverse.herolib.data.paramsparser
import freeflowuniverse.herolib.data.encoderhero
@@ -36,6 +36,24 @@ fn obj_init(mycfg_ GiteaClient) !GiteaClient {
if mycfg.url == '' {
return error('url needs to be filled in for ${mycfg.name}')
}
if mycfg.url.starts_with('https://') {
mycfg.url = mycfg.url.replace('https://', '')
}
if mycfg.url.starts_with('http://') {
mycfg.url = mycfg.url.replace('http://', '')
}
mycfg.url = mycfg.url.trim_right('/')
if mycfg.url.ends_with('/api/v1') {
mycfg.url = mycfg.url.replace('/api/v1', '')
}
if mycfg.url.ends_with('/api') {
mycfg.url = mycfg.url.replace('/api', '')
}
mycfg.url = "https://${mycfg.url}/api/v1"
if mycfg.secret.len == 0 {
return error('secret needs to be filled in for ${mycfg.name}')
}
return mycfg
}

View File

@@ -1,29 +1,25 @@
// File: lib/clients/gitea_client/methods.v
module gitea_client
// File: lib/clients/giteaclient/methods.v
module giteaclient
import freeflowuniverse.herolib.core.httpconnection
import json
import net.http
// NOTE: This file should contain the implementation for all API endpoints from the swagger spec.
// Each public method on GiteaClient corresponds to an API call.
//
// Repository Operations
//
// List a user's own repositories
pub fn (mut client GiteaClient) user_list_repos() ![]Repository {
$dbg;
req := httpconnection.Request{
method: .get
prefix: '/user/repos'
}
mut http_client := client.httpclient()!
return http_client.get_json_list_generic[Repository](req)!
r:=http_client.get_json_list_generic[Repository](req)!
$dbg;
return r
}
// Get a repository
pub fn (mut client GiteaClient) get_repo(owner string, repo string) !&Repository {
pub fn (mut client GiteaClient) get_repo(owner string, repo string) !Repository {
req := httpconnection.Request{
method: .get
prefix: '/repos/${owner}/${repo}'
@@ -33,7 +29,7 @@ pub fn (mut client GiteaClient) get_repo(owner string, repo string) !&Repository
}
// Create a repository for the authenticated user.
pub fn (mut client GiteaClient) create_current_user_repo(args CreateRepoOption) !&Repository {
pub fn (mut client GiteaClient) create_current_user_repo(args CreateRepoOption) !Repository {
req := httpconnection.Request{
method: .post
prefix: '/user/repos'
@@ -59,7 +55,7 @@ pub fn (mut client GiteaClient) list_repo_issues(owner string, repo string) ![]I
}
// Get an issue
pub fn (mut client GiteaClient) get_issue(owner string, repo string, index i64) !&Issue {
pub fn (mut client GiteaClient) get_issue(owner string, repo string, index i64) !Issue {
req := httpconnection.Request{
method: .get
prefix: '/repos/${owner}/${repo}/issues/${index}'
@@ -69,7 +65,7 @@ pub fn (mut client GiteaClient) get_issue(owner string, repo string, index i64)
}
// Create an issue
pub fn (mut client GiteaClient) create_issue(owner string, repo string, args CreateIssueOption) !&Issue {
pub fn (mut client GiteaClient) create_issue(owner string, repo string, args CreateIssueOption) !Issue {
req := httpconnection.Request{
method: .post
prefix: '/repos/${owner}/${repo}/issues'
@@ -85,7 +81,7 @@ pub fn (mut client GiteaClient) create_issue(owner string, repo string, args Cre
//
// get_user gets a user by username
pub fn (mut client GiteaClient) get_user(username string) !&User {
pub fn (mut client GiteaClient) get_user(username string) !User {
req := httpconnection.Request{
method: .get
prefix: '/users/${username}'
@@ -95,7 +91,7 @@ pub fn (mut client GiteaClient) get_user(username string) !&User {
}
// get_current_user gets the authenticated user
pub fn (mut client GiteaClient) get_current_user() !&User {
pub fn (mut client GiteaClient) get_current_user() !User {
req := httpconnection.Request{
method: .get
prefix: '/user'

View File

@@ -1,4 +1,4 @@
module gitea_client
module giteaclient
import time
@@ -27,9 +27,9 @@ pub:
pub struct Activity {
pub:
act_user &User
act_user User
act_user_id i64
comment &Comment
comment Comment
comment_id i64
content string
created time.Time
@@ -37,7 +37,7 @@ pub:
is_private bool
op_type string
ref_name string
repo &Repository
repo Repository
repo_id i64
user_id i64
}
@@ -64,12 +64,12 @@ pub:
pub struct AnnotatedTag {
pub:
message string
object &AnnotatedTagObject
object AnnotatedTagObject
sha string
tag string
tagger &CommitUser
tagger CommitUser
url string
verification &PayloadCommitVerification
verification PayloadCommitVerification
}
pub struct Attachment {
@@ -93,7 +93,7 @@ pub:
pub struct Branch {
pub:
commit &PayloadCommit
commit PayloadCommit
effective_branch_protection_name string
enable_status_check bool
name string
@@ -145,10 +145,10 @@ pub:
pub struct ChangeFilesOptions {
pub:
author &Identity
author Identity
branch string
committer &Identity
dates &CommitDateOptions
committer Identity
dates CommitDateOptions
files []ChangeFileOperation
message string
new_branch string
@@ -170,15 +170,15 @@ pub:
pub struct Commit {
pub:
author &User
commit &RepoCommit
committer &User
author User
commit RepoCommit
committer User
created time.Time
files []CommitAffectedFiles
html_url string
parents []CommitMeta
sha string
stats &CommitStats
stats CommitStats
url string
}
@@ -215,11 +215,26 @@ pub:
name string
}
pub struct Comment {
pub:
assets []Attachment
body string
created_at time.Time
html_url string
id i64
issue_url string
original_author string
original_author_id i64
pull_request_url string
updated_at time.Time
user User
}
pub struct CreateIssueOption {
pub:
title string
assignee string
assignees []string
assignees []string
body string
closed bool
due_date time.Time
@@ -250,21 +265,28 @@ pub:
name string
}
pub struct InternalTracker {
pub:
allow_only_contributors_to_track_time bool
enable_issue_dependencies bool
enable_time_tracker bool
}
pub struct Issue {
pub:
id i64
url string
html_url string
number i64
user &User
user User
original_author string
original_author_id i64
title string
body string
ref string
labels []Label
milestone &Milestone
assignee &User
milestone Milestone
assignee User
assignees []User
state string // StateType
is_locked bool
@@ -273,8 +295,8 @@ pub:
updated_at time.Time
closed_at time.Time
due_date time.Time
pull_request &PullRequestMeta
repository &RepositoryMeta
pull_request PullRequestMeta
repository RepositoryMeta
assets []Attachment
pin_order i64
}
@@ -304,16 +326,59 @@ pub:
due_on time.Time
}
pub struct Organization {
pub:
avatar_url string
description string
email string
full_name string
id i64
location string
name string
repo_admin_change_team_access bool
username string
visibility string
website string
}
pub struct PayloadCommitVerification {
pub:
payload string
reason string
signature string
signer &PayloadUser
signer PayloadUser
verified bool
}
pub struct PayloadCommit {
pub:
added []string
author PayloadUser
committer PayloadUser
id string
message string
modified []string
removed []string
timestamp time.Time
url string
verification PayloadCommitVerification
}
pub struct PayloadUser {
pub:
email string
name string
username string
}
pub struct Permission {
pub:
admin bool
pull bool
push bool
}
pub struct PullRequestMeta {
pub:
merged bool
@@ -324,18 +389,18 @@ pub:
pub struct RepoCommit {
pub:
author &CommitUser
committer &CommitUser
author CommitUser
committer CommitUser
message string
tree &CommitMeta
tree CommitMeta
url string
verification &PayloadCommitVerification
verification PayloadCommitVerification
}
pub struct Repository {
pub:
id i64
owner &User
owner User
name string
full_name string
description string
@@ -343,7 +408,7 @@ pub:
private bool
fork bool
template bool
parent &Repository
parent_id i64
mirror bool
size i64
language string
@@ -365,9 +430,9 @@ pub:
created_at time.Time
updated_at time.Time
archived_at time.Time
permissions &Permission
permissions Permission
has_issues bool
internal_tracker &InternalTracker
internal_tracker InternalTracker
has_wiki bool
has_pull_requests bool
has_projects bool
@@ -388,7 +453,7 @@ pub:
internal bool
mirror_interval string
mirror_updated time.Time
repo_transfer &RepoTransfer
repo_transfer RepoTransfer
}
pub struct RepositoryMeta {
pub:
@@ -398,6 +463,26 @@ pub:
full_name string
}
pub struct Team {
pub:
can_create_org_repo bool
description string
id i64
includes_all_repositories bool
name string
organization Organization
permission string
units []string
units_map map[string]string
}
pub struct RepoTransfer {
pub:
doer User
recipient User
teams []Team
}
pub struct User {
pub:
id i64

View File

@@ -1,5 +1,5 @@
// File: lib/clients/gitea_client/readme.md
# gitea_client
// File: lib/clients/giteaclient/readme.md
# giteaclient
This library provides a client for interacting with the Gitea API.
@@ -8,7 +8,7 @@ This library provides a client for interacting with the Gitea API.
You can configure the client using a HeroScript file:
```hero
!!gitea_client.configure
!!giteaclient.configure
name: 'default' // optional, 'default' is the default instance name
url: 'https://git.ourworld.tf'
secret: 'your-gitea-api-token'
@@ -21,7 +21,7 @@ Save this content in your project's configuration (e.g., `~/.config/hero/config.
Here's how to get the client and use its methods.
```vlang
import freeflowuniverse.herolib.clients.gitea_client
import freeflowuniverse.herolib.clients.giteaclient
import freeflowuniverse.herolib.core.base
fn main() ! {
@@ -29,12 +29,12 @@ fn main() ! {
base.init()!
// Example configuration (can also be loaded from file)
heroscript_config := "!!gitea_client.configure url:'https://gitea.com' secret:'...your_token...'"
heroscript_config := "!!giteaclient.configure url:'https://gitea.com' secret:'...your_token...'"
mut plbook := playbook.new(text: heroscript_config)!
gitea_client.play(mut plbook)!
giteaclient.play(mut plbook)!
// Get the default configured client
mut client := gitea_client.get()!
mut client := giteaclient.get()!
// Get the authenticated user
user := client.get_current_user()!
@@ -57,3 +57,8 @@ fn main() ! {
println(' #${issue.number}: ${issue.title}')
}
}
## tips
- to see the admin api: https://git.ourworld.tf/api/swagger

View File

@@ -96,6 +96,7 @@ pub fn cmd_git(mut cmdroot Command) {
mut allcmdsref := [&list_command, &clone_command, &push_command, &pull_command, &commit_command,
&reload_command, &delete_command, &sourcetree_command, &editor_command]
for mut c in allcmdsref {
c.add_flag(Flag{
flag: .bool
@@ -216,6 +217,7 @@ fn cmd_git_execute(cmd Command) ! {
// create the filter for doing group actions, or action on 1 repo
mut filter := cmd.flags.get_string('filter') or { '' }
if cmd.name in gittools.gitcmds.split(',') {
mut pull := cmd.flags.get_bool('pull') or { false }
mut reset := cmd.flags.get_bool('reset') or { false }
@@ -224,6 +226,7 @@ fn cmd_git_execute(cmd Command) ! {
pull = true
reset = true
}
mypath := gs.do(
filter: filter
reload: reload

View File

@@ -186,7 +186,7 @@ pub fn (mut h HTTPConnection) get_json(req Request) !string {
// Get Request with json data and return response as string
pub fn (mut h HTTPConnection) get(req_ Request) !string {
mut req := req_
req.debug = true
req.debug
req.method = .get
result := h.send(req)!
return result.data

View File

@@ -6,6 +6,7 @@ import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.web.site
import freeflowuniverse.herolib.web.docusaurus
import freeflowuniverse.herolib.clients.openai
import freeflowuniverse.herolib.clients.giteaclient
// -------------------------------------------------------------------
// run entry point for all HeroScript playcommands
@@ -18,6 +19,11 @@ pub mut:
heroscript_path string
plbook ?PlayBook
reset bool
emptycheck bool = true
}
pub fn play(args_ PlayArgs) ! {
return run(args_)
}
pub fn run(args_ PlayArgs) ! {
@@ -45,6 +51,11 @@ pub fn run(args_ PlayArgs) ! {
docusaurus.play(mut plbook)!
// Ensure we did not leave any actions unprocessed
plbook.empty_check()!
giteaclient.play(mut plbook)!
if args.emptycheck{
// Ensure we did not leave any actions unprocessed
plbook.empty_check()!
}
}

View File

@@ -24,6 +24,9 @@ fn decode_struct[T](_ T, data string) !T {
if !data.contains(action_name) {
action_name = '${obj_name}.configure'
if !data.contains(action_name) {
$if debug{
print_backtrace()
}
return error('Data does not contain action name: ${obj_name}.define or ${action_name}')
}
}

View File

@@ -43,7 +43,7 @@ pub mut:
//```
pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
mut args := args_
// console.print_debug('git do ${args.cmd}')
console.print_debug('git do ${args.cmd}')
if args.path == '' && args.url == '' && args.repo == '' && args.account == ''
&& args.provider == '' && args.filter == '' {
@@ -61,17 +61,6 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
}
}
// see if a url was used means we are in 1 repo
if args.url.len > 0 {
if !(args.repo == '' && args.account == '' && args.provider == '' && args.filter == '') {
return error('when specify url cannot specify repo, account, profider or filter')
}
mut r0 := gs.get_repo(url: args.url)!
args.repo = r0.name
args.account = r0.account
args.provider = r0.provider
}
args.cmd = args.cmd.trim_space().to_lower()
mut ui := gui.new()!
@@ -128,6 +117,18 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
return ''
}
// see if a url was used means we are in 1 repo
if args.url.len > 0 {
if !(args.repo == '' && args.account == '' && args.provider == '' && args.filter == '') {
return error('when specify url cannot specify repo, account, profider or filter')
}
mut r0 := gs.get_repo(url: args.url)!
args.repo = r0.name
args.account = r0.account
args.provider = r0.provider
}
if args.cmd in 'pull,push,commit,delete'.split(',') {
gs.repos_print(
filter: args.filter

View File

@@ -24,9 +24,6 @@ pub fn (mut gitstructure GitStructure) clone(args GitCloneArgs) !&GitRepo {
git_location := gitstructure.gitlocation_from_url(args.url)!
mut repo := gitstructure.repo_new_from_gitlocation(git_location)!
// TODO: this seems to be wrong, we should not set the url here
// repo.status_wanted.url = args.url
// repo.status_wanted.branch = git_location.branch_or_tag
mut repopath := repo.patho()!
if repopath.exists() {