Einführung von .discourse-compatibility: Angeheftete Plugin-/Theme-Versionen für ältere Discourse-Versionen

Hallo zusammen :wave:, ich habe gerade ein neues Feature gemergt, das Plugins und Themes dabei hilft, bestimmte Versionen zu verankern, wenn sie auf älteren Discourse-Instanzen installiert werden.

Sie können nun eine .discourse-compatibility-Datei im Stammverzeichnis eines Plugin- oder Theme-Repository einfügen, die angibt, welche Version beim Installieren auf älteren Discourse-Versionen ausgecheckt werden soll.


Begründung

Es ist mühsam, sich zu merken, welche Plugins und Themes mit welchen Discourse-Versionen kompatibel sind. Als Administrator sollte es möglich sein, diese Änderungen einfach zu durchsuchen und eine Version zu finden, die für Ihre Discourse-Installation geeignet ist, ohne die Commit-Historie des Plugins lesen zu müssen. Als Autor eines Plugins oder Themes sollte es möglich sein, Installationsversionen zu verwalten, während Sie abwärtsinkompatible Änderungen vornehmen, damit Sie ältere Installationen nicht beschädigen.

Discourse-Software-Updates werden recht schnell ausgerollt, was zwar toll ist, aber die Wartung von Discourse-Instanzen mit vielen Plugins manchmal sehr schwierig macht, insbesondere wenn Sie anderen Release-Zyklen oder -Versionen folgen, wie beispielsweise der aktuellen stabilen Version. Mein Plan ist es, ein Ökosystem zu schaffen, das den Aktualisierungsprozess für diejenigen erleichtert, die entweder der stabilen Version oder einem anderen Release-Zyklus folgen, und diesen Site-Administratoren eine Methode an die Hand zu geben, schnell und automatisch die Plugin-Version zu erhalten, die mit der Discourse-Version kompatibel ist, die sie anvisieren.

Ursprüngliche Ankündigung (jetzt durch die oben verlinkte Dokumentation ersetzt)

Implementierung

Erstens: Wir verlassen uns hier auf die Tags von Discourse Core, da die Betas von Discourse häufig genug veröffentlicht werden, sodass wir Plugin-Versionen daran verankern können. Die Verankerung an Git-Hashes ist aus vielen Gründen ein Albtraum, daher können wir git describe verwenden, um das nächste Beta- oder Stable-Tag zu erhalten.

In einem Plugin oder Theme unterstützen wir nun eine Versionskompatibilitätsdatei mit dem Namen .discourse-compatibility im Stammverzeichnis. Diese Datei ist eine absteigend sortierte Liste (neuere Discourse-Versionen zuerst), die eine Kompatibilitätszuordnung spezifiziert.

Beispiel

2.5.0.beta2: git-hash-1234e5f5d
2.4.4.beta6: 4444ffff33dd
2.4.2.beta1: named-git-tag-or-branch

Für jedes Plugin/Theme wird bei einem Upgrade oder Neuaufbau weiterhin ein späterer benannter Commit/Branch/Tag ausgecheckt, bis einer gefunden wird, der dem aktuellen Discourse-Version entspricht oder neuer ist.
Beispielsweise würde bei der obigen Versionsdatei, wenn die aktuelle Discourse-Version 2.4.6.beta12 wäre, die Datei gescannt und der Eintrag für 2.5.0.beta2 ausgewählt.

Wenn die aktuelle Discourse-Version 2.4.4.beta6 wäre, würde der entsprechende Eintrag für 2.4.4.beta6 ausgewählt.

Wenn keine spätere Version existiert, bleibt es bei der aktuell ausgecheckten Version.
Beispielsweise würde bei 2.5.0.beta3 keine Verankerung erfolgen.

Wenn keine frühere Version existiert, wird die früheste in der Versionsdatei aufgeführte Version ausgecheckt.
Beispielsweise würde bei 2.2.1.beta22 die frühestmögliche Version gemäß der „Version" ausgecheckt, nämlich der Eintrag für 2.4.2.beta1.


