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