10 Commits

Author SHA256 Message Date
ec5ac4fca3 Don't fail on project git pull request creation. 2025-07-11 10:53:38 +02:00
d7132727a7 Create Pull Requests to specified branches
instead of always using DefaultBranch. This means that target needs
always gets specified now.
2025-07-11 10:52:00 +02:00
74f40f536a message typo 2025-07-11 09:40:36 +02:00
cde46e85f3 Enable code stream publishing 2025-07-11 09:40:36 +02:00
4378568953 Fix logic in crash protection
We must not access review.User object if it is nil
2025-07-11 09:40:36 +02:00
c286e12b67 Try to use Staging Master Project as default build target if available
This allows us to set custom build configuration or repository sets for
pull request projects.
2025-07-11 09:40:36 +02:00
cc9ad1703d Don't crash when new packages got added
The build result request of the base project is failing in this
situation, since the requested package does not exist.

Therefore we need to have seperate lists for proper handling.
2025-07-11 09:40:36 +02:00
2f8b6b4ade Temporary hack to include also changed directories
Need to be clean'd up via proper subdir handling
2025-07-11 09:40:36 +02:00
c11def6005 handle build results different when request with lastbuild=1
In that case we need to

 * ignore repo state as it is the current one. There is no last state
 * handle "unkown" state as finished as the package was never attempted,
   but we don't know the reason (eg. broken source or unresolvable)
2025-07-11 09:40:36 +02:00
0bee48472d Implementing cleanup of closed requests 2025-07-11 09:40:36 +02:00
5 changed files with 92 additions and 60 deletions

View File

