GitRoot
craft your forge, build your project, grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5import { JSON } from "json-as";
6import {
7 PluginRun,
8 pluginRunWhenAll,
9 PluginWrite,
10 PluginWriteRight,
11 PluginWriteRightCanAdd,
12 PluginWriteRightCanMod,
13} from "plugin/plugin";
14import { Commit, Plugin, Server } from "plugin/server";
15
16export * from "plugin/exports";
17
18@json
19class FluxConf {
20 constructor(
21 public link: string,
22 public path: string,
23 public title: string,
24 public description: string,
25 public language: string
26 ) {}
27
28 static build(
29 link: string,
30 path: string,
31 title: string,
32 description: string,
33 language: string
34 ): FluxConf {
35 return new FluxConf(link, path, title, description, language);
36 }
37
38 generateEmptyRss(): string {
39 return `<rss version="2.0">
40 <channel>
41 <title>${this.title}</title>
42 <link>${this.link}</link>
43 <description>${this.description}</description>
44 <language>${this.language}</language>
45 <generator>Pollen plugin - GitRoot</generator>
46 <!-- next -->
47 </channel>
48</rss>`;
49 }
50}
51
52@json
53class Conf {
54 flux: Array<FluxConf> = [
55 FluxConf.build(
56 "https://YOURINSTANCE.com/YOURPROJECT/",
57 "rss/all.xml",
58 "All push",
59 "Every push made in your forge",
60 "en"
61 ),
62 ];
63
64 static default(): JSON.Raw {
65 return JSON.Raw.from(JSON.stringify<Conf>(new Conf()));
66 }
67}
68
69const defaultRun: PluginRun = PluginRun.build(
70 "*",
71 ["*"],
72 pluginRunWhenAll,
73 PluginWrite.build(
74 [],
75 [
76 PluginWriteRight.build("rss/*", [
77 PluginWriteRightCanAdd,
78 PluginWriteRightCanMod,
79 ]),
80 ]
81 ),
82 Conf.default()
83);
84
85function generateItem(conf: FluxConf, commits: Array<Commit>): string {
86 const before = `<item><author>${commits[0].committer}</author><link>${conf.link}</link><title>Has pushed ${commits.length} commits on ${commits[0].branch}</title><description>`;
87 const beforeDesc = `<![CDATA[<p>All commits:</p><ul>`;
88 const afterDesc = `</ul>]]>`;
89 const after = `</description><pubDate>${commits[0].date.toUTCString()}</pubDate><guid>${
90 commits[0].hash
91 }</guid></item>`;
92 const html =
93 beforeDesc +
94 commits
95 .sort((a, b) => a.date.getUTCMilliseconds() - b.date.getUTCMilliseconds())
96 .reduce((acc, item) => {
97 return `${acc}<li>${item.message.replaceAll("\\n", "<br/>")}</li>`;
98 }, "") +
99 afterDesc;
100 return before + html + after;
101}
102
103class Pollen implements Plugin {
104 private server: Server;
105 private conf: Conf | null = null;
106 private commits: Array<Commit> = new Array<Commit>();
107
108 constructor(server: Server) {
109 this.server = server;
110 }
111
112 init(
113 repoName: string,
114 confHasChanged: boolean,
115 serializedConf: string
116 ): void {
117 this.conf = JSON.parse<Conf>(serializedConf);
118
119 for (let i = 0; i < this.conf!.flux.length; ++i) {
120 const flux = this.conf!.flux[i];
121 if (!this.server.webcontent().exists(flux.path)) {
122 this.server.modifyWebContent(flux.path, flux.generateEmptyRss());
123 }
124 }
125 return;
126 }
127
128 startCommit(commit: Commit): void {
129 this.commits.push(commit);
130 return;
131 }
132
133 addFile(path: string): void {
134 return;
135 }
136
137 modFile(fromPath: string, toPath: string): void {
138 return;
139 }
140
141 delFile(path: string): void {
142 return;
143 }
144
145 endCommit(commit: Commit): void {
146 return;
147 }
148
149 finish(): void {
150 if (this.conf != null && this.commits.length > 0) {
151 for (let i = 0; i < this.conf!.flux.length; i++) {
152 this.server.replaceWebContent(
153 this.conf!.flux[i].path,
154 "<!-- next -->",
155 "<!-- next -->\n" + generateItem(this.conf!.flux[i], this.commits)
156 );
157 }
158 }
159 this.conf = null;
160 this.commits = [];
161 return;
162 }
163}
164
165function build(server: Server): Plugin {
166 return new Pollen(server);
167}
168
169export function install(): void {
170 Server.Register([defaultRun], build);
171}