forked from importers/git-importer
Compare commits
49 Commits
main
...
add_old_st
Author | SHA1 | Date | |
---|---|---|---|
|
716db10adf | ||
|
4692d47120 | ||
|
d311d54f26 | ||
|
dddc54ab1c | ||
|
4d1ca8d882 | ||
|
7861a7e9b0 | ||
|
f5b29886ae | ||
|
d1a8a3288d | ||
|
9f6c8f62e7 | ||
|
3e1fbaa1c3 | ||
|
e1b32999f0 | ||
|
86490b51dd | ||
|
da5de04171 | ||
|
be8fb2ab94 | ||
|
9e895e34b6 | ||
|
5e495dbd95 | ||
|
5ae02a413d | ||
|
f1457e8f8e | ||
|
9114c2fff8 | ||
|
834cf61634 | ||
|
a294c0f670 | ||
|
7bc4d6c8b1 | ||
|
bd5bd5a444 | ||
|
4e1d5b42ca | ||
|
0bcc0183c9 | ||
|
7f88e0cc5c | ||
|
4cc0a23d4e | ||
|
a457a16a50 | ||
|
60ced896a3 | ||
|
33a5733cb9 | ||
|
d21ce571f5 | ||
|
ab38332642 | ||
|
651bd94771 | ||
|
dd5e26b779 | ||
|
f2019db8ff | ||
|
ef7755c771 | ||
|
6b26f8ff96 | ||
|
ed4b7367eb | ||
|
f5b3e42165 | ||
6dd3cf3eba | |||
8aed76e52a | |||
639096b548 | |||
7678967ae0 | |||
|
74f5cd901e | ||
|
1c54a74ecd | ||
|
c2294d6200 | ||
|
ba7436f10c | ||
|
75f9f56a57 | ||
|
172242891d |
12
Makefile
12
Makefile
@@ -1,7 +1,13 @@
|
||||
all:
|
||||
isort -rc .
|
||||
autoflake -r --in-place --remove-unused-variables .
|
||||
black .
|
||||
isort *.py lib/*py tests/*py
|
||||
autoflake --in-place --remove-unused-variables *.py lib/*py tests/*py
|
||||
black *.py lib/*py tests/*py
|
||||
|
||||
test:
|
||||
python3 -m unittest -v tests/*.py
|
||||
|
||||
update-packages:
|
||||
f=$$(mktemp) ;\
|
||||
osc api /source/openSUSE:Factory?view=info | grep -v lsrcmd5 | grep srcmd5= | sed -e 's,.*package=",,; s,".*,,' | grep -v : > $$f ;\
|
||||
echo _project >> $$f ;\
|
||||
mv $$f packages
|
||||
|
@@ -7,6 +7,8 @@ import sys
|
||||
|
||||
import osc.core
|
||||
|
||||
from lib.db import DB
|
||||
from lib.db_revision import DBRevision
|
||||
from lib.git_exporter import GitExporter
|
||||
from lib.importer import Importer
|
||||
from lib.test_exporter import TestExporter
|
||||
@@ -42,16 +44,30 @@ PROJECTS = [
|
||||
]
|
||||
|
||||
|
||||
def export_package(package, repodir, cachedir, gc):
|
||||
exporter = GitExporter(URL_OBS, "openSUSE:Factory", package, repodir, cachedir)
|
||||
exporter.set_gc_interval(gc)
|
||||
exporter.export_as_git()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="OBS history importer into git")
|
||||
parser.add_argument("package", help="OBS package name")
|
||||
parser.add_argument("packages", help="OBS package names", nargs="*")
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--repodir",
|
||||
required=False,
|
||||
default=pathlib.Path("repos"),
|
||||
type=pathlib.Path,
|
||||
help="Local git repository directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--cachedir",
|
||||
required=False,
|
||||
type=pathlib.Path,
|
||||
help="Local cache directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-g",
|
||||
"--gc",
|
||||
@@ -86,18 +102,70 @@ def main():
|
||||
requests_log.setLevel(logging.DEBUG)
|
||||
requests_log.propagate = True
|
||||
|
||||
def check_old_package(db: DB, dir: pathlib.Path):
|
||||
md5file = dir / "MD5SUMS"
|
||||
print(md5file)
|
||||
valid_revisions = None
|
||||
with open(md5file, "rb") as f:
|
||||
for line in f.readlines():
|
||||
try:
|
||||
md5, file = line.decode("utf-8").strip().split(" ")
|
||||
except UnicodeDecodeError:
|
||||
logging.error(f"Corrupt MD5 file: {md5file}")
|
||||
return
|
||||
if file == "ready":
|
||||
continue
|
||||
if len(md5) != 32:
|
||||
logging.error(f"Corrupt MD5 file: {md5file}")
|
||||
return
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT revision_id FROM files WHERE md5=%s AND name=%s",
|
||||
(md5, file),
|
||||
)
|
||||
nrevs = set([row[0] for row in cur.fetchall()])
|
||||
if valid_revisions is None:
|
||||
valid_revisions = nrevs
|
||||
else:
|
||||
valid_revisions = valid_revisions & nrevs
|
||||
if not valid_revisions:
|
||||
break
|
||||
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * FROM revisions WHERE id = ANY(%s) AND project=%s",
|
||||
(list(valid_revisions), "openSUSE:Factory"),
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
r = DBRevision(db, row)
|
||||
print("Valid", r, r.files_hash)
|
||||
return True
|
||||
|
||||
if False:
|
||||
import os
|
||||
|
||||
db = DB()
|
||||
basedir = pathlib.Path(
|
||||
f"/mounts/work/SAVE/oldpackages/stable/{args.packages[0]}"
|
||||
)
|
||||
for subdir in sorted(os.listdir(basedir)):
|
||||
if check_old_package(db, basedir / subdir):
|
||||
break
|
||||
|
||||
if args.export:
|
||||
TestExporter(args.package).run()
|
||||
if len(args.packages) != 1:
|
||||
print("Can only export one package")
|
||||
sys.exit(1)
|
||||
TestExporter(args.packages[0]).run()
|
||||
return
|
||||
|
||||
if not args.repodir:
|
||||
args.repodir = pathlib.Path("repos/" + args.package)
|
||||
if not args.cachedir:
|
||||
args.cachedir = pathlib.Path("~/.cache/git-import/").expanduser()
|
||||
|
||||
importer = Importer(URL_OBS, "openSUSE:Factory", args.package)
|
||||
importer = Importer(URL_OBS, "openSUSE:Factory", args.packages)
|
||||
importer.import_into_db()
|
||||
exporter = GitExporter(URL_OBS, "openSUSE:Factory", args.package, args.repodir)
|
||||
exporter.set_gc_interval(args.gc)
|
||||
exporter.export_as_git()
|
||||
for package in args.packages:
|
||||
export_package(package, args.repodir, args.cachedir, args.gc)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -1,6 +1,10 @@
|
||||
class AbstractWalker:
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class AbstractWalker(ABC):
|
||||
"""Just a duck type, most likely not needed by python, but I
|
||||
find interface classes preferable (java school)"""
|
||||
|
||||
@abstractmethod
|
||||
def call(self, node, is_source):
|
||||
pass
|
||||
|
@@ -25,18 +25,28 @@ BINARY = {
|
||||
".zst",
|
||||
}
|
||||
|
||||
TEXT_MIMETYPES = {
|
||||
"message/rfc822",
|
||||
"application/pgp-keys",
|
||||
"application/x-gnupg-keyring",
|
||||
}
|
||||
|
||||
|
||||
def is_text_mimetype(mimetype):
|
||||
if mimetype.startswith("text/"):
|
||||
return True
|
||||
|
||||
return mimetype.split(";")[0] in TEXT_MIMETYPES
|
||||
|
||||
|
||||
def is_binary_or_large(filename, size):
|
||||
"""Decide if is a binary file based on the extension or size"""
|
||||
binary_suffix = BINARY
|
||||
non_binary_suffix = {
|
||||
".1",
|
||||
".8",
|
||||
".SUSE",
|
||||
".asc",
|
||||
".c",
|
||||
".cabal",
|
||||
".cfg",
|
||||
".changes",
|
||||
".conf",
|
||||
".desktop",
|
||||
|
45
lib/db.py
45
lib/db.py
@@ -215,6 +215,51 @@ class DB:
|
||||
"CREATE INDEX ON linked_revs(considered)",
|
||||
"UPDATE scheme SET version=20",
|
||||
)
|
||||
schemes[21] = (
|
||||
"ALTER TABLE revisions ADD COLUMN api_url VARCHAR(40)",
|
||||
"UPDATE revisions SET api_url='https://api.opensuse.org'",
|
||||
"ALTER TABLE revisions ALTER COLUMN api_url SET NOT NULL",
|
||||
"UPDATE scheme SET version=21",
|
||||
)
|
||||
schemes[22] = (
|
||||
"""DROP TABLE IF EXISTS lfs_oids""",
|
||||
"""
|
||||
CREATE TABLE lfs_oids (
|
||||
id SERIAL PRIMARY KEY,
|
||||
project VARCHAR(255) NOT NULL,
|
||||
package VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
rev VARCHAR(40) NOT NULL,
|
||||
sha256 VARCHAR(70) NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
mimetype VARCHAR(255) NOT NULL,
|
||||
file_md5 VARCHAR(40) NOT NULL
|
||||
)
|
||||
""",
|
||||
"CREATE UNIQUE INDEX ON lfs_oids (sha256,size)",
|
||||
"CREATE INDEX ON revisions(package)",
|
||||
"""DROP TABLE IF EXISTS text_files""",
|
||||
"""
|
||||
CREATE TABLE text_files (
|
||||
id SERIAL PRIMARY KEY,
|
||||
package VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL
|
||||
)
|
||||
""",
|
||||
"CREATE UNIQUE INDEX ON text_files (package,filename)",
|
||||
"""DROP TABLE IF EXISTS lfs_oid_in_package""",
|
||||
"""
|
||||
CREATE TABLE lfs_oid_in_package (
|
||||
id SERIAL PRIMARY KEY,
|
||||
lfs_oid_id INTEGER NOT NULL,
|
||||
package VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL
|
||||
)
|
||||
""",
|
||||
"CREATE INDEX ON text_files(package)",
|
||||
"CREATE INDEX ON lfs_oid_in_package(package)",
|
||||
"UPDATE scheme SET version=22",
|
||||
)
|
||||
schema_version = self.schema_version()
|
||||
if (schema_version + 1) not in schemes:
|
||||
return
|
||||
|
@@ -1,15 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from hashlib import md5
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from lib.db import DB
|
||||
from lib.obs_revision import OBSRevision
|
||||
from lib.request import Request
|
||||
|
||||
|
||||
class DBRevision:
|
||||
def __init__(self, row):
|
||||
def __init__(self, db: DB, row: tuple):
|
||||
# need to stay in sync with the schema creation in db.py
|
||||
(
|
||||
self.dbid,
|
||||
@@ -25,9 +26,12 @@ class DBRevision:
|
||||
self.request_number,
|
||||
self.request_id,
|
||||
self.files_hash,
|
||||
self.api_url,
|
||||
) = row
|
||||
self.rev = float(self.rev)
|
||||
self._files = None
|
||||
self.db = db
|
||||
self.git_commit = None
|
||||
|
||||
def short_string(self):
|
||||
return f"{self.project}/{self.package}/{self.rev}"
|
||||
@@ -48,7 +52,29 @@ class DBRevision:
|
||||
return self.package < other.package
|
||||
return self.rev < other.rev
|
||||
|
||||
def as_dict(self, db):
|
||||
def request_accept_message(self):
|
||||
request = Request.find(self.db, self.request_id)
|
||||
msg = f"Accepting request {request.number} from {request.source_project}\n\n"
|
||||
msg += self.comment.strip()
|
||||
url = self.api_url.replace("api.", "build.")
|
||||
msg += f"\n\nOBS-URL: {url}/request/show/{self.request_number}"
|
||||
return msg
|
||||
|
||||
def git_commit_message(self):
|
||||
msg = ""
|
||||
if self.request_id:
|
||||
msg = self.request_accept_message()
|
||||
else:
|
||||
msg = self.comment.strip() + "\n"
|
||||
url = self.api_url.replace("api.", "build.")
|
||||
if self.rev == int(self.rev):
|
||||
# do not link to fake revisions
|
||||
msg += f"\nOBS-URL: {url}/package/show/{self.project}/{self.package}?expand=0&rev={int(self.rev)}"
|
||||
else:
|
||||
msg += f"\nOBS-URL: {url}/package/show/{self.project}/{self.package}?expand=0&rev={self.expanded_srcmd5}"
|
||||
return msg
|
||||
|
||||
def as_dict(self):
|
||||
"""Return a dict we can put into YAML for test cases"""
|
||||
ret = {
|
||||
"project": self.project,
|
||||
@@ -60,26 +86,27 @@ class DBRevision:
|
||||
"comment": self.comment,
|
||||
"broken": self.broken,
|
||||
"expanded_srcmd5": self.expanded_srcmd5,
|
||||
"api_url": self.api_url,
|
||||
"files_hash": self.files_hash,
|
||||
"files": self.files_list(db),
|
||||
"files": self.files_list(),
|
||||
}
|
||||
if self.request_id:
|
||||
ret["request"] = Request.find(db, self.request_id).as_dict()
|
||||
ret["request"] = Request.find(self.db, self.request_id).as_dict()
|
||||
return ret
|
||||
|
||||
def links_to(self, db, project, package):
|
||||
with db.cursor() as cur:
|
||||
def links_to(self, project: str, package: str) -> None:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"INSERT INTO links (revision_id, project, package) VALUES (%s,%s,%s)",
|
||||
(self.dbid, project, package),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def import_obs_rev(cls, db, revision):
|
||||
@staticmethod
|
||||
def import_obs_rev(db: DB, revision: OBSRevision):
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""INSERT INTO revisions (project, package, rev, unexpanded_srcmd5, commit_time, userid, comment, request_number)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
"""INSERT INTO revisions (project, package, rev, unexpanded_srcmd5, commit_time, userid, comment, request_number, api_url)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(
|
||||
revision.project,
|
||||
revision.package,
|
||||
@@ -89,12 +116,17 @@ class DBRevision:
|
||||
revision.userid,
|
||||
revision.comment,
|
||||
revision.request_number,
|
||||
revision.obs.url,
|
||||
),
|
||||
)
|
||||
return cls.fetch_revision(db, revision.project, revision.package, revision.rev)
|
||||
return DBRevision.fetch_revision(
|
||||
db, revision.project, revision.package, revision.rev
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def fetch_revision(db, project, package, rev):
|
||||
"""Technically we would need the api_url as well, but we assume projects are unique
|
||||
(e.g. not importing SLE from obs)"""
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * FROM revisions where project=%s and package=%s and rev=%s",
|
||||
@@ -102,16 +134,21 @@ class DBRevision:
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return DBRevision(row)
|
||||
return DBRevision(db, row)
|
||||
|
||||
@staticmethod
|
||||
def latest_revision(db, project, package):
|
||||
def max_rev(db, project, package):
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT MAX(rev) FROM revisions where project=%s and package=%s",
|
||||
(project, package),
|
||||
)
|
||||
max = cur.fetchone()[0]
|
||||
return cur.fetchone()[0]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def latest_revision(db, project, package):
|
||||
max = DBRevision.max_rev(db, project, package)
|
||||
if max:
|
||||
return DBRevision.fetch_revision(db, project, package, max)
|
||||
return None
|
||||
@@ -125,13 +162,13 @@ class DBRevision:
|
||||
)
|
||||
ret = []
|
||||
for row in cur.fetchall():
|
||||
ret.append(DBRevision(row))
|
||||
ret.append(DBRevision(db, row))
|
||||
return ret
|
||||
|
||||
def linked_rev(self, db):
|
||||
def linked_rev(self):
|
||||
if self.broken:
|
||||
return None
|
||||
with db.cursor() as cur:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT project,package FROM links where revision_id=%s", (self.dbid,)
|
||||
)
|
||||
@@ -143,24 +180,31 @@ class DBRevision:
|
||||
"SELECT * FROM revisions where project=%s and package=%s and commit_time <= %s ORDER BY commit_time DESC LIMIT 1",
|
||||
(project, package, self.commit_time),
|
||||
)
|
||||
revisions = [DBRevision(row) for row in cur.fetchall()]
|
||||
revisions = [DBRevision(self.db, row) for row in cur.fetchall()]
|
||||
if revisions:
|
||||
return revisions[0]
|
||||
else:
|
||||
self.set_broken(db)
|
||||
self.set_broken()
|
||||
return None
|
||||
|
||||
def set_broken(self, db):
|
||||
with db.cursor() as cur:
|
||||
def set_broken(self):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute("UPDATE revisions SET broken=TRUE where id=%s", (self.dbid,))
|
||||
|
||||
def import_dir_list(self, db, xml):
|
||||
with db.cursor() as cur:
|
||||
def import_dir_list(self, xml):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE revisions SET expanded_srcmd5=%s where id=%s",
|
||||
(xml.get("srcmd5"), self.dbid),
|
||||
)
|
||||
for entry in xml.findall("entry"):
|
||||
# this file creates easily 100k commits and is just useless data :(
|
||||
# unfortunately it's stored in the same meta package as the project config
|
||||
if (
|
||||
entry.get("name") == "_staging_workflow"
|
||||
and self.package == "_project"
|
||||
):
|
||||
continue
|
||||
cur.execute(
|
||||
"""INSERT INTO files (name, md5, size, mtime, revision_id)
|
||||
VALUES (%s,%s,%s,%s,%s)""",
|
||||
@@ -173,15 +217,19 @@ class DBRevision:
|
||||
),
|
||||
)
|
||||
|
||||
def previous_commit(self, db):
|
||||
return self.fetch_revision(db, self.project, self.package, int(self.rev) - 1)
|
||||
def previous_commit(self):
|
||||
return DBRevision.fetch_revision(
|
||||
self.db, self.project, self.package, int(self.rev) - 1
|
||||
)
|
||||
|
||||
def next_commit(self, db):
|
||||
return self.fetch_revision(db, self.project, self.package, int(self.rev) + 1)
|
||||
def next_commit(self):
|
||||
return DBRevision.fetch_revision(
|
||||
self.db, self.project, self.package, int(self.rev) + 1
|
||||
)
|
||||
|
||||
def calculate_files_hash(self, db):
|
||||
def calculate_files_hash(self):
|
||||
m = md5()
|
||||
for file_dict in self.files_list(db):
|
||||
for file_dict in self.files_list():
|
||||
m.update(
|
||||
(
|
||||
file_dict["name"]
|
||||
@@ -193,10 +241,10 @@ class DBRevision:
|
||||
)
|
||||
return m.hexdigest()
|
||||
|
||||
def files_list(self, db):
|
||||
def files_list(self):
|
||||
if self._files:
|
||||
return self._files
|
||||
with db.cursor() as cur:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute("SELECT * from files where revision_id=%s", (self.dbid,))
|
||||
self._files = []
|
||||
for row in cur.fetchall():
|
||||
@@ -207,27 +255,23 @@ class DBRevision:
|
||||
self._files.sort(key=lambda x: x["name"])
|
||||
return self._files
|
||||
|
||||
def calc_delta(self, db: DB, current_rev: Optional[DBRevision]):
|
||||
def calc_delta(self, current_rev: Optional[DBRevision]):
|
||||
"""Calculate the list of files to download and to delete.
|
||||
Param current_rev is the revision that's currently checked out.
|
||||
If it's None, the repository is empty.
|
||||
"""
|
||||
to_download = []
|
||||
to_delete = []
|
||||
if current_rev:
|
||||
old_files = {
|
||||
e["name"]: f"{e['md5']}-{e['size']}" for e in current_rev.files_list(db)
|
||||
e["name"]: f"{e['md5']}-{e['size']}" for e in current_rev.files_list()
|
||||
}
|
||||
else:
|
||||
old_files = dict()
|
||||
for entry in self.files_list(db):
|
||||
for entry in self.files_list():
|
||||
if old_files.get(entry["name"]) != f"{entry['md5']}-{entry['size']}":
|
||||
logging.debug(f"Download {entry['name']}")
|
||||
to_download.append((entry["name"], entry["md5"]))
|
||||
to_download.append((Path(entry["name"]), entry["size"], entry["md5"]))
|
||||
old_files.pop(entry["name"], None)
|
||||
for entry in old_files.keys():
|
||||
logging.debug(f"Delete {entry}")
|
||||
to_delete.append(entry)
|
||||
to_delete = [Path(e) for e in old_files.keys()]
|
||||
return to_download, to_delete
|
||||
|
||||
@staticmethod
|
||||
@@ -245,9 +289,9 @@ class DBRevision:
|
||||
"""Used in test cases to read a revision from fixtures into the test database"""
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""INSERT INTO revisions (project, package, rev, unexpanded_srcmd5, expanded_srcmd5,
|
||||
commit_time, userid, comment, broken, files_hash)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING id""",
|
||||
"""INSERT INTO revisions (project, package, rev, unexpanded_srcmd5, expanded_srcmd5,
|
||||
commit_time, userid, comment, broken, files_hash, api_url)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING id""",
|
||||
(
|
||||
rev_dict["project"],
|
||||
rev_dict["package"],
|
||||
@@ -259,6 +303,7 @@ class DBRevision:
|
||||
rev_dict["comment"],
|
||||
rev_dict["broken"],
|
||||
rev_dict["files_hash"],
|
||||
rev_dict.get("api_url", "https://api.opensuse.org"),
|
||||
),
|
||||
)
|
||||
rev_id = cur.fetchone()[0]
|
||||
|
@@ -9,12 +9,8 @@ class FlatNode:
|
||||
self.parent2 = parent2
|
||||
|
||||
def __str__(self) -> str:
|
||||
p1_str = ""
|
||||
if self.parent1:
|
||||
p1_str = f" p1:{self.parent1.short_string()}"
|
||||
p2_str = ""
|
||||
if self.parent2:
|
||||
p2_str = f" p2:{self.parent2.short_string()}"
|
||||
p1_str = f" p1:{self.parent1.short_string()}" if self.parent1 else ""
|
||||
p2_str = f" p2:{self.parent2.short_string()}" if self.parent2 else ""
|
||||
return f"{self.branch} c:{self.commit.short_string()}{p1_str}{p2_str}"
|
||||
|
||||
|
||||
@@ -36,8 +32,7 @@ class FlatTreeWalker(AbstractWalker):
|
||||
def handle_source_node(self, node) -> None:
|
||||
if self.rebase_devel and node.parent and node.parent.merged_into:
|
||||
self.add("devel", node.revision, node.parent.merged_into.revision)
|
||||
return
|
||||
if node.parent:
|
||||
elif node.parent:
|
||||
self.add("devel", node.revision, node.parent.revision)
|
||||
elif self.last_merge:
|
||||
self.add("devel", node.revision, self.last_merge.parent.revision)
|
||||
|
135
lib/git.py
135
lib/git.py
@@ -1,9 +1,11 @@
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
|
||||
import pygit2
|
||||
import requests
|
||||
|
||||
from lib.binary import BINARY
|
||||
|
||||
@@ -23,7 +25,6 @@ class Git:
|
||||
def is_open(self):
|
||||
return self.repo is not None
|
||||
|
||||
# TODO: Extend it to packages and files
|
||||
def exists(self):
|
||||
"""Check if the path is a valid git repository"""
|
||||
return (self.path / ".git").exists()
|
||||
@@ -31,10 +32,12 @@ class Git:
|
||||
def create(self):
|
||||
"""Create a local git repository"""
|
||||
self.path.mkdir(parents=True, exist_ok=True)
|
||||
self.open()
|
||||
|
||||
def open(self):
|
||||
# Convert the path to string, to avoid some limitations in
|
||||
# older pygit2
|
||||
self.repo = pygit2.init_repository(str(self.path))
|
||||
return self
|
||||
|
||||
def is_dirty(self):
|
||||
"""Check if there is something to commit"""
|
||||
@@ -73,10 +76,8 @@ class Git:
|
||||
committer=None,
|
||||
committer_email=None,
|
||||
committer_time=None,
|
||||
allow_empty=False,
|
||||
):
|
||||
"""Add all the files and create a new commit in the current HEAD"""
|
||||
assert allow_empty or self.is_dirty()
|
||||
|
||||
if not committer:
|
||||
committer = self.committer if self.committer else self.user
|
||||
@@ -85,96 +86,20 @@ class Git:
|
||||
)
|
||||
committer_time = committer_time if committer_time else user_time
|
||||
|
||||
try:
|
||||
if self.is_dirty():
|
||||
self.repo.index.add_all()
|
||||
except pygit2.GitError as e:
|
||||
if not allow_empty:
|
||||
raise e
|
||||
|
||||
self.repo.index.write()
|
||||
author = pygit2.Signature(user, user_email, int(user_time.timestamp()))
|
||||
committer = pygit2.Signature(
|
||||
committer, committer_email, int(committer_time.timestamp())
|
||||
)
|
||||
if not parents:
|
||||
try:
|
||||
parents = [self.repo.head.target]
|
||||
except pygit2.GitError as e:
|
||||
parents = []
|
||||
if not allow_empty:
|
||||
raise e
|
||||
|
||||
tree = self.repo.index.write_tree()
|
||||
return self.repo.create_commit(
|
||||
"HEAD", author, committer, message, tree, parents
|
||||
)
|
||||
|
||||
def merge(
|
||||
self,
|
||||
user,
|
||||
user_email,
|
||||
user_time,
|
||||
message,
|
||||
commit,
|
||||
committer=None,
|
||||
committer_email=None,
|
||||
committer_time=None,
|
||||
clean_on_conflict=True,
|
||||
merged=False,
|
||||
allow_empty=False,
|
||||
):
|
||||
new_branch = False
|
||||
|
||||
if not merged:
|
||||
try:
|
||||
self.repo.merge(commit)
|
||||
except KeyError:
|
||||
# If it is the first commit, we will have a missing
|
||||
# "HEAD", but the files will be there. We can proceed
|
||||
# to the commit directly.
|
||||
new_branch = True
|
||||
|
||||
if not merged and self.repo.index.conflicts:
|
||||
for conflict in self.repo.index.conflicts:
|
||||
conflict = [c for c in conflict if c]
|
||||
if conflict:
|
||||
logging.info(f"CONFLICT {conflict[0].path}")
|
||||
|
||||
if clean_on_conflict:
|
||||
self.clean()
|
||||
# Now I miss Rust enums
|
||||
return "CONFLICT"
|
||||
|
||||
# Some merges are empty in OBS (no changes, not sure
|
||||
# why), for now we signal them
|
||||
if not allow_empty and not self.is_dirty():
|
||||
# I really really do miss Rust enums
|
||||
return "EMPTY"
|
||||
|
||||
if new_branch:
|
||||
parents = [commit]
|
||||
else:
|
||||
parents = [
|
||||
self.repo.head.target,
|
||||
commit,
|
||||
]
|
||||
commit = self.commit(
|
||||
user,
|
||||
user_email,
|
||||
user_time,
|
||||
message,
|
||||
parents,
|
||||
committer,
|
||||
committer_email,
|
||||
committer_time,
|
||||
allow_empty=allow_empty,
|
||||
)
|
||||
|
||||
return commit
|
||||
|
||||
def merge_abort(self):
|
||||
self.repo.state_cleanup()
|
||||
|
||||
def last_commit(self):
|
||||
try:
|
||||
return self.repo.head.target
|
||||
@@ -184,8 +109,11 @@ class Git:
|
||||
def branch_head(self, branch):
|
||||
return self.repo.references["refs/heads/" + branch].target
|
||||
|
||||
def set_branch_head(self, branch, commit):
|
||||
self.repo.references["refs/heads/" + branch].set_target(commit)
|
||||
|
||||
def gc(self):
|
||||
logging.info(f"Garbage recollect and repackage {self.path}")
|
||||
logging.debug(f"Garbage recollect and repackage {self.path}")
|
||||
subprocess.run(
|
||||
["git", "gc", "--auto"],
|
||||
cwd=self.path,
|
||||
@@ -256,11 +184,44 @@ class Git:
|
||||
)
|
||||
return any(fnmatch.fnmatch(filename, line) for line in patterns)
|
||||
|
||||
def remove(self, filename):
|
||||
self.repo.index.remove(filename)
|
||||
(self.path / filename).unlink()
|
||||
def remove(self, file: pathlib.Path):
|
||||
self.repo.index.remove(file.name)
|
||||
(self.path / file).unlink()
|
||||
|
||||
patterns = self.get_specific_lfs_gitattributes()
|
||||
if filename in patterns:
|
||||
patterns.remove(filename)
|
||||
if file.name in patterns:
|
||||
patterns.remove(file.name)
|
||||
self.add_specific_lfs_gitattributes(patterns)
|
||||
|
||||
def add_gitea_remote(self, package):
|
||||
repo_name = package.replace("+", "_")
|
||||
org_name = "rpm"
|
||||
|
||||
if not os.getenv("GITEA_TOKEN"):
|
||||
logging.warning("Not adding a remote due to missing $GITEA_TOKEN")
|
||||
return
|
||||
|
||||
url = f"https://gitea.opensuse.org/api/v1/org/{org_name}/repos"
|
||||
response = requests.post(
|
||||
url,
|
||||
data={"name": repo_name},
|
||||
headers={"Authorization": f"token {os.getenv('GITEA_TOKEN')}"},
|
||||
timeout=10,
|
||||
)
|
||||
# 409 Conflict (Already existing)
|
||||
# 201 Created
|
||||
if response.status_code not in (201, 409):
|
||||
print(response.data)
|
||||
url = f"gitea@gitea.opensuse.org:{org_name}/{repo_name}.git"
|
||||
self.repo.remotes.create("origin", url)
|
||||
|
||||
def push(self):
|
||||
remo = self.repo.remotes["origin"]
|
||||
|
||||
keypair = pygit2.KeypairFromAgent("gitea")
|
||||
callbacks = pygit2.RemoteCallbacks(credentials=keypair)
|
||||
|
||||
refspecs = ["refs/heads/factory"]
|
||||
if "refs/heads/devel" in self.repo.references:
|
||||
refspecs.append("refs/heads/devel")
|
||||
remo.push(refspecs, callbacks=callbacks)
|
||||
|
@@ -6,89 +6,38 @@ import yaml
|
||||
from lib.binary import is_binary_or_large
|
||||
from lib.db import DB
|
||||
from lib.git import Git
|
||||
from lib.lfs_oid import LFSOid
|
||||
from lib.obs import OBS
|
||||
from lib.proxy_sha256 import ProxySHA256, md5
|
||||
from lib.proxy_sha256 import ProxySHA256
|
||||
from lib.tree_builder import TreeBuilder
|
||||
from lib.user import User
|
||||
|
||||
|
||||
class GitExporter:
|
||||
def __init__(self, api_url, project, package, repodir):
|
||||
self.obs = OBS()
|
||||
def __init__(self, api_url, project, package, repodir, cachedir):
|
||||
self.obs = OBS(api_url)
|
||||
self.project = project
|
||||
self.package = package
|
||||
# TODO: Store the api url in the revision
|
||||
self.obs.change_url(api_url)
|
||||
self.proxy_sha256 = ProxySHA256(self.obs, enabled=True)
|
||||
self.db = DB()
|
||||
self.proxy_sha256 = ProxySHA256(self.obs, self.db)
|
||||
self.git = Git(
|
||||
repodir,
|
||||
repodir / package,
|
||||
committer="Git OBS Bridge",
|
||||
committer_email="obsbridge@suse.de",
|
||||
).create()
|
||||
)
|
||||
if self.git.exists():
|
||||
self.git.open()
|
||||
else:
|
||||
self.git.create()
|
||||
self.git.add_gitea_remote(package)
|
||||
self.state_file = os.path.join(self.git.path, ".git", "_flat_state.yaml")
|
||||
self.gc_interval = 200
|
||||
|
||||
def download(self, revision):
|
||||
obs_files = self.obs.files(revision.project, revision.package, revision.srcmd5)
|
||||
git_files = {
|
||||
(f.name, f.stat().st_size, md5(f))
|
||||
for f in self.git.path.iterdir()
|
||||
if f.is_file() and f.name not in (".gitattributes")
|
||||
}
|
||||
|
||||
# Overwrite ".gitattributes" with the
|
||||
self.git.add_default_lfs_gitattributes(force=True)
|
||||
|
||||
# Download each file in OBS if it is not a binary (or large)
|
||||
# file
|
||||
for (name, size, file_md5) in obs_files:
|
||||
# this file creates easily 100k commits and is just useless data :(
|
||||
# unfortunately it's stored in the same meta package as the project config
|
||||
if revision.package == "_project" and name == "_staging_workflow":
|
||||
continue
|
||||
# have such files been detected as text mimetype before?
|
||||
is_text = self.proxy_sha256.is_text(name)
|
||||
if not is_text and is_binary_or_large(name, size):
|
||||
file_sha256 = self.proxy_sha256.get_or_put(
|
||||
revision.project,
|
||||
revision.package,
|
||||
name,
|
||||
revision.srcmd5,
|
||||
file_md5,
|
||||
size,
|
||||
)
|
||||
self.git.add_lfs(name, file_sha256["sha256"], size)
|
||||
else:
|
||||
if (name, size, file_md5) not in git_files:
|
||||
logging.debug(f"Download {name}")
|
||||
self.obs.download(
|
||||
revision.project,
|
||||
revision.package,
|
||||
name,
|
||||
revision.srcmd5,
|
||||
self.git.path,
|
||||
file_md5=file_md5,
|
||||
)
|
||||
# Validate the MD5 of the downloaded file
|
||||
if md5(self.git.path / name) != file_md5:
|
||||
raise Exception(f"Download error in {name}")
|
||||
self.git.add(name)
|
||||
|
||||
# Remove extra files
|
||||
obs_names = {n for (n, _, _) in obs_files}
|
||||
git_names = {n for (n, _, _) in git_files}
|
||||
for name in git_names - obs_names:
|
||||
logging.debug(f"Remove {name}")
|
||||
self.git.remove(name)
|
||||
self.cachedir = cachedir
|
||||
|
||||
def set_gc_interval(self, gc):
|
||||
self.gc_interval = gc
|
||||
|
||||
def export_as_git(self):
|
||||
db = DB()
|
||||
tree = TreeBuilder(db).build(self.project, self.package)
|
||||
flats = tree.as_flat_list()
|
||||
|
||||
branch_state = {"factory": None, "devel": None}
|
||||
def check_repo_state(self, flats, branch_state):
|
||||
state_data = dict()
|
||||
if os.path.exists(self.state_file):
|
||||
with open(self.state_file, "r") as f:
|
||||
@@ -109,55 +58,110 @@ class GitExporter:
|
||||
found_state = True
|
||||
if not found_state:
|
||||
left_to_commit.append(flat)
|
||||
return left_to_commit
|
||||
|
||||
def export_as_git(self):
|
||||
if os.getenv("CHECK_ALL_LFS"):
|
||||
LFSOid.check_all(self.db, self.package)
|
||||
tree = TreeBuilder(self.db).build(self.project, self.package)
|
||||
flats = tree.as_flat_list()
|
||||
|
||||
branch_state = {"factory": None, "devel": None}
|
||||
left_to_commit = self.check_repo_state(flats, branch_state)
|
||||
|
||||
if not left_to_commit:
|
||||
return
|
||||
|
||||
logging.info(f"Commiting into {self.git.path}")
|
||||
self.run_gc()
|
||||
users = dict()
|
||||
|
||||
gc_cnt = self.gc_interval
|
||||
if len(left_to_commit) > 0:
|
||||
self.git.gc()
|
||||
for flat in left_to_commit:
|
||||
gc_cnt -= 1
|
||||
if gc_cnt <= 0 and self.gc_interval:
|
||||
self.git.gc()
|
||||
gc_cnt = self.gc_interval
|
||||
if flat.commit.userid not in users:
|
||||
users[flat.commit.userid] = User.find(self.db, flat.commit.userid)
|
||||
flat.user = users[flat.commit.userid]
|
||||
self.gc_cnt -= 1
|
||||
if self.gc_cnt <= 0 and self.gc_interval:
|
||||
self.run_gc()
|
||||
logging.debug(f"Committing {flat}")
|
||||
self.commit_flat(db, flat, branch_state)
|
||||
self.commit_flat(flat, branch_state)
|
||||
|
||||
def limit_download(self, file):
|
||||
if file.endswith(".spec") or file.endswith(".changes"):
|
||||
return True
|
||||
return False
|
||||
self.git.push()
|
||||
|
||||
def commit_flat(self, db, flat, branch_state):
|
||||
parents = []
|
||||
self.git.checkout(flat.branch)
|
||||
if flat.parent1:
|
||||
parents.append(flat.parent1.git_commit)
|
||||
if flat.parent2:
|
||||
parents.append(flat.parent2.git_commit)
|
||||
to_download, to_delete = flat.commit.calc_delta(db, branch_state[flat.branch])
|
||||
for file in to_delete:
|
||||
if not self.limit_download(file):
|
||||
continue
|
||||
self.git.remove(file)
|
||||
for file, md5 in to_download:
|
||||
if not self.limit_download(file):
|
||||
continue
|
||||
self.obs.download(
|
||||
def run_gc(self):
|
||||
self.gc_cnt = self.gc_interval
|
||||
self.git.gc()
|
||||
|
||||
def is_lfs_file(self, package, filename, size):
|
||||
if not is_binary_or_large(filename, size):
|
||||
return False
|
||||
return not self.proxy_sha256.is_text(package, filename)
|
||||
|
||||
def commit_file(self, flat, file, size, md5):
|
||||
# have such files been detected as text mimetype before?
|
||||
if self.is_lfs_file(flat.commit.package, file.name, size):
|
||||
file_sha256 = self.proxy_sha256.get_or_put(
|
||||
flat.commit.project,
|
||||
flat.commit.package,
|
||||
file,
|
||||
file.name,
|
||||
flat.commit.expanded_srcmd5,
|
||||
self.git.path,
|
||||
file_md5=md5,
|
||||
md5,
|
||||
size,
|
||||
)
|
||||
self.git.add(file)
|
||||
# as it's newly registered, it might be a text file now, so double check
|
||||
if not self.proxy_sha256.is_text(flat.commit.package, file.name):
|
||||
self.git.add_lfs(file.name, file_sha256, size)
|
||||
return
|
||||
self.commit_non_lfs_file(flat, file, md5)
|
||||
|
||||
def commit_non_lfs_file(self, flat, file, md5):
|
||||
self.obs.change_url(flat.commit.api_url)
|
||||
self.obs.download(
|
||||
flat.commit.project,
|
||||
flat.commit.package,
|
||||
file.name,
|
||||
flat.commit.expanded_srcmd5,
|
||||
self.git.path,
|
||||
self.cachedir,
|
||||
file_md5=md5,
|
||||
)
|
||||
self.git.add(file)
|
||||
|
||||
def branch_fits_parent1(self, flat, branch_state):
|
||||
if branch_state[flat.branch] is None:
|
||||
# everything fits nothing
|
||||
return True
|
||||
return flat.parent1 == branch_state[flat.branch]
|
||||
|
||||
def commit_flat(self, flat, branch_state):
|
||||
parents = []
|
||||
self.git.checkout(flat.branch)
|
||||
|
||||
if flat.parent1:
|
||||
if not self.branch_fits_parent1(flat, branch_state):
|
||||
logging.debug(f"Reset {flat.branch} onto {flat.parent1.short_string()}")
|
||||
assert flat.parent1.git_commit
|
||||
self.git.set_branch_head(flat.branch, flat.parent1.git_commit)
|
||||
self.git.checkout(flat.branch)
|
||||
parents.append(flat.parent1.git_commit)
|
||||
if flat.parent2:
|
||||
assert flat.parent2.git_commit
|
||||
parents.append(flat.parent2.git_commit)
|
||||
|
||||
# create file if not existant
|
||||
self.git.add_default_lfs_gitattributes(force=False)
|
||||
|
||||
to_download, to_delete = flat.commit.calc_delta(branch_state[flat.branch])
|
||||
for file in to_delete:
|
||||
self.git.remove(file)
|
||||
for file, size, md5 in to_download:
|
||||
self.commit_file(flat, file, size, md5)
|
||||
|
||||
commit = self.git.commit(
|
||||
f"OBS User {flat.commit.userid}",
|
||||
"null@suse.de",
|
||||
flat.user.realname,
|
||||
flat.user.email,
|
||||
flat.commit.commit_time,
|
||||
# TODO: Normalize better the commit message
|
||||
f"{flat.commit.comment}\n\n{flat.commit}",
|
||||
allow_empty=True,
|
||||
flat.commit.git_commit_message(),
|
||||
parents=parents,
|
||||
)
|
||||
flat.commit.git_commit = commit
|
||||
|
20
lib/hash.py
Normal file
20
lib/hash.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import functools
|
||||
import hashlib
|
||||
|
||||
|
||||
def _hash(hash_alg, file_or_path):
|
||||
h = hash_alg()
|
||||
|
||||
def __hash(f):
|
||||
while chunk := f.read(1024 * 4):
|
||||
h.update(chunk)
|
||||
|
||||
if hasattr(file_or_path, "read"):
|
||||
__hash(file_or_path)
|
||||
else:
|
||||
with file_or_path.open("rb") as f:
|
||||
__hash(f)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
md5 = functools.partial(_hash, hashlib.md5)
|
199
lib/importer.py
199
lib/importer.py
@@ -1,3 +1,4 @@
|
||||
import concurrent.futures
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
@@ -8,46 +9,61 @@ from lib.obs_revision import OBSRevision
|
||||
from lib.user import User
|
||||
|
||||
|
||||
def refresh_package(importer, project, package):
|
||||
importer.refresh_package(project, package)
|
||||
|
||||
|
||||
def import_request(importer, number):
|
||||
importer.import_request(number)
|
||||
|
||||
|
||||
def import_rev(importer, rev):
|
||||
importer.import_rev(rev)
|
||||
|
||||
|
||||
class Importer:
|
||||
def __init__(self, api_url, project, package):
|
||||
# Import a Factory package into the database
|
||||
self.package = package
|
||||
def __init__(self, api_url, project, packages):
|
||||
# Import multiple Factory packages into the database
|
||||
self.packages = packages
|
||||
self.project = project
|
||||
|
||||
self.obs = OBS()
|
||||
self.db = DB()
|
||||
self.obs = OBS(api_url)
|
||||
assert project == "openSUSE:Factory"
|
||||
self.obs.change_url(api_url)
|
||||
self.refreshed_packages = set()
|
||||
|
||||
def update_db_package(self, db, project, package):
|
||||
def import_request(self, number):
|
||||
self.obs.request(number).import_into_db(self.db)
|
||||
|
||||
def update_db_package(self, project, package):
|
||||
root = self.obs._history(project, package)
|
||||
if root is None:
|
||||
return
|
||||
latest = DBRevision.latest_revision(db, project, package)
|
||||
latest = DBRevision.max_rev(self.db, project, package)
|
||||
for r in root.findall("revision"):
|
||||
rev = OBSRevision(self.obs, project, package).parse(r)
|
||||
if not latest or rev.rev > latest.rev:
|
||||
dbrev = DBRevision.import_obs_rev(db, rev)
|
||||
if not latest or rev.rev > latest:
|
||||
dbrev = DBRevision.import_obs_rev(self.db, rev)
|
||||
try:
|
||||
root = rev.read_link()
|
||||
except ET.ParseError:
|
||||
dbrev.set_broken(db)
|
||||
dbrev.set_broken()
|
||||
continue
|
||||
if root is not None:
|
||||
tprj = root.get("project") or project
|
||||
tpkg = root.get("package") or package
|
||||
dbrev.links_to(db, tprj, tpkg)
|
||||
dbrev.links_to(tprj, tpkg)
|
||||
|
||||
def find_linked_revs(self, db):
|
||||
with db.cursor() as cur:
|
||||
def find_linked_revs(self):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT * from revisions WHERE id in (SELECT l.revision_id FROM links l
|
||||
LEFT JOIN linked_revs lrevs ON lrevs.revision_id=l.revision_id
|
||||
WHERE lrevs.id IS NULL) and broken is FALSE;"""
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
rev = DBRevision(row)
|
||||
linked_rev = rev.linked_rev(db)
|
||||
rev = DBRevision(self.db, row)
|
||||
linked_rev = rev.linked_rev()
|
||||
if not linked_rev:
|
||||
logging.debug(f"No link {rev}")
|
||||
continue
|
||||
@@ -57,8 +73,8 @@ class Importer:
|
||||
(rev.dbid, linked_rev.dbid),
|
||||
)
|
||||
|
||||
def fetch_all_linked_packages(self, db, project, package):
|
||||
with db.cursor() as cur:
|
||||
def fetch_all_linked_packages(self, project, package):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT DISTINCT l.project, l.package from links l JOIN revisions r
|
||||
on r.id=l.revision_id WHERE r.project=%s AND r.package=%s""",
|
||||
@@ -67,26 +83,26 @@ class Importer:
|
||||
for row in cur.fetchall():
|
||||
(lproject, lpackage) = row
|
||||
# recurse
|
||||
self.refresh_package(db, lproject, lpackage)
|
||||
self.refresh_package(lproject, lpackage)
|
||||
|
||||
def find_fake_revisions(self, db):
|
||||
with db.cursor() as cur:
|
||||
def find_fake_revisions(self):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * from revisions WHERE id in (SELECT linked_id from linked_revs WHERE considered=FALSE)"
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
self._find_fake_revision(db, DBRevision(row))
|
||||
self._find_fake_revision(DBRevision(self.db, row))
|
||||
|
||||
def _find_fake_revision(self, db, rev):
|
||||
prev = rev.previous_commit(db)
|
||||
def _find_fake_revision(self, rev):
|
||||
prev = rev.previous_commit()
|
||||
if not prev:
|
||||
with db.cursor() as cur:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE linked_revs SET considered=TRUE where linked_id=%s",
|
||||
(rev.dbid,),
|
||||
)
|
||||
return
|
||||
with db.cursor() as cur:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT * FROM revisions WHERE id IN
|
||||
(SELECT revision_id from linked_revs WHERE linked_id=%s)
|
||||
@@ -95,8 +111,8 @@ class Importer:
|
||||
)
|
||||
last_linked = None
|
||||
for linked in cur.fetchall():
|
||||
linked = DBRevision(linked)
|
||||
nextrev = linked.next_commit(db)
|
||||
linked = DBRevision(self.db, linked)
|
||||
nextrev = linked.next_commit()
|
||||
if nextrev and nextrev.commit_time < rev.commit_time:
|
||||
continue
|
||||
last_linked = linked
|
||||
@@ -107,7 +123,7 @@ class Importer:
|
||||
if not last_linked:
|
||||
return
|
||||
|
||||
with db.cursor() as cur:
|
||||
with self.db.cursor() as cur:
|
||||
linked = last_linked
|
||||
cur.execute(
|
||||
"SELECT 1 FROM fake_revs where revision_id=%s AND linked_id=%s",
|
||||
@@ -120,10 +136,10 @@ class Importer:
|
||||
)
|
||||
return
|
||||
fake_rev = linked.rev + rev.rev / 1000.0
|
||||
comment = f"Updating link to change in {rev.project}/{rev.package} revision {rev.rev}"
|
||||
comment = f"Updating link to change in {rev.project}/{rev.package} revision {int(rev.rev)}"
|
||||
cur.execute(
|
||||
"""INSERT INTO revisions (project,package,rev,unexpanded_srcmd5,
|
||||
commit_time, userid, comment) VALUES(%s,%s,%s,%s,%s,%s,%s) RETURNING id""",
|
||||
commit_time, userid, comment, api_url) VALUES(%s,%s,%s,%s,%s,%s,%s,%s) RETURNING id""",
|
||||
(
|
||||
linked.project,
|
||||
linked.package,
|
||||
@@ -132,6 +148,7 @@ class Importer:
|
||||
rev.commit_time,
|
||||
"buildservice-autocommit",
|
||||
comment,
|
||||
linked.api_url,
|
||||
),
|
||||
)
|
||||
new_id = cur.fetchone()[0]
|
||||
@@ -144,70 +161,96 @@ class Importer:
|
||||
(rev.dbid, linked.dbid),
|
||||
)
|
||||
|
||||
def revisions_without_files(self, db):
|
||||
with db.cursor() as cur:
|
||||
def revisions_without_files(self):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * FROM revisions WHERE broken=FALSE AND expanded_srcmd5 IS NULL"
|
||||
)
|
||||
return [DBRevision(row) for row in cur.fetchall()]
|
||||
return [DBRevision(self.db, row) for row in cur.fetchall()]
|
||||
|
||||
def fill_file_lists(self, db):
|
||||
self.find_linked_revs(db)
|
||||
|
||||
self.find_fake_revisions(db)
|
||||
for rev in self.revisions_without_files(db):
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT unexpanded_srcmd5 from revisions WHERE
|
||||
id=(SELECT linked_id FROM linked_revs WHERE revision_id=%s)""",
|
||||
(rev.dbid,),
|
||||
)
|
||||
linked_rev = cur.fetchone()
|
||||
if linked_rev:
|
||||
linked_rev = linked_rev[0]
|
||||
list = self.obs.list(
|
||||
rev.project, rev.package, rev.unexpanded_srcmd5, linked_rev
|
||||
def import_rev(self, rev):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT unexpanded_srcmd5 from revisions WHERE
|
||||
id=(SELECT linked_id FROM linked_revs WHERE revision_id=%s)""",
|
||||
(rev.dbid,),
|
||||
)
|
||||
if list:
|
||||
rev.import_dir_list(db, list)
|
||||
md5 = rev.calculate_files_hash(db)
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE revisions SET files_hash=%s WHERE id=%s",
|
||||
(md5, rev.dbid),
|
||||
)
|
||||
else:
|
||||
rev.set_broken(db)
|
||||
linked_rev = cur.fetchone()
|
||||
if linked_rev:
|
||||
linked_rev = linked_rev[0]
|
||||
list = self.obs.list(
|
||||
rev.project, rev.package, rev.unexpanded_srcmd5, linked_rev
|
||||
)
|
||||
if list:
|
||||
rev.import_dir_list(list)
|
||||
md5 = rev.calculate_files_hash()
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE revisions SET files_hash=%s WHERE id=%s",
|
||||
(md5, rev.dbid),
|
||||
)
|
||||
else:
|
||||
rev.set_broken()
|
||||
|
||||
def refresh_package(self, db, project, package):
|
||||
def fill_file_lists(self):
|
||||
self.find_linked_revs()
|
||||
|
||||
self.find_fake_revisions()
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
|
||||
fs = [
|
||||
executor.submit(import_rev, self, rev)
|
||||
for rev in self.revisions_without_files()
|
||||
]
|
||||
concurrent.futures.wait(fs)
|
||||
|
||||
def refresh_package(self, project, package):
|
||||
key = f"{project}/{package}"
|
||||
if key in self.refreshed_packages:
|
||||
# refreshing once is good enough
|
||||
return
|
||||
logging.debug(f"Refresh {project}/{package}")
|
||||
self.refreshed_packages.add(key)
|
||||
self.update_db_package(db, project, package)
|
||||
self.fetch_all_linked_packages(db, project, package)
|
||||
self.update_db_package(project, package)
|
||||
self.fetch_all_linked_packages(project, package)
|
||||
|
||||
def import_into_db(self):
|
||||
db = DB()
|
||||
|
||||
self.refresh_package(db, self.project, self.package)
|
||||
for number in DBRevision.requests_to_fetch(db):
|
||||
self.obs.request(number).import_into_db(db)
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT DISTINCT source_project,source_package FROM requests
|
||||
WHERE id IN (SELECT request_id FROM revisions WHERE project=%s and package=%s);""",
|
||||
(self.project, self.package),
|
||||
)
|
||||
for project, package in cur.fetchall():
|
||||
self.refresh_package(db, project, package)
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
|
||||
fs = [
|
||||
executor.submit(refresh_package, self, self.project, package)
|
||||
for package in self.packages
|
||||
]
|
||||
concurrent.futures.wait(fs)
|
||||
|
||||
missing_users = User.missing_users(db)
|
||||
self.db.conn.commit()
|
||||
|
||||
fs = [
|
||||
executor.submit(import_request, self, number)
|
||||
for number in DBRevision.requests_to_fetch(self.db)
|
||||
]
|
||||
concurrent.futures.wait(fs)
|
||||
|
||||
self.db.conn.commit()
|
||||
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT DISTINCT source_project,source_package FROM requests
|
||||
WHERE id IN (SELECT request_id FROM revisions WHERE project=%s and package = ANY(%s));""",
|
||||
(self.project, self.packages),
|
||||
)
|
||||
fs = [
|
||||
executor.submit(refresh_package, self, project, package)
|
||||
for project, package in cur.fetchall()
|
||||
]
|
||||
concurrent.futures.wait(fs)
|
||||
self.db.conn.commit()
|
||||
|
||||
missing_users = User.missing_users(self.db)
|
||||
for userid in missing_users:
|
||||
missing_user = self.obs.user(userid)
|
||||
if missing_user:
|
||||
missing_user.import_into_db(db)
|
||||
missing_user.import_into_db(self.db)
|
||||
self.db.conn.commit()
|
||||
|
||||
self.fill_file_lists(db)
|
||||
db.conn.commit()
|
||||
self.fill_file_lists()
|
||||
self.db.conn.commit()
|
||||
|
193
lib/lfs_oid.py
Normal file
193
lib/lfs_oid.py
Normal file
@@ -0,0 +1,193 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import requests
|
||||
|
||||
from lib.binary import is_text_mimetype
|
||||
from lib.db import DB
|
||||
|
||||
|
||||
# no need for this class yet, so just leave the migration code here
|
||||
class LFSOid:
|
||||
def __init__(self, db: DB) -> None:
|
||||
self.db = db
|
||||
self.dbid = None
|
||||
self.project = None
|
||||
self.package = None
|
||||
self.filename = None
|
||||
self.revision = None
|
||||
self.sha = None
|
||||
self.size = None
|
||||
self.mimetype = None
|
||||
self.file_md5 = None
|
||||
|
||||
@staticmethod
|
||||
def check_all(db, package):
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT lfs_oid_id FROM lfs_oid_in_package WHERE package=%s ORDER BY lfs_oid_id DESC limit 10 ",
|
||||
(package,),
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
oid = LFSOid(db).set_from_dbid(row[0])
|
||||
if not oid.check():
|
||||
oid.register()
|
||||
|
||||
def add(
|
||||
self,
|
||||
project: str,
|
||||
package: str,
|
||||
filename: str,
|
||||
revision: str,
|
||||
sha256: str,
|
||||
size: int,
|
||||
mimetype: str,
|
||||
file_md5: str,
|
||||
) -> None:
|
||||
with self.db.cursor() as cur:
|
||||
# we UPDATE here so the return functions. conflicts are likely as we look for filename/md5 but conflict on sha256
|
||||
cur.execute(
|
||||
"""INSERT INTO lfs_oids (project,package,filename,rev,sha256,size,mimetype,file_md5)
|
||||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
|
||||
ON CONFLICT (sha256,size) DO UPDATE SET mimetype=EXCLUDED.mimetype
|
||||
RETURNING id""",
|
||||
(
|
||||
project,
|
||||
package,
|
||||
filename,
|
||||
revision,
|
||||
sha256,
|
||||
size,
|
||||
mimetype,
|
||||
file_md5,
|
||||
),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
lfs_oid_id = row[0]
|
||||
cur.execute(
|
||||
"""INSERT INTO lfs_oid_in_package (package,filename,lfs_oid_id)
|
||||
VALUES (%s,%s,%s)""",
|
||||
(package, filename, lfs_oid_id),
|
||||
)
|
||||
if is_text_mimetype(mimetype):
|
||||
cur.execute(
|
||||
"INSERT INTO text_files (package,filename) VALUES (%s,%s)",
|
||||
(package, filename),
|
||||
)
|
||||
self.db.conn.commit()
|
||||
self.set_from_dbid(lfs_oid_id)
|
||||
if not self.check():
|
||||
self.register()
|
||||
|
||||
def check(self):
|
||||
url = f"http://gitea.opensuse.org:9999/check/{self.sha256}/{self.size}"
|
||||
response = requests.get(
|
||||
url,
|
||||
timeout=10,
|
||||
)
|
||||
return response.status_code == 200
|
||||
|
||||
def set_from_dbid(self, dbid: int) -> LFSOid:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute("SELECT * from lfs_oids where id=%s", (dbid,))
|
||||
row = cur.fetchone()
|
||||
self.set_from_row(row)
|
||||
assert self.dbid == dbid
|
||||
return self
|
||||
|
||||
def set_from_row(self, row: list) -> LFSOid:
|
||||
(
|
||||
self.dbid,
|
||||
self.project,
|
||||
self.package,
|
||||
self.filename,
|
||||
self.revision,
|
||||
self.sha256,
|
||||
self.size,
|
||||
self.mimetype,
|
||||
self.file_md5,
|
||||
) = row
|
||||
return self
|
||||
|
||||
def register(self):
|
||||
if not os.getenv("GITEA_REGISTER_SECRET"):
|
||||
logging.info("Not registering LFS due to missing secret")
|
||||
return
|
||||
|
||||
data = {
|
||||
"secret": os.getenv("GITEA_REGISTER_SECRET"),
|
||||
"project": self.project,
|
||||
"package": self.package,
|
||||
"filename": self.filename,
|
||||
"rev": self.revision,
|
||||
"sha256": self.sha256,
|
||||
"size": self.size,
|
||||
}
|
||||
|
||||
url = "http://gitea.opensuse.org:9999/register"
|
||||
response = requests.post(
|
||||
url,
|
||||
json=data,
|
||||
timeout=10,
|
||||
)
|
||||
logging.info(f"Register LFS returned {response.status_code}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
Import the old data - it only makes sense on a DB with previously scanned revisions
|
||||
curl -s https://stephan.kulow.org/git_lfs.csv.xz | xz -cd | PYTHONPATH=$PWD /usr/bin/python3 lib/lfs_oid.py
|
||||
"""
|
||||
db = DB()
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
with db.cursor() as cur:
|
||||
while True:
|
||||
line = sys.stdin.readline()
|
||||
if not line:
|
||||
break
|
||||
(
|
||||
project,
|
||||
package,
|
||||
filename,
|
||||
rev,
|
||||
sha256,
|
||||
size,
|
||||
mimetype,
|
||||
md5,
|
||||
) = line.strip().split("\t")
|
||||
cur.execute(
|
||||
"""INSERT INTO lfs_oids (project,package,filename,rev,sha256,size,mimetype,file_md5)
|
||||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s) ON CONFLICT DO NOTHING""",
|
||||
(project, package, filename, rev, sha256, size, mimetype, md5),
|
||||
)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TEMPORARY TABLE lfs_oid_in_revision (
|
||||
revision_id INTEGER,
|
||||
lfs_oid_id INTEGER NOT NULL,
|
||||
name VARCHAR(255) NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
cur.execute(
|
||||
"""INSERT INTO lfs_oid_in_revision (revision_id, lfs_oid_id, name)
|
||||
SELECT revision_id,lfs_oids.id,files.name FROM lfs_oids JOIN files ON files.md5=lfs_oids.file_md5"""
|
||||
)
|
||||
cur.execute(
|
||||
"""INSERT INTO text_files (package,filename)
|
||||
SELECT DISTINCT r.package, lfs_oid_in_revision.name FROM lfs_oids
|
||||
JOIN lfs_oid_in_revision on lfs_oid_in_revision.lfs_oid_id=lfs_oids.id
|
||||
JOIN revisions r ON r.id=lfs_oid_in_revision.revision_id
|
||||
WHERE lfs_oids.mimetype like 'text/%' ON CONFLICT DO NOTHING"""
|
||||
)
|
||||
cur.execute(
|
||||
"""INSERT INTO lfs_oid_in_package (lfs_oid_id, package, filename)
|
||||
SELECT DISTINCT lfs_oids.id,r.package, lfs_oid_in_revision.name FROM lfs_oids
|
||||
JOIN lfs_oid_in_revision on lfs_oid_in_revision.lfs_oid_id=lfs_oids.id
|
||||
JOIN revisions r ON r.id=lfs_oid_in_revision.revision_id"""
|
||||
)
|
||||
db.conn.commit()
|
41
lib/obs.py
41
lib/obs.py
@@ -1,5 +1,7 @@
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
import urllib.parse
|
||||
import xml.etree.ElementTree as ET
|
||||
@@ -7,6 +9,7 @@ from urllib.error import HTTPError
|
||||
|
||||
import osc.core
|
||||
|
||||
from lib.hash import md5
|
||||
from lib.request import Request
|
||||
from lib.user import User
|
||||
|
||||
@@ -56,13 +59,14 @@ osc.core.http_GET = retry(osc.core.http_GET)
|
||||
|
||||
|
||||
class OBS:
|
||||
def __init__(self, url=None):
|
||||
if url:
|
||||
self.change_url(url)
|
||||
def __init__(self, url):
|
||||
self.url = None
|
||||
self.change_url(url)
|
||||
|
||||
def change_url(self, url):
|
||||
self.url = url
|
||||
osc.conf.get_config(override_apiurl=url)
|
||||
if url != self.url:
|
||||
self.url = url
|
||||
osc.conf.get_config(override_apiurl=url)
|
||||
|
||||
def _xml(self, url_path, **params):
|
||||
url = osc.core.makeurl(self.url, [url_path], params)
|
||||
@@ -158,10 +162,25 @@ class OBS:
|
||||
name: str,
|
||||
revision: str,
|
||||
dirpath: str,
|
||||
cachedir: str,
|
||||
file_md5: str,
|
||||
) -> None:
|
||||
with (dirpath / name).open("wb") as f:
|
||||
f.write(self._download(project, package, name, revision).read())
|
||||
|
||||
cached_file = self._path_from_md5(name, cachedir, file_md5)
|
||||
if not self.in_cache(name, cachedir, file_md5):
|
||||
with (dirpath / name).open("wb") as f:
|
||||
logging.debug(f"Download {project}/{package}/{name}")
|
||||
f.write(self._download(project, package, name, revision).read())
|
||||
|
||||
# Validate the MD5 of the downloaded file
|
||||
if md5(dirpath / name) != file_md5:
|
||||
raise Exception(f"Download error in {name}")
|
||||
|
||||
shutil.copy(dirpath / name, cached_file.with_suffix(".new"))
|
||||
os.rename(cached_file.with_suffix(".new"), cached_file)
|
||||
else:
|
||||
shutil.copy(cached_file, dirpath / name)
|
||||
logging.debug(f"Use cached {project}/{package}/{name}")
|
||||
|
||||
def list(self, project, package, srcmd5, linkrev):
|
||||
params = {"rev": srcmd5, "expand": "1"}
|
||||
@@ -179,3 +198,11 @@ class OBS:
|
||||
raise e
|
||||
|
||||
return root
|
||||
|
||||
def _path_from_md5(self, name, cachedir, md5):
|
||||
filepath = cachedir / md5[:3]
|
||||
filepath.mkdir(parents=True, exist_ok=True)
|
||||
return filepath / md5[3:]
|
||||
|
||||
def in_cache(self, name, cachedir, md5):
|
||||
return self._path_from_md5(name, cachedir, md5).exists()
|
||||
|
@@ -1,106 +1,92 @@
|
||||
import functools
|
||||
import hashlib
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
try:
|
||||
import magic
|
||||
except:
|
||||
print("Install python3-python-magic, not python3-magic")
|
||||
raise
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def _hash(hash_alg, file_or_path):
|
||||
h = hash_alg()
|
||||
|
||||
def __hash(f):
|
||||
while chunk := f.read(1024 * 4):
|
||||
h.update(chunk)
|
||||
|
||||
if hasattr(file_or_path, "read"):
|
||||
__hash(file_or_path)
|
||||
else:
|
||||
with file_or_path.open("rb") as f:
|
||||
__hash(f)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
md5 = functools.partial(_hash, hashlib.md5)
|
||||
sha256 = functools.partial(_hash, hashlib.sha256)
|
||||
from lib.db import DB
|
||||
from lib.lfs_oid import LFSOid
|
||||
from lib.obs import OBS
|
||||
|
||||
|
||||
class ProxySHA256:
|
||||
def __init__(self, obs, url=None, enabled=True):
|
||||
def __init__(self, obs: OBS, db: DB):
|
||||
self.obs = obs
|
||||
self.url = url if url else "http://source.dyn.cloud.suse.de"
|
||||
self.enabled = enabled
|
||||
self.db = db
|
||||
self.hashes = None
|
||||
self.texts = set()
|
||||
|
||||
def load_package(self, package):
|
||||
# _project is unreachable for the proxy - due to being a fake package
|
||||
if package == "_project":
|
||||
self.enabled = False
|
||||
self.texts = set(["_config", "_service"])
|
||||
self.hashes = dict()
|
||||
return
|
||||
logging.info("Retrieve all previously defined SHA256")
|
||||
response = requests.get(f"http://source.dyn.cloud.suse.de/package/{package}")
|
||||
if response.status_code == 200:
|
||||
json = response.json()
|
||||
self.hashes = json["shas"]
|
||||
self.texts = set(json["texts"])
|
||||
self.texts = None
|
||||
self.mime = None
|
||||
|
||||
def get(self, package, name, file_md5):
|
||||
key = f"{file_md5}-{name}"
|
||||
if self.hashes is None:
|
||||
if self.enabled:
|
||||
self.load_package(package)
|
||||
else:
|
||||
self.hashes = {}
|
||||
return self.hashes.get(key, None)
|
||||
self.load_hashes(package)
|
||||
key = f"{file_md5}-{name}"
|
||||
ret = self.hashes.get(key)
|
||||
return ret
|
||||
|
||||
def _proxy_put(self, project, package, name, revision, file_md5, size):
|
||||
quoted_name = urllib.parse.quote(name)
|
||||
url = f"{self.obs.url}/public/source/{project}/{package}/{quoted_name}?rev={revision}"
|
||||
response = requests.put(
|
||||
self.url,
|
||||
data={
|
||||
"hash": file_md5,
|
||||
"filename": name,
|
||||
"url": url,
|
||||
"package": package,
|
||||
},
|
||||
)
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Redirector error on {self.url} for {url}")
|
||||
|
||||
key = (file_md5, name)
|
||||
self.hashes[key] = {
|
||||
"sha256": response.content.decode("utf-8"),
|
||||
"fsize": size,
|
||||
}
|
||||
return self.hashes[key]
|
||||
|
||||
def _obs_put(self, project, package, name, revision, file_md5, size):
|
||||
key = (file_md5, name)
|
||||
self.hashes[key] = {
|
||||
"sha256": sha256(self.obs._download(project, package, name, revision)),
|
||||
"fsize": size,
|
||||
}
|
||||
return self.hashes[key]
|
||||
def load_hashes(self, package):
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(
|
||||
"""SELECT lfs_oids.file_md5,lop.filename,lfs_oids.sha256,lfs_oids.size
|
||||
FROM lfs_oid_in_package lop
|
||||
JOIN lfs_oids ON lfs_oids.id=lop.lfs_oid_id
|
||||
WHERE lop.package=%s""",
|
||||
(package,),
|
||||
)
|
||||
self.hashes = {
|
||||
f"{row[0]}-{row[1]}": (row[2], row[3]) for row in cur.fetchall()
|
||||
}
|
||||
|
||||
def put(self, project, package, name, revision, file_md5, size):
|
||||
if not self.enabled:
|
||||
return self._obs_put(project, package, name, revision, file_md5, size)
|
||||
return self._proxy_put(project, package, name, revision, file_md5, size)
|
||||
|
||||
def is_text(self, filename):
|
||||
if not self.mime:
|
||||
self.mime = magic.Magic(mime=True)
|
||||
|
||||
mimetype = None
|
||||
logging.debug(f"Add LFS for {project}/{package}/{name}")
|
||||
fin = self.obs._download(project, package, name, revision)
|
||||
sha = hashlib.sha256()
|
||||
while True:
|
||||
buffer = fin.read(10000)
|
||||
if not buffer:
|
||||
break
|
||||
sha.update(buffer)
|
||||
# only guess from the first 10K
|
||||
if not mimetype:
|
||||
mimetype = self.mime.from_buffer(buffer)
|
||||
fin.close()
|
||||
LFSOid(self.db).add(
|
||||
project, package, name, revision, sha.hexdigest(), size, mimetype, file_md5
|
||||
)
|
||||
|
||||
# reset
|
||||
self.hashes = None
|
||||
self.texts = None
|
||||
return self.get(package, name, file_md5)
|
||||
|
||||
def is_text(self, package, filename):
|
||||
if self.texts is None:
|
||||
self.load_texts(package)
|
||||
return filename in self.texts
|
||||
|
||||
def load_texts(self, package):
|
||||
self.texts = set()
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute("SELECT filename from text_files where package=%s", (package,))
|
||||
for row in cur.fetchall():
|
||||
self.texts.add(row[0])
|
||||
|
||||
def get_or_put(self, project, package, name, revision, file_md5, size):
|
||||
result = self.get(package, name, file_md5)
|
||||
if not result:
|
||||
result = self.put(project, package, name, revision, file_md5, size)
|
||||
|
||||
# Sanity check
|
||||
if result["fsize"] != size:
|
||||
raise Exception(f"Redirector has different size for {name}")
|
||||
sha256, db_size = result
|
||||
assert db_size == size
|
||||
|
||||
return result
|
||||
return sha256
|
||||
|
@@ -16,11 +16,11 @@ class TestExporter:
|
||||
db = DB()
|
||||
with db.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT * from revisions where package=%s ORDER BY project,rev",
|
||||
"SELECT * from revisions where package=%s ORDER BY commit_time",
|
||||
(self.package,),
|
||||
)
|
||||
data = {"revisions": []}
|
||||
for row in cur.fetchall():
|
||||
data["revisions"].append(DBRevision(row).as_dict(db))
|
||||
data["revisions"].append(DBRevision(db, row).as_dict())
|
||||
|
||||
yaml.dump(data, sys.stdout, default_flow_style=False)
|
||||
|
@@ -104,14 +104,24 @@ class TreeBuilder:
|
||||
"""For a given revision in the target, find the node in the source chain
|
||||
that matches the files"""
|
||||
node = source_chain
|
||||
candidates = []
|
||||
while node:
|
||||
# exclude reverts happening after the merge
|
||||
if (
|
||||
node.revision.commit_time <= revision.commit_time
|
||||
and node.revision.files_hash == revision.files_hash
|
||||
):
|
||||
return node
|
||||
candidates.append(node)
|
||||
if node.merged_into:
|
||||
# we can't have candidates that are crossing previous merges
|
||||
# see https://gitea.opensuse.org/importers/git-importer/issues/14
|
||||
candidates = []
|
||||
node = node.parent
|
||||
if candidates:
|
||||
# the first candidate is the youngest one that matches the check. That's
|
||||
# good enough. See FastCGI test case for rev 36 and 38: 37 reverted 36 and
|
||||
# then 38 reverting the revert before it was submitted.
|
||||
return candidates[0]
|
||||
|
||||
def add_merge_points(self, factory_revisions):
|
||||
"""For all target revisions that accepted a request, look up the merge
|
||||
|
20
lib/user.py
20
lib/user.py
@@ -1,3 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from lib.db import DB
|
||||
|
||||
FAKE_ACCOUNTS = (
|
||||
"unknown",
|
||||
"buildservice-autocommit",
|
||||
@@ -15,6 +19,22 @@ FAKE_ACCOUNTS = (
|
||||
|
||||
|
||||
class User:
|
||||
@staticmethod
|
||||
def find(db: DB, userid: str) -> User:
|
||||
row = User.lookup(db, userid)
|
||||
self = User()
|
||||
self.userid = userid
|
||||
if row:
|
||||
(_, _, self.email, self.realname) = row
|
||||
else:
|
||||
self.email = ""
|
||||
self.realname = ""
|
||||
if not self.email:
|
||||
self.email = "null@suse.de"
|
||||
if not self.realname:
|
||||
self.realname = f"OBS User {userid}"
|
||||
return self
|
||||
|
||||
def parse(self, xml, userid):
|
||||
self.userid = userid
|
||||
self.realname = xml.find("realname").text
|
||||
|
@@ -6,11 +6,14 @@ from lib.db_revision import DBRevision
|
||||
from lib.obs import OBS
|
||||
from lib.obs_revision import OBSRevision
|
||||
|
||||
# needs to exist in local oscrc (little tricky)
|
||||
API_URL = "https://api.opensuse.org"
|
||||
|
||||
|
||||
class TestDBMethods(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.db = DB(section="test")
|
||||
self.obs = OBS()
|
||||
self.obs = OBS(API_URL)
|
||||
|
||||
def test_import(self):
|
||||
test_rev = OBSRevision(self.obs, "openSUSE:Factory", "xz")
|
||||
@@ -30,6 +33,7 @@ class TestDBMethods(unittest.TestCase):
|
||||
db_rev = DBRevision.fetch_revision(
|
||||
self.db, project="openSUSE:Factory", package="xz", rev="70"
|
||||
)
|
||||
self.assertEqual(db_rev.api_url, API_URL)
|
||||
self.assertEqual(str(test_rev), str(db_rev))
|
||||
|
||||
|
||||
|
4528
tests/fixtures/FastCGI-data.yaml
vendored
Normal file
4528
tests/fixtures/FastCGI-data.yaml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
33
tests/fixtures/FastCGI-expected-list.yaml
vendored
Normal file
33
tests/fixtures/FastCGI-expected-list.yaml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
- factory c:openSUSE:Factory/FastCGI/29.0 p1:openSUSE:Factory/FastCGI/28.0 p2:devel:libraries:c_c++/FastCGI/40.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/40.0 p1:devel:libraries:c_c++/FastCGI/38.0
|
||||
- factory c:openSUSE:Factory/FastCGI/28.0 p1:openSUSE:Factory/FastCGI/27.0 p2:devel:libraries:c_c++/FastCGI/38.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/38.0 p1:devel:libraries:c_c++/FastCGI/37.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/37.0 p1:devel:libraries:c_c++/FastCGI/36.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/36.0 p1:devel:libraries:c_c++/FastCGI/34.0
|
||||
- factory c:openSUSE:Factory/FastCGI/27.0 p1:openSUSE:Factory/FastCGI/26.0 p2:devel:libraries:c_c++/FastCGI/34.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/34.0 p1:devel:libraries:c_c++/FastCGI/32.0
|
||||
- factory c:openSUSE:Factory/FastCGI/26.0 p1:openSUSE:Factory/FastCGI/23.0 p2:devel:libraries:c_c++/FastCGI/32.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/32.0 p1:devel:libraries:c_c++/FastCGI/30.0
|
||||
- factory c:openSUSE:Factory/FastCGI/23.0 p1:openSUSE:Factory/FastCGI/20.0 p2:devel:libraries:c_c++/FastCGI/30.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/30.0 p1:devel:libraries:c_c++/FastCGI/28.0
|
||||
- factory c:openSUSE:Factory/FastCGI/20.0 p1:openSUSE:Factory/FastCGI/19.0 p2:devel:libraries:c_c++/FastCGI/28.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/28.0 p1:devel:libraries:c_c++/FastCGI/26.0
|
||||
- factory c:openSUSE:Factory/FastCGI/19.0 p1:openSUSE:Factory/FastCGI/18.0 p2:devel:libraries:c_c++/FastCGI/26.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/26.0 p1:devel:libraries:c_c++/FastCGI/24.0
|
||||
- factory c:openSUSE:Factory/FastCGI/18.0 p1:openSUSE:Factory/FastCGI/16.0 p2:devel:libraries:c_c++/FastCGI/24.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/24.0 p1:devel:libraries:c_c++/FastCGI/22.0
|
||||
- factory c:openSUSE:Factory/FastCGI/16.0 p1:openSUSE:Factory/FastCGI/15.0 p2:devel:libraries:c_c++/FastCGI/22.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/22.0 p1:devel:libraries:c_c++/FastCGI/20.0
|
||||
- factory c:openSUSE:Factory/FastCGI/15.0 p1:openSUSE:Factory/FastCGI/14.0 p2:devel:libraries:c_c++/FastCGI/20.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/20.0 p1:devel:libraries:c_c++/FastCGI/19.014
|
||||
- devel c:devel:libraries:c_c++/FastCGI/19.014 p1:devel:libraries:c_c++/FastCGI/18.0
|
||||
- factory c:openSUSE:Factory/FastCGI/14.0 p1:openSUSE:Factory/FastCGI/13.0
|
||||
- factory c:openSUSE:Factory/FastCGI/13.0 p1:openSUSE:Factory/FastCGI/11.0 p2:devel:libraries:c_c++/FastCGI/18.0
|
||||
- devel c:devel:libraries:c_c++/FastCGI/18.0 p1:openSUSE:Factory/FastCGI/11.0
|
||||
- factory c:openSUSE:Factory/FastCGI/11.0 p1:openSUSE:Factory/FastCGI/10.0
|
||||
- factory c:openSUSE:Factory/FastCGI/10.0 p1:openSUSE:Factory/FastCGI/7.0
|
||||
- factory c:openSUSE:Factory/FastCGI/7.0 p1:openSUSE:Factory/FastCGI/6.0
|
||||
- factory c:openSUSE:Factory/FastCGI/6.0 p1:openSUSE:Factory/FastCGI/4.0
|
||||
- factory c:openSUSE:Factory/FastCGI/4.0 p1:openSUSE:Factory/FastCGI/3.0
|
||||
- factory c:openSUSE:Factory/FastCGI/3.0 p1:openSUSE:Factory/FastCGI/1.0
|
||||
- factory c:openSUSE:Factory/FastCGI/1.0
|
44
tests/fixtures/FastCGI-expected-tree.yaml
vendored
Normal file
44
tests/fixtures/FastCGI-expected-tree.yaml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
- commit: openSUSE:Factory/FastCGI/29.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/40.0
|
||||
- commit: openSUSE:Factory/FastCGI/28.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/38.0
|
||||
- devel:libraries:c_c++/FastCGI/37.0
|
||||
- devel:libraries:c_c++/FastCGI/36.0
|
||||
- commit: openSUSE:Factory/FastCGI/27.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/34.0
|
||||
- commit: openSUSE:Factory/FastCGI/26.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/32.0
|
||||
- commit: openSUSE:Factory/FastCGI/23.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/30.0
|
||||
- commit: openSUSE:Factory/FastCGI/20.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/28.0
|
||||
- commit: openSUSE:Factory/FastCGI/19.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/26.0
|
||||
- commit: openSUSE:Factory/FastCGI/18.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/24.0
|
||||
- commit: openSUSE:Factory/FastCGI/16.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/22.0
|
||||
- commit: openSUSE:Factory/FastCGI/15.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/20.0
|
||||
- devel:libraries:c_c++/FastCGI/19.014
|
||||
- commit: openSUSE:Factory/FastCGI/14.0
|
||||
- commit: openSUSE:Factory/FastCGI/13.0
|
||||
merged:
|
||||
- devel:libraries:c_c++/FastCGI/18.0
|
||||
- commit: openSUSE:Factory/FastCGI/11.0
|
||||
- commit: openSUSE:Factory/FastCGI/10.0
|
||||
- commit: openSUSE:Factory/FastCGI/7.0
|
||||
- commit: openSUSE:Factory/FastCGI/6.0
|
||||
- commit: openSUSE:Factory/FastCGI/4.0
|
||||
- commit: openSUSE:Factory/FastCGI/3.0
|
||||
- commit: openSUSE:Factory/FastCGI/1.0
|
9756
tests/fixtures/breeze-data.yaml
vendored
Normal file
9756
tests/fixtures/breeze-data.yaml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
171
tests/fixtures/breeze-expected-list.yaml
vendored
Normal file
171
tests/fixtures/breeze-expected-list.yaml
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
- factory c:openSUSE:Factory/breeze/43.0 p1:openSUSE:Factory/breeze/42.0 p2:KDE:Frameworks5/breeze/150.0
|
||||
- devel c:KDE:Frameworks5/breeze/150.0 p1:KDE:Frameworks5/breeze/148.0
|
||||
- factory c:openSUSE:Factory/breeze/42.0 p1:openSUSE:Factory/breeze/41.0 p2:KDE:Frameworks5/breeze/148.0
|
||||
- devel c:KDE:Frameworks5/breeze/148.0 p1:KDE:Frameworks5/breeze/147.0
|
||||
- devel c:KDE:Frameworks5/breeze/147.0 p1:KDE:Frameworks5/breeze/145.0
|
||||
- factory c:openSUSE:Factory/breeze/41.0 p1:openSUSE:Factory/breeze/40.0 p2:KDE:Frameworks5/breeze/145.0
|
||||
- devel c:KDE:Frameworks5/breeze/145.0 p1:KDE:Frameworks5/breeze/143.0
|
||||
- factory c:openSUSE:Factory/breeze/40.0 p1:openSUSE:Factory/breeze/39.0 p2:KDE:Frameworks5/breeze/143.0
|
||||
- devel c:KDE:Frameworks5/breeze/143.0 p1:KDE:Frameworks5/breeze/142.0
|
||||
- devel c:KDE:Frameworks5/breeze/142.0 p1:KDE:Frameworks5/breeze/141.0
|
||||
- devel c:KDE:Frameworks5/breeze/141.0 p1:KDE:Frameworks5/breeze/139.0
|
||||
- factory c:openSUSE:Factory/breeze/39.0 p1:openSUSE:Factory/breeze/38.0 p2:KDE:Frameworks5/breeze/139.0
|
||||
- devel c:KDE:Frameworks5/breeze/139.0 p1:KDE:Frameworks5/breeze/137.0
|
||||
- factory c:openSUSE:Factory/breeze/38.0 p1:openSUSE:Factory/breeze/37.0 p2:KDE:Frameworks5/breeze/137.0
|
||||
- devel c:KDE:Frameworks5/breeze/137.0 p1:KDE:Frameworks5/breeze/136.0
|
||||
- devel c:KDE:Frameworks5/breeze/136.0 p1:KDE:Frameworks5/breeze/135.0
|
||||
- devel c:KDE:Frameworks5/breeze/135.0 p1:KDE:Frameworks5/breeze/134.0
|
||||
- devel c:KDE:Frameworks5/breeze/134.0 p1:KDE:Frameworks5/breeze/132.0
|
||||
- factory c:openSUSE:Factory/breeze/37.0 p1:openSUSE:Factory/breeze/36.0 p2:KDE:Frameworks5/breeze/132.0
|
||||
- devel c:KDE:Frameworks5/breeze/132.0 p1:KDE:Frameworks5/breeze/130.0
|
||||
- factory c:openSUSE:Factory/breeze/36.0 p1:openSUSE:Factory/breeze/35.0 p2:KDE:Frameworks5/breeze/130.0
|
||||
- devel c:KDE:Frameworks5/breeze/130.0 p1:KDE:Frameworks5/breeze/128.0
|
||||
- factory c:openSUSE:Factory/breeze/35.0 p1:openSUSE:Factory/breeze/34.0 p2:KDE:Frameworks5/breeze/128.0
|
||||
- devel c:KDE:Frameworks5/breeze/128.0 p1:KDE:Frameworks5/breeze/127.0
|
||||
- devel c:KDE:Frameworks5/breeze/127.0 p1:KDE:Frameworks5/breeze/126.034
|
||||
- devel c:KDE:Frameworks5/breeze/126.034 p1:KDE:Frameworks5/breeze/126.0
|
||||
- devel c:KDE:Frameworks5/breeze/126.0 p1:KDE:Frameworks5/breeze/125.0
|
||||
- devel c:KDE:Frameworks5/breeze/125.0 p1:KDE:Frameworks5/breeze/124.0
|
||||
- devel c:KDE:Frameworks5/breeze/124.0 p1:KDE:Frameworks5/breeze/123.0
|
||||
- devel c:KDE:Frameworks5/breeze/123.0 p1:KDE:Frameworks5/breeze/122.0
|
||||
- devel c:KDE:Frameworks5/breeze/122.0 p1:KDE:Frameworks5/breeze/120.0
|
||||
- factory c:openSUSE:Factory/breeze/34.0 p1:openSUSE:Factory/breeze/33.0 p2:KDE:Frameworks5:LTS/breeze/14.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/14.0 p1:KDE:Frameworks5:LTS/breeze/13.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/13.0 p1:KDE:Frameworks5:LTS/breeze/12.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/12.0 p1:KDE:Frameworks5:LTS/breeze/11.0
|
||||
- factory c:openSUSE:Factory/breeze/33.0 p1:openSUSE:Factory/breeze/32.0 p2:KDE:Frameworks5:LTS/breeze/11.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/11.0 p1:KDE:Frameworks5:LTS/breeze/10.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/10.0 p1:KDE:Frameworks5:LTS/breeze/9.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/9.0 p1:KDE:Frameworks5:LTS/breeze/8.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/8.0 p1:KDE:Frameworks5:LTS/breeze/7.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/7.0 p1:KDE:Frameworks5:LTS/breeze/6.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/6.0 p1:KDE:Frameworks5:LTS/breeze/5.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/5.0 p1:KDE:Frameworks5:LTS/breeze/4.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/4.0 p1:KDE:Frameworks5:LTS/breeze/3.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/3.0 p1:KDE:Frameworks5:LTS/breeze/2.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/2.0 p1:KDE:Frameworks5:LTS/breeze/1.0
|
||||
- devel c:KDE:Frameworks5:LTS/breeze/1.0 p1:openSUSE:Factory/breeze/32.0
|
||||
- factory c:openSUSE:Factory/breeze/32.0 p1:openSUSE:Factory/breeze/31.0 p2:KDE:Frameworks5/breeze/120.0
|
||||
- devel c:KDE:Frameworks5/breeze/120.0 p1:KDE:Frameworks5/breeze/117.0
|
||||
- factory c:openSUSE:Factory/breeze/31.0 p1:openSUSE:Factory/breeze/30.0 p2:KDE:Frameworks5/breeze/117.0
|
||||
- devel c:KDE:Frameworks5/breeze/117.0 p1:KDE:Frameworks5/breeze/116.0
|
||||
- factory c:openSUSE:Factory/breeze/30.0 p1:openSUSE:Factory/breeze/29.0 p2:KDE:Frameworks5/breeze/116.0
|
||||
- devel c:KDE:Frameworks5/breeze/116.0 p1:KDE:Frameworks5/breeze/115.0
|
||||
- devel c:KDE:Frameworks5/breeze/115.0 p1:KDE:Frameworks5/breeze/113.0
|
||||
- devel c:KDE:Frameworks5/breeze/113.0 p1:KDE:Frameworks5/breeze/112.0
|
||||
- devel c:KDE:Frameworks5/breeze/112.0 p1:KDE:Frameworks5/breeze/111.0
|
||||
- factory c:openSUSE:Factory/breeze/29.0 p1:openSUSE:Factory/breeze/28.0 p2:KDE:Frameworks5/breeze/111.0
|
||||
- devel c:KDE:Frameworks5/breeze/111.0 p1:KDE:Frameworks5/breeze/110.0
|
||||
- devel c:KDE:Frameworks5/breeze/110.0 p1:KDE:Frameworks5/breeze/109.0
|
||||
- devel c:KDE:Frameworks5/breeze/109.0 p1:KDE:Frameworks5/breeze/108.0
|
||||
- devel c:KDE:Frameworks5/breeze/108.0 p1:KDE:Frameworks5/breeze/107.0
|
||||
- devel c:KDE:Frameworks5/breeze/107.0 p1:KDE:Frameworks5/breeze/105.0
|
||||
- factory c:openSUSE:Factory/breeze/28.0 p1:openSUSE:Factory/breeze/27.0 p2:KDE:Frameworks5/breeze/105.0
|
||||
- devel c:KDE:Frameworks5/breeze/105.0 p1:KDE:Frameworks5/breeze/103.0
|
||||
- factory c:openSUSE:Factory/breeze/27.0 p1:openSUSE:Factory/breeze/26.0 p2:KDE:Frameworks5/breeze/103.0
|
||||
- devel c:KDE:Frameworks5/breeze/103.0 p1:KDE:Frameworks5/breeze/100.0
|
||||
- factory c:openSUSE:Factory/breeze/26.0 p1:openSUSE:Factory/breeze/25.0 p2:KDE:Frameworks5/breeze/100.0
|
||||
- devel c:KDE:Frameworks5/breeze/100.0 p1:KDE:Frameworks5/breeze/99.0
|
||||
- factory c:openSUSE:Factory/breeze/25.0 p1:openSUSE:Factory/breeze/24.0 p2:KDE:Frameworks5/breeze/99.0
|
||||
- devel c:KDE:Frameworks5/breeze/99.0 p1:KDE:Frameworks5/breeze/98.0
|
||||
- devel c:KDE:Frameworks5/breeze/98.0 p1:KDE:Frameworks5/breeze/97.0
|
||||
- devel c:KDE:Frameworks5/breeze/97.0 p1:KDE:Frameworks5/breeze/95.0
|
||||
- factory c:openSUSE:Factory/breeze/24.0 p1:openSUSE:Factory/breeze/23.0 p2:KDE:Frameworks5/breeze/95.0
|
||||
- devel c:KDE:Frameworks5/breeze/95.0 p1:KDE:Frameworks5/breeze/93.0
|
||||
- factory c:openSUSE:Factory/breeze/23.0 p1:openSUSE:Factory/breeze/22.0 p2:KDE:Frameworks5/breeze/93.0
|
||||
- devel c:KDE:Frameworks5/breeze/93.0 p1:KDE:Frameworks5/breeze/91.0
|
||||
- factory c:openSUSE:Factory/breeze/22.0 p1:openSUSE:Factory/breeze/21.0 p2:KDE:Frameworks5/breeze/91.0
|
||||
- devel c:KDE:Frameworks5/breeze/91.0 p1:KDE:Frameworks5/breeze/88.0
|
||||
- factory c:openSUSE:Factory/breeze/21.0 p1:openSUSE:Factory/breeze/20.0 p2:KDE:Frameworks5/breeze/88.0
|
||||
- devel c:KDE:Frameworks5/breeze/88.0 p1:KDE:Frameworks5/breeze/87.0
|
||||
- factory c:openSUSE:Factory/breeze/20.0 p1:openSUSE:Factory/breeze/19.0 p2:KDE:Frameworks5/breeze/87.0
|
||||
- devel c:KDE:Frameworks5/breeze/87.0 p1:KDE:Frameworks5/breeze/86.0
|
||||
- devel c:KDE:Frameworks5/breeze/86.0 p1:KDE:Frameworks5/breeze/85.0
|
||||
- devel c:KDE:Frameworks5/breeze/85.0 p1:KDE:Frameworks5/breeze/84.0
|
||||
- devel c:KDE:Frameworks5/breeze/84.0 p1:KDE:Frameworks5/breeze/83.0
|
||||
- devel c:KDE:Frameworks5/breeze/83.0 p1:KDE:Frameworks5/breeze/82.0
|
||||
- devel c:KDE:Frameworks5/breeze/82.0 p1:KDE:Frameworks5/breeze/81.0
|
||||
- devel c:KDE:Frameworks5/breeze/81.0 p1:KDE:Frameworks5/breeze/80.0
|
||||
- devel c:KDE:Frameworks5/breeze/80.0 p1:KDE:Frameworks5/breeze/79.0
|
||||
- devel c:KDE:Frameworks5/breeze/79.0 p1:KDE:Frameworks5/breeze/78.0
|
||||
- devel c:KDE:Frameworks5/breeze/78.0 p1:KDE:Frameworks5/breeze/76.0
|
||||
- devel c:KDE:Frameworks5/breeze/76.0 p1:KDE:Frameworks5/breeze/75.0
|
||||
- factory c:openSUSE:Factory/breeze/19.0 p1:openSUSE:Factory/breeze/18.0 p2:KDE:Frameworks5/breeze/75.0
|
||||
- devel c:KDE:Frameworks5/breeze/75.0 p1:KDE:Frameworks5/breeze/74.0
|
||||
- devel c:KDE:Frameworks5/breeze/74.0 p1:KDE:Frameworks5/breeze/73.0
|
||||
- devel c:KDE:Frameworks5/breeze/73.0 p1:KDE:Frameworks5/breeze/71.0
|
||||
- factory c:openSUSE:Factory/breeze/18.0 p1:openSUSE:Factory/breeze/17.0 p2:KDE:Frameworks5/breeze/71.0
|
||||
- devel c:KDE:Frameworks5/breeze/71.0 p1:KDE:Frameworks5/breeze/70.0
|
||||
- devel c:KDE:Frameworks5/breeze/70.0 p1:KDE:Frameworks5/breeze/69.0
|
||||
- devel c:KDE:Frameworks5/breeze/69.0 p1:KDE:Frameworks5/breeze/68.0
|
||||
- devel c:KDE:Frameworks5/breeze/68.0 p1:KDE:Frameworks5/breeze/67.0
|
||||
- devel c:KDE:Frameworks5/breeze/67.0 p1:KDE:Frameworks5/breeze/65.0
|
||||
- factory c:openSUSE:Factory/breeze/17.0 p1:openSUSE:Factory/breeze/16.0 p2:KDE:Frameworks5/breeze/65.0
|
||||
- devel c:KDE:Frameworks5/breeze/65.0 p1:KDE:Frameworks5/breeze/64.0
|
||||
- devel c:KDE:Frameworks5/breeze/64.0 p1:KDE:Frameworks5/breeze/62.0
|
||||
- factory c:openSUSE:Factory/breeze/16.0 p1:openSUSE:Factory/breeze/15.0 p2:KDE:Frameworks5/breeze/62.0
|
||||
- devel c:KDE:Frameworks5/breeze/62.0 p1:KDE:Frameworks5/breeze/61.0
|
||||
- devel c:KDE:Frameworks5/breeze/61.0 p1:KDE:Frameworks5/breeze/60.0
|
||||
- devel c:KDE:Frameworks5/breeze/60.0 p1:KDE:Frameworks5/breeze/59.0
|
||||
- devel c:KDE:Frameworks5/breeze/59.0 p1:KDE:Frameworks5/breeze/58.0
|
||||
- devel c:KDE:Frameworks5/breeze/58.0 p1:KDE:Frameworks5/breeze/57.0
|
||||
- devel c:KDE:Frameworks5/breeze/57.0 p1:KDE:Frameworks5/breeze/55.0
|
||||
- factory c:openSUSE:Factory/breeze/15.0 p1:openSUSE:Factory/breeze/14.0 p2:KDE:Frameworks5/breeze/55.0
|
||||
- devel c:KDE:Frameworks5/breeze/55.0 p1:KDE:Frameworks5/breeze/53.0
|
||||
- factory c:openSUSE:Factory/breeze/14.0 p1:openSUSE:Factory/breeze/13.0 p2:KDE:Frameworks5/breeze/53.0
|
||||
- devel c:KDE:Frameworks5/breeze/53.0 p1:KDE:Frameworks5/breeze/51.0
|
||||
- factory c:openSUSE:Factory/breeze/13.0 p1:openSUSE:Factory/breeze/12.0 p2:KDE:Frameworks5/breeze/51.0
|
||||
- devel c:KDE:Frameworks5/breeze/51.0 p1:KDE:Frameworks5/breeze/50.0
|
||||
- devel c:KDE:Frameworks5/breeze/50.0 p1:KDE:Frameworks5/breeze/49.0
|
||||
- devel c:KDE:Frameworks5/breeze/49.0 p1:KDE:Frameworks5/breeze/48.0
|
||||
- devel c:KDE:Frameworks5/breeze/48.0 p1:KDE:Frameworks5/breeze/47.0
|
||||
- devel c:KDE:Frameworks5/breeze/47.0 p1:KDE:Frameworks5/breeze/46.0
|
||||
- devel c:KDE:Frameworks5/breeze/46.0 p1:KDE:Frameworks5/breeze/45.0
|
||||
- devel c:KDE:Frameworks5/breeze/45.0 p1:KDE:Frameworks5/breeze/44.0
|
||||
- devel c:KDE:Frameworks5/breeze/44.0 p1:KDE:Frameworks5/breeze/43.0
|
||||
- devel c:KDE:Frameworks5/breeze/43.0 p1:KDE:Frameworks5/breeze/41.0
|
||||
- factory c:openSUSE:Factory/breeze/12.0 p1:openSUSE:Factory/breeze/11.0 p2:KDE:Frameworks5/breeze/41.0
|
||||
- devel c:KDE:Frameworks5/breeze/41.0 p1:KDE:Frameworks5/breeze/40.0
|
||||
- devel c:KDE:Frameworks5/breeze/40.0 p1:KDE:Frameworks5/breeze/39.0
|
||||
- devel c:KDE:Frameworks5/breeze/39.0 p1:KDE:Frameworks5/breeze/38.0
|
||||
- factory c:openSUSE:Factory/breeze/11.0 p1:openSUSE:Factory/breeze/10.0 p2:KDE:Frameworks5/breeze/38.0
|
||||
- devel c:KDE:Frameworks5/breeze/38.0 p1:KDE:Frameworks5/breeze/36.0
|
||||
- factory c:openSUSE:Factory/breeze/10.0 p1:openSUSE:Factory/breeze/9.0 p2:KDE:Frameworks5/breeze/36.0
|
||||
- devel c:KDE:Frameworks5/breeze/36.0 p1:KDE:Frameworks5/breeze/35.0
|
||||
- devel c:KDE:Frameworks5/breeze/35.0 p1:KDE:Frameworks5/breeze/33.0
|
||||
- factory c:openSUSE:Factory/breeze/9.0 p1:openSUSE:Factory/breeze/8.0 p2:KDE:Frameworks5/breeze/33.0
|
||||
- devel c:KDE:Frameworks5/breeze/33.0 p1:KDE:Frameworks5/breeze/32.0
|
||||
- devel c:KDE:Frameworks5/breeze/32.0 p1:KDE:Frameworks5/breeze/31.0
|
||||
- devel c:KDE:Frameworks5/breeze/31.0 p1:KDE:Frameworks5/breeze/30.0
|
||||
- devel c:KDE:Frameworks5/breeze/30.0 p1:KDE:Frameworks5/breeze/28.0
|
||||
- factory c:openSUSE:Factory/breeze/8.0 p1:openSUSE:Factory/breeze/7.0 p2:KDE:Frameworks5/breeze/28.0
|
||||
- devel c:KDE:Frameworks5/breeze/28.0 p1:KDE:Frameworks5/breeze/27.0
|
||||
- devel c:KDE:Frameworks5/breeze/27.0 p1:KDE:Frameworks5/breeze/25.0
|
||||
- factory c:openSUSE:Factory/breeze/7.0 p1:openSUSE:Factory/breeze/6.0 p2:KDE:Frameworks5/breeze/25.0
|
||||
- devel c:KDE:Frameworks5/breeze/25.0 p1:KDE:Frameworks5/breeze/24.0
|
||||
- devel c:KDE:Frameworks5/breeze/24.0 p1:KDE:Frameworks5/breeze/22.0
|
||||
- factory c:openSUSE:Factory/breeze/6.0 p1:openSUSE:Factory/breeze/5.0 p2:KDE:Frameworks5/breeze/22.0
|
||||
- devel c:KDE:Frameworks5/breeze/22.0 p1:KDE:Frameworks5/breeze/21.0
|
||||
- devel c:KDE:Frameworks5/breeze/21.0 p1:KDE:Frameworks5/breeze/20.0
|
||||
- devel c:KDE:Frameworks5/breeze/20.0 p1:KDE:Frameworks5/breeze/19.0
|
||||
- devel c:KDE:Frameworks5/breeze/19.0 p1:KDE:Frameworks5/breeze/18.0
|
||||
- devel c:KDE:Frameworks5/breeze/18.0 p1:KDE:Frameworks5/breeze/17.0
|
||||
- factory c:openSUSE:Factory/breeze/5.0 p1:openSUSE:Factory/breeze/4.0 p2:KDE:Frameworks5/breeze/17.0
|
||||
- devel c:KDE:Frameworks5/breeze/17.0 p1:KDE:Frameworks5/breeze/16.0
|
||||
- devel c:KDE:Frameworks5/breeze/16.0 p1:KDE:Frameworks5/breeze/15.0
|
||||
- devel c:KDE:Frameworks5/breeze/15.0 p1:KDE:Frameworks5/breeze/14.0
|
||||
- devel c:KDE:Frameworks5/breeze/14.0 p1:KDE:Frameworks5/breeze/13.0
|
||||
- devel c:KDE:Frameworks5/breeze/13.0 p1:KDE:Frameworks5/breeze/12.0
|
||||
- devel c:KDE:Frameworks5/breeze/12.0 p1:KDE:Frameworks5/breeze/11.0
|
||||
- factory c:openSUSE:Factory/breeze/4.0 p1:openSUSE:Factory/breeze/2.0 p2:KDE:Frameworks5/breeze/11.0
|
||||
- devel c:KDE:Frameworks5/breeze/11.0 p1:KDE:Frameworks5/breeze/10.0
|
||||
- devel c:KDE:Frameworks5/breeze/10.0 p1:KDE:Frameworks5/breeze/9.0
|
||||
- devel c:KDE:Frameworks5/breeze/9.0 p1:KDE:Frameworks5/breeze/8.0
|
||||
- devel c:KDE:Frameworks5/breeze/8.0 p1:KDE:Frameworks5/breeze/6.0
|
||||
- factory c:openSUSE:Factory/breeze/2.0 p1:openSUSE:Factory/breeze/1.0 p2:KDE:Frameworks5/breeze/6.0
|
||||
- devel c:KDE:Frameworks5/breeze/6.0 p1:openSUSE:Factory/breeze/1.0
|
||||
- factory c:openSUSE:Factory/breeze/1.0 p1:KDE:Frameworks5/breeze/4.0
|
||||
- factory c:KDE:Frameworks5/breeze/4.0 p1:KDE:Frameworks5/breeze/3.0
|
||||
- factory c:KDE:Frameworks5/breeze/3.0 p1:KDE:Frameworks5/breeze/2.0
|
||||
- factory c:KDE:Frameworks5/breeze/2.0 p1:KDE:Frameworks5/breeze/1.0
|
||||
- factory c:KDE:Frameworks5/breeze/1.0
|
212
tests/fixtures/breeze-expected-tree.yaml
vendored
Normal file
212
tests/fixtures/breeze-expected-tree.yaml
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
- commit: openSUSE:Factory/breeze/43.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/150.0
|
||||
- commit: openSUSE:Factory/breeze/42.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/148.0
|
||||
- KDE:Frameworks5/breeze/147.0
|
||||
- commit: openSUSE:Factory/breeze/41.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/145.0
|
||||
- commit: openSUSE:Factory/breeze/40.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/143.0
|
||||
- KDE:Frameworks5/breeze/142.0
|
||||
- KDE:Frameworks5/breeze/141.0
|
||||
- commit: openSUSE:Factory/breeze/39.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/139.0
|
||||
- commit: openSUSE:Factory/breeze/38.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/137.0
|
||||
- KDE:Frameworks5/breeze/136.0
|
||||
- KDE:Frameworks5/breeze/135.0
|
||||
- KDE:Frameworks5/breeze/134.0
|
||||
- commit: openSUSE:Factory/breeze/37.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/132.0
|
||||
- commit: openSUSE:Factory/breeze/36.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/130.0
|
||||
- commit: openSUSE:Factory/breeze/35.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/128.0
|
||||
- KDE:Frameworks5/breeze/127.0
|
||||
- KDE:Frameworks5/breeze/126.034
|
||||
- KDE:Frameworks5/breeze/126.0
|
||||
- KDE:Frameworks5/breeze/125.0
|
||||
- KDE:Frameworks5/breeze/124.0
|
||||
- KDE:Frameworks5/breeze/123.0
|
||||
- KDE:Frameworks5/breeze/122.0
|
||||
- commit: openSUSE:Factory/breeze/34.0
|
||||
merged:
|
||||
- KDE:Frameworks5:LTS/breeze/14.0
|
||||
- KDE:Frameworks5:LTS/breeze/13.0
|
||||
- KDE:Frameworks5:LTS/breeze/12.0
|
||||
- commit: openSUSE:Factory/breeze/33.0
|
||||
merged:
|
||||
- KDE:Frameworks5:LTS/breeze/11.0
|
||||
- KDE:Frameworks5:LTS/breeze/10.0
|
||||
- KDE:Frameworks5:LTS/breeze/9.0
|
||||
- KDE:Frameworks5:LTS/breeze/8.0
|
||||
- KDE:Frameworks5:LTS/breeze/7.0
|
||||
- KDE:Frameworks5:LTS/breeze/6.0
|
||||
- KDE:Frameworks5:LTS/breeze/5.0
|
||||
- KDE:Frameworks5:LTS/breeze/4.0
|
||||
- KDE:Frameworks5:LTS/breeze/3.0
|
||||
- KDE:Frameworks5:LTS/breeze/2.0
|
||||
- KDE:Frameworks5:LTS/breeze/1.0
|
||||
- commit: openSUSE:Factory/breeze/32.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/120.0
|
||||
- commit: openSUSE:Factory/breeze/31.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/117.0
|
||||
- commit: openSUSE:Factory/breeze/30.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/116.0
|
||||
- KDE:Frameworks5/breeze/115.0
|
||||
- KDE:Frameworks5/breeze/113.0
|
||||
- KDE:Frameworks5/breeze/112.0
|
||||
- commit: openSUSE:Factory/breeze/29.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/111.0
|
||||
- KDE:Frameworks5/breeze/110.0
|
||||
- KDE:Frameworks5/breeze/109.0
|
||||
- KDE:Frameworks5/breeze/108.0
|
||||
- KDE:Frameworks5/breeze/107.0
|
||||
- commit: openSUSE:Factory/breeze/28.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/105.0
|
||||
- commit: openSUSE:Factory/breeze/27.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/103.0
|
||||
- commit: openSUSE:Factory/breeze/26.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/100.0
|
||||
- commit: openSUSE:Factory/breeze/25.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/99.0
|
||||
- KDE:Frameworks5/breeze/98.0
|
||||
- KDE:Frameworks5/breeze/97.0
|
||||
- commit: openSUSE:Factory/breeze/24.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/95.0
|
||||
- commit: openSUSE:Factory/breeze/23.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/93.0
|
||||
- commit: openSUSE:Factory/breeze/22.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/91.0
|
||||
- commit: openSUSE:Factory/breeze/21.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/88.0
|
||||
- commit: openSUSE:Factory/breeze/20.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/87.0
|
||||
- KDE:Frameworks5/breeze/86.0
|
||||
- KDE:Frameworks5/breeze/85.0
|
||||
- KDE:Frameworks5/breeze/84.0
|
||||
- KDE:Frameworks5/breeze/83.0
|
||||
- KDE:Frameworks5/breeze/82.0
|
||||
- KDE:Frameworks5/breeze/81.0
|
||||
- KDE:Frameworks5/breeze/80.0
|
||||
- KDE:Frameworks5/breeze/79.0
|
||||
- KDE:Frameworks5/breeze/78.0
|
||||
- KDE:Frameworks5/breeze/76.0
|
||||
- commit: openSUSE:Factory/breeze/19.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/75.0
|
||||
- KDE:Frameworks5/breeze/74.0
|
||||
- KDE:Frameworks5/breeze/73.0
|
||||
- commit: openSUSE:Factory/breeze/18.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/71.0
|
||||
- KDE:Frameworks5/breeze/70.0
|
||||
- KDE:Frameworks5/breeze/69.0
|
||||
- KDE:Frameworks5/breeze/68.0
|
||||
- KDE:Frameworks5/breeze/67.0
|
||||
- commit: openSUSE:Factory/breeze/17.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/65.0
|
||||
- KDE:Frameworks5/breeze/64.0
|
||||
- commit: openSUSE:Factory/breeze/16.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/62.0
|
||||
- KDE:Frameworks5/breeze/61.0
|
||||
- KDE:Frameworks5/breeze/60.0
|
||||
- KDE:Frameworks5/breeze/59.0
|
||||
- KDE:Frameworks5/breeze/58.0
|
||||
- KDE:Frameworks5/breeze/57.0
|
||||
- commit: openSUSE:Factory/breeze/15.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/55.0
|
||||
- commit: openSUSE:Factory/breeze/14.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/53.0
|
||||
- commit: openSUSE:Factory/breeze/13.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/51.0
|
||||
- KDE:Frameworks5/breeze/50.0
|
||||
- KDE:Frameworks5/breeze/49.0
|
||||
- KDE:Frameworks5/breeze/48.0
|
||||
- KDE:Frameworks5/breeze/47.0
|
||||
- KDE:Frameworks5/breeze/46.0
|
||||
- KDE:Frameworks5/breeze/45.0
|
||||
- KDE:Frameworks5/breeze/44.0
|
||||
- KDE:Frameworks5/breeze/43.0
|
||||
- commit: openSUSE:Factory/breeze/12.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/41.0
|
||||
- KDE:Frameworks5/breeze/40.0
|
||||
- KDE:Frameworks5/breeze/39.0
|
||||
- commit: openSUSE:Factory/breeze/11.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/38.0
|
||||
- commit: openSUSE:Factory/breeze/10.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/36.0
|
||||
- KDE:Frameworks5/breeze/35.0
|
||||
- commit: openSUSE:Factory/breeze/9.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/33.0
|
||||
- KDE:Frameworks5/breeze/32.0
|
||||
- KDE:Frameworks5/breeze/31.0
|
||||
- KDE:Frameworks5/breeze/30.0
|
||||
- commit: openSUSE:Factory/breeze/8.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/28.0
|
||||
- KDE:Frameworks5/breeze/27.0
|
||||
- commit: openSUSE:Factory/breeze/7.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/25.0
|
||||
- KDE:Frameworks5/breeze/24.0
|
||||
- commit: openSUSE:Factory/breeze/6.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/22.0
|
||||
- KDE:Frameworks5/breeze/21.0
|
||||
- KDE:Frameworks5/breeze/20.0
|
||||
- KDE:Frameworks5/breeze/19.0
|
||||
- KDE:Frameworks5/breeze/18.0
|
||||
- commit: openSUSE:Factory/breeze/5.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/17.0
|
||||
- KDE:Frameworks5/breeze/16.0
|
||||
- KDE:Frameworks5/breeze/15.0
|
||||
- KDE:Frameworks5/breeze/14.0
|
||||
- KDE:Frameworks5/breeze/13.0
|
||||
- KDE:Frameworks5/breeze/12.0
|
||||
- commit: openSUSE:Factory/breeze/4.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/11.0
|
||||
- KDE:Frameworks5/breeze/10.0
|
||||
- KDE:Frameworks5/breeze/9.0
|
||||
- KDE:Frameworks5/breeze/8.0
|
||||
- commit: openSUSE:Factory/breeze/2.0
|
||||
merged:
|
||||
- KDE:Frameworks5/breeze/6.0
|
||||
- commit: openSUSE:Factory/breeze/1.0
|
||||
- commit: KDE:Frameworks5/breeze/4.0
|
||||
- commit: KDE:Frameworks5/breeze/3.0
|
||||
- commit: KDE:Frameworks5/breeze/2.0
|
||||
- commit: KDE:Frameworks5/breeze/1.0
|
9551
tests/fixtures/firewalld-data.yaml
vendored
Normal file
9551
tests/fixtures/firewalld-data.yaml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
173
tests/fixtures/firewalld-expected-list.yaml
vendored
Normal file
173
tests/fixtures/firewalld-expected-list.yaml
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
- factory c:openSUSE:Factory/firewalld/73.0 p1:openSUSE:Factory/firewalld/72.0 p2:security:netfilter/firewalld/131.0
|
||||
- devel c:security:netfilter/firewalld/131.0 p1:security:netfilter/firewalld/129.0
|
||||
- factory c:openSUSE:Factory/firewalld/72.0 p1:openSUSE:Factory/firewalld/71.0 p2:security:netfilter/firewalld/129.0
|
||||
- devel c:security:netfilter/firewalld/129.0 p1:security:netfilter/firewalld/128.0
|
||||
- devel c:security:netfilter/firewalld/128.0 p1:security:netfilter/firewalld/127.0
|
||||
- factory c:openSUSE:Factory/firewalld/71.0 p1:openSUSE:Factory/firewalld/70.0 p2:security:netfilter/firewalld/127.0
|
||||
- devel c:security:netfilter/firewalld/127.0 p1:security:netfilter/firewalld/126.0
|
||||
- factory c:openSUSE:Factory/firewalld/70.0 p1:openSUSE:Factory/firewalld/69.0
|
||||
- factory c:openSUSE:Factory/firewalld/69.0 p1:openSUSE:Factory/firewalld/68.0 p2:security:netfilter/firewalld/126.0
|
||||
- devel c:security:netfilter/firewalld/126.0 p1:security:netfilter/firewalld/125.0
|
||||
- factory c:openSUSE:Factory/firewalld/68.0 p1:openSUSE:Factory/firewalld/67.0 p2:security:netfilter/firewalld/125.0
|
||||
- devel c:security:netfilter/firewalld/125.0 p1:security:netfilter/firewalld/124.0
|
||||
- factory c:openSUSE:Factory/firewalld/67.0 p1:openSUSE:Factory/firewalld/66.0 p2:security:netfilter/firewalld/124.0
|
||||
- devel c:security:netfilter/firewalld/124.0 p1:security:netfilter/firewalld/123.0
|
||||
- factory c:openSUSE:Factory/firewalld/66.0 p1:openSUSE:Factory/firewalld/65.0 p2:security:netfilter/firewalld/123.0
|
||||
- devel c:security:netfilter/firewalld/123.0 p1:security:netfilter/firewalld/122.0
|
||||
- factory c:openSUSE:Factory/firewalld/65.0 p1:openSUSE:Factory/firewalld/64.0 p2:security:netfilter/firewalld/122.0
|
||||
- devel c:security:netfilter/firewalld/122.0 p1:security:netfilter/firewalld/121.0
|
||||
- factory c:openSUSE:Factory/firewalld/64.0 p1:openSUSE:Factory/firewalld/63.0 p2:security:netfilter/firewalld/121.0
|
||||
- devel c:security:netfilter/firewalld/121.0 p1:security:netfilter/firewalld/120.0
|
||||
- factory c:openSUSE:Factory/firewalld/63.0 p1:openSUSE:Factory/firewalld/62.0 p2:security:netfilter/firewalld/120.0
|
||||
- devel c:security:netfilter/firewalld/120.0 p1:security:netfilter/firewalld/119.0
|
||||
- factory c:openSUSE:Factory/firewalld/62.0 p1:openSUSE:Factory/firewalld/61.0 p2:security:netfilter/firewalld/119.0
|
||||
- devel c:security:netfilter/firewalld/119.0 p1:security:netfilter/firewalld/118.0
|
||||
- factory c:openSUSE:Factory/firewalld/61.0 p1:openSUSE:Factory/firewalld/60.0 p2:security:netfilter/firewalld/118.0
|
||||
- devel c:security:netfilter/firewalld/118.0 p1:security:netfilter/firewalld/117.0
|
||||
- factory c:openSUSE:Factory/firewalld/60.0 p1:openSUSE:Factory/firewalld/59.0 p2:security:netfilter/firewalld/117.0
|
||||
- devel c:security:netfilter/firewalld/117.0 p1:security:netfilter/firewalld/116.0
|
||||
- factory c:openSUSE:Factory/firewalld/59.0 p1:openSUSE:Factory/firewalld/58.0 p2:security:netfilter/firewalld/116.0
|
||||
- devel c:security:netfilter/firewalld/116.0 p1:security:netfilter/firewalld/115.0
|
||||
- factory c:openSUSE:Factory/firewalld/58.0 p1:openSUSE:Factory/firewalld/57.0 p2:security:netfilter/firewalld/115.0
|
||||
- devel c:security:netfilter/firewalld/115.0 p1:security:netfilter/firewalld/114.0
|
||||
- factory c:openSUSE:Factory/firewalld/57.0 p1:openSUSE:Factory/firewalld/56.0 p2:security:netfilter/firewalld/114.0
|
||||
- devel c:security:netfilter/firewalld/114.0 p1:security:netfilter/firewalld/113.0
|
||||
- factory c:openSUSE:Factory/firewalld/56.0 p1:openSUSE:Factory/firewalld/55.0 p2:security:netfilter/firewalld/113.0
|
||||
- devel c:security:netfilter/firewalld/113.0 p1:security:netfilter/firewalld/112.0
|
||||
- factory c:openSUSE:Factory/firewalld/55.0 p1:openSUSE:Factory/firewalld/54.0 p2:security:netfilter/firewalld/112.0
|
||||
- devel c:security:netfilter/firewalld/112.0 p1:security:netfilter/firewalld/111.0
|
||||
- devel c:security:netfilter/firewalld/111.0 p1:security:netfilter/firewalld/110.0
|
||||
- devel c:security:netfilter/firewalld/110.0 p1:security:netfilter/firewalld/109.0
|
||||
- devel c:security:netfilter/firewalld/109.0 p1:security:netfilter/firewalld/108.0
|
||||
- factory c:openSUSE:Factory/firewalld/54.0 p1:openSUSE:Factory/firewalld/53.0 p2:security:netfilter/firewalld/108.0
|
||||
- devel c:security:netfilter/firewalld/108.0 p1:security:netfilter/firewalld/107.0
|
||||
- factory c:openSUSE:Factory/firewalld/53.0 p1:openSUSE:Factory/firewalld/52.0 p2:security:netfilter/firewalld/107.0
|
||||
- devel c:security:netfilter/firewalld/107.0 p1:security:netfilter/firewalld/106.0
|
||||
- factory c:openSUSE:Factory/firewalld/52.0 p1:openSUSE:Factory/firewalld/51.0
|
||||
- factory c:openSUSE:Factory/firewalld/51.0 p1:openSUSE:Factory/firewalld/50.0
|
||||
- factory c:openSUSE:Factory/firewalld/50.0 p1:openSUSE:Factory/firewalld/49.0 p2:security:netfilter/firewalld/106.0
|
||||
- devel c:security:netfilter/firewalld/106.0 p1:security:netfilter/firewalld/105.0
|
||||
- factory c:openSUSE:Factory/firewalld/49.0 p1:openSUSE:Factory/firewalld/48.0 p2:security:netfilter/firewalld/105.0
|
||||
- devel c:security:netfilter/firewalld/105.0 p1:security:netfilter/firewalld/104.0
|
||||
- devel c:security:netfilter/firewalld/104.0 p1:security:netfilter/firewalld/103.0
|
||||
- devel c:security:netfilter/firewalld/103.0 p1:security:netfilter/firewalld/102.0
|
||||
- factory c:openSUSE:Factory/firewalld/48.0 p1:openSUSE:Factory/firewalld/47.0 p2:security:netfilter/firewalld/102.0
|
||||
- devel c:security:netfilter/firewalld/102.0 p1:security:netfilter/firewalld/101.0
|
||||
- factory c:openSUSE:Factory/firewalld/47.0 p1:openSUSE:Factory/firewalld/46.0 p2:security:netfilter/firewalld/101.0
|
||||
- devel c:security:netfilter/firewalld/101.0 p1:security:netfilter/firewalld/100.0
|
||||
- factory c:openSUSE:Factory/firewalld/46.0 p1:openSUSE:Factory/firewalld/45.0 p2:security:netfilter/firewalld/100.0
|
||||
- devel c:security:netfilter/firewalld/100.0 p1:security:netfilter/firewalld/99.0
|
||||
- factory c:openSUSE:Factory/firewalld/45.0 p1:openSUSE:Factory/firewalld/44.0 p2:security:netfilter/firewalld/99.0
|
||||
- devel c:security:netfilter/firewalld/99.0 p1:security:netfilter/firewalld/98.0
|
||||
- factory c:openSUSE:Factory/firewalld/44.0 p1:openSUSE:Factory/firewalld/43.0 p2:security:netfilter/firewalld/98.0
|
||||
- devel c:security:netfilter/firewalld/98.0 p1:security:netfilter/firewalld/97.0
|
||||
- factory c:openSUSE:Factory/firewalld/43.0 p1:openSUSE:Factory/firewalld/42.0 p2:security:netfilter/firewalld/97.0
|
||||
- devel c:security:netfilter/firewalld/97.0 p1:security:netfilter/firewalld/96.0
|
||||
- devel c:security:netfilter/firewalld/96.0 p1:security:netfilter/firewalld/95.0
|
||||
- devel c:security:netfilter/firewalld/95.0 p1:security:netfilter/firewalld/94.0
|
||||
- devel c:security:netfilter/firewalld/94.0 p1:security:netfilter/firewalld/93.0
|
||||
- factory c:openSUSE:Factory/firewalld/42.0 p1:openSUSE:Factory/firewalld/41.0 p2:security:netfilter/firewalld/93.0
|
||||
- devel c:security:netfilter/firewalld/93.0 p1:security:netfilter/firewalld/92.0
|
||||
- factory c:openSUSE:Factory/firewalld/41.0 p1:openSUSE:Factory/firewalld/40.0 p2:security:netfilter/firewalld/92.0
|
||||
- devel c:security:netfilter/firewalld/92.0 p1:security:netfilter/firewalld/91.0
|
||||
- factory c:openSUSE:Factory/firewalld/40.0 p1:openSUSE:Factory/firewalld/39.0 p2:security:netfilter/firewalld/91.0
|
||||
- devel c:security:netfilter/firewalld/91.0 p1:security:netfilter/firewalld/90.0
|
||||
- factory c:openSUSE:Factory/firewalld/39.0 p1:openSUSE:Factory/firewalld/38.0 p2:security:netfilter/firewalld/90.0
|
||||
- devel c:security:netfilter/firewalld/90.0 p1:security:netfilter/firewalld/89.0
|
||||
- factory c:openSUSE:Factory/firewalld/38.0 p1:openSUSE:Factory/firewalld/37.0 p2:security:netfilter/firewalld/89.0
|
||||
- devel c:security:netfilter/firewalld/89.0 p1:security:netfilter/firewalld/88.0
|
||||
- factory c:openSUSE:Factory/firewalld/37.0 p1:openSUSE:Factory/firewalld/36.0 p2:security:netfilter/firewalld/88.0
|
||||
- devel c:security:netfilter/firewalld/88.0 p1:security:netfilter/firewalld/87.0
|
||||
- devel c:security:netfilter/firewalld/87.0 p1:security:netfilter/firewalld/86.0
|
||||
- devel c:security:netfilter/firewalld/86.0 p1:security:netfilter/firewalld/85.0
|
||||
- devel c:security:netfilter/firewalld/85.0 p1:security:netfilter/firewalld/84.0
|
||||
- factory c:openSUSE:Factory/firewalld/36.0 p1:openSUSE:Factory/firewalld/35.0 p2:security:netfilter/firewalld/84.0
|
||||
- devel c:security:netfilter/firewalld/84.0 p1:security:netfilter/firewalld/83.0
|
||||
- devel c:security:netfilter/firewalld/83.0 p1:security:netfilter/firewalld/82.0
|
||||
- factory c:openSUSE:Factory/firewalld/35.0 p1:openSUSE:Factory/firewalld/34.0 p2:security:netfilter/firewalld/82.0
|
||||
- devel c:security:netfilter/firewalld/82.0 p1:security:netfilter/firewalld/81.0
|
||||
- devel c:security:netfilter/firewalld/81.0 p1:security:netfilter/firewalld/80.0
|
||||
- devel c:security:netfilter/firewalld/80.0 p1:security:netfilter/firewalld/79.0
|
||||
- devel c:security:netfilter/firewalld/79.0 p1:security:netfilter/firewalld/78.0
|
||||
- devel c:security:netfilter/firewalld/78.0 p1:security:netfilter/firewalld/77.0
|
||||
- factory c:openSUSE:Factory/firewalld/34.0 p1:openSUSE:Factory/firewalld/33.0 p2:security:netfilter/firewalld/77.0
|
||||
- devel c:security:netfilter/firewalld/77.0 p1:security:netfilter/firewalld/76.0
|
||||
- devel c:security:netfilter/firewalld/76.0 p1:security:netfilter/firewalld/75.0
|
||||
- devel c:security:netfilter/firewalld/75.0 p1:security:netfilter/firewalld/74.0
|
||||
- factory c:openSUSE:Factory/firewalld/33.0 p1:openSUSE:Factory/firewalld/32.0
|
||||
- factory c:openSUSE:Factory/firewalld/32.0 p1:openSUSE:Factory/firewalld/31.0 p2:security:netfilter/firewalld/74.0
|
||||
- devel c:security:netfilter/firewalld/74.0 p1:security:netfilter/firewalld/71.0
|
||||
- factory c:openSUSE:Factory/firewalld/31.0 p1:openSUSE:Factory/firewalld/30.0
|
||||
- factory c:openSUSE:Factory/firewalld/30.0 p1:openSUSE:Factory/firewalld/29.0 p2:security:netfilter/firewalld/71.0
|
||||
- devel c:security:netfilter/firewalld/71.0 p1:security:netfilter/firewalld/69.0
|
||||
- factory c:openSUSE:Factory/firewalld/29.0 p1:openSUSE:Factory/firewalld/28.0 p2:security:netfilter/firewalld/69.0
|
||||
- devel c:security:netfilter/firewalld/69.0 p1:security:netfilter/firewalld/68.0
|
||||
- factory c:openSUSE:Factory/firewalld/28.0 p1:openSUSE:Factory/firewalld/27.0 p2:security:netfilter/firewalld/68.0
|
||||
- devel c:security:netfilter/firewalld/68.0 p1:security:netfilter/firewalld/67.0
|
||||
- devel c:security:netfilter/firewalld/67.0 p1:security:netfilter/firewalld/65.0
|
||||
- factory c:openSUSE:Factory/firewalld/27.0 p1:openSUSE:Factory/firewalld/26.0 p2:security:netfilter/firewalld/65.0
|
||||
- devel c:security:netfilter/firewalld/65.0 p1:security:netfilter/firewalld/63.0
|
||||
- factory c:openSUSE:Factory/firewalld/26.0 p1:openSUSE:Factory/firewalld/25.0 p2:security:netfilter/firewalld/63.0
|
||||
- devel c:security:netfilter/firewalld/63.0 p1:security:netfilter/firewalld/61.0
|
||||
- factory c:openSUSE:Factory/firewalld/25.0 p1:openSUSE:Factory/firewalld/24.0 p2:security:netfilter/firewalld/61.0
|
||||
- devel c:security:netfilter/firewalld/61.0 p1:security:netfilter/firewalld/60.0
|
||||
- devel c:security:netfilter/firewalld/60.0 p1:security:netfilter/firewalld/59.0
|
||||
- devel c:security:netfilter/firewalld/59.0 p1:security:netfilter/firewalld/57.0
|
||||
- factory c:openSUSE:Factory/firewalld/24.0 p1:openSUSE:Factory/firewalld/23.0 p2:security:netfilter/firewalld/57.0
|
||||
- devel c:security:netfilter/firewalld/57.0 p1:security:netfilter/firewalld/55.0
|
||||
- factory c:openSUSE:Factory/firewalld/23.0 p1:openSUSE:Factory/firewalld/22.0 p2:security:netfilter/firewalld/55.0
|
||||
- devel c:security:netfilter/firewalld/55.0 p1:security:netfilter/firewalld/54.0
|
||||
- devel c:security:netfilter/firewalld/54.0 p1:security:netfilter/firewalld/53.0
|
||||
- devel c:security:netfilter/firewalld/53.0 p1:security:netfilter/firewalld/51.0
|
||||
- factory c:openSUSE:Factory/firewalld/22.0 p1:openSUSE:Factory/firewalld/21.0 p2:security:netfilter/firewalld/51.0
|
||||
- devel c:security:netfilter/firewalld/51.0 p1:security:netfilter/firewalld/50.0
|
||||
- devel c:security:netfilter/firewalld/50.0 p1:security:netfilter/firewalld/48.0
|
||||
- factory c:openSUSE:Factory/firewalld/21.0 p1:openSUSE:Factory/firewalld/20.0 p2:security:netfilter/firewalld/48.0
|
||||
- devel c:security:netfilter/firewalld/48.0 p1:security:netfilter/firewalld/47.0
|
||||
- devel c:security:netfilter/firewalld/47.0 p1:security:netfilter/firewalld/45.0
|
||||
- factory c:openSUSE:Factory/firewalld/20.0 p1:openSUSE:Factory/firewalld/19.0 p2:security:netfilter/firewalld/45.0
|
||||
- devel c:security:netfilter/firewalld/45.0 p1:security:netfilter/firewalld/43.0
|
||||
- factory c:openSUSE:Factory/firewalld/19.0 p1:openSUSE:Factory/firewalld/18.0 p2:security:netfilter/firewalld/43.0
|
||||
- devel c:security:netfilter/firewalld/43.0 p1:security:netfilter/firewalld/41.0
|
||||
- factory c:openSUSE:Factory/firewalld/18.0 p1:openSUSE:Factory/firewalld/17.0 p2:security:netfilter/firewalld/41.0
|
||||
- devel c:security:netfilter/firewalld/41.0 p1:security:netfilter/firewalld/39.0
|
||||
- factory c:openSUSE:Factory/firewalld/17.0 p1:openSUSE:Factory/firewalld/16.0 p2:security:netfilter/firewalld/39.0
|
||||
- devel c:security:netfilter/firewalld/39.0 p1:security:netfilter/firewalld/38.0
|
||||
- devel c:security:netfilter/firewalld/38.0 p1:security:netfilter/firewalld/36.0
|
||||
- factory c:openSUSE:Factory/firewalld/16.0 p1:openSUSE:Factory/firewalld/15.0 p2:security:netfilter/firewalld/36.0
|
||||
- devel c:security:netfilter/firewalld/36.0 p1:security:netfilter/firewalld/34.0
|
||||
- factory c:openSUSE:Factory/firewalld/15.0 p1:openSUSE:Factory/firewalld/14.0 p2:security:netfilter/firewalld/34.0
|
||||
- devel c:security:netfilter/firewalld/34.0 p1:security:netfilter/firewalld/32.0
|
||||
- factory c:openSUSE:Factory/firewalld/14.0 p1:openSUSE:Factory/firewalld/13.0 p2:security:netfilter/firewalld/32.0
|
||||
- devel c:security:netfilter/firewalld/32.0 p1:security:netfilter/firewalld/30.0
|
||||
- factory c:openSUSE:Factory/firewalld/13.0 p1:openSUSE:Factory/firewalld/12.0 p2:security:netfilter/firewalld/30.0
|
||||
- devel c:security:netfilter/firewalld/30.0 p1:security:netfilter/firewalld/28.0
|
||||
- factory c:openSUSE:Factory/firewalld/12.0 p1:openSUSE:Factory/firewalld/11.0 p2:security:netfilter/firewalld/28.0
|
||||
- devel c:security:netfilter/firewalld/28.0 p1:security:netfilter/firewalld/26.0
|
||||
- factory c:openSUSE:Factory/firewalld/11.0 p1:openSUSE:Factory/firewalld/10.0 p2:security:netfilter/firewalld/26.0
|
||||
- devel c:security:netfilter/firewalld/26.0 p1:security:netfilter/firewalld/24.0
|
||||
- factory c:openSUSE:Factory/firewalld/10.0 p1:openSUSE:Factory/firewalld/9.0 p2:security:netfilter/firewalld/24.0
|
||||
- devel c:security:netfilter/firewalld/24.0 p1:security:netfilter/firewalld/22.0
|
||||
- factory c:openSUSE:Factory/firewalld/9.0 p1:openSUSE:Factory/firewalld/8.0 p2:security:netfilter/firewalld/22.0
|
||||
- devel c:security:netfilter/firewalld/22.0 p1:security:netfilter/firewalld/21.0
|
||||
- devel c:security:netfilter/firewalld/21.0 p1:security:netfilter/firewalld/19.0
|
||||
- factory c:openSUSE:Factory/firewalld/8.0 p1:openSUSE:Factory/firewalld/7.0 p2:security:netfilter/firewalld/19.0
|
||||
- devel c:security:netfilter/firewalld/19.0 p1:security:netfilter/firewalld/17.0
|
||||
- factory c:openSUSE:Factory/firewalld/7.0 p1:openSUSE:Factory/firewalld/6.0 p2:security:netfilter/firewalld/17.0
|
||||
- devel c:security:netfilter/firewalld/17.0 p1:security:netfilter/firewalld/15.0
|
||||
- factory c:openSUSE:Factory/firewalld/6.0 p1:openSUSE:Factory/firewalld/5.0 p2:security:netfilter/firewalld/15.0
|
||||
- devel c:security:netfilter/firewalld/15.0 p1:security:netfilter/firewalld/13.0
|
||||
- factory c:openSUSE:Factory/firewalld/5.0 p1:openSUSE:Factory/firewalld/4.0 p2:security:netfilter/firewalld/13.0
|
||||
- devel c:security:netfilter/firewalld/13.0 p1:security:netfilter/firewalld/11.0
|
||||
- factory c:openSUSE:Factory/firewalld/4.0 p1:openSUSE:Factory/firewalld/3.0 p2:security:netfilter/firewalld/11.0
|
||||
- devel c:security:netfilter/firewalld/11.0 p1:security:netfilter/firewalld/9.0
|
||||
- factory c:openSUSE:Factory/firewalld/3.0 p1:openSUSE:Factory/firewalld/2.0 p2:security:netfilter/firewalld/9.0
|
||||
- devel c:security:netfilter/firewalld/9.0 p1:security:netfilter/firewalld/8.0
|
||||
- devel c:security:netfilter/firewalld/8.0 p1:security:netfilter/firewalld/6.0
|
||||
- factory c:openSUSE:Factory/firewalld/2.0 p1:openSUSE:Factory/firewalld/1.0 p2:security:netfilter/firewalld/6.0
|
||||
- devel c:security:netfilter/firewalld/6.0 p1:security:netfilter/firewalld/5.0
|
||||
- devel c:security:netfilter/firewalld/5.0 p1:security:netfilter/firewalld/4.0
|
||||
- devel c:security:netfilter/firewalld/4.0 p1:openSUSE:Factory/firewalld/1.0
|
||||
- factory c:openSUSE:Factory/firewalld/1.0 p1:security:netfilter/firewalld/2.0
|
||||
- factory c:security:netfilter/firewalld/2.0 p1:security:netfilter/firewalld/1.0
|
||||
- factory c:security:netfilter/firewalld/1.0
|
240
tests/fixtures/firewalld-expected-tree.yaml
vendored
Normal file
240
tests/fixtures/firewalld-expected-tree.yaml
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
- commit: openSUSE:Factory/firewalld/73.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/131.0
|
||||
- commit: openSUSE:Factory/firewalld/72.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/129.0
|
||||
- security:netfilter/firewalld/128.0
|
||||
- commit: openSUSE:Factory/firewalld/71.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/127.0
|
||||
- commit: openSUSE:Factory/firewalld/70.0
|
||||
- commit: openSUSE:Factory/firewalld/69.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/126.0
|
||||
- commit: openSUSE:Factory/firewalld/68.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/125.0
|
||||
- commit: openSUSE:Factory/firewalld/67.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/124.0
|
||||
- commit: openSUSE:Factory/firewalld/66.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/123.0
|
||||
- commit: openSUSE:Factory/firewalld/65.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/122.0
|
||||
- commit: openSUSE:Factory/firewalld/64.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/121.0
|
||||
- commit: openSUSE:Factory/firewalld/63.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/120.0
|
||||
- commit: openSUSE:Factory/firewalld/62.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/119.0
|
||||
- commit: openSUSE:Factory/firewalld/61.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/118.0
|
||||
- commit: openSUSE:Factory/firewalld/60.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/117.0
|
||||
- commit: openSUSE:Factory/firewalld/59.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/116.0
|
||||
- commit: openSUSE:Factory/firewalld/58.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/115.0
|
||||
- commit: openSUSE:Factory/firewalld/57.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/114.0
|
||||
- commit: openSUSE:Factory/firewalld/56.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/113.0
|
||||
- commit: openSUSE:Factory/firewalld/55.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/112.0
|
||||
- security:netfilter/firewalld/111.0
|
||||
- security:netfilter/firewalld/110.0
|
||||
- security:netfilter/firewalld/109.0
|
||||
- commit: openSUSE:Factory/firewalld/54.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/108.0
|
||||
- commit: openSUSE:Factory/firewalld/53.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/107.0
|
||||
- commit: openSUSE:Factory/firewalld/52.0
|
||||
- commit: openSUSE:Factory/firewalld/51.0
|
||||
- commit: openSUSE:Factory/firewalld/50.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/106.0
|
||||
- commit: openSUSE:Factory/firewalld/49.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/105.0
|
||||
- security:netfilter/firewalld/104.0
|
||||
- security:netfilter/firewalld/103.0
|
||||
- commit: openSUSE:Factory/firewalld/48.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/102.0
|
||||
- commit: openSUSE:Factory/firewalld/47.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/101.0
|
||||
- commit: openSUSE:Factory/firewalld/46.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/100.0
|
||||
- commit: openSUSE:Factory/firewalld/45.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/99.0
|
||||
- commit: openSUSE:Factory/firewalld/44.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/98.0
|
||||
- commit: openSUSE:Factory/firewalld/43.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/97.0
|
||||
- security:netfilter/firewalld/96.0
|
||||
- security:netfilter/firewalld/95.0
|
||||
- security:netfilter/firewalld/94.0
|
||||
- commit: openSUSE:Factory/firewalld/42.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/93.0
|
||||
- commit: openSUSE:Factory/firewalld/41.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/92.0
|
||||
- commit: openSUSE:Factory/firewalld/40.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/91.0
|
||||
- commit: openSUSE:Factory/firewalld/39.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/90.0
|
||||
- commit: openSUSE:Factory/firewalld/38.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/89.0
|
||||
- commit: openSUSE:Factory/firewalld/37.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/88.0
|
||||
- security:netfilter/firewalld/87.0
|
||||
- security:netfilter/firewalld/86.0
|
||||
- security:netfilter/firewalld/85.0
|
||||
- commit: openSUSE:Factory/firewalld/36.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/84.0
|
||||
- security:netfilter/firewalld/83.0
|
||||
- commit: openSUSE:Factory/firewalld/35.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/82.0
|
||||
- security:netfilter/firewalld/81.0
|
||||
- security:netfilter/firewalld/80.0
|
||||
- security:netfilter/firewalld/79.0
|
||||
- security:netfilter/firewalld/78.0
|
||||
- commit: openSUSE:Factory/firewalld/34.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/77.0
|
||||
- security:netfilter/firewalld/76.0
|
||||
- security:netfilter/firewalld/75.0
|
||||
- commit: openSUSE:Factory/firewalld/33.0
|
||||
- commit: openSUSE:Factory/firewalld/32.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/74.0
|
||||
- commit: openSUSE:Factory/firewalld/31.0
|
||||
- commit: openSUSE:Factory/firewalld/30.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/71.0
|
||||
- commit: openSUSE:Factory/firewalld/29.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/69.0
|
||||
- commit: openSUSE:Factory/firewalld/28.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/68.0
|
||||
- security:netfilter/firewalld/67.0
|
||||
- commit: openSUSE:Factory/firewalld/27.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/65.0
|
||||
- commit: openSUSE:Factory/firewalld/26.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/63.0
|
||||
- commit: openSUSE:Factory/firewalld/25.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/61.0
|
||||
- security:netfilter/firewalld/60.0
|
||||
- security:netfilter/firewalld/59.0
|
||||
- commit: openSUSE:Factory/firewalld/24.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/57.0
|
||||
- commit: openSUSE:Factory/firewalld/23.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/55.0
|
||||
- security:netfilter/firewalld/54.0
|
||||
- security:netfilter/firewalld/53.0
|
||||
- commit: openSUSE:Factory/firewalld/22.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/51.0
|
||||
- security:netfilter/firewalld/50.0
|
||||
- commit: openSUSE:Factory/firewalld/21.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/48.0
|
||||
- security:netfilter/firewalld/47.0
|
||||
- commit: openSUSE:Factory/firewalld/20.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/45.0
|
||||
- commit: openSUSE:Factory/firewalld/19.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/43.0
|
||||
- commit: openSUSE:Factory/firewalld/18.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/41.0
|
||||
- commit: openSUSE:Factory/firewalld/17.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/39.0
|
||||
- security:netfilter/firewalld/38.0
|
||||
- commit: openSUSE:Factory/firewalld/16.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/36.0
|
||||
- commit: openSUSE:Factory/firewalld/15.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/34.0
|
||||
- commit: openSUSE:Factory/firewalld/14.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/32.0
|
||||
- commit: openSUSE:Factory/firewalld/13.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/30.0
|
||||
- commit: openSUSE:Factory/firewalld/12.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/28.0
|
||||
- commit: openSUSE:Factory/firewalld/11.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/26.0
|
||||
- commit: openSUSE:Factory/firewalld/10.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/24.0
|
||||
- commit: openSUSE:Factory/firewalld/9.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/22.0
|
||||
- security:netfilter/firewalld/21.0
|
||||
- commit: openSUSE:Factory/firewalld/8.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/19.0
|
||||
- commit: openSUSE:Factory/firewalld/7.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/17.0
|
||||
- commit: openSUSE:Factory/firewalld/6.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/15.0
|
||||
- commit: openSUSE:Factory/firewalld/5.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/13.0
|
||||
- commit: openSUSE:Factory/firewalld/4.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/11.0
|
||||
- commit: openSUSE:Factory/firewalld/3.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/9.0
|
||||
- security:netfilter/firewalld/8.0
|
||||
- commit: openSUSE:Factory/firewalld/2.0
|
||||
merged:
|
||||
- security:netfilter/firewalld/6.0
|
||||
- security:netfilter/firewalld/5.0
|
||||
- security:netfilter/firewalld/4.0
|
||||
- commit: openSUSE:Factory/firewalld/1.0
|
||||
- commit: security:netfilter/firewalld/2.0
|
||||
- commit: security:netfilter/firewalld/1.0
|
@@ -65,6 +65,15 @@ class TestTreeMethods(unittest.TestCase):
|
||||
def test_000update_repos_tree(self):
|
||||
self.verify_package("000update-repos")
|
||||
|
||||
def test_breeze_tree(self):
|
||||
self.verify_package("breeze")
|
||||
|
||||
def test_firewalld_tree(self):
|
||||
self.verify_package("firewalld")
|
||||
|
||||
def test_FastCGI_tree(self):
|
||||
self.verify_package("FastCGI")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Reference in New Issue
Block a user