Skip to content

Commit edfa9ec

Browse files
committed
createCommitWithSignature can now handle dangling / non-existent refs
1 parent 0438567 commit edfa9ec

3 files changed

Lines changed: 127 additions & 8 deletions

File tree

generate/input/descriptor.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3068,7 +3068,15 @@
30683068
"ignore": true
30693069
},
30703070
"git_repository_ident": {
3071-
"ignore": true
3071+
"args": {
3072+
"name": {
3073+
"isReturn": true
3074+
},
3075+
"email": {
3076+
"isReturn": true
3077+
}
3078+
},
3079+
"isAsync": false
30723080
},
30733081
"git_repository_init_init_options": {
30743082
"ignore": true

lib/reference.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,111 @@ Reference.prototype.isValid = function() {
6363
Reference.prototype.toString = function() {
6464
return this.name();
6565
};
66+
67+
const MAX_NESTING_LEVEL = 10;
68+
69+
const getTerminal = (repo, refName, nesting, prevRef = null) => {
70+
if (nesting > MAX_NESTING_LEVEL) {
71+
return Promise.resolve({
72+
error: NodeGit.Error.CODE.ENOTFOUND,
73+
out: prevRef
74+
});
75+
}
76+
77+
return NodeGit.Reference.lookup(repo, refName)
78+
.then((ref) => {
79+
if (ref.type() === NodeGit.Reference.TYPE.OID) {
80+
return {
81+
error: NodeGit.Error.CODE.OK,
82+
out: ref
83+
};
84+
} else {
85+
return getTerminal(repo, ref.symbolicTarget(), nesting + 1, ref)
86+
.then(({ error, out }) => {
87+
if (error === NodeGit.Error.CODE.ENOTFOUND && !out) {
88+
return { error, out: ref };
89+
} else {
90+
return { error, out };
91+
}
92+
});
93+
}
94+
})
95+
.catch((error) => {
96+
return {
97+
error: error.errno,
98+
out: null
99+
};
100+
});
101+
};
102+
103+
const getSignatureForReflog = (repo) => {
104+
const { email, name } = repo.ident();
105+
if (email && name) {
106+
return Promise.resolve(NodeGit.Signature.now(name, email));
107+
}
108+
109+
return NodeGit.Signature.default(repo)
110+
.catch(() => NodeGit.Signature.now("unknown", "unknown"));
111+
};
112+
113+
Reference.updateTerminal = function (
114+
repo,
115+
refName,
116+
oid,
117+
signature,
118+
logMessage
119+
) {
120+
let signatureToUse;
121+
let promiseChain = Promise.resolve();
122+
123+
if (!signature) {
124+
promiseChain = promiseChain
125+
.then(() => getSignatureForReflog(repo))
126+
.then((sig) => {
127+
signatureToUse = sig;
128+
return Promise.resolve();
129+
});
130+
} else {
131+
signatureToUse = signature;
132+
}
133+
134+
return promiseChain
135+
.then(() => getTerminal(repo, refName, 0))
136+
.then(({ error, out }) => {
137+
if (error === NodeGit.Error.CODE.ENOTFOUND && out) {
138+
return NodeGit.Reference.create(
139+
repo,
140+
out.symbolicTarget(),
141+
oid,
142+
0,
143+
logMessage
144+
);
145+
} else if (error === NodeGit.Error.CODE.ENOTFOUND) {
146+
return NodeGit.Reference.create(
147+
repo,
148+
refName,
149+
oid,
150+
0,
151+
logMessage
152+
);
153+
} else {
154+
return NodeGit.Reference.createMatching(
155+
repo,
156+
out.name(),
157+
oid,
158+
1,
159+
out.target(),
160+
logMessage
161+
);
162+
}
163+
})
164+
.then(() => NodeGit.Reflog.read(repo, refName))
165+
.then((reflog) => {
166+
// We may want some kind of transactional logic for this
167+
// There is a theoretical timing issue that could result in updating
168+
// the wrong reflog
169+
reflog.drop(0, 1);
170+
reflog.append(oid, signatureToUse, logMessage);
171+
return reflog.write();
172+
});
173+
};

lib/repository.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,6 @@ Repository.prototype.createCommitWithSignature = function(
683683
var repo = this;
684684
var promises = [];
685685
var commitContent;
686-
var commit;
687686
var skippedSigning;
688687

689688
parents = parents || [];
@@ -766,14 +765,18 @@ Repository.prototype.createCommitWithSignature = function(
766765

767766
return repo.getCommit(commitOid)
768767
.then(function(commitResult) {
769-
commit = commitResult;
770-
return repo.getReference(updateRef);
771-
}).then(function(ref) {
772-
return ref.setTarget(commitOid, getReflogMessageForCommit(commit));
773-
}).then(function() {
768+
return Reference.updateTerminal(
769+
repo,
770+
updateRef,
771+
commitOid,
772+
committer,
773+
getReflogMessageForCommit(commitResult)
774+
);
775+
})
776+
.then(function() {
774777
return commitOid;
775778
});
776-
});
779+
});
777780
};
778781

779782
/**

0 commit comments

Comments
 (0)