/// <summary>Parse the footer lines (e.g.</summary> /// <remarks> /// Parse the footer lines (e.g. "Signed-off-by") for machine processing. /// <p> /// This method splits all of the footer lines out of the last paragraph of /// the commit message, providing each line as a key-value pair, ordered by /// the order of the line's appearance in the commit message itself. /// <p> /// A footer line's key must match the pattern /// <code>^[A-Za-z0-9-]+:</code> /// , while /// the value is free-form, but must not contain an LF. Very common keys seen /// in the wild are: /// <ul> /// <li> /// <code>Signed-off-by</code> /// (agrees to Developer Certificate of Origin) /// <li> /// <code>Acked-by</code> /// (thinks change looks sane in context) /// <li> /// <code>Reported-by</code> /// (originally found the issue this change fixes) /// <li> /// <code>Tested-by</code> /// (validated change fixes the issue for them) /// <li> /// <code>CC</code> /// , /// <code>Cc</code> /// (copy on all email related to this change) /// <li> /// <code>Bug</code> /// (link to project's bug tracking system) /// </ul> /// </remarks> /// <returns>ordered list of footer lines; empty list if no footers found.</returns> public IList <FooterLine> GetFooterLines() { byte[] raw = buffer; int ptr = raw.Length - 1; while (raw[ptr] == '\n') { // trim any trailing LFs, not interesting ptr--; } int msgB = RawParseUtils.CommitMessage(raw, 0); AList <FooterLine> r = new AList <FooterLine>(4); System.Text.Encoding enc = Encoding; for (; ;) { ptr = RawParseUtils.PrevLF(raw, ptr); if (ptr <= msgB) { break; } // Don't parse commit headers as footer lines. int keyStart = ptr + 2; if (raw[keyStart] == '\n') { break; } // Stop at first paragraph break, no footers above it. int keyEnd = RawParseUtils.EndOfFooterLineKey(raw, keyStart); if (keyEnd < 0) { continue; } // Not a well formed footer line, skip it. // Skip over the ': *' at the end of the key before the value. // int valStart = keyEnd + 1; while (valStart < raw.Length && raw[valStart] == ' ') { valStart++; } // Value ends at the LF, and does not include it. // int valEnd = RawParseUtils.NextLF(raw, valStart); if (raw[valEnd - 1] == '\n') { valEnd--; } r.AddItem(new FooterLine(raw, enc, keyStart, keyEnd, valStart, valEnd)); } Sharpen.Collections.Reverse(r); return(r); }
public virtual void TestInsertChangeId() { Git git = new Git(db); string messageHeader = "Some header line\n\nSome detail explanation\n"; string changeIdTemplate = "\nChange-Id: I" + ObjectId.ZeroId.GetName() + "\n"; string messageFooter = "Some foooter lines\nAnother footer line\n"; RevCommit commit = git.Commit().SetMessage(messageHeader + messageFooter).SetInsertChangeId (true).Call(); // we should find a real change id (at the end of the file) byte[] chars = Sharpen.Runtime.GetBytesForString(commit.GetFullMessage()); int lastLineBegin = RawParseUtils.PrevLF(chars, chars.Length - 2); string lastLine = RawParseUtils.Decode(chars, lastLineBegin + 1, chars.Length); NUnit.Framework.Assert.IsTrue(lastLine.Contains("Change-Id:")); NUnit.Framework.Assert.IsFalse(lastLine.Contains("Change-Id: I" + ObjectId.ZeroId .GetName())); commit = git.Commit().SetMessage(messageHeader + changeIdTemplate + messageFooter ).SetInsertChangeId(true).Call(); // we should find a real change id (in the line as dictated by the // template) chars = Sharpen.Runtime.GetBytesForString(commit.GetFullMessage()); int lineStart = 0; int lineEnd = 0; for (int i = 0; i < 4; i++) { lineStart = RawParseUtils.NextLF(chars, lineStart); } lineEnd = RawParseUtils.NextLF(chars, lineStart); string line = RawParseUtils.Decode(chars, lineStart, lineEnd); NUnit.Framework.Assert.IsTrue(line.Contains("Change-Id:")); NUnit.Framework.Assert.IsFalse(line.Contains("Change-Id: I" + ObjectId.ZeroId.GetName ())); commit = git.Commit().SetMessage(messageHeader + changeIdTemplate + messageFooter ).SetInsertChangeId(false).Call(); // we should find the untouched template chars = Sharpen.Runtime.GetBytesForString(commit.GetFullMessage()); lineStart = 0; lineEnd = 0; for (int i_1 = 0; i_1 < 4; i_1++) { lineStart = RawParseUtils.NextLF(chars, lineStart); } lineEnd = RawParseUtils.NextLF(chars, lineStart); line = RawParseUtils.Decode(chars, lineStart, lineEnd); NUnit.Framework.Assert.IsTrue(commit.GetFullMessage().Contains("Change-Id: I" + ObjectId .ZeroId.GetName())); }
/// <param name="max">max number of entries to read</param> /// <returns>all reflog entries in reverse order</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public virtual IList <ReflogEntry> GetReverseEntries(int max) { byte[] log; try { log = IOUtil.ReadFully(logName); } catch (FileNotFoundException) { return(Sharpen.Collections.EmptyList <ReflogEntry>()); } int rs = RawParseUtils.PrevLF(log, log.Length); IList <ReflogEntry> ret = new AList <ReflogEntry>(); while (rs >= 0 && max-- > 0) { rs = RawParseUtils.PrevLF(log, rs); ReflogEntry entry = new ReflogEntry(log, rs < 0 ? 0 : rs + 2); ret.AddItem(entry); } return(ret); }