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