Das Ziel ist es, die Schmerzen bei der Wartung alternativer Bereitstellungen, die in Zukunft nicht strikt auf „tests-passed" basieren, zu lindern und Administratoren Flexibilität bei Zeit und Ort des Upgrades zu geben. Wir erreichen dies, indem wir Autoren von Plugins und Themes eine Möglichkeit bieten, abwärtsinkompatible Änderungen zu entwickeln, ohne Installationen auf älteren Discourse-Versionen zu beeinträchtigen.

50 „Gefällt mir“

Das ist eine großartige Funktion, vielen Dank :slight_smile:

Ich mag die Ausrichtung dabei, d. h. es ermöglicht, dieses Problem direkt im Plugin zu verwalten, ohne dass der Seitenadministrator dafür etwas tun muss.

Ich habe ein paar erste Fragen:

  • Bleibt die bestehende Plugin-Metadatenprüfung für required_version bei der Plugin-Aktivierung erhalten? Und wie sehen Sie die Wechselwirkung damit (falls vorhanden)?

  • Ich sehe, dass dies derzeit als Rake-Aufgabe hinzugefügt wurde. Wie hängt das mit discourse_docker (d. h. dem Launcher) und docker_manager zusammen? Was ist der beabsichtigte Verwendungszweck? Ich sehe, dass Sie Änderungen in beiden Repositories vorgenommen haben, aber könnten Sie erklären, wie es in beiden Umgebungen funktionieren soll?

12 „Gefällt mir“

Ja, genau das ist die Idee – wir ermöglichen es Plugin-Entwicklern, Abwärtskompatibilität hinzuzufügen, damit Administratoren sich keine Sorgen machen müssen!

Es gibt derzeit keine Pläne, die required_version-Plugin-Metadaten zu ändern oder zu entfernen. Sie hängen zusammen, sind aber in meinen Augen dennoch getrennt: Die required_version-Min/Max-Punktsetzung verhindert die Installation des Plugins, indem sie einen Fehler auslöst, und wird nach diesem Kompatibilitäts-Check geladen. Wenn Sie verhindern möchten, dass uralte Discourse-Instanzen Ihr Plugin nutzen, ist es nach wie vor ratsam, required_version für die erste Mindestversion anzugeben – keine Menge an Kompatibilitätsprüfungen wird das ändern :wink:

Im normalen Betrieb sollten keine Konfigurationsänderungen erforderlich sein; Änderungen werden automatisch erkannt. Der Rake-Task wird in discourse_docker aufgerufen, nachdem die Plugins geklont wurden, also in dieser Reihenfolge im Launcher:

  • Plugins werden geklont
  • Kompatibilität wird geprüft und ggf. ausgecheckt
  • Migration

In docker_manager können ältere Discourse-Versionen Plugins auf eine kompatible Version aktualisieren. Die Benutzeroberfläche bleibt dabei unverändert, aber ein Plugin gilt nun als „auf dem neuesten Stand“, wenn es der Kompatibilitätsdatei entspricht.

TL;DR: Für beide Anwendungsfälle sind keine Änderungen erforderlich, um davon zu profitieren, falls Sie sich das gefragt haben.

Im Hintergrund wird git show HEAD@{upstream}:.discourse-compatibility verwendet, um die neueste Datei auszulesen, und git reset --hard #{checkout_version}, um die korrekte Version auszuchecken. Auf diese Weise können wir die neueste Kompatibilitätsinformation nutzen, und ältere Discourse-Versionen bleiben nicht auf einer alten (möglicherweise ungültigen) Kompatibilitätsdatei hängen.

11 „Gefällt mir“

Cool, danke für die Erklärung.

Also habe ich mir ein :wine_glass: eingeschenkt und es mit dem Custom Wizard Plugin ausprobiert.

Ich habe jedes Tag einzeln in umgekehrter Reihenfolge durchgegangen, beginnend mit v2.6.0.beta1. Diese Git-Befehle waren hilfreich:

git tag --list \\ z. B. git tag --list 'v2.5.0*'
git checkout tags/tag \\ z. B. git checkout tags/v2.5.0.beta7

Es hat nicht lange gedauert, bis ich ein Tag fand, das mit der aktuellen Version des Plugins nicht funktionierte: v2.5.0.beta7 enthält nicht discourse/app/components/d-textarea, das der benutzerdefinierte Assistent zu importieren versucht.

