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  Plugin,
  9  PluginRun,
 10  pluginRunWhenAll,
 11  PluginWrite,
 12  PluginWriteRight,
 13  PluginWriteRightCanAdd,
 14  PluginWriteRightCanMod,
 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  static default(): JSON.Raw {
 68    return JSON.Raw.from(JSON.stringify<Conf>(new Conf()));
 69  }
 70}
 71
 72const defaultRun: PluginRun = PluginRun.build(
 73  "*",
 74  ["*"],
 75  pluginRunWhenAll,
 76  PluginWrite.build(
 77    [],
 78    [
 79      PluginWriteRight.build("rss/*", [
 80        PluginWriteRightCanAdd,
 81        PluginWriteRightCanMod,
 82      ]),
 83    ]
 84  ),
 85  Conf.default()
 86);
 87
 88function generateItem(conf: FluxConf, commits: Array<Commit>): string {
 89  const before = `<item><author>${commits[0].committer}</author><link>${conf.link}</link><title>Has pushed ${commits.length} commits on ${commits[0].branch}</title><description>`;
 90  const beforeDesc = `<![CDATA[<p>All commits:</p><ul>`;
 91  const afterDesc = `</ul>]]>`;
 92  const after = `</description><pubDate>${commits[0].date.toUTCString()}</pubDate><guid>${
 93    commits[0].hash
 94  }</guid></item>`;
 95  const html =
 96    beforeDesc +
 97    commits
 98      .sort((a, b) => a.date.getUTCMilliseconds() - b.date.getUTCMilliseconds())
 99      .reduce((acc, item) => {
100        return `${acc}<li>${item.message.replaceAll("\\n", "<br/>")}</li>`;
101      }, "") +
102    afterDesc;
103  return before + html + after;
104}
105
106class Pollen implements Plugin {
107  private server: Server;
108  private conf: Conf | null = null;
109  private commits: Array<Commit> = new Array<Commit>();
110
111  constructor(server: Server) {
112    this.server = server;
113  }
114
115  init(
116    repoName: string,
117    confHasChanged: boolean,
118    serializedConf: string
119  ): void {
120    this.conf = JSON.parse<Conf>(serializedConf);
121
122    for (let i = 0; i < this.conf!.flux.length; ++i) {
123      const flux = this.conf!.flux[i];
124      if (!this.server.webcontent().exists(flux.path)) {
125        this.server.modifyWebContent(flux.path, flux.generateEmptyRss());
126      }
127    }
128    return;
129  }
130
131  startCommit(commit: Commit): void {
132    this.commits.push(commit);
133    return;
134  }
135
136  addFile(path: string): void {
137    return;
138  }
139
140  modFile(fromPath: string, toPath: string): void {
141    return;
142  }
143
144  delFile(path: string): void {
145    return;
146  }
147
148  endCommit(commit: Commit): void {
149    return;
150  }
151
152  finish(): void {
153    if (this.conf != null && this.commits.length > 0) {
154      for (let i = 0; i < this.conf!.flux.length; i++) {
155        this.server.replaceWebContent(
156          this.conf!.flux[i].path,
157          "<!-- next -->",
158          "<!-- next -->\n" + generateItem(this.conf!.flux[i], this.commits)
159        );
160      }
161    }
162    this.conf = null;
163    this.commits = [];
164    return;
165  }
166}
167
168function build(server: Server): Plugin {
169  return new Pollen(server);
170}
171
172export function install(): void {
173  Register([defaultRun], build);
174}