@@ -70,6 +70,37 @@ def refspecFor(String rev) {
7070 return " ${ heads} +refs/pull/${ parts[1]} /${ parts[2]} :refs/remotes/origin/pr/${ parts[1]} "
7171}
7272
73+ // Resolves rev to the commit to build.
74+ //
75+ // url is the repo to ask.
76+ // rev is what revFor returned: a branch, tag, pull/<n>/merge ref,
77+ // refs/... ref, or commit id.
78+ //
79+ // Returns '' when rev names no ref, as a commit id does.
80+ //
81+ // A bare name is an ls-remote pattern matched against the tail of every ref,
82+ // not a ref name: 'master' also matched core's CFE-159/master, which sorts
83+ // first and so won. Ask for the full ref, refs/heads before refs/tags before
84+ // refs/, and take the first that exists.
85+ def resolveRev (String url , String rev ) {
86+ def candidates = rev. startsWith(' refs/' ) ? [rev]
87+ : [" refs/heads/${ rev} " , " refs/tags/${ rev} " , " refs/${ rev} " ]
88+ for (ref in candidates) {
89+ // An annotated tag's own ref names the tag object, its ^{} the commit.
90+ def peeled = " ${ ref} ^{}"
91+ def out = sh(returnStdout : true ,
92+ script : " git ls-remote '${ url} ' '${ ref} ' '${ peeled} '" ). trim()
93+ def sha = ' '
94+ for (line in out. readLines()) {
95+ def parts = line. split()
96+ if (parts[1 ] == peeled) { return parts[0 ] }
97+ if (parts[1 ] == ref) { sha = parts[0 ] }
98+ }
99+ if (sha) { return sha }
100+ }
101+ return ' '
102+ }
103+
73104// Runs one build in the workspace of the node the caller allocated.
74105//
75106// Cleans up after the previous build. Checks out each repo at its commit from
@@ -195,12 +226,7 @@ pipeline {
195226 sshagent([' jenkins-github' ]) {
196227 repos. each { repo ->
197228 def rev = revs[repo]
198- // "refs/$rev" as well, so pull/<n>/merge resolves like it does in
199- // the other jobs. No pipe: it would mask git's own exit status, and
200- // an unreachable repo would then look like an unresolvable ref.
201- def out = sh(returnStdout : true , script :
202- " git ls-remote git@github.com:cfengine/${ repo} .git '${ rev} ' 'refs/${ rev} '" ). trim()
203- def sha = out ? out. readLines()[0 ]. split()[0 ] : ' '
229+ def sha = resolveRev(" git@github.com:cfengine/${ repo} .git" , rev)
204230 if (! sha) {
205231 // A commit id matches no ref, which is the one case where an
206232 // empty answer is fine.
0 commit comments