2024-08-07 01:37:55 +02:00
|
|
|
package main
|
|
|
|
|
2024-09-10 18:24:41 +02:00
|
|
|
/*
|
|
|
|
* This file is part of Autogits.
|
|
|
|
*
|
|
|
|
* Copyright © 2024 SUSE LLC
|
|
|
|
*
|
|
|
|
* Autogits 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 2 of the License, or (at your option) any later
|
|
|
|
* version.
|
|
|
|
*
|
|
|
|
* Autogits 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
|
|
|
|
* Foobar. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2024-08-07 01:37:55 +02:00
|
|
|
import (
|
|
|
|
"errors"
|
2024-08-09 17:53:18 +02:00
|
|
|
"flag"
|
2024-09-16 13:10:25 +02:00
|
|
|
"log"
|
2024-08-07 01:37:55 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2024-08-11 23:27:34 +02:00
|
|
|
"path"
|
2024-08-09 17:53:18 +02:00
|
|
|
"slices"
|
2024-08-07 01:37:55 +02:00
|
|
|
"strings"
|
2024-08-13 09:28:04 +02:00
|
|
|
"time"
|
2024-08-07 01:37:55 +02:00
|
|
|
|
|
|
|
transport "github.com/go-openapi/runtime/client"
|
|
|
|
"src.opensuse.org/autogits/common"
|
|
|
|
apiclient "src.opensuse.org/autogits/common/gitea-generated/client"
|
2024-08-09 17:53:18 +02:00
|
|
|
"src.opensuse.org/autogits/common/gitea-generated/client/organization"
|
2024-08-07 01:37:55 +02:00
|
|
|
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
|
|
|
|
"src.opensuse.org/autogits/common/gitea-generated/models"
|
|
|
|
)
|
|
|
|
|
|
|
|
const commandLineHelp = `
|
|
|
|
SYNTAX
|
|
|
|
devel-importer <obs-project> <gitea-org>`
|
|
|
|
|
|
|
|
func printHelp() {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(commandLineHelp)
|
2024-08-07 01:37:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func runObsCommand(args ...string) ([]byte, error) {
|
|
|
|
cmd := exec.Command("osc", args...)
|
|
|
|
return cmd.Output()
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2024-08-09 17:53:18 +02:00
|
|
|
if err := common.RequireGiteaSecretToken(); err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Missing GITEA_TOKEN")
|
2024-08-07 01:37:55 +02:00
|
|
|
}
|
|
|
|
|
2024-08-09 17:53:18 +02:00
|
|
|
if err := common.RequireObsSecretToken(); err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Missing OBS_PASSWORD and/or OBS_USER")
|
2024-08-09 17:53:18 +02:00
|
|
|
}
|
|
|
|
|
2024-09-16 13:10:25 +02:00
|
|
|
git, err := common.CreateGitHandler("Autogits - Devel Importer", "not.exist", "devel-importer")
|
|
|
|
if err != nil {
|
|
|
|
log.Panicln("Failed to allocate git handler. Err:", err)
|
2024-08-09 17:53:18 +02:00
|
|
|
}
|
|
|
|
|
2024-08-11 23:27:34 +02:00
|
|
|
purgeOnly := flag.Bool("purge", false, "Purges package repositories. Use with caution")
|
|
|
|
// revNew := flag.Int("nrevs", 20, "Number of new revisions in factory branch. Indicator of broken history import")
|
2024-08-09 17:53:18 +02:00
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if flag.NArg() != 2 {
|
2024-08-07 01:37:55 +02:00
|
|
|
printHelp()
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2024-08-09 17:56:39 +02:00
|
|
|
prj := flag.Arg(0)
|
|
|
|
org := flag.Arg(1)
|
2024-08-07 01:37:55 +02:00
|
|
|
packageList, err := runObsCommand("ls", prj)
|
|
|
|
|
|
|
|
if err != nil {
|
2024-09-16 13:10:25 +02:00
|
|
|
log.Printf("Cannot list packages for project '%s'. Err: %v\n", prj, err)
|
2024-08-07 01:37:55 +02:00
|
|
|
}
|
|
|
|
packages := strings.Split(strings.TrimSpace(string(packageList)), "\n")
|
2024-09-16 16:05:46 +02:00
|
|
|
slices.Sort(packages)
|
|
|
|
for i := range packages {
|
|
|
|
packages[i] = strings.Split(packages[i], ":")[0]
|
|
|
|
}
|
|
|
|
packages = slices.Compact(packages)
|
|
|
|
|
|
|
|
log.Printf("%d packages: %s\n\n", len(packages), strings.Join(packages, " "))
|
2024-08-07 01:37:55 +02:00
|
|
|
|
|
|
|
r := transport.New("src.opensuse.org", apiclient.DefaultBasePath, [](string){"https"})
|
|
|
|
r.DefaultAuthentication = transport.BearerToken(common.GetGiteaToken())
|
2024-08-09 17:53:18 +02:00
|
|
|
// r.SetDebug(true)
|
2024-08-07 01:37:55 +02:00
|
|
|
client := apiclient.New(r, nil)
|
|
|
|
|
2024-08-11 23:27:34 +02:00
|
|
|
if *purgeOnly {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println("Purging repositories...")
|
2024-08-09 17:53:18 +02:00
|
|
|
for _, pkg := range packages {
|
|
|
|
client.Repository.RepoDelete(repository.NewRepoDeleteParams().WithOwner(org).WithRepo(pkg), r.DefaultAuthentication)
|
|
|
|
}
|
|
|
|
os.Exit(10)
|
|
|
|
}
|
|
|
|
|
|
|
|
oldPackageRepos := make([]*models.Repository, 0, len(packages))
|
|
|
|
newPackages := make([]string, 0, len(packages))
|
2024-08-07 01:37:55 +02:00
|
|
|
for _, pkg := range packages {
|
2024-09-16 16:05:46 +02:00
|
|
|
src_pkg_name := strings.Split(pkg, ":")
|
2024-08-07 01:37:55 +02:00
|
|
|
repo, err := client.Repository.RepoGet(
|
|
|
|
repository.NewRepoGetParams().
|
2024-09-16 16:05:46 +02:00
|
|
|
WithDefaults().WithOwner("pool").WithRepo(src_pkg_name[0]),
|
2024-08-07 01:37:55 +02:00
|
|
|
r.DefaultAuthentication)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if !errors.Is(err, &repository.RepoGetNotFound{}) {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln(err)
|
2024-08-07 01:37:55 +02:00
|
|
|
}
|
|
|
|
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println("Cannot find src package:", src_pkg_name)
|
|
|
|
newPackages = append(newPackages, src_pkg_name[0])
|
2024-08-07 01:37:55 +02:00
|
|
|
} else {
|
2024-08-09 17:53:18 +02:00
|
|
|
oldPackageRepos = append(oldPackageRepos, repo.Payload)
|
|
|
|
}
|
|
|
|
}
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println("Num repos found:", len(oldPackageRepos))
|
2024-08-09 17:53:18 +02:00
|
|
|
|
|
|
|
// fork packags from pool
|
2024-08-11 23:27:34 +02:00
|
|
|
cmd := exec.Command("./git-importer", func(r []*models.Repository) []string {
|
|
|
|
ret := make([]string, len(r))
|
|
|
|
for i := range r {
|
|
|
|
ret[i] = r[i].Name
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}(oldPackageRepos)...)
|
|
|
|
out, err := cmd.CombinedOutput()
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(string(out))
|
2024-08-11 23:27:34 +02:00
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println("Error returned by importer.", err)
|
2024-08-11 23:27:34 +02:00
|
|
|
}
|
2024-08-13 09:28:04 +02:00
|
|
|
|
|
|
|
reposOK := true
|
2024-08-09 17:53:18 +02:00
|
|
|
for i := range oldPackageRepos {
|
|
|
|
pkg := oldPackageRepos[i]
|
2024-08-11 23:27:34 +02:00
|
|
|
dir := path.Join("repos", pkg.Name)
|
2024-08-09 17:53:18 +02:00
|
|
|
|
2024-08-11 23:27:34 +02:00
|
|
|
// add remote repos
|
2024-09-16 13:10:25 +02:00
|
|
|
out := git.GitExecWithOutputOrPanic(dir, "remote", "show", "-n")
|
2024-08-11 23:27:34 +02:00
|
|
|
if !slices.Contains(strings.Split(out, "\n"), "factory") {
|
2024-09-16 13:10:25 +02:00
|
|
|
out := git.GitExecWithOutputOrPanic(dir, "remote", "add", "factory", pkg.CloneURL)
|
2024-08-11 23:27:34 +02:00
|
|
|
if len(strings.TrimSpace(out)) > 1 {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(out)
|
2024-08-11 23:27:34 +02:00
|
|
|
}
|
2024-08-09 17:53:18 +02:00
|
|
|
}
|
2024-08-11 23:27:34 +02:00
|
|
|
if !slices.Contains(strings.Split(out, "\n"), "rpm") {
|
2024-09-16 13:10:25 +02:00
|
|
|
out := git.GitExecWithOutputOrPanic(dir, "remote", "add", "rpm", "https://src.opensuse.org/rpm/"+pkg.Name+".git")
|
2024-08-11 23:27:34 +02:00
|
|
|
if len(strings.TrimSpace(out)) > 1 {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(out)
|
2024-08-09 17:53:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-16 13:10:25 +02:00
|
|
|
out = git.GitExecWithOutputOrPanic(dir, "fetch", "--multiple", "factory", "rpm")
|
2024-08-11 23:27:34 +02:00
|
|
|
if len(strings.TrimSpace(out)) > 1 {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(out)
|
2024-08-11 23:27:34 +02:00
|
|
|
}
|
2024-08-09 17:53:18 +02:00
|
|
|
|
2024-08-11 23:27:34 +02:00
|
|
|
// check that nothing is broken with the update
|
2024-09-16 13:10:25 +02:00
|
|
|
out = git.GitExecWithOutputOrPanic(dir, "rev-list", "factory")
|
2024-08-11 23:27:34 +02:00
|
|
|
old_revs := strings.Split(out, "\n")
|
2024-09-16 13:10:25 +02:00
|
|
|
out = git.GitExecWithOutputOrPanic(dir, "rev-list", "factory", "^factory/factory")
|
2024-08-11 23:27:34 +02:00
|
|
|
added_revs := strings.Split(out, "\n")
|
2024-09-16 13:10:25 +02:00
|
|
|
out = git.GitExecWithOutputOrPanic(dir, "rev-list", "factory", "^rpm/factory")
|
2024-08-11 23:27:34 +02:00
|
|
|
added_rpm_revs := strings.Split(out, "\n")
|
|
|
|
if len(added_revs) == len(old_revs) && len(added_rpm_revs) == len(old_revs) {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Printf("Something is wrong with rev-ist for (len %d): %s\n", len(added_revs), pkg.Name)
|
2024-08-13 09:28:04 +02:00
|
|
|
reposOK = false
|
2024-08-11 23:27:34 +02:00
|
|
|
}
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
args := make([]string, 2, len(newPackages)+2)
|
|
|
|
args[0] = "-p"
|
|
|
|
args[1] = prj
|
|
|
|
args = append(args, newPackages...)
|
|
|
|
cmd = exec.Command("./git-importer", args...)
|
|
|
|
out, err = cmd.CombinedOutput()
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println(out)
|
2024-08-13 09:28:04 +02:00
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Error returned by importer.", err)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !reposOK {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Println("aborting import due to broken repos above...")
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-08-11 23:27:34 +02:00
|
|
|
|
2024-08-13 09:28:04 +02:00
|
|
|
for _, pkg := range oldPackageRepos {
|
2024-08-11 23:27:34 +02:00
|
|
|
// update package
|
2024-08-13 09:28:04 +02:00
|
|
|
fork, err := client.Repository.CreateFork(repository.NewCreateForkParams().
|
|
|
|
WithOwner("pool").
|
|
|
|
WithRepo(pkg.Name).
|
|
|
|
WithBody(&models.CreateForkOption{
|
|
|
|
Organization: org,
|
|
|
|
}), r.DefaultAuthentication)
|
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Error while trying to create fork from pool/", pkg.Name, err)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-08-11 23:27:34 +02:00
|
|
|
|
2024-08-13 09:28:04 +02:00
|
|
|
repo := fork.Payload
|
|
|
|
repoList, err := client.Repository.RepoListBranches(
|
|
|
|
repository.NewRepoListBranchesParams().WithOwner(org).WithRepo(pkg.Name),
|
|
|
|
r.DefaultAuthentication,
|
|
|
|
)
|
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Cannot get list of branches for forked repo:", org, "/", pkg.Name)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
|
|
|
priorityBranches := []string{
|
|
|
|
"devel",
|
|
|
|
"factory",
|
|
|
|
}
|
|
|
|
idx := len(priorityBranches)
|
|
|
|
for _, branch := range repoList.Payload {
|
|
|
|
i := slices.Index(priorityBranches, branch.Name)
|
|
|
|
if i > -1 && i < idx {
|
|
|
|
idx = i
|
2024-08-11 23:27:34 +02:00
|
|
|
}
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-08-11 23:27:34 +02:00
|
|
|
|
2024-08-13 09:28:04 +02:00
|
|
|
branchName := priorityBranches[idx]
|
|
|
|
dir := path.Join("repos", pkg.Name)
|
2024-09-16 13:10:25 +02:00
|
|
|
remotes := git.GitExecWithOutputOrPanic(dir, "remote", "show")
|
2024-08-13 09:28:04 +02:00
|
|
|
if !slices.Contains(strings.Split(remotes, "\n"), "devel") {
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "remote", "add", "devel", repo.SSHURL)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "branch", "main", "-f", branchName)
|
2024-08-13 09:28:04 +02:00
|
|
|
time.Sleep(2 * time.Second)
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "push", "devel", "main")
|
2024-08-13 09:28:04 +02:00
|
|
|
time.Sleep(2 * time.Second)
|
2024-08-11 23:27:34 +02:00
|
|
|
|
2024-08-13 09:28:04 +02:00
|
|
|
_, err = client.Repository.RepoEdit(repository.NewRepoEditParams().WithOwner(org).WithRepo(repo.Name).WithBody(&models.EditRepoOption{
|
|
|
|
DefaultBranch: "main",
|
|
|
|
DefaultMergeStyle: "fast-forward-only",
|
|
|
|
}), r.DefaultAuthentication)
|
|
|
|
|
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Failed to set default branch for package fork:", repo.Owner.UserName, "/", repo.Name, err)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-08-09 17:53:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, pkg := range newPackages {
|
2024-08-13 09:28:04 +02:00
|
|
|
ret, err := client.Organization.CreateOrgRepo(organization.NewCreateOrgRepoParams().WithOrg(org).WithBody(
|
|
|
|
&models.CreateRepoOption{
|
|
|
|
ObjectFormatName: "sha256",
|
|
|
|
AutoInit: false,
|
|
|
|
Name: &pkg,
|
|
|
|
DefaultBranch: "main",
|
|
|
|
}),
|
|
|
|
r.DefaultAuthentication,
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Error creating new package repository:", pkg, err)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
repo := ret.Payload
|
|
|
|
dir := path.Join("repos", pkg)
|
2024-09-16 13:10:25 +02:00
|
|
|
remotes := git.GitExecWithOutputOrPanic(dir, "remote", "show")
|
2024-08-13 09:28:04 +02:00
|
|
|
if !slices.Contains(strings.Split(remotes, "\n"), "devel") {
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "remote", "add", "devel", repo.SSHURL)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "branch", "main", "-f", "factory")
|
2024-08-13 09:28:04 +02:00
|
|
|
time.Sleep(2 * time.Second)
|
2024-09-16 13:10:25 +02:00
|
|
|
git.GitExecOrPanic(dir, "push", "devel", "main")
|
2024-08-13 09:28:04 +02:00
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
|
|
|
|
_, err = client.Repository.RepoEdit(repository.NewRepoEditParams().WithOwner(org).WithRepo(pkg).WithBody(&models.EditRepoOption{
|
|
|
|
DefaultBranch: "main",
|
|
|
|
DefaultMergeStyle: "fast-forward-only",
|
|
|
|
}), r.DefaultAuthentication)
|
|
|
|
|
|
|
|
if err != nil {
|
2024-09-16 16:05:46 +02:00
|
|
|
log.Panicln("Failed to set default branch for package fork:", repo.Owner.UserName, "/", repo.Name, err)
|
2024-08-13 09:28:04 +02:00
|
|
|
}
|
2024-08-07 01:37:55 +02:00
|
|
|
}
|
|
|
|
}
|