Daraufhin fand ich den Commit im Plugin, der diesen Import hinzugefügt hat, nahm die SHA1 des vorherigen Commits, checkte diesen aus und testete (funktionierte einwandfrei). Anschließend fügte ich Folgendes zu .discourse-compatibility hinzu:

v2.5.0.beta7: 802d74bab2ebe19a106f75275342dc2e9cc6066a

Danach habe ich das auf einen Branch mit dem neuesten Plugin-Code gepusht (ein Test-Branch, normalerweise nicht erforderlich), und einen Docker-Testserver mit diesem Plugin-Branch und der version auf v2.5.0.beta7 neu aufgebaut.

Das funktionierte nicht. Dann fiel mir ein, dass die Rake-Aufgabe plugin:pull_compatible_all natürlich in v2.5.0.beta1 noch nicht existiert, also wird das rückwirkend nicht funktionieren (ich gebe dem :wine_glass: die Schuld). Tatsächlich sehe ich in den Launcher-Logs:

Don't know how to build task 'plugin:pull_compatible_all' (See the list of available tasks with `rake --tasks`)

Ist das im Großen und Ganzen das, wie du dir die Anwendung vorstellst?

Bezüglich required_version bin ich hier darauf gestoßen, da der Testserver das Plugin discourse-legal-tools installiert hatte, das eine required_version von v2.5.0 hat, weshalb es zunächst bei v2.5.0.beta7 fehlschlug. Ich denke, ich werde dieses Plugin in das neue System überführen. Ich kann mir trotzdem vorstellen, dass required_version nützlich ist, um, wie du sagst, eine absolute Basislinie festzulegen.

11 „Gefällt mir“

Ja, das ist korrekt – da dies erst jetzt in das Discourse-Kernsystem integriert wurde, funktioniert es derzeit nichts unter 2.6.0.beta1. Ich muss dies noch auf die stabile Version und die neueste Beta portieren, sodass wir es dann auch mit 2.5.0 verwenden können. Eine Portierung auf ältere Versionen ist jedoch nicht geplant.

11 „Gefällt mir“

Nur eine kurze Ergänzung: Ich habe nun eine Kompatibilitätsdatei zum Custom Wizard-Master hinzugefügt und werde diese verwenden, um das Plugin zu verankern, einschließlich v2.6.0.beta1 (aktuelles Beta) und v2.5.0 (aktuell stabil), sobald dies portiert wird. Weitere Informationen findest du hier:

https://meta.discourse.org/t/custom-wizard-plugin/73345/562?u=angus

5 „Gefällt mir“

Hier nur eine Anmerkung und eine Frage.

Zunächst einmal nur zur Info: Die Syntax für Discourse-Versions-Tags in der Datei .discourse-compatibility lautet 2.5.0 (wie im Beispiel von @featheredtoast), nicht v2.5.0. Wenn Sie ein v verwenden, erhalten Sie diesen Fehler:

Malformed version number string v2.6.0.beta1

Zweitens hat @featheredtoast darauf hingewiesen, dass das Pinning-System nun auch auf stable zurückportiert wurde. Das habe ich übersehen, da ich den Tag v2.5.0 betrachtet habe.

Das wirft für mich eine leichte Frage auf. Die Branches von Discourse entsprechen nicht direkt den Versions-Tags von Discourse. Die meisten Sites, die ältere Versionen von Discourse betreiben, laufen wahrscheinlich auf einem Branch, also stable, und nicht auf einem Release, also v2.5.0.

Wenn eine Breaking Change (für ein Plugin) auch in einem „älteren

6 „Gefällt mir“

Versionen entsprechen der im App-Code definierten Discourse-Version, nicht dem Git-Tag.

Das bedeutet, dass „2.5.0

7 „Gefällt mir“

Das funktioniert größtenteils, es sei denn, Sie klonen mit --depth=1.

Ich werde bald einen Hook implementieren, der git fetch --depth 1 {upstream} commit aufruft, falls das Ziel zunächst nicht gefunden werden kann. Andernfalls wären wir gezwungen, einen partiellen oder vollständigen Klon durchzuführen, was nicht ideal ist. Wir sollten in der Lage sein, das Benötigte zu holen.

