The fact that Copy Artifacts fails 50% of the time when running from a manual trigger in the Build Pipeline Plugin has been driving me crazy, so in good open source denizen style I am trying to fix it. Turns out there's a larger underlying problem that I need some advice on.
When the job is manually triggered in the Build Pipeline plugin there are two causes-- the upstream job and the user who triggered the run. In BuildPipelineView.triggerBuild(), AbstractProject.scheduleBuild is ultimately called with a cause of Cause.UpstreamCause, but also with a CauseAction(new MyUserIdCause()) in the Actions passed to it. Copy Artifact uses Run.getCauses() which uses Run.getAction(CauseAction.class). GetAction returns only the first action, so if the CauseAction with UpstreamCause comes first, it works. Otherwise it fails to copy. Various solutions: 1 -- As suggested on JENKINS-14656, put both causes under the same CauseAction. The problem is that one of the Causes is created by AbstractProject.scheduleBuild and there's no way to inject the MyUserIdCause. AbstractProject could be extended to allow a Collection of Causes easily enough. 2-- Change Copy artifact to use Run.getActions(CauseAction.class) and iterate over the contained actions, itself, until it finds an UpstreamCause. 3-- Change Run.getCauses() to call Run.getActions(CauseAction.class) and merge them all. Questions: Seems like some things implicitly assume that there is only ever one CauseAction. Is this a valid constraint? If so, then #1 makes sense and there should be guards against multiple CauseActions. If multiple CauseActions are allowed, should convenience functions like getCauses() merge them into one view? If so, then #3 makes sense, otherwise #2. Any ramifications of any of these approaches? Thanks!
