diff options
author | KN4CK3R <admin@oldschoolhack.me> | 2021-11-14 20:11:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-14 20:11:10 +0100 |
commit | 42ea0023a30fd6a0e2e2da1e32ece0a484c03a65 (patch) | |
tree | 9a279ebc1b1300dc7ee6bb9aeaaea90eb63b22a3 | |
parent | d2163df6a0d6b9663a65438c1d960ea4ab5c2df0 (diff) | |
download | gitea-42ea0023a30fd6a0e2e2da1e32ece0a484c03a65.tar.gz gitea-42ea0023a30fd6a0e2e2da1e32ece0a484c03a65.zip |
Add migration from GitBucket (#16767)
This PR adds [GitBucket](https://gitbucket.github.io/) as migration source.
Supported:
- Milestones
- Issues
- Pull Requests
- Comments
- Reviews
- Labels
There is no public usable instance so no integration tests added.
-rw-r--r-- | modules/convert/utils.go | 2 | ||||
-rw-r--r-- | modules/migrations/gitbucket.go | 72 | ||||
-rw-r--r-- | modules/migrations/github.go | 209 | ||||
-rw-r--r-- | modules/structs/repo.go | 18 | ||||
-rw-r--r-- | options/locale/locale_en-US.ini | 1 | ||||
-rw-r--r-- | public/img/svg/gitea-gitbucket.svg | 1 | ||||
-rw-r--r-- | templates/repo/migrate/gitbucket.tmpl | 129 | ||||
-rw-r--r-- | web_src/svg/gitea-gitbucket.svg | 39 |
8 files changed, 365 insertions, 106 deletions
diff --git a/modules/convert/utils.go b/modules/convert/utils.go index a0463d7b10..52fbcf547f 100644 --- a/modules/convert/utils.go +++ b/modules/convert/utils.go @@ -35,6 +35,8 @@ func ToGitServiceType(value string) structs.GitServiceType { return structs.GogsService case "onedev": return structs.OneDevService + case "gitbucket": + return structs.GitBucketService default: return structs.PlainGitService } diff --git a/modules/migrations/gitbucket.go b/modules/migrations/gitbucket.go new file mode 100644 index 0000000000..72090c2490 --- /dev/null +++ b/modules/migrations/gitbucket.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "context" + "net/url" + "strings" + + "code.gitea.io/gitea/modules/migrations/base" + "code.gitea.io/gitea/modules/structs" +) + +var ( + _ base.Downloader = &GitBucketDownloader{} + _ base.DownloaderFactory = &GitBucketDownloaderFactory{} +) + +func init() { + RegisterDownloaderFactory(&GitBucketDownloaderFactory{}) +} + +// GitBucketDownloaderFactory defines a GitBucket downloader factory +type GitBucketDownloaderFactory struct { +} + +// New returns a Downloader related to this factory according MigrateOptions +func (f *GitBucketDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) { + u, err := url.Parse(opts.CloneAddr) + if err != nil { + return nil, err + } + + baseURL := u.Scheme + "://" + u.Host + fields := strings.Split(u.Path, "/") + oldOwner := fields[1] + oldName := strings.TrimSuffix(fields[2], ".git") + + return NewGitBucketDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil +} + +// GitServiceType returns the type of git service +func (f *GitBucketDownloaderFactory) GitServiceType() structs.GitServiceType { + return structs.GitBucketService +} + +// GitBucketDownloader implements a Downloader interface to get repository information +// from GitBucket via GithubDownloader +type GitBucketDownloader struct { + *GithubDownloaderV3 +} + +// NewGitBucketDownloader creates a GitBucket downloader +func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader { + githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName) + githubDownloader.SkipReactions = true + return &GitBucketDownloader{ + githubDownloader, + } +} + +// SupportGetRepoComments return true if it supports get repo comments +func (g *GitBucketDownloader) SupportGetRepoComments() bool { + return false +} + +// GetReviews is not supported +func (g *GitBucketDownloader) GetReviews(context base.IssueContext) ([]*base.Review, error) { + return nil, &base.ErrNotSupported{Entity: "Reviews"} +} diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 874cd05439..50cffc467a 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -68,15 +68,16 @@ func (f *GithubDownloaderV3Factory) GitServiceType() structs.GitServiceType { // from github via APIv3 type GithubDownloaderV3 struct { base.NullDownloader - ctx context.Context - clients []*github.Client - repoOwner string - repoName string - userName string - password string - rates []*github.Rate - curClientIdx int - maxPerPage int + ctx context.Context + clients []*github.Client + repoOwner string + repoName string + userName string + password string + rates []*github.Rate + curClientIdx int + maxPerPage int + SkipReactions bool } // NewGithubDownloaderV3 creates a github Downloader via github v3 API @@ -428,25 +429,27 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, // get reactions var reactions []*base.Reaction - for i := 1; ; i++ { - g.waitAndPickClient() - res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, issue.GetNumber(), &github.ListOptions{ - Page: i, - PerPage: perPage, - }) - if err != nil { - return nil, false, err - } - g.setRate(&resp.Rate) - if len(res) == 0 { - break - } - for _, reaction := range res { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.GetID(), - UserName: reaction.User.GetLogin(), - Content: reaction.GetContent(), + if !g.SkipReactions { + for i := 1; ; i++ { + g.waitAndPickClient() + res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, issue.GetNumber(), &github.ListOptions{ + Page: i, + PerPage: perPage, }) + if err != nil { + return nil, false, err + } + g.setRate(&resp.Rate) + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } } } @@ -516,25 +519,27 @@ func (g *GithubDownloaderV3) getComments(issueContext base.IssueContext) ([]*bas for _, comment := range comments { // get reactions var reactions []*base.Reaction - for i := 1; ; i++ { - g.waitAndPickClient() - res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ - Page: i, - PerPage: g.maxPerPage, - }) - if err != nil { - return nil, err - } - g.setRate(&resp.Rate) - if len(res) == 0 { - break - } - for _, reaction := range res { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.GetID(), - UserName: reaction.User.GetLogin(), - Content: reaction.GetContent(), + if !g.SkipReactions { + for i := 1; ; i++ { + g.waitAndPickClient() + res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ + Page: i, + PerPage: g.maxPerPage, }) + if err != nil { + return nil, err + } + g.setRate(&resp.Rate) + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } } } @@ -588,25 +593,27 @@ func (g *GithubDownloaderV3) GetAllComments(page, perPage int) ([]*base.Comment, for _, comment := range comments { // get reactions var reactions []*base.Reaction - for i := 1; ; i++ { - g.waitAndPickClient() - res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ - Page: i, - PerPage: g.maxPerPage, - }) - if err != nil { - return nil, false, err - } - g.setRate(&resp.Rate) - if len(res) == 0 { - break - } - for _, reaction := range res { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.GetID(), - UserName: reaction.User.GetLogin(), - Content: reaction.GetContent(), + if !g.SkipReactions { + for i := 1; ; i++ { + g.waitAndPickClient() + res, resp, err := g.getClient().Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ + Page: i, + PerPage: g.maxPerPage, }) + if err != nil { + return nil, false, err + } + g.setRate(&resp.Rate) + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } } } idx := strings.LastIndex(*comment.IssueURL, "/") @@ -656,25 +663,27 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq // get reactions var reactions []*base.Reaction - for i := 1; ; i++ { - g.waitAndPickClient() - res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, pr.GetNumber(), &github.ListOptions{ - Page: i, - PerPage: perPage, - }) - if err != nil { - return nil, false, err - } - g.setRate(&resp.Rate) - if len(res) == 0 { - break - } - for _, reaction := range res { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.GetID(), - UserName: reaction.User.GetLogin(), - Content: reaction.GetContent(), + if !g.SkipReactions { + for i := 1; ; i++ { + g.waitAndPickClient() + res, resp, err := g.getClient().Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, pr.GetNumber(), &github.ListOptions{ + Page: i, + PerPage: perPage, }) + if err != nil { + return nil, false, err + } + g.setRate(&resp.Rate) + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } } } @@ -737,25 +746,27 @@ func (g *GithubDownloaderV3) convertGithubReviewComments(cs []*github.PullReques for _, c := range cs { // get reactions var reactions []*base.Reaction - for i := 1; ; i++ { - g.waitAndPickClient() - res, resp, err := g.getClient().Reactions.ListPullRequestCommentReactions(g.ctx, g.repoOwner, g.repoName, c.GetID(), &github.ListOptions{ - Page: i, - PerPage: g.maxPerPage, - }) - if err != nil { - return nil, err - } - g.setRate(&resp.Rate) - if len(res) == 0 { - break - } - for _, reaction := range res { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.GetID(), - UserName: reaction.User.GetLogin(), - Content: reaction.GetContent(), + if !g.SkipReactions { + for i := 1; ; i++ { + g.waitAndPickClient() + res, resp, err := g.getClient().Reactions.ListPullRequestCommentReactions(g.ctx, g.repoOwner, g.repoName, c.GetID(), &github.ListOptions{ + Page: i, + PerPage: g.maxPerPage, }) + if err != nil { + return nil, err + } + g.setRate(&resp.Rate) + if len(res) == 0 { + break + } + for _, reaction := range res { + reactions = append(reactions, &base.Reaction{ + UserID: reaction.User.GetID(), + UserName: reaction.User.GetLogin(), + Content: reaction.GetContent(), + }) + } } } diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 313a982f43..8482a2128d 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -242,13 +242,14 @@ type GitServiceType int // enumerate all GitServiceType const ( - NotMigrated GitServiceType = iota // 0 not migrated from external sites - PlainGitService // 1 plain git service - GithubService // 2 github.com - GiteaService // 3 gitea service - GitlabService // 4 gitlab service - GogsService // 5 gogs service - OneDevService // 6 onedev service + NotMigrated GitServiceType = iota // 0 not migrated from external sites + PlainGitService // 1 plain git service + GithubService // 2 github.com + GiteaService // 3 gitea service + GitlabService // 4 gitlab service + GogsService // 5 gogs service + OneDevService // 6 onedev service + GitBucketService // 7 gitbucket service ) // Name represents the service type's name @@ -270,6 +271,8 @@ func (gt GitServiceType) Title() string { return "Gogs" case OneDevService: return "OneDev" + case GitBucketService: + return "GitBucket" case PlainGitService: return "Git" } @@ -326,5 +329,6 @@ var ( GiteaService, GogsService, OneDevService, + GitBucketService, } ) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6fad20c87e..7d6c878ad6 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -911,6 +911,7 @@ migrate.gitlab.description = Migrate data from gitlab.com or other GitLab instan migrate.gitea.description = Migrate data from gitea.com or other Gitea instances. migrate.gogs.description = Migrate data from notabug.org or other Gogs instances. migrate.onedev.description = Migrate data from code.onedev.io or other OneDev instances. +migrate.gitbucket.description = Migrating data from GitBucket instances. migrate.migrating_git = Migrating Git Data migrate.migrating_topics = Migrating Topics migrate.migrating_milestones = Migrating Milestones diff --git a/public/img/svg/gitea-gitbucket.svg b/public/img/svg/gitea-gitbucket.svg new file mode 100644 index 0000000000..50ddd44e1b --- /dev/null +++ b/public/img/svg/gitea-gitbucket.svg @@ -0,0 +1 @@ +<svg version="1.0" viewBox="0 0 316 329" class="svg gitea-gitbucket" width="16" height="16" aria-hidden="true"><g fill="#303030"><path d="M123 21.1c-44.8 2.8-84 12.8-97.1 24.6-5 4.5-5 7.1 0 11.6C41.7 71.5 96.6 82.9 150 83h10.6l5.4-5.6c11.8-12.1 21.3-12.4 32.6-1.2l5.2 5 13.3-1.7c33.8-4.2 61.5-12.7 71.8-22 5.3-4.8 5.3-7.2 0-12-10.1-9.1-39.1-18.1-70.4-21.9-28.3-3.4-65.6-4.4-95.5-2.5zM23.2 80.6c.4 1.6 7 42.9 14.8 91.9 7.9 49 14.7 89.5 15.2 90.2 1.7 2.1 25.8 11.4 41.6 15.9 13 3.7 35.1 8.4 40 8.4.6 0 1.2-.6 1.2-1.3 0-.6-17.4-18.5-38.6-39.7C57.9 206.6 55 203.2 55 196c0-7.2 3-10.7 38.3-45.9 30.1-30 34.8-34.3 36.6-33.5 1.1.5 8.7 7.4 17 15.2l15.1 14.4v5.9c0 7.3 2.4 12.4 7.7 16.7l3.8 3v61.8l-3.8 3.4c-10.2 8.9-10.2 22.9-.1 30.7 3.1 2.3 4.9 2.8 10.8 3.1 8.2.4 11.5-1.1 16.2-7.3 2.2-3 2.9-5.1 3.2-10 .4-6.5-.2-8.3-5.3-15.4l-2.5-3.4v-26.6c0-26.7.3-31.1 2.3-31.1.5 0 5.4 4.4 10.9 9.7 9.6 9.5 9.9 10 10.8 15.7 1.7 10.3 8.9 16.6 19 16.6 7.6 0 13.5-3.9 17.4-11.7 3.2-6.4 1.6-14.3-4.3-20.6-4.1-4.4-7.3-5.7-14.9-5.7h-6.8l-12.7-12.1c-10.7-10.1-12.7-12.6-13.2-15.7-1.2-7.2-1.6-8.2-4.7-11.7-3.9-4.5-7.7-6.5-12.2-6.5-1.9 0-4.5-.4-5.8-.9-1.3-.5-9.9-8.2-19.3-17l-17-16-7.1-.1c-10.6 0-36-2.7-52.4-5.5-22.8-4-38.5-8.6-57.9-17.2-1.1-.5-1.3 0-.9 2.3zM278.5 83.6c-8.6 3.6-28 8.8-42.5 11.4-6.9 1.2-12.9 2.6-13.5 3.1-.6.6 9.3 11.2 27.5 29.4 15.6 15.6 28.5 28.3 28.7 28.1.2-.2 1.9-15.8 3.8-34.7 1.9-18.9 3.7-35.6 4-37.2.6-3.4-.2-3.4-8-.1zM255.2 259.3c-7.8 7.8-14.2 14.6-14.2 15 0 .4.7.7 1.6.7 2.2 0 23-8.9 24.2-10.3.9-1.1 3.5-18.7 2.9-19.3-.2-.2-6.7 6.1-14.5 13.9zM56 283.5c0 3.4 4 9.5 8.4 12.9 6.1 4.6 19.7 10.4 31.7 13.5 16.9 4.3 32.1 6.2 53.4 6.8l19 .5-7-7.1c-6.8-6.9-7.1-7.1-12-7.1-18.9 0-55.1-7.9-80.6-17.6C62.5 283 57 281 56.6 281c-.3 0-.6 1.1-.6 2.5zM262 283.4c-5.3 2.8-25 9.7-36 12.6l-11.4 2.9-7.8 7.8c-4.2 4.2-7.6 7.9-7.4 8.1.9.8 24.4-4.1 33.4-6.9 16.4-5.3 26.7-11.4 30.8-18.5 2.4-4 3.1-7.4 1.7-7.4-.5.1-1.9.7-3.3 1.4z"/></g></svg>
\ No newline at end of file diff --git a/templates/repo/migrate/gitbucket.tmpl b/templates/repo/migrate/gitbucket.tmpl new file mode 100644 index 0000000000..b554a3a756 --- /dev/null +++ b/templates/repo/migrate/gitbucket.tmpl @@ -0,0 +1,129 @@ +{{template "base/head" .}} +<div class="page-content repository new migrate"> + <div class="ui middle very relaxed page grid"> + <div class="column"> + <form class="ui form" action="{{.Link}}" method="post"> + {{.CsrfTokenHtml}} + <h3 class="ui top attached header"> + {{.i18n.Tr "repo.migrate.migrate" .service.Title}} + <input id="service_type" type="hidden" name="service" value="{{.service}}"> + </h3> + <div class="ui attached segment"> + {{template "base/alert" .}} + <div class="inline required field {{if .Err_CloneAddr}}error{{end}}"> + <label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label> + <input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required> + <span class="help"> + {{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} + </span> + </div> + + <div class="inline field {{if .Err_Auth}}error{{end}}"> + <label for="auth_username">{{.i18n.Tr "username"}}</label> + <input id="auth_username" name="auth_username" value="{{.auth_username}}" {{if not .auth_username}}data-need-clear="true"{{end}}> + </div> + <input class="fake" type="password"> + <div class="inline field {{if .Err_Auth}}error{{end}}"> + <label for="auth_password">{{.i18n.Tr "password"}}</label> + <input id="auth_password" name="auth_password" type="password" value="{{.auth_password}}"> + </div> + + {{template "repo/migrate/options" .}} + + <span class="help">{{.i18n.Tr "repo.migrate.migrate_items_options"}}</span> + <div id="migrate_items"> + <div class="inline field"> + <label>{{.i18n.Tr "repo.migrate_items"}}</label> + <div class="ui checkbox"> + <input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_wiki" | Safe}}</label> + </div> + <div class="ui checkbox"> + <input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_milestones" | Safe}}</label> + </div> + </div> + <div class="inline field"> + <label></label> + <div class="ui checkbox"> + <input name="labels" type="checkbox" {{if .labels}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_labels" | Safe}}</label> + </div> + <div class="ui checkbox"> + <input name="issues" type="checkbox" {{if .issues}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_issues" | Safe}}</label> + </div> + </div> + <div class="inline field"> + <label></label> + <div class="ui checkbox"> + <input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_pullrequests" | Safe}}</label> + </div> + <div class="ui checkbox"> + <input name="releases" type="checkbox" {{if .releases}}checked{{end}}> + <label>{{.i18n.Tr "repo.migrate_items_releases" | Safe}}</label> + </div> + </div> + </div> + + <div class="ui divider"></div> + + <div class="inline required field {{if .Err_Owner}}error{{end}}"> + <label>{{.i18n.Tr "repo.owner"}}</label> + <div class="ui selection owner dropdown"> + <input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required> + <span class="text truncated-item-container" title="{{.ContextUser.Name}}"> + {{avatar .ContextUser 28 "mini"}} + <span class="truncated-item-name">{{.ContextUser.ShortName 40}}</span> + </span> + {{svg "octicon-triangle-down" 14 "dropdown icon"}} + <div class="menu" title="{{.SignedUser.Name}}"> + <div class="item truncated-item-container" data-value="{{.SignedUser.ID}}"> + {{avatar .SignedUser 28 "mini"}} + <span class="truncated-item-name">{{.SignedUser.ShortName 40}}</span> + </div> + {{range .Orgs}} + <div class="item truncated-item-container" data-value="{{.ID}}" title="{{.Name}}"> + {{avatar . 28 "mini"}} + <span class="truncated-item-name">{{.ShortName 40}}</span> + </div> + {{end}} + </div> + </div> + </div> + + <div class="inline required field {{if .Err_RepoName}}error{{end}}"> + <label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> + <input id="repo_name" name="repo_name" value="{{.repo_name}}" required> + </div> + <div class="inline field"> + <label>{{.i18n.Tr "repo.visibility"}}</label> + <div class="ui checkbox"> + {{if .IsForcedPrivate}} + <input name="private" type="checkbox" checked readonly> + <label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label> + {{else}} + <input name="private" type="checkbox" {{if .private}}checked{{end}}> + <label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label> + {{end}} + </div> + </div> + <div class="inline field {{if .Err_Description}}error{{end}}"> + <label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> + <textarea id="description" name="description">{{.description}}</textarea> + </div> + + <div class="inline field"> + <label></label> + <button class="ui green button"> + {{.i18n.Tr "repo.migrate_repo"}} + </button> + <a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> + </div> + </div> + </form> + </div> + </div> +</div> +{{template "base/footer" .}} diff --git a/web_src/svg/gitea-gitbucket.svg b/web_src/svg/gitea-gitbucket.svg new file mode 100644 index 0000000000..24da154968 --- /dev/null +++ b/web_src/svg/gitea-gitbucket.svg @@ -0,0 +1,39 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" + width="316.000000pt" height="329.000000pt" viewBox="0 0 316.000000 329.000000" + preserveAspectRatio="xMidYMid meet"> +<metadata> +Created by potrace 1.14, written by Peter Selinger 2001-2017 +</metadata> +<g transform="translate(0.000000,329.000000) scale(0.100000,-0.100000)" +fill="#303030" stroke="none"> +<path d="M1230 3079 c-448 -28 -840 -128 -971 -246 -50 -45 -50 -71 0 -116 +158 -142 707 -256 1241 -257 l106 0 54 56 c118 121 213 124 326 12 l52 -50 +133 17 c338 42 615 127 718 220 53 48 53 72 0 120 -101 91 -391 181 -704 219 +-283 34 -656 44 -955 25z"/> +<path d="M232 2484 c4 -16 70 -429 148 -919 79 -490 147 -895 152 -902 17 -21 +258 -114 416 -159 130 -37 351 -84 400 -84 6 0 12 6 12 13 0 6 -174 185 -386 +397 -395 394 -424 428 -424 500 0 72 30 107 383 459 301 300 348 343 366 335 +11 -5 87 -74 170 -152 l151 -144 0 -59 c0 -73 24 -124 77 -167 l38 -30 0 -309 +0 -309 -38 -34 c-102 -89 -102 -229 -1 -307 31 -23 49 -28 108 -31 82 -4 115 +11 162 73 22 30 29 51 32 100 4 65 -2 83 -53 154 l-25 34 0 266 c0 267 3 311 +23 311 5 0 54 -44 109 -97 96 -95 99 -100 108 -157 17 -103 89 -166 190 -166 +76 0 135 39 174 117 32 64 16 143 -43 206 -41 44 -73 57 -149 57 l-68 0 -127 +121 c-107 101 -127 126 -132 157 -12 72 -16 82 -47 117 -39 45 -77 65 -122 65 +-19 0 -45 4 -58 9 -13 5 -99 82 -193 170 l-170 160 -71 1 c-106 0 -360 27 +-524 55 -228 40 -385 86 -579 172 -11 5 -13 0 -9 -23z"/> +<path d="M2785 2454 c-86 -36 -280 -88 -425 -114 -69 -12 -129 -26 -135 -31 +-6 -6 93 -112 275 -294 156 -156 285 -283 287 -281 2 2 19 158 38 347 19 189 +37 356 40 372 6 34 -2 34 -80 1z"/> +<path d="M2552 697 c-78 -78 -142 -146 -142 -150 0 -4 7 -7 16 -7 22 0 230 89 +242 103 9 11 35 187 29 193 -2 2 -67 -61 -145 -139z"/> +<path d="M560 455 c0 -34 40 -95 84 -129 61 -46 197 -104 317 -135 169 -43 +321 -62 534 -68 l190 -5 -70 71 c-68 69 -71 71 -120 71 -189 0 -551 79 -806 +176 -64 24 -119 44 -123 44 -3 0 -6 -11 -6 -25z"/> +<path d="M2620 456 c-53 -28 -250 -97 -360 -126 l-114 -29 -78 -78 c-42 -42 +-76 -79 -74 -81 9 -8 244 41 334 69 164 53 267 114 308 185 24 40 31 74 17 74 +-5 -1 -19 -7 -33 -14z"/> +</g> +</svg>
\ No newline at end of file |