fbrnch-1.8: src/Cmd/RequestBranch.hs
{-# LANGUAGE CPP, OverloadedStrings #-}
module Cmd.RequestBranch (
requestBranchesCmd,
requestPkgBranches,
waitForKojiPkgBranch
) where
import Fedora.Krb (fasIdFromKrb)
import Network.HTTP.Query (lookupKey')
import SimplePrompt (promptEnter)
import System.Time.Extra (sleep)
import Common
import Common.System
import Branches
import Bugzilla
import Cmd.SrcDeps (srcDeps)
import Git
import Koji (fedoraHub, kojiBuildTarget')
import ListReviews
import Package
import Pagure
-- FIXME try to catch expired token (maybe record date when key updated?)
-- request-branch and request-repo require pagure.io API key in ~/.config/rpkg/fedpkg.conf for opening releng-scm issue: following is error for expired key
-- "Could not execute request_branch: The following error occurred while creating a new issue in Pagure: Invalid or expired token. Please visit https://pagure.io/settings#nav-api-tab to get or renew your API token.
-- For invalid or expired tokens please set a new token in your user configuration by running:
-- fedpkg set-pagure-token
-- The command is interactive; enter the new token when prompted."
-- FIXME option to do koji scratch build instead of mock
requestBranchesCmd :: Bool -> Bool -> Bool -> Maybe Branch -> Bool
-> (BranchesReq,[String]) -> IO ()
requestBranchesCmd quiet reviews skipcheck mrecursebr mock (breq, ps) = do
if null ps
then do
when (isJust mrecursebr) $
error' "please specify a package dir when using --recurse-deps"
isPkgGit <- isPkgGitSshRepo
if reviews
then do
pkgs <- map reviewBugToPackage <$> listReviews ReviewUnbranched
when isPkgGit $
promptEnter "Press Enter to continue inside this dist-git dir!"
mapM_ (\ p -> withExistingDirectory p $ requestPkgBranches quiet (length pkgs > 1) mock breq (Package $ takeFileName p)) pkgs
else
if isPkgGit
then do
pkg <- Package <$> getDirectoryName
requestPkgBranches quiet False mock breq pkg >>=
mapM_ (waitForKojiPkgBranch skipcheck pkg)
else error' "not a dist-git dir: specify package(s)"
else do
pkgs <-
case mrecursebr of
Just br -> do
-- FIXME --rpmopt
deps <- concat <$> srcDeps False [] (br,ps)
when (null deps) $
error' "no deps found!"
putStrLn $ unwords deps
unless quiet $
promptEnter "\nPress Enter to check these packages for branches"
return deps
Nothing -> return ps
newPkgBranches <-
forM pkgs $ \ p ->
withExistingDirectory p $ do
pkg <- Package <$> getDirectoryName
requestPkgBranches quiet (length pkgs > 1) mock breq pkg
putNewLn
forM_ (zip pkgs newPkgBranches) $ \(pkg,newbrs) ->
forM_ newbrs $ waitForKojiPkgBranch skipcheck (Package $ takeFileName pkg)
requestPkgBranches :: Bool -> Bool -> Bool -> BranchesReq -> Package
-> IO [Branch]
requestPkgBranches quiet multiple mock breq pkg = do
when (multiple && not quiet) $
putPkgHdr pkg
brs <- localBranches False
branches <- getRequestedBranches brs breq
if null branches
then do
case breq of
Branches [_] -> putStrLn "exists"
_ -> putStrLn "branches exist"
return []
else do
gitFetchSilent True
brs' <- localBranches False
forM_ branches $ \br ->
when (showBranch br `elem` brs') $
let pkgPrefix = if multiple then unPackage pkg ++ ": " else ""
in putStrLn $ pkgPrefix ++ showBranch br +-+ "branch already exists locally"
if null (map showBranch branches \\ brs')
then return []
else do
branches' <- getRequestedBranches brs' (Branches branches)
haveAccess <- havePkgAccess pkg
if not haveAccess
then do
putStrLn "You do not have commit access to this package: request would be rejected"
return []
else do
newbranches <- filterExistingBranchRequests branches'
if null newbranches
then return []
else do
mbidsession <- bzReviewSession
urls <- forM newbranches $ \ br -> do
when mock $ fedpkg_ "mockbuild" ["--root", mockRoot br Nothing]
when (length branches > 1) $ putStr $ showBranch br ++ " "
-- 1. Can timeout like this:
-- Could not execute request_branch: HTTPSConnectionPool(host='pagure.io', port=443): Read timed out. (read timeout=60)
-- fbrnch: readCreateProcess: fedpkg "request-branch" "epel9" (exit 1): failed
-- &
-- 2. Can fail like this:
-- Could not execute request_branch: The following error occurred while trying to get the active release branches in PDC: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
-- <title>500 Internal Server Error</title>
-- <p>The server encountered an internal error or
-- misconfiguration and was unable to complete
-- your request.</p> [...]
-- fbrnch: readCreateProcess: fedpkg "request-branch" "epel9" (exit 1): failed
u <- fedpkg "request-branch" [showBranch br]
putStrLn u
return u
whenJust mbidsession $ \(bid,session) ->
commentBug session bid $ unlines urls
return newbranches
where
-- doRequestBr :: Bool -> Branch -> IO String
-- doRequestBr multibr br = do
-- when mock $ fedpkg_ "mockbuild" ["--root", mockRoot br]
-- when multiple $ putStr (unPackage pkg ++ " ")
-- when multibr $ putStr (show br)
-- -- Can timeout like this:
-- -- Could not execute request_branch: HTTPSConnectionPool(host='pagure.io', port=443): Read timed out. (read timeout=60)
-- -- fbrnch: readCreateProcess: fedpkg "request-branch" "epel9" (exit 1): failed
-- u <- fedpkg "request-branch" [show br]
-- putStrLn $ ' ' : u
-- return $ show br +-+ u
filterExistingBranchRequests :: [Branch] -> IO [Branch]
filterExistingBranchRequests branches = do
existing <- fedoraBranchesNoRawhide (localBranches True)
let pkgPrefix = if multiple then unPackage pkg ++ ": " else ""
forM_ branches $ \ br ->
when (br `elem` existing) $
putStrLn $ pkgPrefix ++ showBranch br +-+ "branch already exists"
let brs' = branches \\ existing
if null brs'
then return []
else do
current <- delete Rawhide <$> listRemoteBranches (unPackage pkg)
forM_ brs' $ \ br ->
when (br `elem` current) $
putStrLn $ pkgPrefix ++ showBranch br +-+ "remote branch already exists"
let newbranches = brs' \\ current
if null newbranches
then return []
else do
fasid <- fasIdFromKrb
-- FIXME retry on HttpExceptionRequest ... ConnectionTimeout
erecent <- pagureListProjectIssueTitlesStatus "pagure.io"
"releng/fedora-scm-requests"
[makeItem "author" fasid, makeItem "status" "all",
makeItem "per_page" "100"]
case erecent of
Left err -> error' err
Right recent -> filterM (notExistingRequest recent) newbranches
-- FIXME print invalid requests?
notExistingRequest :: [IssueTitleStatus] -> Branch -> IO Bool
notExistingRequest requests br = do
let processed = filter processedIssueFilter requests
unless (null processed) $ do
putStrLn $ "Branch request already exists for" +-+ unPackage pkg ++ ":" ++ showBranch br
mapM_ printScmIssue processed
return $ null processed
where
processedIssueFilter issue =
pagureIssueTitle issue == ("New Branch \"" ++ showBranch br ++ "\" for \"rpms/" ++ unPackage pkg ++ "\"")
&&
pagureIssueCloseStatus issue == Just "Processed"
havePkgAccess :: Package -> IO Bool
havePkgAccess pkg = do
fasid <- fasIdFromKrb
epkginfo <- pagureProjectInfo srcfpo ("rpms" </> unPackage pkg)
case epkginfo of
Left err -> error' err
Right pkginfo -> do
let (admins, committers) = usersWithAccess pkginfo :: ([String],[String])
(gadmins, gcommitters) = groupsWithAccess pkginfo :: ([String],[String])
access <- do
if fasid `elem` admins ++ committers
then return True
else
fmap or <$>
forM (gadmins ++ gcommitters) $ \grp -> do
egrpinfo <- pagureGroupInfo srcfpo grp []
case egrpinfo of
Left err -> error' err
Right grpinfo ->
return $ fasid `elem` (lookupKey' "members" grpinfo :: [String])
unless access $
warning $ "-" +-+ fasid +-+ "does not have access, ask:" +-+ unwords (nub $ admins ++ gadmins)
return access
where
usersWithAccess pkginfo =
let access = lookupKey' "access_users" pkginfo
owners = lookupKey' "owner" access
admins = lookupKey' "admin" access
collabs = lookupKey' "collaborator" access
commits = lookupKey' "commit" access
in (owners ++ admins, commits ++ collabs)
groupsWithAccess pkginfo =
let access = lookupKey' "access_groups" pkginfo
admins = lookupKey' "admin" access
collabs = lookupKey' "collaborator" access
commits = lookupKey' "commit" access
in (admins, commits ++ collabs)
waitForKojiPkgBranch :: Bool -- skipcheck
-> Package -> Branch -> IO ()
waitForKojiPkgBranch skipcheck pkg br =
unless skipcheck $ do
putStrLn $ "waiting for" +-+ unPackage pkg +-+ "to be added to" +-+ showBranch br ++ "-build"
(buildtag,_desttag) <- kojiBuildTarget' fedoraHub (showBranch br)
waitBuildTag buildtag
where
waitBuildTag :: String -> IO ()
waitBuildTag buildtag = do
sleep 30 -- wait first to avoid "(undefined package)"
ok <- cmdBool "koji" ["list-pkgs", "--quiet", "--package=" ++ unPackage pkg, "--tag=" ++ buildtag]
unless ok $ waitBuildTag buildtag