Edit: Hier aktualisiert:

Ich habe dies auch auf Beta und Stable zurückportiert – wir sollten also nun sogar mit flachen Klonen festlegen können.

6 „Gefällt mir“

Ich entschuldige mich im Voraus, da ich mich oft erst spät in der Nacht an dieses Thema wende, sodass ich nicht sicher bin, ob ich hier zu 100 % richtig liege. Es könnte auch sein, dass Ihnen das bereits bekannt ist. Ich halte dies hier fest, teilweise auch für meine eigene geistige Gesundheit, da es mich bereits mehrmals verwirrt hat.

Ich denke, dieser Mechanismus ist für den Zweig beta effektiv nicht funktionsfähig, wenn das Plugin auf einer Instanz verwendet wird, die Sie nicht kontrollieren (d. h. sie ist Open Source) und die auf übliche Weise aktualisiert wird. Die übliche Art der Aktualisierung besteht darin, dass der Site-Administrator dies tut, wenn er im Admin-UI dazu aufgefordert wird.

Angesichts dessen

Und dies

Und dass tests-passed und beta die gleiche Discourse-Version, aber nicht den gleichen Code haben, z. B. sind beide derzeit 2.6.0.beta2:

Daraus folgt:

  1. Um den Zweig beta zu unterstützen, müssen Sie einen Commit an das neueste Beta-Release anheften, da dies die Version ist, die Sites auf dem beta-Zweig verwenden werden.

  2. Wenn jedoch die neueste Beta-Version in der Kompatibilitätsdatei enthalten ist, verwenden Instanzen, die tests-passed ausführen, ebenfalls den angehefteten Commit.

Das bedeutet, dass Sie die Standardnutzung von tests-passed und beta gleichzeitig in einem Open-Source-Plugin nicht unterstützen können. Da die Mehrheit der Personen, die Plugins installieren, auf tests-passed läuft, können Sie beta mit dieser Methode effektiv nicht unterstützen.

Beachten Sie, dass dies in der Praxis für den Zweig stable funktioniert, da stable eine andere Discourse-Version als beta und tests-passed hat.

4 „Gefällt mir“

Ach ja, das ist mir bewusst. Es wird erst mit dem nächsten Beta-Schnitt wirklich behoben. Wir sollten auf jeden Fall auch einen Weg finden, zwischen Beta- und Test-bestandenen Versionen zu unterscheiden.

Als ich die Funktion eingerichtet habe, hatte ich stabile und inoffizielle Forks im Sinn und habe erst später bemerkt, dass ‘latest’ und ‘stable’ dieselben Versionen teilen.

6 „Gefällt mir“

Danke für die Bestätigung.

Es scheint, dass das wesentliche Ergebnis ist, dass der Prozess nicht ausgeführt werden sollte, wenn die Instanz tests-passed läuft. Die tests-passed-Version kann aus den oben beschriebenen Gründen nicht in die Datei aufgenommen werden, sodass das Aussperren des Prozesses bei tests-passed sein aktuelles Verhalten nicht ändern würde.

Eine Möglichkeit, dies zu implementieren, wäre:

def self.find_compatible_resource(version_list, version = ::Discourse::VERSION::STRING)
 
   return if Discourse.git_branch === 'tests-passed'

   ...
end

Dies würde es ermöglichen, die neueste beta-Version in der Datei zu verwenden, um Plugins für Sites zu verankern, die beta ausführen. Und Sie könnten weiterhin tests-passed im neuesten Commit des Plugins unterstützen, also ohne diese Datei zu verwenden. Wenn Sie damit einverstanden sind, kann ich einen PR erstellen.

Alternativ habe ich das Gefühl, dass das zugrunde liegende Problem hier Folgendes ist:

Ich bin mir sicher, dass Sie das bereits diskutiert haben, aber wäre es möglich, etwas wie Folgendes zu tun:

  • tests-passed: 2.6.0.tests-passed, d. h. das PRE-Tag auf tests-passed im tests-passed-Branch setzen.

  • beta: 2.6.0.beta2, also wie bisher.