@@ -802,6 +802,7 @@ func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleLi
for _, te := range tree.items {
if te.isTree() {
trees[p+te.name+"/"] = te.hash
submoduleList[p+te.name] = te.hash
} else if te.isSubmodule() {
submoduleList[p+te.name] = te.hash
}

View File

@@ -603,14 +603,14 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName s
func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error) {
prOptions := models.CreatePullRequestOption{
Base: repo.DefaultBranch,
Base: targetId,
Head: srcId,
Title: title,
Body: body,
}
if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead(
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(repo.DefaultBranch).WithHead(srcId),
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(targetId).WithHead(srcId),
gitea.transport.DefaultAuthentication,
); err == nil {
return pr.Payload, nil

View File

@@ -551,7 +551,6 @@ func (c *ObsClient) DeleteProject(project string) error {
query.Add("force", "1")
url.RawQuery = query.Encode()
res, err := c.ObsRequestRaw("DELETE", url.String(), nil)
if err != nil {
return err
}

View File

@@ -263,7 +263,7 @@ func ProcessRepoBuildStatus(results, ref []common.PackageBuildStatus) (status Bu
return BuildStatusSummarySuccess, SomeSuccess
}
func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingPrj, buildPrj string) (*common.ProjectMeta, error) {
func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingPrj, buildPrj string, stagingMasterPrj string) (*common.ProjectMeta, error) {
common.LogDebug("repo content fetching ...")
err := FetchPrGit(git, pr)
if err != nil {
@@ -289,7 +289,15 @@ func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullReque
}
}
meta, err := ObsClient.GetProjectMeta(buildPrj)
common.LogDebug("Trying first staging master project: ", stagingMasterPrj)
meta, err := ObsClient.GetProjectMeta(stagingMasterPrj)
if err == nil {
// success, so we use that staging master project as our build project
buildPrj = stagingMasterPrj
} else {
common.LogInfo("error fetching project meta for ", stagingMasterPrj, ". Fall Back to ", buildPrj)
meta, err = ObsClient.GetProjectMeta(buildPrj)
}
if err != nil {
common.LogError("error fetching project meta for", buildPrj, ". Err:", err)
return nil, err
@@ -315,7 +323,9 @@ func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullReque
}
meta.ScmSync = pr.Head.Repo.CloneURL + "?" + strings.Join(urlPkg, "&") + "#" + pr.Head.Sha
meta.Title = fmt.Sprintf("PR#%d to %s", pr.Index, pr.Base.Name)
meta.PublicFlags = common.Flags{Contents: "<disable/>"}
// QE wants it published ... also we should not hardcode it here, since
// it is configurable via the :PullRequest project
// meta.PublicFlags = common.Flags{Contents: "<disable/>"}
meta.Groups = nil
meta.Persons = nil
@@ -412,7 +422,8 @@ func StartOrUpdateBuild(config *common.StagingConfig, git common.Git, gitea comm
var state RequestModification = RequestModificationSourceChanged
if meta == nil {
// new build
meta, err = GenerateObsPrjMeta(git, gitea, pr, obsPrProject, config.ObsProject)
common.LogDebug(" Staging master:", config.StagingProject)
meta, err = GenerateObsPrjMeta(git, gitea, pr, obsPrProject, config.ObsProject, config.StagingProject)
if err != nil {
return RequestModificationNoChange, err
}
@@ -426,6 +437,8 @@ func StartOrUpdateBuild(config *common.StagingConfig, git common.Git, gitea comm
} else {
err = ObsClient.SetProjectMeta(meta)
if err != nil {
x, _ := xml.MarshalIndent(meta, "", " ")
common.LogDebug(" meta:", string(x))
common.LogError("cannot create meta project:", err)
return RequestModificationNoChange, err
}
@@ -459,7 +472,7 @@ func FetchOurLatestActionableReview(gitea common.Gitea, org, repo string, id int
for idx := len(reviews) - 1; idx >= 0; idx-- {
review := reviews[idx]
if review.User != nil || review.User.UserName == Username {
if review.User == nil || review.User.UserName == Username {
if IsDryRun {
// for purposes of moving forward a no-op check
return review, nil
@@ -547,7 +560,7 @@ func CleanupPullNotification(gitea common.Gitea, thread *models.NotificationThre
}
if pr.State != "closed" {
common.LogInfo(" ignoring peding PR", thread.Subject.HTMLURL, " state:", pr.State)
common.LogInfo(" ignoring pending PR", thread.Subject.HTMLURL, " state:", pr.State)
return false
}
@@ -641,7 +654,6 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
common.LogError("No PR associated with review:", org, "/", repo, "#", id, "Error:", err)
return true, err
}
common.LogDebug("PR state:", pr.State)
if pr.State == "closed" {
// dismiss the review
@@ -658,40 +670,68 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
}
}
if review, err := FetchOurLatestActionableReview(gitea, org, repo, id); err == nil {
common.LogInfo("processing review", review.HTMLURL, "state", review.State)
// Fetching data
review, review_error := FetchOurLatestActionableReview(gitea, org, repo, id)
if pr.State != "closed" && review_error != nil {
// Nothing to do
return true, nil
}
err = FetchPrGit(git, pr)
if err != nil {
common.LogError("Cannot fetch PR git:", pr.URL)
return false, err
err = FetchPrGit(git, pr)
if err != nil {
common.LogError("Cannot fetch PR git:", pr.URL)
return false, err
}
// we want the possibly pending modification here, in case stagings are added, etc.
// jobs of review team to deal with issues
common.LogDebug("QA configuration fetching ...", common.StagingConfigFile)
data, err := git.GitCatFile(pr.Head.Sha, pr.Head.Sha, common.StagingConfigFile)
if err != nil {
common.LogError("Staging config", common.StagingConfigFile, "not found in PR to the project. Aborting.")
if !IsDryRun {
_, err = gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find project config in PR: "+common.ProjectConfigFile)
}
return true, err
}
// we want the possibly pending modification here, in case stagings are added, etc.
// jobs of review team to deal with issues
common.LogDebug("QA configuration fetching ...", common.StagingConfigFile)
data, err := git.GitCatFile(pr.Head.Sha, pr.Head.Sha, common.StagingConfigFile)
if err != nil {
common.LogError("Staging config", common.StagingConfigFile, "not found in PR to the project. Aborting.")
if !IsDryRun {
_, err = gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find project config in PR: "+common.ProjectConfigFile)
}
stagingConfig, err := common.ParseStagingConfig(data)
if err != nil {
common.LogError("Error parsing config file", common.StagingConfigFile, err)
}
if stagingConfig.ObsProject == "" {
common.LogError("Cannot find reference project for PR#", pr.Index)
if !IsDryRun && review_error == nil {
_, err := gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find reference project")
return true, err
}
return true, nil
}
stagingConfig, err := common.ParseStagingConfig(data)
if err != nil {
common.LogError("Error parsing config file", common.StagingConfigFile, err)
}
common.LogDebug("ObsProject:", stagingConfig.ObsProject)
stagingProject := GetObsProjectAssociatedWithPr(stagingConfig, ObsClient.HomeProject, pr)
if stagingConfig.ObsProject == "" {
common.LogError("Cannot find reference project for PR#", pr.Index)
// Cleanup projects
if pr.State == "closed" {
// review is done, cleanup
common.LogInfo(" -- closed request, cleanup staging projects")
for _, setup := range stagingConfig.QA {
if !IsDryRun {
_, err := gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find reference project")
return true, err
ObsClient.DeleteProject(stagingProject + ":" + setup.Name)
}
return true, nil
}
if stagingProject != "" {
if !IsDryRun {
ObsClient.DeleteProject(stagingProject)
}
}
return true, nil
}
// Process review aka setup projects
if review_error == nil {
common.LogInfo("processing review", review.HTMLURL, "state", review.State)
meta, err := ObsClient.GetProjectMeta(stagingConfig.ObsProject)
if err != nil {
@@ -725,16 +765,6 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
}
}
if stagingConfig.StagingProject != "" {
// staging project must either be nothing or be *under* the target project.
// other setups are currently not supported
// NOTE: this is user input, so we need some limits here
l := len(stagingConfig.ObsProject)
if l >= len(stagingConfig.StagingProject) || stagingConfig.ObsProject != stagingConfig.StagingProject[0:l] {
common.LogError("StagingProject (", stagingConfig.StagingProject, ") is not child of target project", stagingConfig.ObsProject)
}
}
if meta.Name != stagingConfig.ObsProject {
common.LogError("staging.config . ObsProject:", stagingConfig.ObsProject, " is not target project name", meta.Name)
if !IsDryRun {
@@ -755,17 +785,22 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
common.LogDebug(" # head submodules:", len(headSubmodules))
common.LogDebug(" # base submodules:", len(baseSubmodules))
modifiedOrNew := make([]string, 0, 16)
modifiedPackages := make([]string, 0, 16)
newPackages := make([]string, 0, 16)
if !stagingConfig.RebuildAll {
for pkg, headOid := range headSubmodules {
if baseOid, exists := baseSubmodules[pkg]; !exists || baseOid != headOid {
modifiedOrNew = append(modifiedOrNew, pkg)
if len(baseOid) > 0 {
modifiedPackages = append(modifiedPackages, pkg)
} else {
newPackages = append(newPackages, pkg)
}
common.LogDebug(pkg, ":", baseOid, "->", headOid)
}
}
}
if len(modifiedOrNew) == 0 {
if len(modifiedPackages) == 0 && len(newPackages) == 0 {
rebuild_all := false || stagingConfig.RebuildAll
reviews, err := gitea.GetPullRequestReviews(pr.Base.Repo.Owner.UserName, pr.Base.Repo.Name, pr.Index)
@@ -842,13 +877,13 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
gitea.AddComment(pr, msg)
}
baseResult, err := ObsClient.LastBuildResults(stagingConfig.ObsProject, modifiedOrNew...)
baseResult, err := ObsClient.LastBuildResults(stagingConfig.ObsProject, modifiedPackages...)
if err != nil {
common.LogError("failed fetching ref project status for", stagingConfig.ObsProject, ":", err)
}
stagingResult, err := ObsClient.BuildStatus(stagingProject)
if err != nil {
common.LogError("failed fetching ref project status for", stagingProject, ":", err)
common.LogError("failed fetching stage project status for", stagingProject, ":", err)
}
buildStatus := ProcessBuildStatus(stagingResult, baseResult)

View File

@@ -87,11 +87,6 @@ func AllocatePRProcessor(req *common.PullRequestWebhookEvent, configs common.Aut
}
func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string, []string, error) {
prjGitPR, err := prset.GetPrjGitPR()
if err != nil {
return nil, nil, err
}
git := pr.git
subList, err := git.GitSubmoduleList(common.DefaultGitPrj, "HEAD")
if err != nil {
@@ -113,13 +108,15 @@ func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string,
revert := false
if pr.PR.State != "open" {
// remove PR from PrjGit
var valid bool
if prHead, valid = git.GitSubmoduleCommitId(common.DefaultGitPrj, repo, prjGitPR.PR.MergeBase); !valid {
common.LogError("Failed fetching original submodule commit id for repo")
return nil, nil, err
prjGitPR, err := prset.GetPrjGitPR()
if prjGitPR != nil {
// remove PR from PrjGit
var valid bool
if prHead, valid = git.GitSubmoduleCommitId(common.DefaultGitPrj, repo, prjGitPR.PR.MergeBase); !valid {
common.LogError("Failed fetching original submodule commit id for repo")
return nil, nil, err
}
}
revert = true
}