jenkinsci / jenkinsci/git-plugin
Expose the resolved commit ID through GitSCMFileSystem.getRevision() when constructed via SCMFileSystem.of(Item, SCM)
- Dominant language
- Java
- Stars
- 694
- Forks
- 1.1k
- Avg merge
- 1h 29m
- Merged PRs (30d)
- 3
Description
### What feature do you want to see added?
### Summary
`GitSCMFileSystem` resolves the head commit ID during construction and stores it in a private `commitId` field, but `getRevision()` returns `null` whenever the filesystem is created via the two-argument `SCMFileSystem.of(Item, SCM)` overload, even though the resolved commit is sitting in the object.
This makes it impossible for callers using that overload to obtain the exact commit a file (e.g. a `Jenkinsfile`) was read from, despite the data being available internally.
### Current behaviour
In [`GitSCMFileSystem`](https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/jenkins/plugins/git/GitSCMFileSystem.java#L117):
```
protected GitSCMFileSystem(GitClient client, String remote, final String head, @CheckForNull
AbstractGitSCMSource.SCMRevisionImpl rev) throws IOException, InterruptedException {
super(rev);
/// ...
commitId = rev == null ?
invoke((Repository repository) -> repository.findRef(head).getObjectId()) :
ObjectId.fromString(rev.getHash());
}
```
When `BuilderImpl.build(Item owner, SCM scm, SCMRevision rev)` is invoked through `SCMFileSystem.of(Item, SCM)`, `rev` is `null`. The constructor resolves a real `ObjectId` via `findRef(head)` and stores it in `commitId`, but passes `null` to `super(rev)`. Consequently `getRevision()` (inherited from `SCMFileSystem`) returns `null` and the resolved commit is unreachable from outside the class.
### Proposed change
- After resolving `commitId`, construct an `AbstractGitSCMSource.SCMRevisionImpl` from it and pass that into `super(...)` (or assign it to the inherited revision field), so that `getRevision()` returns a non-null value reflecting the actually-resolved commit.
Or
- keep the current constructor body and add a public `getResolvedHead()` (or override `getRevision()` directly) that returns an `SCMRevisionImpl` built from the existing private `commitId` field.
### Why this matters
Downstream code needs to know the exact commit from which a `Jenkinsfile` or other repository file was loaded. The standard, SCM-agnostic API for that is `SCMFileSystem.getRevision()`. Subversion and Mercurial implementations return real revisions through this method; `GitSCMFileSystem` is the outlier in returning `null` for the `(Item, SCM)` path despite having the data.
### AC
- `SCMFileSystem.of(item, gitScm)` returns a `GitSCMFileSystem` whose `getRevision()` is non-null and reflects the commit `commitId` resolves to.
- Behaviour is unchanged when the three-argument overload `SCMFileSystem.of(scmSource, head, rev)` is used with an explicit non-null `rev`.
### Related
- The standalone `CpsScmFlowDefinition` build path in [`workflow-cps-plugin`](https://github.com/jenkinsci/workflow-cps-plugin) calls `SCMFileSystem.of(build.getParent(), scm)` to load the `Jenkinsfile` lightweight. With this change, that call site (and any equivalent in third-party plugins) gains visibility of the resolved commit through the standard API.
- The comment in [`workflow-multibranch-plugin/SCMVar.java`](https://github.com/jenkinsci/workflow-multibranch-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/multibranch/SCMVar.java#L79) refers to this same gap from a consumer's perspective.
- Related JIRA: [JENKINS-31386](https://issues.jenkins.io/browse/JENKINS-31386), [JENKINS-33273](https://issues.jenkins.io/browse/JENKINS-33273), [JENKINS-42971](https://issues.jenkins.io/browse/JENKINS-42971).
### Upstream changes
_No response_
### Are you interested in contributing this feature?
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.