diff --git a/behave/container-files/opt/setup/fixtures/pac/test-GitPkgB.xml b/behave/container-files/opt/setup/fixtures/pac/test-GitPkgB.xml
new file mode 100644
index 000000000..b98eab39d
--- /dev/null
+++ b/behave/container-files/opt/setup/fixtures/pac/test-GitPkgB.xml
@@ -0,0 +1,5 @@
+
+
+
+ http://localhost:3000/pool/test-GitPkgB#factory
+
diff --git a/behave/container-files/opt/setup/gitea.sh b/behave/container-files/opt/setup/gitea.sh
index 0e64887a0..8e9aa99de 100644
--- a/behave/container-files/opt/setup/gitea.sh
+++ b/behave/container-files/opt/setup/gitea.sh
@@ -96,6 +96,10 @@ function add_ssh_key {
create_org pool
create_org_repo pool test-GitPkgA
+create_org_repo pool test-GitPkgB
+create_org_repo pool test-GitPkgC
+create_org openSUSE
+create_org_repo openSUSE Leap
add_ssh_key admin $TOKEN_ADMIN /root/.ssh/admin.pub
add_ssh_key alice $TOKEN_ALICE /root/.ssh/alice.pub
add_ssh_key bob $TOKEN_BOB /root/.ssh/bob.pub
@@ -143,6 +147,116 @@ popd
$OSC api -X PUT '/source/test:factory/test-GitPkgA/_meta' --file "$TOPDIR"/fixtures/pac/test-GitPkgA.xml
+# create test-GitPkgB package based on test-pkgA
+# * change the package name
+# * use changelog dates as commit/commiter dates for reproducibility
+
+GITDIR="$(mktemp -d)"
+pushd "$GITDIR"
+
+git init --initial-branch factory
+# git commiter equals to the configured user
+git config user.name "Geeko Packager"
+git config user.email "email@example.com"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-1.spec test-GitPkgB.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-1.changes test-GitPkgB.changes
+sed 's@test-pkgA@test-GitPkgB@' -i *
+git add *
+DATE="2022-01-03 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Initial commit" --date "$DATE"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-2.spec test-GitPkgB.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-2.changes test-GitPkgB.changes
+sed 's@test-pkgA@test-GitPkgB@' -i *
+git add *
+DATE="2022-01-04 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Version 2" --date "$DATE"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-3.spec test-GitPkgB.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-3.changes test-GitPkgB.changes
+sed 's@test-pkgA@test-GitPkgB@' -i *
+git add *
+DATE="2022-01-05 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Version 3" --date "$DATE"
+
+git remote add origin http://admin:opensuse@localhost:3000/pool/test-GitPkgB.git
+git push --set-upstream origin factory
+
+popd
+
+# create test-GitPkgB package in test:factory that has scmsync set to gitea
+$OSC api -X PUT '/source/test:factory/test-GitPkgB/_meta' --file "$TOPDIR"/fixtures/pac/test-GitPkgB.xml
+
+
+# create test-GitPkgC package based on test-pkgA
+# * change the package name
+# * use changelog dates as commit/commiter dates for reproducibility
+
+GITDIR="$(mktemp -d)"
+pushd "$GITDIR"
+
+git init --initial-branch factory
+# git commiter equals to the configured user
+git config user.name "Geeko Packager"
+git config user.email "email@example.com"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-1.spec test-GitPkgC.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-1.changes test-GitPkgC.changes
+sed 's@test-pkgA@test-GitPkgC@' -i *
+git add *
+DATE="2022-01-03 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Initial commit" --date "$DATE"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-2.spec test-GitPkgC.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-2.changes test-GitPkgC.changes
+sed 's@test-pkgA@test-GitPkgC@' -i *
+git add *
+DATE="2022-01-04 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Version 2" --date "$DATE"
+
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-3.spec test-GitPkgC.spec
+cp -a "$TOPDIR"/fixtures/pac/test-pkgA-3.changes test-GitPkgC.changes
+sed 's@test-pkgA@test-GitPkgC@' -i *
+git add *
+DATE="2022-01-05 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Version 3" --date "$DATE"
+
+git remote add origin http://admin:opensuse@localhost:3000/pool/test-GitPkgC.git
+git push --set-upstream origin factory
+
+popd
+
+# create test-GitPkgC package in test:factory that has scmsync set to gitea
+$OSC api -X PUT '/source/test:factory/test-GitPkgC/_meta' --file "$TOPDIR"/fixtures/pac/test-GitPkgC.xml
+
+
+# create openSUSE/Leap project repository with submodules test-GitPkgA, test-GitPkgB and test-GitPkgC
+
+GITDIR="$(mktemp -d)"
+pushd "$GITDIR"
+
+git init --initial-branch factory
+git config user.name "Geeko Packager"
+git config user.email "email@example.com"
+git remote add origin http://admin:opensuse@localhost:3000/openSUSE/Leap.git
+
+# Add test-GitPkgA as a submodule
+git submodule add -b factory ../../pool/test-GitPkgA.git test-GitPkgA
+# Add test-GitPkgB as a submodule
+git submodule add -b factory ../../pool/test-GitPkgB.git test-GitPkgB
+# Add test-GitPkgC as a submodule
+git submodule add -b factory ../../pool/test-GitPkgC.git test-GitPkgC
+
+git add .gitmodules test-GitPkgA test-GitPkgB test-GitPkgC
+DATE="2022-01-06 11:22:33 UTC"
+GIT_COMMITTER_DATE="$DATE" git commit -a -m "Add package submodules" --date "$DATE"
+
+git push --set-upstream origin factory
+
+popd
+
+
# gitea-action-runner
systemctl enable podman.socket
systemctl enable gitea-action-runner.service
diff --git a/behave/features/git-staging-group.feature b/behave/features/git-staging-group.feature
new file mode 100644
index 000000000..39ca78ce7
--- /dev/null
+++ b/behave/features/git-staging-group.feature
@@ -0,0 +1,675 @@
+Feature: `git-obs staging group` command
+
+
+Background:
+ Given I set working directory to "{context.osc.temp}"
+
+@destructive
+Scenario: Conflicts check for --fork-repo and --target
+ When I execute git-obs with args "staging group --target pool/test-GitPkgA#1 --fork-repo myfork pool/test-GitPkgA#2 pool/test-GitPkgA#3"
+ Then the exit code is 2
+ And stderr contains "--fork-repo conflicts with --target"
+
+@destructive
+Scenario: Group PRs then add and remove one using --target and staging remove
+ # Setup:
+ # - Bob creates package PRs for pkgA, pkgB and pkgC
+ # - Admin creates staging PRs Leap#1 (pkgA), Leap#2 (pkgB), Leap#3 (pkgC)
+ # - Bob groups Leap#1 + Leap#2 → creates Leap#4 from Bob's fork
+ # - Bob adds Leap#3 to the group using --target openSUSE/Leap#4
+ # - Bob removes Leap#3 from the group using staging remove
+ Given I use git-obs login "bob"
+ # Package PR 1 (Bob → pkgA)
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Bob/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2 (Bob → pkgB)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Bob/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ # Package PR 3 (Bob → pkgC)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgC"
+ And I execute git-obs with args "repo clone Bob/test-GitPkgC --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgC"
+ And I execute "git checkout -b pkg3"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.3@' *.spec"
+ And I execute "git commit -m 'v1.3' -a"
+ And I execute "git push origin pkg3"
+ And I execute git-obs with args "pr create --title 'Package update 3' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Bob/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add bob ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Bob/test-GitPkgA.git"
+ And I execute "git fetch bob pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Bob/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add bob ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Bob/test-GitPkgB.git"
+ And I execute "git fetch bob pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Staging Project PR 3 (update submodule to Bob/test-GitPkgC pkg3)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgC"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgC"
+ And I execute "git remote add bob ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Bob/test-GitPkgC.git"
+ And I execute "git fetch bob pkg3"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgC"
+ And I execute "git commit -m 'Update test-GitPkgC submodule'"
+ And I execute "git push origin leap-pkgC"
+ And I execute git-obs with args "pr create --title 'Staging Group C' --description='PR: pool/test-GitPkgC!1' --target-branch factory --self"
+ # Add labels
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/3/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ Given I use git-obs login "bob"
+ # Bob groups Leap#1 + Leap#2 → creates Leap#4 from Bob's fork
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2"
+ Then the exit code is 0
+ And stderr contains "WARNING: No fork organization specified. Defaulting to a private fork in 'Bob'."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/4 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+ # Bob adds Leap#3 (pkgC) to the existing group
+ When I execute git-obs with args "staging group openSUSE/Leap#3 --target openSUSE/Leap#4"
+ Then the exit code is 0
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/4 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+ And stdout contains "PR: pool/test-gitpkgc!1"
+ # Bob removes Leap#3 (pkgC) from the group
+ When I execute git-obs with args "staging remove openSUSE/Leap#4 pool/test-GitPkgC#1"
+ Then the exit code is 0
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/4 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+ And stdout doesn't contain "PR: pool/test-gitpkgc!1"
+
+@destructive
+Scenario: Collaborator adds a staging PR to an existing group using --target
+ # Setup:
+ # - Alice creates pkgA and pkgB package PRs
+ # - Bob creates pkgC package PR
+ # - Admin creates staging PRs Leap#1 (pkgA), Leap#2 (pkgB), Leap#3 (pkgC)
+ # - Bob groups Leap#1 + Leap#2 → creates Leap#4 from Bob's fork
+ # - Admin grants Alice write access to Bob's Leap fork
+ # - Alice adds Leap#3 to the existing group via --target Leap#4
+ Given I use git-obs login "alice"
+ # Package PR 1 (Alice → pkgA)
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2 (Alice → pkgB)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "bob"
+ # Package PR 3 (Bob → pkgC)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgC"
+ And I execute git-obs with args "repo clone Bob/test-GitPkgC --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgC"
+ And I execute "git checkout -b pkg3"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.3@' *.spec"
+ And I execute "git commit -m 'v1.3' -a"
+ And I execute "git push origin pkg3"
+ And I execute git-obs with args "pr create --title 'Package update 3' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Staging Project PR 3 (update submodule to Bob/test-GitPkgC pkg3)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgC"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgC"
+ And I execute "git remote add bob ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Bob/test-GitPkgC.git"
+ And I execute "git fetch bob pkg3"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgC"
+ And I execute "git commit -m 'Update test-GitPkgC submodule'"
+ And I execute "git push origin leap-pkgC"
+ And I execute git-obs with args "pr create --title 'Staging Group C' --description='PR: pool/test-GitPkgC!1' --target-branch factory --self"
+ # Add labels
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/3/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ Given I use git-obs login "bob"
+ # Bob groups Leap#1 + Leap#2, creating Leap#4 from Bob's fork (Bob/Leap)
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2"
+ Then the exit code is 0
+ And stderr contains "WARNING: No fork organization specified. Defaulting to a private fork in 'Bob'."
+ Given I use git-obs login "admin"
+ # Grant Alice write access to Bob's Leap fork so she can push to it
+ And I execute git-obs with args "api -X PUT /repos/Bob/Leap/collaborators/Alice --data='{{"permission": "admin"}}'"
+ Given I use git-obs login "alice"
+ # Alice adds Leap#3 (pkgC) to the existing staging group (Leap#4)
+ When I execute git-obs with args "staging group openSUSE/Leap#3 --target openSUSE/Leap#4"
+ Then the exit code is 0
+ And stdout contains "Unable to update pull request openSUSE/Leap#4"
+ And I execute git-obs with args "api -X GET "/repos/openSUSE/leap/pulls/4/commits" | jq '.[].commit | select (.author.name|startswith("Alice")) | .message'"
+ And stdout contains "Merge package submodules from openSUSE/Leap!3"
+
+@destructive
+Scenario: Collaborator adds a staging PR to an existing org group using --target
+ # Setup:
+ # - Alice creates pkgA and pkgB package PRs
+ # - Bob creates pkgC package PR
+ # - Admin creates staging PRs Leap#1 (pkgA), Leap#2 (pkgB), Leap#3 (pkgC)
+ # - Admin creates a 'devel' org and adds both Alice and Bob as members
+ # - Bob groups Leap#1 + Leap#2 using --fork-owner devel → creates Leap#4 from devel/Leap fork
+ # - Alice adds Leap#3 to the existing group via --target openSUSE/Leap#4
+ Given I use git-obs login "alice"
+ # Package PR 1 (Alice → pkgA)
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2 (Alice → pkgB)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "bob"
+ # Package PR 3 (Bob → pkgC)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgC"
+ And I execute git-obs with args "repo clone Bob/test-GitPkgC --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgC"
+ And I execute "git checkout -b pkg3"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.3@' *.spec"
+ And I execute "git commit -m 'v1.3' -a"
+ And I execute "git push origin pkg3"
+ And I execute git-obs with args "pr create --title 'Package update 3' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Staging Project PR 3 (update submodule to Bob/test-GitPkgC pkg3)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgC"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgC"
+ And I execute "git remote add bob ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Bob/test-GitPkgC.git"
+ And I execute "git fetch bob pkg3"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgC"
+ And I execute "git commit -m 'Update test-GitPkgC submodule'"
+ And I execute "git push origin leap-pkgC"
+ And I execute git-obs with args "pr create --title 'Staging Group C' --description='PR: pool/test-GitPkgC!1' --target-branch factory --self"
+ # Add labels
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/3/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ # Create the 'devel' org and add both Alice and Bob as members (team id=3 is the Owners team)
+ And I execute git-obs with args "api -X POST /orgs --data='{{"username": "devel"}}'"
+ And I execute git-obs with args "api -X PUT '/teams/3/members/Alice'"
+ And I execute git-obs with args "api -X PUT '/teams/3/members/Bob'"
+ Given I use git-obs login "bob"
+ # Bob groups Leap#1 + Leap#2 into devel/Leap fork → creates Leap#4
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2 --fork-owner devel"
+ Then the exit code is 0
+ And stderr contains "Cannot find a matching fork of openSUSE/Leap for devel, creating one..."
+ Given I use git-obs login "alice"
+ # Alice adds Leap#3 (pkgC) to the existing staging group (Leap#4) via devel/Leap fork
+ When I execute git-obs with args "staging group openSUSE/Leap#3 --target openSUSE/Leap#4"
+ Then the exit code is 0
+ And stdout contains "You have push access to the head repository devel/Leap"
+ And I execute git-obs with args "api -X GET "/repos/openSUSE/leap/pulls/4/commits" | jq '.[].commit | select (.author.name|startswith("Alice")) | .message'"
+ And stdout contains "Merge package submodules from openSUSE/Leap!3"
+
+@destructive
+Scenario: User is a collaborator in the project repository
+ # setup: create package PRs and then two staging project PRs
+ Given I use git-obs login "alice"
+ # Package PR 1
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Add labels and create devel org
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X PUT '/repos/openSUSE/leap/collaborators/Alice' --data='{{"permission": "write"}}'"
+ Given I use git-obs login "alice"
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2"
+ Then the exit code is 0
+ And stdout contains "You have push access to the target repository openSUSE/Leap, the pull request will be created from a branch in the target repository."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/3 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+
+@destructive
+Scenario: Warning when --fork-owner is not specified with multiple PRs
+ # setup: create package PRs and then two staging project PRs
+ Given I use git-obs login "alice"
+ # Package PR 1
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Add labels
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ Given I use git-obs login "alice"
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2"
+ Then the exit code is 0
+ And stderr contains "WARNING: No fork organization specified. Defaulting to a private fork in 'Alice'."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/3 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+
+@destructive
+Scenario: Warning when --fork-owner is not specified with multiple PRs, but --fork-repo is specified
+ # setup: create package PRs and then two staging project PRs
+ Given I use git-obs login "alice"
+ # Package PR 1
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Add labels
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ Given I use git-obs login "alice"
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2 --fork-repo myLeap"
+ Then the exit code is 0
+ And stderr contains "WARNING: No fork organization specified. Defaulting to a private fork in 'Alice'."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/3 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+
+
+@destructive
+Scenario: Create a fork in the specified organization
+ # setup: create package PRs and then two staging project PRs
+ Given I use git-obs login "alice"
+ # Package PR 1
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Add labels and create devel org
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /orgs --data='{{"username": "devel"}}'"
+ And I execute git-obs with args "api -X PUT '/teams/3/members/Alice'"
+ Given I use git-obs login "alice"
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2 --fork-owner devel"
+ Then the exit code is 0
+ And stderr contains "Cannot find a matching fork of openSUSE/Leap for devel, creating one..."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/3 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
+ And stdout contains "PR: pool/test-gitpkgb!1"
+
+@destructive
+Scenario: Create a fork in a specified organization with a different repo name
+ # setup: create package PRs and then two staging project PRs
+ Given I use git-obs login "alice"
+ # Package PR 1
+ And I execute git-obs with args "repo fork pool/test-GitPkgA"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgA --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgA"
+ And I execute "git checkout -b pkg1"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
+ And I execute "git commit -m 'v1.1' -a"
+ And I execute "git push origin pkg1"
+ And I execute git-obs with args "pr create --title 'Package update 1' --description='some text' --target-branch factory"
+ # Package PR 2
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo fork pool/test-GitPkgB"
+ And I execute git-obs with args "repo clone Alice/test-GitPkgB --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/test-GitPkgB"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b pkg2"
+ And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
+ And I execute "git commit -m 'v1.2' -a"
+ And I execute "git push origin pkg2"
+ And I execute git-obs with args "pr create --title 'Package update 2' --description='some text' --target-branch factory"
+ Given I use git-obs login "admin"
+ # Staging Project PR 1 (update submodule to Alice/test-GitPkgA pkg1)
+ And I set working directory to "{context.osc.temp}"
+ And I execute git-obs with args "repo clone openSUSE/Leap --no-ssh-strict-host-key-checking"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout -b leap-pkgA"
+ And I set env "GIT_SSH_COMMAND" to "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i {context.fixtures}/ssh-keys/admin"
+ And I execute "git submodule update --init --recursive"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgA"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgA.git"
+ And I execute "git fetch alice pkg1"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgA"
+ And I execute "git commit -m 'Update test-GitPkgA submodule'"
+ And I execute "git push origin leap-pkgA"
+ And I execute git-obs with args "pr create --title 'Staging Group A' --description='PR: pool/test-GitPkgA!1' --target-branch factory --self"
+ # Staging Project PR 2 (update submodule to Alice/test-GitPkgB pkg2)
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git checkout factory"
+ And I execute "git checkout -b leap-pkgB"
+ And I set working directory to "{context.osc.temp}/Leap/test-GitPkgB"
+ And I execute "git remote add alice ssh://gitea@localhost:$GITEA_SERVER_SSH_PORT/Alice/test-GitPkgB.git"
+ And I execute "git fetch alice pkg2"
+ And I execute "git checkout FETCH_HEAD"
+ And I set working directory to "{context.osc.temp}/Leap"
+ And I execute "git add test-GitPkgB"
+ And I execute "git commit -m 'Update test-GitPkgB submodule'"
+ And I execute "git push origin leap-pkgB"
+ And I execute git-obs with args "pr create --title 'Staging Group B' --description='PR: pool/test-GitPkgB!1' --target-branch factory --self"
+ # Add labels and create devel org
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/Backlog", "color": "ffffff"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/labels --data='{{"name": "staging/In Progress", "color": "afafaf"}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/1/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /repos/openSUSE/Leap/issues/2/labels --data='{{"labels": ["staging/Backlog"]}}'"
+ And I execute git-obs with args "api -X POST /orgs --data='{{"username": "devel"}}'"
+ And I execute git-obs with args "api -X PUT '/teams/3/members/Alice'"
+ Given I use git-obs login "alice"
+ When I execute git-obs with args "staging group openSUSE/Leap#1 openSUSE/Leap#2 --fork-owner devel --fork-repo myLeap"
+ Then the exit code is 0
+ And stderr contains "Fork devel/myLeap doesn't exist, creating it..."
+ And I execute git-obs with args "api -X GET /repos/openSUSE/Leap/pulls/3 | jq .body"
+ And stdout contains "PR: pool/test-gitpkga!1"
\ No newline at end of file
diff --git a/behave/features/steps/osc.py b/behave/features/steps/osc.py
index 6825e75e4..f0080a19e 100644
--- a/behave/features/steps/osc.py
+++ b/behave/features/steps/osc.py
@@ -109,6 +109,10 @@ def get_cmd(self):
class GitObs(CommandBase):
CONFIG_NAME = "config.yml"
+ def __init__(self, context):
+ self.login_name = "admin"
+ super().__init__(context)
+
def write_config(self):
data = {
"logins": [
@@ -118,6 +122,7 @@ def write_config(self):
"user": "Admin",
"token": 40 * "1",
"ssh_key": f"{self.context.fixtures}/ssh-keys/admin",
+ "ssh_strict_host_key_checking": False,
"default": True,
},
{
@@ -126,6 +131,7 @@ def write_config(self):
"user": "Alice",
"token": 40 * "a",
"ssh_key": f"{self.context.fixtures}/ssh-keys/alice",
+ "ssh_strict_host_key_checking": False,
"default": False,
},
{
@@ -134,6 +140,7 @@ def write_config(self):
"user": "Bob",
"token": 40 * "b",
"ssh_key": f"{self.context.fixtures}/ssh-keys/bob",
+ "ssh_strict_host_key_checking": False,
"default": False,
},
],
@@ -147,7 +154,7 @@ def get_cmd(self):
git_obs_cmd = self.context.config.userdata.get("git-obs", "git-obs")
cmd = [git_obs_cmd]
cmd += ["--gitea-config", self.config]
- cmd += ["-G", f"admin"]
+ cmd += ["-G", self.login_name]
return cmd
@@ -176,6 +183,37 @@ def step_impl(context, args):
context.cmd_stderr = re.sub(r"^.*InsecureRequestWarning.*\n warnings.warn\(\n", "", context.cmd_stderr)
+@behave.step("I use git-obs login \"{login}\"")
+def step_impl(context, login):
+ context.git_obs.login_name = login
+ # Set git identity env vars to match the Gitea user for this login,
+ # so commits made in subsequent steps are attributed to the right author.
+ git_identity = {
+ "admin": ("Admin", "admin@example.com"),
+ "alice": ("Alice", "alice@example.com"),
+ "bob": ("Bob", "bob@example.com"),
+ }
+ name, email = git_identity.get(login.lower(), (login, f"{login.lower()}@example.com"))
+ context.env["GIT_AUTHOR_NAME"] = name
+ context.env["GIT_AUTHOR_EMAIL"] = email
+ context.env["GIT_COMMITTER_NAME"] = name
+ context.env["GIT_COMMITTER_EMAIL"] = email
+ # Set GIT_SSH_COMMAND for this login so that both direct git commands and
+ # submodule clones (which spawn child git processes that don't inherit
+ # core.sshCommand from the parent repo config) use the right SSH key.
+ ssh_keys = {
+ "admin": "admin",
+ "alice": "alice",
+ "bob": "bob",
+ }
+ key_name = ssh_keys.get(login.lower(), login.lower())
+ key_path = f"{context.fixtures}/ssh-keys/{key_name}"
+ context.env["GIT_SSH_COMMAND"] = (
+ f"ssh -o IdentitiesOnly=yes -o IdentityFile={key_path}"
+ f" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR"
+ )
+
+
@behave.step('I execute git-osc-precommit-hook with args "{args}"')
def step_impl(context, args):
args = args.format(context=context)
diff --git a/osc/commandline_git.py b/osc/commandline_git.py
index ab484410a..98f6bef25 100644
--- a/osc/commandline_git.py
+++ b/osc/commandline_git.py
@@ -216,6 +216,7 @@ def init_arguments(self):
" - GIT_OBS_LOGIN__USER\n"
" - GIT_OBS_LOGIN__TOKEN\n"
" - GIT_OBS_LOGIN__SSH_KEY\n"
+ " - GIT_OBS_LOGIN__SSH_STRICT_HOST_KEY_CHECKING\n"
"Setting new ``name`` or ``url`` is not possible.\n"
"Please note that the login name that is part of the environmental variable name is case sensitive."
),
diff --git a/osc/commands_git/login_add.py b/osc/commands_git/login_add.py
index 124f514f8..4066a1a27 100644
--- a/osc/commands_git/login_add.py
+++ b/osc/commands_git/login_add.py
@@ -21,6 +21,12 @@ def init_arguments(self):
self.parser.add_argument("--user", help="Gitea username", required=True)
self.parser.add_argument("--token", help="Gitea access token; omit or set to '-' to invoke a secure interactive prompt")
self.parser.add_argument("--ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
+ self.parser.add_argument(
+ "--ssh-strict-host-key-checking",
+ help="Enable strict SSH host key checking",
+ choices=["0", "1", "yes", "no"],
+ default=None,
+ )
self.parser.add_argument("--git-uses-http", action="store_true", help="Git uses http(s) instead of SSH", default=None)
self.parser.add_argument("--quiet", action="store_true", help="Mute unnecessary output when using this login entry")
self.parser.add_argument("--set-as-default", help="Set the new login entry as default", action="store_true", default=None)
@@ -40,12 +46,20 @@ def run(self, args):
if args.token and not re.match(r"^[0-9a-f]{40}$", args.token):
self.parser.error("Invalid token format, 40 hexadecimal characters expected")
+ if args.ssh_strict_host_key_checking in ("0", "no"):
+ ssh_strict_host_key_checking = False
+ elif args.ssh_strict_host_key_checking in ("1", "yes"):
+ ssh_strict_host_key_checking = True
+ else:
+ ssh_strict_host_key_checking = None
+
login_obj = gitea_api.Login(
name=args.name,
url=args.url,
user=args.user,
token=args.token,
ssh_key=args.ssh_key,
+ ssh_strict_host_key_checking=ssh_strict_host_key_checking,
git_uses_http=args.git_uses_http,
default=args.set_as_default,
)
diff --git a/osc/commands_git/login_update.py b/osc/commands_git/login_update.py
index c682252fc..ebebf76b3 100644
--- a/osc/commands_git/login_update.py
+++ b/osc/commands_git/login_update.py
@@ -22,6 +22,12 @@ def init_arguments(self):
self.parser.add_argument("--new-user", metavar="USER", help="Gitea username")
self.parser.add_argument("--new-token", metavar="TOKEN", help="Gitea access token; set to '-' to invoke a secure interactive prompt")
self.parser.add_argument("--new-ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
+ self.parser.add_argument(
+ "--new-ssh-strict-host-key-checking",
+ help="Enable strict SSH host key checking",
+ choices=["0", "1", "yes", "no"],
+ default=None,
+ )
self.parser.add_argument("--new-git-uses-http", help="Git uses http(s) instead of SSH", choices=["0", "1", "yes", "no"], default=None)
self.parser.add_argument("--new-quiet", help="Mute unnecessary output when using this login entry", choices=["0", "1", "yes", "no"], default=None)
self.parser.add_argument("--set-as-default", action="store_true", help="Set the login entry as default")
@@ -52,6 +58,13 @@ def run(self, args):
else:
new_git_uses_http = None
+ if args.new_ssh_strict_host_key_checking in ("0", "no"):
+ new_ssh_strict_host_key_checking = False
+ elif args.new_ssh_strict_host_key_checking in ("1", "yes"):
+ new_ssh_strict_host_key_checking = True
+ else:
+ new_ssh_strict_host_key_checking = None
+
if args.new_quiet in ("0", "no"):
new_quiet = False
elif args.new_quiet in ("1", "yes"):
@@ -66,6 +79,7 @@ def run(self, args):
new_user=args.new_user,
new_token=args.new_token,
new_ssh_key=args.new_ssh_key,
+ new_ssh_strict_host_key_checking=new_ssh_strict_host_key_checking,
new_git_uses_http=new_git_uses_http,
new_quiet=new_quiet,
set_as_default=args.set_as_default,
diff --git a/osc/commands_git/staging_group.py b/osc/commands_git/staging_group.py
index 94719bf53..8d77cdc06 100644
--- a/osc/commands_git/staging_group.py
+++ b/osc/commands_git/staging_group.py
@@ -1,4 +1,6 @@
import os
+import subprocess
+import sys
import osc.commandline_git
@@ -27,6 +29,11 @@ def init_arguments(self):
help="Owner of the fork used to create a new pull request. Defaults to the currently logged user. Conflicts with --target.",
)
+ self.add_argument(
+ "--fork-repo",
+ help="Name of the fork repository used to create a new pull request. Conflicts with --target.",
+ )
+
self.add_argument(
"--fork-branch",
help="Branch in the fork used to create a new pull request. Defaults to 'for//group-YYYY-MM-DD_HH-MM-SS'. Conflicts with --target."
@@ -75,6 +82,9 @@ def run(self, args):
if args.fork_owner and args.target:
self.parser.error("--fork-owner conflicts with --target")
+ if args.fork_repo and args.target:
+ self.parser.error("--fork-repo conflicts with --target")
+
if args.fork_branch and args.target:
self.parser.error("--fork-branch conflicts with --target")
@@ -161,15 +171,50 @@ def run(self, args):
fork_owner = target_owner
fork_repo = target_repo
else:
- fork_owner = args.fork_owner if args.fork_owner else user_obj.login
- fork_repo = None
- forks = gitea_api.Fork.list(self.gitea_conn, target_owner, target_repo)
- for repo in forks:
- if repo.owner.lower() == fork_owner.lower():
- fork_repo = repo.repo
- break
- if not fork_repo:
- raise gitea_api.GitObsRuntimeError(f"Cannot find a matching fork of {target_owner}/{target_repo} for user {fork_owner}")
+ if args.fork_owner:
+ fork_owner = args.fork_owner
+ else:
+ fork_owner = user_obj.login
+ from osc.output import tty
+ print(f" * {tty.colorize('WARNING', 'yellow,bold')}: No fork organization specified. Defaulting to a private fork in '{fork_owner}'.", file=sys.stderr)
+
+ if args.fork_repo:
+ fork_repo = args.fork_repo
+ try:
+ gitea_api.Repo.get(self.gitea_conn, fork_owner, fork_repo)
+ except gitea_api.GiteaException as e:
+ if e.status == 404:
+ print(f"Fork {fork_owner}/{fork_repo} doesn't exist, creating it...", file=sys.stderr)
+ try:
+ # Only pass target_org if fork_owner is not the current user (i.e., forking to an org)
+ fork_target_org = None if fork_owner.lower() == user_obj.login.lower() else fork_owner
+ repo_obj = gitea_api.Fork.create(
+ self.gitea_conn, target_owner, target_repo,
+ new_repo_name=fork_repo, target_org=fork_target_org
+ )
+ except gitea_api.ForkExists as e2:
+ pass
+ else:
+ raise
+ else:
+ fork_repo = None
+ forks = gitea_api.Fork.list(self.gitea_conn, target_owner, target_repo)
+ for repo in forks:
+ if repo.owner.lower() == fork_owner.lower():
+ fork_repo = repo.repo
+ break
+ if not fork_repo:
+ print(f"Cannot find a matching fork of {target_owner}/{target_repo} for {fork_owner}, creating one...", file=sys.stderr)
+ try:
+ # Only pass target_org if fork_owner is not the current user (i.e., forking to an org)
+ fork_target_org = None if fork_owner.lower() == user_obj.login.lower() else fork_owner
+ repo_obj = gitea_api.Fork.create(
+ self.gitea_conn, target_owner, target_repo,
+ target_org=fork_target_org
+ )
+ fork_repo = repo_obj.repo
+ except gitea_api.ForkExists as e:
+ fork_repo = e.fork_repo
# dates in ISO 8601 format cannot be part of a valid branch name, we need a custom format
fork_branch = args.fork_branch if args.fork_branch else f"for/{target_branch}/group-{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}"
@@ -226,12 +271,17 @@ def run(self, args):
has_push_access = False
if target.pr_obj.head_can_push:
- print(f"You have push access to the head repository of the target pull request {target_owner}/{target_repo}#{target_number}, the pull request will be updated by pushing to the head branch.")
+ print(f"You have push access to the head repository {target.pr_obj._data['head']['repo']['full_name']}, the pull request will be updated by pushing to the head branch.")
has_push_access = True
if target.pr_obj._data['head']['repo']['fork'] and has_push_access:
# if the head repo is a fork and we have push access to it, we can push directly to the head branch
- target.git._run_git(["remote", "set-url", "fork", target.pr_obj._data['head']['repo']['ssh_url']])
+ fork_ssh_url = target.pr_obj._data['head']['repo']['ssh_url']
+ try:
+ target.git._run_git(["remote", "set-url", "fork", fork_ssh_url])
+ except subprocess.CalledProcessError:
+ target.git._run_git(["remote", "add", "fork", fork_ssh_url])
+
# locally merge package pull requests to the target project pull request (don't change anything on server yet)
updated_packages = []
@@ -258,9 +308,12 @@ def run(self, args):
updated_packages_str += f" + {len(updated_packages) - max_packages} more"
title = args.title if args.title else f"{target.pr_obj.title}, {updated_packages_str}"
- # if args.target is not set, we've created a new pull request with all 'PR:' references included
- # if args.target is set (which is the case here), we need to update the description with the newly added 'PR:' references
- target.pr_obj.set(self.gitea_conn, target_owner, target_repo, target_number, title=title, description=target.pr_obj.body)
+ try:
+ # if args.target is not set, we've created a new pull request with all 'PR:' references included
+ # if args.target is set (which is the case here), we need to update the description with the newly added 'PR:' references
+ target.pr_obj.set(self.gitea_conn, target_owner, target_repo, target_number, title=title, description=target.pr_obj.body)
+ except Exception as e:
+ print(f"Unable to update pull request {target_owner}/{target_repo}#{target_number}: {e}")
for owner, repo, number in args.pr_list:
pr = pr_map[(owner.lower(), repo.lower(), number)]
diff --git a/osc/commands_git/staging_remove.py b/osc/commands_git/staging_remove.py
index e29a6e168..304f7b856 100644
--- a/osc/commands_git/staging_remove.py
+++ b/osc/commands_git/staging_remove.py
@@ -1,5 +1,5 @@
import osc.commandline_git
-
+import subprocess
class StagingRemoveCommand(osc.commandline_git.GitObsCommand):
"""
@@ -52,7 +52,7 @@ def run(self, args):
refs = [(owner.lower(), repo.lower(), number) for owner, repo, number in refs]
missing_refs = []
for owner, repo, number in args.pr_list:
- if (owner, repo, number) not in refs:
+ if (owner.lower(), repo.lower(), number) not in refs:
missing_refs.append(f"{owner}/{repo}#{number}")
if missing_refs:
msg = f"The following pull requests are not referenced in the project pull request: {', '.join(missing_refs)}"
@@ -73,6 +73,13 @@ def run(self, args):
pr = pr_map[(owner.lower(), repo.lower(), number)]
target.remove(pr)
+ if target.pr_obj._data['head']['repo']['fork']:
+ fork_ssh_url = target.pr_obj._data['head']['repo']['ssh_url']
+ try:
+ target.git._run_git(["remote", "set-url", "fork", fork_ssh_url])
+ except subprocess.CalledProcessError:
+ target.git._run_git(["remote", "add", "fork", fork_ssh_url])
+
# push to git repo associated with the target pull request
target.git.push(remote="fork", branch=f"pull/{target.pr_obj.number}:{target.pr_obj.head_branch}")
# update target pull request
diff --git a/osc/gitea_api/conf.py b/osc/gitea_api/conf.py
index ce79d28cb..2b7fd16fe 100644
--- a/osc/gitea_api/conf.py
+++ b/osc/gitea_api/conf.py
@@ -20,6 +20,7 @@ class Login(BaseModel):
user: str = Field() # type: ignore[assignment]
token: str = Field() # type: ignore[assignment]
ssh_key: Optional[str] = Field() # type: ignore[assignment]
+ ssh_strict_host_key_checking: Optional[bool] = Field() # type: ignore[assignment]
git_uses_http: Optional[bool] = Field() # type: ignore[assignment]
quiet: Optional[bool] = Field() # type: ignore[assignment]
default: Optional[bool] = Field() # type: ignore[assignment]
@@ -77,6 +78,11 @@ def to_human_readable_string(self, *, show_token: bool = False):
table.add("User", self.user)
if self.ssh_key:
table.add("Private SSH key path", self.ssh_key)
+ if self.ssh_strict_host_key_checking is not None:
+ table.add(
+ "SSH strict host key checking",
+ "yes" if self.ssh_strict_host_key_checking else "no",
+ )
if self.git_uses_http:
table.add("Git uses http(s)", "yes" if self.git_uses_http else "no")
if self.quiet:
@@ -143,6 +149,9 @@ def get_login(self, name: Optional[str] = None) -> Login:
env_gitea_user = os.environ.get("GIT_OBS_GITEA_USER", None)
env_gitea_token = os.environ.get("GIT_OBS_GITEA_TOKEN", None)
env_ssh_key = os.environ.get("GIT_OBS_GITEA_SSH_KEY", None)
+ env_ssh_strict_host_key_checking = os.environ.get("GIT_OBS_GITEA_SSH_STRICT_HOST_KEY_CHECKING", None)
+ if env_ssh_strict_host_key_checking is not None:
+ env_ssh_strict_host_key_checking = env_ssh_strict_host_key_checking.lower() in ("1", "yes", "true")
if env_gitea_url and env_gitea_user and env_gitea_token:
return Login(
name="",
@@ -150,6 +159,7 @@ def get_login(self, name: Optional[str] = None) -> Login:
user=env_gitea_user,
token=env_gitea_token,
ssh_key=env_ssh_key,
+ ssh_strict_host_key_checking=env_ssh_strict_host_key_checking,
)
for login in self.list_logins():
@@ -241,6 +251,7 @@ def update_login(
new_user: Optional[str] = None,
new_token: Optional[str] = None,
new_ssh_key: Optional[str] = None,
+ new_ssh_strict_host_key_checking: Optional[bool] = None,
new_git_uses_http: Optional[bool] = None,
new_quiet: Optional[bool] = None,
set_as_default: Optional[bool] = None,
@@ -258,6 +269,12 @@ def update_login(
if new_ssh_key is not None:
login.ssh_key = new_ssh_key
+ if new_ssh_strict_host_key_checking is None:
+ # keep the original value
+ pass
+ else:
+ login.ssh_strict_host_key_checking = new_ssh_strict_host_key_checking
+
if new_git_uses_http is None:
# keep the original value
pass
diff --git a/osc/gitea_api/pr.py b/osc/gitea_api/pr.py
index a39e54552..3e5fd0e41 100644
--- a/osc/gitea_api/pr.py
+++ b/osc/gitea_api/pr.py
@@ -6,6 +6,8 @@
from typing import Optional
from typing import Tuple
+from osc.gitea_api.exceptions import GitObsRuntimeError
+
from .common import GiteaModel
from .connection import Connection
from .connection import GiteaHTTPResponse
@@ -374,6 +376,10 @@ def create(
url = conn.makeurl("repos", target_owner, target_repo, "pulls")
if labels:
ids = Repo.get_label_ids(conn, target_owner, target_repo)
+ # Check that all requested labels exist in the target repo
+ missing_labels = [i for i in labels if i not in ids]
+ if missing_labels:
+ raise GitObsRuntimeError(f"Label(s) not found in {target_owner}/{target_repo}: {', '.join(missing_labels)}")
labels = [ids[i] for i in labels]
data = {
"base": target_branch,
diff --git a/osc/gitea_api/repo.py b/osc/gitea_api/repo.py
index c82751dea..99d8fcd98 100644
--- a/osc/gitea_api/repo.py
+++ b/osc/gitea_api/repo.py
@@ -102,7 +102,7 @@ def clone(
reference_if_able: Optional[str] = None,
depth: Optional[int] = None,
ssh_private_key_path: Optional[str] = None,
- ssh_strict_host_key_checking: bool = True,
+ ssh_strict_host_key_checking: Optional[bool] = None,
) -> str:
"""
Clone a repository using 'git clone' command, return absolute path to it.
@@ -162,6 +162,11 @@ def clone(
f"-o IdentityFile={shlex.quote(ssh_private_key_path)}",
]
+ if ssh_strict_host_key_checking is None:
+ ssh_strict_host_key_checking = conn.login.ssh_strict_host_key_checking
+ if ssh_strict_host_key_checking is None:
+ ssh_strict_host_key_checking = True
+
if not ssh_strict_host_key_checking:
ssh_args += [
"-o StrictHostKeyChecking=no",
@@ -233,6 +238,7 @@ def clone_or_update(
depth: Optional[int] = None,
remote: Optional[str] = None,
ssh_private_key_path: Optional[str] = None,
+ ssh_strict_host_key_checking: Optional[bool] = None,
):
from osc import gitea_api
@@ -248,6 +254,7 @@ def clone_or_update(
reference_if_able=reference_if_able,
depth=depth,
ssh_private_key_path=ssh_private_key_path,
+ ssh_strict_host_key_checking=ssh_strict_host_key_checking,
)
git = gitea_api.Git(directory)
diff --git a/osc/gitea_api/staging.py b/osc/gitea_api/staging.py
index 97a4fc01e..0d02755f5 100644
--- a/osc/gitea_api/staging.py
+++ b/osc/gitea_api/staging.py
@@ -130,7 +130,7 @@ def remove(self, package_pr):
from . import GitObsRuntimeError
from . import PullRequest
- self.pr_obj._data["body"] = PullRequest.remove_pr_references(self.pr_obj.body, [(package_pr.owner, package_pr.repo, package_pr.number)])
+ self.pr_obj._data["body"] = PullRequest.remove_pr_references(self.pr_obj.body, [(package_pr.owner.lower(), package_pr.repo.lower(), package_pr.number)])
submodule = self.submodules_by_owner_repo.get((package_pr.owner.lower(), package_pr.repo.lower()), None)
base_submodule = self.base_submodules_by_owner_repo.get((package_pr.owner.lower(), package_pr.repo.lower()), None)