Skip to content

Commit 42c943f

Browse files
author
Vitor Castro
committed
Use a single repo URL in LinkedIn release posts.
Drop download/notes link spam and pull What's new bullets from that section only.
1 parent d6aef8d commit 42c943f

2 files changed

Lines changed: 24 additions & 12 deletions

File tree

‎tools/linkedin-announcer/PostFormatter.cs‎

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ public static string FormatReleasePost(string tagName, string releaseBody, strin
2020
{
2121
hook ??= Hooks[Math.Abs(tagName.GetHashCode(StringComparison.Ordinal)) % Hooks.Length];
2222
var baseUrl = repoUrl.TrimEnd('/');
23-
var notesUrl = $"{baseUrl}/releases/tag/{tagName}";
24-
var version = tagName.TrimStart('v', 'V');
25-
var setupAsset = $"CodeForge-Setup-{version}-win32-x64.exe";
26-
var downloadUrl = $"{baseUrl}/releases/download/{tagName}/{setupAsset}";
2723
var improvements = SummarizeImprovements(releaseBody);
2824
var hashtags = "#AI #OpenSource #LocalLLM #CodingAgent #DeveloperTools #llama.cpp";
2925

@@ -44,17 +40,15 @@ public static string FormatReleasePost(string tagName, string releaseBody, strin
4440
}
4541

4642
sb.AppendLine();
47-
sb.AppendLine($"Repo: {baseUrl}");
48-
sb.AppendLine($"Download: {downloadUrl}");
49-
sb.AppendLine($"Release notes: {notesUrl}");
43+
sb.AppendLine(baseUrl);
5044
sb.AppendLine();
5145
sb.Append(hashtags);
5246

5347
var text = sb.ToString();
5448
if (text.Length <= MaxLength)
5549
return text;
5650

57-
var footer = $"\n\nRepo: {baseUrl}\nDownload: {downloadUrl}\nRelease notes: {notesUrl}\n\n{hashtags}";
51+
var footer = $"\n\n{baseUrl}\n\n{hashtags}";
5852
var head = hook + $"\n\nCodeForge {tagName} is out.\n\nWhat's new:\n";
5953
var budget = MaxLength - head.Length - footer.Length - 1;
6054
var bullets = new StringBuilder();
@@ -82,13 +76,23 @@ private static List<string> SummarizeImprovements(string releaseBody)
8276
if (string.IsNullOrWhiteSpace(releaseBody))
8377
return [];
8478

79+
// Prefer the "## What's new" section when present (skip AHA marketing prose).
80+
var body = releaseBody.Replace("\r\n", "\n");
81+
var whatsNew = WhatsNewSectionRegex().Match(body);
82+
if (whatsNew.Success)
83+
body = whatsNew.Groups[1].Value;
84+
8585
var items = new List<string>();
86-
foreach (var raw in releaseBody.Replace("\r\n", "\n").Split('\n'))
86+
foreach (var raw in body.Split('\n'))
8787
{
8888
var line = CleanMarkdownLine(raw.TrimEnd());
8989
if (string.IsNullOrWhiteSpace(line) || IsNoiseLine(line))
9090
continue;
9191

92+
// Prefer real bullets over narrative paragraphs for LinkedIn.
93+
if (!(line.StartsWith('•') || raw.TrimStart().StartsWith('-') || raw.TrimStart().StartsWith('*')))
94+
continue;
95+
9296
var text = line.TrimStart('•', '-', '*', ' ').Trim();
9397
if (string.IsNullOrWhiteSpace(text) || IsNoiseLine(text))
9498
continue;
@@ -97,7 +101,7 @@ private static List<string> SummarizeImprovements(string releaseBody)
97101
text = text[..177].TrimEnd() + "…";
98102

99103
items.Add(text);
100-
if (items.Count >= 6)
104+
if (items.Count >= 5)
101105
break;
102106
}
103107

@@ -110,7 +114,8 @@ private static bool IsNoiseLine(string line)
110114
if (lower.Length == 0)
111115
return true;
112116
if (lower is "summary" or "what's new" or "whats new" or "what shipped" or "notes"
113-
or "release notes" or "install" or "fixes" or "changes")
117+
or "release notes" or "install" or "fixes" or "changes"
118+
or "the aha moment" or "measured on our local stack" or "not in this release")
114119
return true;
115120
if (lower.StartsWith("try it", StringComparison.Ordinal))
116121
return true;
@@ -120,6 +125,10 @@ private static bool IsNoiseLine(string line)
120125
return true;
121126
if (lower.StartsWith("full notes", StringComparison.Ordinal))
122127
return true;
128+
if (lower.StartsWith("release date", StringComparison.Ordinal))
129+
return true;
130+
if (lower.StartsWith("linkedin draft", StringComparison.Ordinal))
131+
return true;
123132
if (lower.StartsWith("download **", StringComparison.Ordinal) || lower.StartsWith("download ", StringComparison.Ordinal))
124133
return true;
125134
if (lower.StartsWith("codeforge", StringComparison.Ordinal) && lower.Contains("is out", StringComparison.Ordinal))
@@ -151,4 +160,7 @@ private static string CleanMarkdownLine(string line)
151160

152161
[GeneratedRegex(@"`([^`]+)`")]
153162
private static partial Regex InlineCodeRegex();
163+
164+
[GeneratedRegex(@"##\s*What's new\s*\n([\s\S]*?)(?=\n##\s|\z)", RegexOptions.IgnoreCase)]
165+
private static partial Regex WhatsNewSectionRegex();
154166
}

‎tools/linkedin-announcer/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ export REPO_URL=https://github.com/Kortexio/CodeForge
1919
dotnet run --project tools/linkedin-announcer -- post
2020
```
2121

22-
Post format: short hook + what's new + repo / download / notes CTA. Optional `LINKEDIN_ORG_URN` posts as the company page.
22+
Post format: short hook + what's new bullets + **one** repo URL CTA. Optional `LINKEDIN_ORG_URN` posts as the company page.
2323

2424
Put `[skip-announce]` in the GitHub Release notes body to publish a release without posting to LinkedIn.

0 commit comments

Comments
 (0)