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}