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 @@ + + + <description/> + <scmsync>http://localhost:3000/pool/test-GitPkgB#factory</scmsync> +</package> 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_<LOGIN-NAME>_USER\n" " - GIT_OBS_LOGIN_<LOGIN-NAME>_TOKEN\n" " - GIT_OBS_LOGIN_<LOGIN-NAME>_SSH_KEY\n" + " - GIT_OBS_LOGIN_<LOGIN-NAME>_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/<target_branch>/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="<ENV>", @@ -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)