@jomaxro Könntest du mir das bitte näher erklären?

7 „Gefällt mir“

Ja, ich bin dafür, eine zusätzliche Kennzeichnung für Pre-Beta- und echte Beta-Releases einzuführen, sofern dies einfach umzusetzen ist. Das würde helfen, das zugrunde liegende Problem zu lösen. Ich habe bei anderen Softwareprojekten gesehen, dass die Versionsnummer vor dem Release auf die nächste Version hochgesetzt wird (z. B. nach der Veröffentlichung von Beta1 wird die „Version“ auf Beta2 erhöht).

Traditionell hat Discourse das jedoch nicht getan, also hängt es davon ab, welche Methode für das Projekt am einfachsten zu übernehmen ist.

6 „Gefällt mir“

Ich bin auf ein weiteres Problem gestoßen.

Diese Änderung führt $danger-low-mid in 2.6.0beta2 ein.

Das hat das discourse-styleguide-Plugin kaputt gemacht, sodass es aktualisiert wurde und eine .discourse-compatibility-Datei eingeführt wurde, um das Plugin beim vorherigen Commit für Discourse 2.5.0 zu halten.

Das bricht bei Discourse 2.5.1. Da diese Änderung nie auf die stabile Version zurückportiert wird, müsste die discourse-compatibility-Datei bei jeder neuen 2.5.x-Stable-Version aktualisiert werden.

Jede discourse-compatibility-Datei von jedem Plugin müsste bei jeder neuen 2.5.x-Stable-Version aktualisiert werden.

Alternativ könnte die Kompatibilitätsdatei auf Version 2.5.999 verweisen, wodurch das Plugin effektiv für die gesamte Lebensdauer von 2.5.x beim Commit 1f86468b2c81b40e97f1bcd16ea4bb780634e2c7 gehalten würde. Das kommt mir jedoch sehr hakelig vor.

6 „Gefällt mir“

Es klingt danach, als wäre es sicher, auf 2.6.0beta1 zu pinnen, was zudem korrekter wäre, da das Problem in beta2 eingeführt wurde. Ergibt das Sinn? Damit wären dann auch alle Versionen der 2.5er-Reihe abgedeckt.

Deine „hackige

6 „Gefällt mir“

Ja, das kommt mir auch weniger hackig vor.

Aber sowohl die Lösung mit 2.5.999 als auch die mit 2.6.0beta0 decken einen ähnlichen Fall nicht ab: Was ist, wenn in 2.6.0beta3 ein Problem eingeführt wird, das dann auf 2.5.2 zurückportiert wird?

Mehr Randfälle, mehr versteckte Funktionen: Sie können den Pin tatsächlich mit einem leeren Eintrag “aufheben”:

Mit einer Kompatibilitätsdatei wie:

        2.6.0.beta1: twofiveall
        2.4.4.beta6: ~
        2.4.2.beta1: twofourtwobetaone

Alles zwischen 2.4.2.beta1 und 2.4.4.beta6 wird nicht zurückgesetzt. Alles danach bis einschließlich 2.6.0.beta1 wird gepinnd. Danach wird es wieder entsperrt.

Im Hintergrund bleibt alles, was zu einem nil-Wert ausgewertet wird, unverändert bzw. bleibt auf der neuesten Version. Ein leerer Eintrag oder ~ wird als nil ausgewertet (über den Ruby-YAML-Parser), wodurch die Pin-Funktion umgangen wird.

8 „Gefällt mir“

Ist es möglich, ein Plugin einer älteren Version auf einer selbst gehosteten Instanz zu verwenden?

1 „Gefällt mir“

Ja, Sie können die Git-Clone-Befehle in Ihrer app.yml anpassen, um die gewünschte Version zu klonen. Beachten Sie, dass Sie auch sicherstellen müssen, dass Discourse auf die gewünschte Version gesetzt ist. Möglicherweise müssen Sie auch discourse_docker auf eine Version setzen, die mit der von Ihnen ausgeführten Version von Discourse kompatibel ist. Wenn Sie all das tun, ist es einfacher, nicht zu aktualisieren.

2 „Gefällt mir“