Compare commits
1 Commits
actions/bl
...
add-to-wis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50b8b4be4b |
35
.github/workflows/autoblack.yml
vendored
@@ -1,35 +0,0 @@
|
||||
name: Check / auto apply Black
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
black:
|
||||
name: Check / auto apply black
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check files using the black formatter
|
||||
uses: psf/black@stable
|
||||
id: black
|
||||
with:
|
||||
options: "."
|
||||
continue-on-error: true
|
||||
- shell: pwsh
|
||||
id: check_files_changed
|
||||
run: |
|
||||
# Diff HEAD with the previous commit
|
||||
$diff = git diff
|
||||
$HasDiff = $diff.Length -gt 0
|
||||
Write-Host "::set-output name=files_changed::$HasDiff"
|
||||
- name: Create Pull Request
|
||||
if: steps.check_files_changed.outputs.files_changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
title: "Format Python code with Black"
|
||||
commit-message: ":art: Format Python code with Black"
|
||||
body: |
|
||||
This pull request uses the [psf/black](https://github.com/psf/black) formatter.
|
||||
base: ${{ github.head_ref }} # Creates pull request onto pull request or commit branch
|
||||
branch: actions/black
|
||||
@@ -1,6 +1,6 @@
|
||||
# YunoHost application catalog
|
||||
|
||||
<img alt="YunoHost logo" src="https://avatars.githubusercontent.com/u/1519495?s=200&v=4" width=80><img alt="Package logo" src="https://yunohost.org/user/images/yunohost_package.png" width=80>
|
||||
<img src="https://avatars.githubusercontent.com/u/1519495?s=200&v=4" width=80><img src="https://yunohost.org/user/images/yunohost_package.png" width=80>
|
||||
|
||||
This repository contains the default YunoHost app catalog, as well as related
|
||||
tools that can be run manually or automatically.
|
||||
@@ -16,7 +16,7 @@ them such as their category or maintenance state. This file is regularly read by
|
||||
|
||||
- You can browse [the contributor documentation](https://yunohost.org/contributordoc)
|
||||
- If you are not familiar with Git/GitHub, you can have a look at our [homemade guide](https://yunohost.org/packaging_apps_git)
|
||||
- Don't hesitate to reach for help on the dedicated [application packaging chatroom](https://yunohost.org/chat_rooms)... we can even schedule an audio meeting to help you get started!
|
||||
- Don't hesitate to reach for help on the dedicated [application packaging chatroom](https://yunohost.org/chat_rooms) ... we can even schedule an audio meeting to help you get started!
|
||||
|
||||
## How to add your app to the application catalog
|
||||
|
||||
@@ -46,9 +46,9 @@ App example addition:
|
||||
|
||||
```toml
|
||||
[your_app]
|
||||
antifeatures = [ "deprecated-software" ] # Replace with the appropriate category id found in antifeatures.toml, remove if no relevant antifeature applies
|
||||
antifeatures = [ "deprecated-software" ] # Remove if no relevant antifeature applies
|
||||
potential_alternative_to = [ "YouTube" ] # Indicate if your app can be thought of as an alternative to popular proprietary services (or remove if none applies)
|
||||
category = "foobar" # Replace with the appropriate category id found in categories.toml, don't invent a category
|
||||
category = "foobar" # Replace with the appropriate category id found in categories.toml
|
||||
state = "working"
|
||||
url = "https://github.com/YunoHost-Apps/your_app_ynh"
|
||||
```
|
||||
|
||||
@@ -1,151 +1,123 @@
|
||||
[tracking]
|
||||
icon = "user-secret"
|
||||
title.en = "Tracking"
|
||||
title.eu = "Jarraipena"
|
||||
title.fr = "Pistage"
|
||||
title.it = "Tracciamento"
|
||||
description.en = "Tracks you and/or reports your activity to upstream maintainer or third parties, either without your permission or by default."
|
||||
description.eu = "Zure jardueraren jarraipena egiten du eta/edo jardueraren berri ematen die aplikazioaren arduradunari edo hirugarrenei, baimenik gabe edo defektuz."
|
||||
description.fr = "Vous piste et/ou rapporte vos activités au mainteneur source ou à des tiers, sans votre permission ou par défaut."
|
||||
description.it = "Ti traccia e/o riporta la tua attività a chi mantiene il codice sorgente o a terze parti, facendolo senza il tuo permesso o di default."
|
||||
|
||||
[non-free-network]
|
||||
icon = "sitemap"
|
||||
title.en = "Non-free Network Services"
|
||||
title.eu = "Libreak ez diren sareko zerbitzuak"
|
||||
title.fr = "Services réseau non libres"
|
||||
title.it = "Servizi di rete non liberi"
|
||||
description.en = "Promotes or depends entirely on a non-free network service."
|
||||
description.eu = "Librea ez den sare-zerbitzu bat sustatzen du edo horren mende dago erabat."
|
||||
description.fr = "Promeut ou utilise des services réseau non libres."
|
||||
description.it = "Promuove o dipende interamente da servizi di rete non liberi."
|
||||
|
||||
[non-free-addons]
|
||||
icon = "puzzle-piece"
|
||||
title.en = "Non-free Addons"
|
||||
title.eu = "Libreak ez diren gehigarriak"
|
||||
title.fr = "Extensions non libres"
|
||||
title.it = "Estensioni non libere"
|
||||
description.en = "Promotes other non-free applications or plugins."
|
||||
description.eu = "Libreak ez diren beste aplikazio edo gehigarri batzuk sustatzen ditu."
|
||||
description.fr = "Promeut d'autres applications ou plugins non libres."
|
||||
description.it = "Promoove altre applicazioni o plugin non liberi"
|
||||
|
||||
[non-free-dependencies]
|
||||
icon = "book"
|
||||
title.en = "Non-free dependencies"
|
||||
title.eu = "Libreak ez diren dependentziak"
|
||||
title.fr = "Dépendances non libres"
|
||||
title.it = "Dipendenze non libere"
|
||||
description.en = "Relies on software dependencies that are not free in order to run."
|
||||
description.eu = "Libreak ez diren dependentzien mende dago exekutatu ahal izateko."
|
||||
description.fr = "Dépend pour fonctionner de dépendances logicielles non libres."
|
||||
description.it = "Per funzionare, si basa su dipendenze software non libere."
|
||||
|
||||
[non-free-assets]
|
||||
icon = "file-image-o"
|
||||
title.en = "Non-free assets"
|
||||
title.eu = "Libreak ez diren baliabideak"
|
||||
title.fr = "Ressources non libres"
|
||||
title.it = "Risorse non libere"
|
||||
description.en = "Contains and makes use of non-free assets. The most common case is apps using artwork - images, sounds, music, etc. - under a commercial license."
|
||||
description.eu = "Libreak ez diren baliabideak ditu eta erabiltzen ditu. Kasurik ohikoena artelanak (irudiak, soinuak, musika, etab.) erabiltzen dituzten aplikazioak dira. - jabedun-lizentziapean."
|
||||
description.fr = "Contient ou utilise des médias non libres. Le cas le plus fréquent concerne des applications utilisant des œuvres (images, sons, musiques, etc.) sous une licence commerciale."
|
||||
description.it = "Contiene ed utilizza risorse mediatiche non libere. Il caso più comune è l’utilizzo da parte dell’app di contenuti artistici (immagini, suoni, musica, ecc.) coperti da licenza commerciale."
|
||||
|
||||
[bad-security-reputation]
|
||||
icon = "bug"
|
||||
title.en = "Bad security reputation"
|
||||
title.eu = "Segurtasun txarreko ospea"
|
||||
title.fr = "Mauvaise réputation en matière de sécurité"
|
||||
title.it = "Cattiva reputazione di sicurezza"
|
||||
description.en = "Has a bad security reputation, such as deprecated addons."
|
||||
description.eu = "Segurtasun ospe txarra du, utzitako gehigarriak esaterako."
|
||||
description.fr = "A une mauvaise réputation en matière de sécurité, en utilisant des plugins dépréciés par exemple."
|
||||
description.it = "Ha una cattiva reputazione in termini di sicurezza (per esempio, potrebbe utilizzare addon obsoleti)."
|
||||
|
||||
[deprecated-software]
|
||||
icon = "trash-o"
|
||||
title.en = "Upstream not maintained"
|
||||
title.eu = "Jatorrizko garapena utzita"
|
||||
title.fr = "Application non maintenue"
|
||||
title.it = "Applicazione non mantenuta"
|
||||
description.en = "This software is not maintained anymore. Expect it to break down over time, be exposed to unfixed security breaches, etc."
|
||||
description.eu = "Software honek ez du arduradunik. Denborak aurrera egin ahala funtzionatzeari utziko dio, konpondu gabeko segurtasun arazoak izango ditu, etab."
|
||||
description.fr = "Ce logiciel n'est plus maintenu. Attendez-vous à ce qu'il ne fonctionne plus avec le temps, et que l'on découvre des failles de sécurité qui ne seront pas corrigées, etc."
|
||||
description.it = "Questo software non è più mantenuto. Ci si può aspettare che con il passare del tempo smetta di funzionare, sia esposto a falle di sicurezza, ecc."
|
||||
|
||||
[package-not-maintained]
|
||||
icon = "user-times"
|
||||
title.en = "Package not maintained"
|
||||
title.eu = "Mantendu gabeko paketea"
|
||||
title.fr = "Paquet non maintenu"
|
||||
title.it = "Pacchetto non mantenuto"
|
||||
description.en = "This YunoHost package is not maintained and needs adoption."
|
||||
description.eu = "Pakete honek ez du mantenduko duenik, boluntario baten beharra dauka."
|
||||
description.fr = "Ce package YunoHost n'est plus maintenu et doit être adopté."
|
||||
description.it = "Questo pacchetto di YunoHost non è più mantenuto e necessita di essere adottato."
|
||||
|
||||
[paid-content]
|
||||
icon = "money"
|
||||
title.en = "Paid content"
|
||||
title.eu = "Ordainpeko edukia"
|
||||
title.fr = "Contenu payant"
|
||||
title.it = "Contenuti a pagamento"
|
||||
description.en = "Promotes or depends, entirely or partially, on a paid service."
|
||||
description.eu = "Ordainpeko zerbitzu bat sustatzen du edo bere mende dago, osorik edo neurri batean."
|
||||
description.fr = "Promeut ou dépend, entièrement ou partiellement, d'un service payant."
|
||||
description.it = "Promuove o dipende, interamente o parzialmente, da un servizio a pagamento."
|
||||
|
||||
[arbitrary-limitations]
|
||||
icon = "star-half-empty"
|
||||
title.en = "Arbitrary limitations"
|
||||
title.eu = "Muga arbitrarioak"
|
||||
title.fr = "Limitations arbitraires"
|
||||
title.it = "Limitazioni arbitrarie"
|
||||
description.en = "Features arbitrary limitations. Please refer to the README."
|
||||
description.eu = "Muga arbitrarioak ditu. Irakurri README fitxategia."
|
||||
description.fr = "Contient des limitations arbitraires. Se référer au fichier README."
|
||||
description.it = "Contiene limitazioni arbitrarie. Fare riferimento al file “README”."
|
||||
|
||||
[replaced-by-another-app]
|
||||
icon = "repeat"
|
||||
title.en = "Replaced by another app"
|
||||
title.eu = "Beste aplikazio batek ordeztu du"
|
||||
title.fr = "Remplacé par une autre application"
|
||||
title.it = "Sostituita da un’altra app"
|
||||
description.en = "Was replaced by another app. Please refer to the README."
|
||||
description.eu = "Beste aplikazio batek ordeztu du. Irakurri README fitxategia."
|
||||
description.fr = "A été remplacé par une autre application. Se référer au fichier README."
|
||||
description.it = "Quest’app è stata sostituita da un’altra app. Fare riferimento al file “README”."
|
||||
|
||||
[alpha-software]
|
||||
icon = "flask"
|
||||
title.en = "Alpha software"
|
||||
title.eu = "Alfa softwarea"
|
||||
title.fr = "Logiciel en version alpha"
|
||||
title.it = "Software in versione alpha"
|
||||
description.en = "Early development stage. May contain changing or unstable features, bugs, and security vulnerability."
|
||||
description.eu = "Garapenaren hasierako fasean dago. Ezaugarri aldakor edo ezegonkorrak, erroreak eta segurtasuneko arazoak izan ditzazke."
|
||||
description.fr = "Le logiciel est au tout début de son développement. Il pourrait contenir des fonctionnalités changeantes ou instables, des bugs, et des failles de sécurité."
|
||||
description.it = "Questo software è all’inizio della sua fase di sviluppo. Potrebbe dunque essere instabile, contenere bug e vulnerabilità di sicurezza."
|
||||
|
||||
[not-totally-free-upstream]
|
||||
icon = "lock"
|
||||
title.en = "Not totally free upstream"
|
||||
title.eu = "Jatorrizkoa ez da erabat librea"
|
||||
title.fr = "Application sous licence libre restreinte"
|
||||
title.it = "Applicazione con licenza parzialmente libera"
|
||||
description.en = "The packaged app is under an overall free licence, but with clauses that restrict its use."
|
||||
description.eu = "Aplikazioak lizentzia librea du orokorrean, baina bere erabilera mugatzen duten klausulekin."
|
||||
description.fr = "L'application packagée est sous une licence globalement libre, mais avec des clauses qui pourraient restreindre son utilisation."
|
||||
description.it = "Quest’applicazione è protetta da licenza generalmente libera, ma con delle clausole che potrebbero limitare il suo utilizzo."
|
||||
|
||||
[not-totally-free-package]
|
||||
icon = "archive"
|
||||
title.en = "Not totally free package"
|
||||
title.eu = "Paketea ez da erabat librea"
|
||||
title.fr = "Package sous licence libre restreinte"
|
||||
description.en = "The YunoHost package of this app is under an overall free licence, but with clauses that restrict its use."
|
||||
description.eu = "Aplikazio honen YunoHost paketeak lizentzia librea du orokorrean, baina bere erabilera mugatzen duten klausulekin."
|
||||
description.fr = "Le package YunoHost de cette application est sous une licence globalement libre, mais avec des clauses qui pourraient restreindre son utilisation."
|
||||
|
||||
11
apps.toml
@@ -502,13 +502,6 @@ state = "working"
|
||||
subtags = [ "wiki" ]
|
||||
url = "https://github.com/YunoHost-Apps/cowyo_ynh"
|
||||
|
||||
[crabfit]
|
||||
category = "productivity_and_management"
|
||||
potential_alternative_to = [ "Doodle", "OpenSondage" ]
|
||||
state = "working"
|
||||
subtags = [ "poll" ]
|
||||
url = "https://github.com/YunoHost-Apps/crabfit_ynh"
|
||||
|
||||
[cryptpad]
|
||||
category = "office"
|
||||
level = 8
|
||||
@@ -1572,7 +1565,6 @@ url = "https://github.com/YunoHost-Apps/kanboard_ynh"
|
||||
|
||||
[kavita]
|
||||
category = "reading"
|
||||
antifeatures = [ "paid-content" ]
|
||||
level = 8
|
||||
state = "working"
|
||||
subtags = [ "books" ]
|
||||
@@ -1935,7 +1927,6 @@ url = "https://github.com/YunoHost-Apps/mautrix_discord_ynh"
|
||||
|
||||
[mautrix_facebook]
|
||||
category = "communication"
|
||||
antifeatures = [ "deprecated-software" ]
|
||||
level = 6
|
||||
potential_alternative_to = [ "Facebook Messenger" ]
|
||||
state = "working"
|
||||
@@ -2709,7 +2700,7 @@ url = "https://github.com/YunoHost-Apps/privatebin_ynh"
|
||||
category = "publishing"
|
||||
level = 8
|
||||
potential_alternative_to = [ "Blogger", "Blogspot", "Wix" ]
|
||||
state = "notworking"
|
||||
state = "working"
|
||||
subtags = [ "website", "blog" ]
|
||||
url = "https://github.com/YunoHost-Apps/processwire_ynh"
|
||||
|
||||
|
||||
@@ -2,40 +2,34 @@
|
||||
icon = "cloud"
|
||||
title.en = "Synchronization"
|
||||
title.es = "Sincronización"
|
||||
title.eu = "Sinkronizazioa"
|
||||
title.fr = "Synchronisation"
|
||||
title.it = "Sincronizzazione"
|
||||
description.en = "Files sync, contact, calendar, password managers..."
|
||||
description.es = "Sincronización, contactos, calendario, gestor de contraseñas..."
|
||||
description.eu = "Sinkronizazioa, kontaktuak, egutegia, pasahitzen kudeaketa..."
|
||||
description.fr = "Fichiers, contacts, calendrier, mots de passe..."
|
||||
description.it = "Sincronizzazione di file, contatti, calendari, gestione password…"
|
||||
|
||||
[synchronization.subtags.files]
|
||||
title.en = "Files"
|
||||
title.es = "Archivos"
|
||||
title.eu = "Fitxategiak"
|
||||
title.fr = "Fichiers"
|
||||
title.it = "File"
|
||||
|
||||
[synchronization.subtags.calendar]
|
||||
title.en = "Calendar"
|
||||
title.es = "Calendario"
|
||||
title.eu = "Egutegia"
|
||||
title.fr = "Calendrier"
|
||||
title.it = "Calendario"
|
||||
|
||||
[synchronization.subtags.contacts]
|
||||
title.en = "Contacts"
|
||||
title.es = "Contactos"
|
||||
title.eu = "Kontaktuak"
|
||||
title.fr = "Contacts"
|
||||
title.it = "Contatti"
|
||||
|
||||
[synchronization.subtags.password]
|
||||
title.en = "Passwords"
|
||||
title.es = "Contraseñas"
|
||||
title.eu = "Pasahitzak"
|
||||
title.fr = "Mots de passe"
|
||||
title.it = "Password"
|
||||
|
||||
@@ -43,47 +37,40 @@ description.it = "Sincronizzazione di file, contatti, calendari, gestione passwo
|
||||
icon = "globe"
|
||||
title.en = "Publishing"
|
||||
title.es = "Publicaciones"
|
||||
title.eu = "Argitalpenak"
|
||||
title.fr = "Publication"
|
||||
title.it = "Pubblicazione"
|
||||
description.en = "Websites, blog, wiki, CMS..."
|
||||
description.es = "Paginas Web, blog, wiki, CMS..."
|
||||
description.eu = "Web orriak, blogak, wikiak, CMSak..."
|
||||
description.fr = "Site web, blog, wiki, CMS..."
|
||||
description.it = "Siti web, blog, wiki, CMS…"
|
||||
|
||||
[publishing.subtags.website]
|
||||
title.en = "Website"
|
||||
title.es = "Paginas web"
|
||||
title.eu = "Web orriak"
|
||||
title.fr = "Site web"
|
||||
title.it = "Siti web"
|
||||
|
||||
[publishing.subtags.blog]
|
||||
title.en = "Blog"
|
||||
title.es = "blog"
|
||||
title.eu = "Blogak"
|
||||
title.fr = "Blog"
|
||||
title.it = "Blog"
|
||||
|
||||
[publishing.subtags.wiki]
|
||||
title.en = "Wiki"
|
||||
title.es = "Wiki"
|
||||
title.eu = "Wikiak"
|
||||
title.fr = "Wiki"
|
||||
title.it = "Wiki"
|
||||
|
||||
[publishing.subtags.ecommerce]
|
||||
title.en = "E-commerce"
|
||||
title.es = "Comercio eletronico"
|
||||
title.eu = "Merkataritza elektronikoa"
|
||||
title.fr = "Vente en ligne"
|
||||
title.it = "Vendite online"
|
||||
|
||||
[publishing.subtags.analytics]
|
||||
title.en = "Analytics"
|
||||
title.es = "Estadisticas"
|
||||
title.eu = "Estatistikak"
|
||||
title.fr = "Statistiques"
|
||||
title.it = "Analisi del traffico"
|
||||
|
||||
@@ -91,40 +78,34 @@ description.it = "Siti web, blog, wiki, CMS…"
|
||||
icon = "comments-o"
|
||||
title.en = "Communication"
|
||||
title.es = "Comunicacion"
|
||||
title.eu = "Komunikazioa"
|
||||
title.fr = "Communication"
|
||||
title.it = "Comunicazione"
|
||||
description.en = "Chat, email, forum, meetings..."
|
||||
description.es = "Chat, email, foro, reuniones en grupo..."
|
||||
description.eu = "Txata, ePosta, foroak, talde-bilerak..."
|
||||
description.fr = "Chat, email, forum, meetings..."
|
||||
description.it = "Messaggistica, posta elettronica, forum, riunioni…"
|
||||
|
||||
[communication.subtags.chat]
|
||||
title.en = "Instant messaging"
|
||||
title.es = "Mensajeria Instantanea"
|
||||
title.eu = "Bat-bateko mezularitza"
|
||||
title.fr = "Messagerie instantannée"
|
||||
title.it = "Messaggistica istantanea"
|
||||
|
||||
[communication.subtags.forum]
|
||||
title.en = "Forum"
|
||||
title.es = "Foro"
|
||||
title.eu = "Foroak"
|
||||
title.fr = "Forum"
|
||||
title.it = "Forum"
|
||||
|
||||
[communication.subtags.email]
|
||||
title.en = "Email"
|
||||
title.es = "Email"
|
||||
title.eu = "ePosta"
|
||||
title.fr = "Email"
|
||||
title.it = "Posta elettronica"
|
||||
|
||||
[communication.subtags.meeting]
|
||||
title.en = "Meetings"
|
||||
title.es = "Reuniones"
|
||||
title.eu = "Bilerak"
|
||||
title.fr = "Meetings"
|
||||
title.it = "Riunioni"
|
||||
|
||||
@@ -132,323 +113,268 @@ description.it = "Messaggistica, posta elettronica, forum, riunioni…"
|
||||
icon = "file-text-o"
|
||||
title.en = "Office"
|
||||
title.es = "Ofimatica"
|
||||
title.eu = "Bulegoa"
|
||||
title.fr = "Bureautique"
|
||||
title.it = "Burocrazia"
|
||||
description.en = "Collaborative text editing, spreadsheets..."
|
||||
description.es = "Edición de texto colaborativo, hojas de cálculo..."
|
||||
description.eu = "Testu eta kalkulu-orrien edizioa..."
|
||||
description.fr = "Édition de texte collaborative, tableurs..."
|
||||
description.it = "Modifica di testo collaborativa, tabelle…"
|
||||
|
||||
[office.subtags.text]
|
||||
title.en = "Text"
|
||||
title.es = "Texto"
|
||||
title.eu = "Testua"
|
||||
title.fr = "Texte"
|
||||
title.it = "Testo"
|
||||
|
||||
[office.subtags.spreadsheet]
|
||||
title.en = "Spreadsheet"
|
||||
title.es = "Hoja de cálculo"
|
||||
title.eu = "Kalkulu-orriak"
|
||||
title.fr = "Tableur"
|
||||
title.it = "Tabelle"
|
||||
|
||||
[office.subtags.impress]
|
||||
title.en = "Slide show"
|
||||
title.es = "Diapositivas"
|
||||
title.eu = "Diapositiba-aurkezpenak"
|
||||
title.fr = "Diaporama"
|
||||
title.it = "Diapositive"
|
||||
|
||||
[office.subtags.draw]
|
||||
title.en = "Graphism"
|
||||
title.es = "Graficos"
|
||||
title.eu = "Grafikoak"
|
||||
title.fr = "Graphisme"
|
||||
title.it = "Grafica"
|
||||
|
||||
[office.subtags.mindmap]
|
||||
title.en = "Mindmap"
|
||||
title.eu = "Ideia-zuhaitzak"
|
||||
title.fr = "Cartes mentale"
|
||||
title.it = "Mappe mentali"
|
||||
|
||||
[productivity_and_management]
|
||||
icon = "area-chart"
|
||||
title.en = "Productivity & management"
|
||||
title.eu = "Produktibitatea eta kudeaketa"
|
||||
title.fr = "Productivité & gestion"
|
||||
title.it = "Produttività & gestionale"
|
||||
description.en = "Tasks, polls, accounting, ERP..."
|
||||
description.eu = "Zereginak, inkestak, kontabilitatea, enpresa-baliabideen plangintza (ERP)..."
|
||||
description.fr = "Tâches, sondages, comptabilité, ERP..."
|
||||
description.it = "Gestione attività, sondaggi, contabilità, ERP…"
|
||||
|
||||
[productivity_and_management.subtags.task]
|
||||
title.en = "Task"
|
||||
title.eu = "Zereginak"
|
||||
title.fr = "Tâches"
|
||||
title.it = "Gestione attività"
|
||||
|
||||
[productivity_and_management.subtags.poll]
|
||||
title.en = "Poll"
|
||||
title.eu = "Inkestak"
|
||||
title.fr = "Sondage"
|
||||
title.it = "Sondaggi"
|
||||
|
||||
[productivity_and_management.subtags.accounting]
|
||||
title.en = "Accounting"
|
||||
title.eu = "Kontabilitatea"
|
||||
title.fr = "Comptabilité"
|
||||
title.it = "Contabilità"
|
||||
|
||||
[productivity_and_management.subtags.business_and_ngos]
|
||||
title.en = "Business and NGOs"
|
||||
title.eu = "Korporazio eta GKEak"
|
||||
title.fr = "Entreprises et associations"
|
||||
title.it = "Imprese e associazioni"
|
||||
|
||||
[small_utilities]
|
||||
icon = "umbrella"
|
||||
title.en = "Small utilities"
|
||||
title.eu = "Tresna txikiak"
|
||||
title.fr = "Petits utilitaires"
|
||||
title.it = "Piccoli strumenti"
|
||||
description.en = "Pastebins, URL shortener, proxies..."
|
||||
description.eu = "Pastebinak, URL laburtzaileak, proxyak..."
|
||||
description.fr = "Pastebins, raccourcisseurs d'URL, proxys..."
|
||||
description.it = "Pastebin, accorciamento di URL, proxy…"
|
||||
|
||||
[small_utilities.subtags.pastebin]
|
||||
title.en = "Pastebin"
|
||||
title.eu = "Pastebinak"
|
||||
title.fr = "Pastebin"
|
||||
title.it = "Pastebin"
|
||||
|
||||
[small_utilities.subtags.url_shortener]
|
||||
title.en = "URL shortener"
|
||||
title.eu = "URL laburtzaileak"
|
||||
title.fr = "Raccourcisseurs d'URL"
|
||||
title.it = "Accorciatore di URL"
|
||||
|
||||
[small_utilities.subtags.proxy]
|
||||
title.en = "Proxy"
|
||||
title.eu = "Proxyak"
|
||||
title.fr = "Proxy (Intermédiaire)"
|
||||
title.it = "Proxy"
|
||||
|
||||
[reading]
|
||||
icon = "newspaper-o"
|
||||
title.en = "Reading"
|
||||
title.eu = "Irakurketa"
|
||||
title.fr = "Lecture"
|
||||
title.it = "Lettura"
|
||||
description.en = "Newsfeed readers, books library..."
|
||||
description.eu = "Albiste-jarioak, liburutegiak..."
|
||||
description.fr = "Fils d'actualité, livres..."
|
||||
description.it = "Notizie, libri…"
|
||||
|
||||
[reading.subtags.rssreader]
|
||||
title.en = "RSS readers"
|
||||
title.eu = "RSS irakurleak"
|
||||
title.fr = "Lecteurs RSS"
|
||||
title.it = "Lettore RSS"
|
||||
|
||||
[reading.subtags.books]
|
||||
title.en = "Books"
|
||||
title.eu = "Liburuak"
|
||||
title.fr = "Livres"
|
||||
title.it = "Libri"
|
||||
|
||||
[multimedia]
|
||||
icon = "music"
|
||||
title.en = "Multimedia"
|
||||
title.eu = "Multimedia"
|
||||
title.fr = "Multimédia"
|
||||
title.it = "Multimedia"
|
||||
description.en = "Music library, pictures gallery, P2P, TV shows..."
|
||||
description.eu = "Musika liburutegiak, argazki-bildumak, P2P, TB saioak..."
|
||||
description.fr = "Bibliothèque de musique, d'images, P2P, séries..."
|
||||
description.it = "Librerie musicali, gallerie d’immagini, P2P, serie TV…"
|
||||
|
||||
[multimedia.subtags.mediacenter]
|
||||
title.en = "Media center"
|
||||
title.eu = "Multimedia"
|
||||
title.fr = "Centre multimédia"
|
||||
title.it = "Centro multimediale"
|
||||
|
||||
[multimedia.subtags.download]
|
||||
title.en = "Download"
|
||||
title.eu = "Deskargak"
|
||||
title.fr = "Téléchargement"
|
||||
title.it = "Download"
|
||||
|
||||
[multimedia.subtags.music]
|
||||
title.en = "Music"
|
||||
title.eu = "Musika"
|
||||
title.fr = "Musique"
|
||||
title.it = "Musica"
|
||||
|
||||
[multimedia.subtags.pictures]
|
||||
title.en = "Pictures"
|
||||
title.eu = "Irudiak"
|
||||
title.fr = "Images"
|
||||
title.it = "Immagini"
|
||||
|
||||
[multimedia.subtags.videos]
|
||||
title.en = "Videos"
|
||||
title.eu = "Bideoak"
|
||||
title.fr = "Vidéos"
|
||||
title.it = "Video"
|
||||
|
||||
[social_media]
|
||||
icon = "users"
|
||||
title.en = "Social media"
|
||||
title.eu = "Sare sozialak"
|
||||
title.fr = "Médias sociaux"
|
||||
title.it = "Social media"
|
||||
description.en = "Microblogging, federated media"
|
||||
description.eu = "Mikroblogak, federatutako media"
|
||||
description.fr = "Microblogging, médias fédérés"
|
||||
description.it = "Microblogging, media federati"
|
||||
|
||||
[social_media.subtags.microblogging]
|
||||
title.en = "Microblogging"
|
||||
title.eu = "Mikroblogintza"
|
||||
title.fr = "Microblogging"
|
||||
title.it = "Microblogging"
|
||||
|
||||
[social_media.subtags.blogging]
|
||||
title.en = "Blogging"
|
||||
title.eu = "Blogintza"
|
||||
title.fr = "Blogging"
|
||||
title.it = "Blogging"
|
||||
|
||||
[social_media.subtags.events]
|
||||
title.en = "Events"
|
||||
title.eu = "Gertaerak"
|
||||
title.fr = "Événements"
|
||||
title.it = "Eventi"
|
||||
|
||||
[social_media.subtags.videos]
|
||||
title.en = "Videos"
|
||||
title.eu = "Bideoak"
|
||||
title.fr = "Vidéos"
|
||||
title.it = "Video"
|
||||
|
||||
[social_media.subtags.pictures]
|
||||
title.en = "Pictures"
|
||||
title.eu = "Irudiak"
|
||||
title.fr = "Images"
|
||||
title.it = "Immagini"
|
||||
|
||||
[social_media.subtags.music]
|
||||
title.en = "Music"
|
||||
title.eu = "Musika"
|
||||
title.fr = "Musique"
|
||||
title.it = "Musica"
|
||||
|
||||
[games]
|
||||
icon = "gamepad"
|
||||
title.en = "Games"
|
||||
title.eu = "Jolasak"
|
||||
title.fr = "Jeux"
|
||||
title.it = "Giochi"
|
||||
description.en = "Wanna have some fun? ;)"
|
||||
description.eu = "Dibertitu nahi duzu? ;)"
|
||||
description.fr = "Envie de s'amuser ? ;)"
|
||||
description.it = "Voglia di divertirti? ;)"
|
||||
|
||||
[dev]
|
||||
icon = "flask"
|
||||
title.en = "Development"
|
||||
title.eu = "Garapena"
|
||||
title.fr = "Développement"
|
||||
title.it = "Sviluppo"
|
||||
description.en = "Git forges, apps skeleton, CI, translation..."
|
||||
description.eu = "Forge Git, aplikazioen eskematizazioa, CI, itzulpengintza..."
|
||||
description.fr = "Forges Git, squelette d'apps, CI, traduction..."
|
||||
description.it = "Forge Git, schematizzazione di applicazioni, CI, traduzioni…"
|
||||
|
||||
[dev.subtags.forge]
|
||||
title.en = "Forge"
|
||||
title.eu = "Forge"
|
||||
title.fr = "Forge"
|
||||
title.it = "Forgia"
|
||||
|
||||
[dev.subtags.skeleton]
|
||||
title.en = "Skeleton"
|
||||
title.eu = "Eskematizazioa"
|
||||
title.fr = "Squelettes"
|
||||
title.it = "Schematizzazione"
|
||||
|
||||
[dev.subtags.programming]
|
||||
title.en = "Programming"
|
||||
title.eu = "Programazioa"
|
||||
title.fr = "Programmation"
|
||||
title.it = "Programmazione"
|
||||
|
||||
[dev.subtags.design]
|
||||
title.en = "Design"
|
||||
title.eu = "Diseinua"
|
||||
title.fr = "Design"
|
||||
title.it = "Progettazione"
|
||||
|
||||
[system_tools]
|
||||
icon = "wrench"
|
||||
title.en = "System tools"
|
||||
title.eu = "Sistemaren tresnak"
|
||||
title.fr = "Outils système"
|
||||
title.it = "Strumenti di sistema"
|
||||
description.en = "Monitoring, backup, network, DB tools..."
|
||||
description.eu = "Monitorizazioa, babeskopiak, sarea, datu-baseen tresnak..."
|
||||
description.fr = "Monitoring, sauvegardes, outils réseau, bases de données..."
|
||||
description.it = "Monitoraggio, backup, servizi di rete, database…"
|
||||
|
||||
[system_tools.subtags.backup]
|
||||
title.en = "Backup"
|
||||
title.eu = "Babeskopiak"
|
||||
title.fr = "Sauvegardes"
|
||||
title.it = "Backup"
|
||||
|
||||
[system_tools.subtags.monitoring]
|
||||
title.en = "Monitoring"
|
||||
title.eu = "Monitorizazioa"
|
||||
title.fr = "Monitoring"
|
||||
title.it = "Monitoraggio"
|
||||
|
||||
[system_tools.subtags.network]
|
||||
title.en = "Network"
|
||||
title.eu = "Sarea"
|
||||
title.fr = "Réseau"
|
||||
title.it = "Rete"
|
||||
|
||||
[system_tools.subtags.db]
|
||||
title.en = "Databases"
|
||||
title.eu = "Datu-baseak"
|
||||
title.fr = "Bases de données"
|
||||
title.it = "Database"
|
||||
|
||||
[iot]
|
||||
icon = "home"
|
||||
title.en = "Internet of Things (IoT)"
|
||||
title.eu = "Gauzen internet (IoT)"
|
||||
title.fr = "Internet des objets (IoT)"
|
||||
title.it = "Interned delle Cose (IoT)"
|
||||
description.en = "Home automation, energy dashboard..."
|
||||
description.eu = "Domotika, automatizazioa, energiaren kudeaketa..."
|
||||
description.fr = "Domotique, énergie..."
|
||||
description.it = "Domotica, controllo energia…"
|
||||
|
||||
[wat]
|
||||
icon = "tree"
|
||||
title.en = "Wat"
|
||||
title.eu = "Wat"
|
||||
title.fr = "Wat"
|
||||
title.it = "Wat"
|
||||
description.en = "Weird experimental or very-custom stuff"
|
||||
description.eu = "Esperimentuak, kontu arraroak edo gauza oso bereziak"
|
||||
description.fr = "Trucs expérimentaux et autres projets spécifiques"
|
||||
description.it = "Esperimenti e altri progetti particolari"
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 311 KiB |
BIN
logos/shuri.png
|
Before Width: | Height: | Size: 170 KiB |
6
store/.gitignore
vendored
@@ -1,8 +1,2 @@
|
||||
config.toml
|
||||
.stars
|
||||
|
||||
assets/fork-awesome.*
|
||||
assets/forkawesome-webfont.*
|
||||
assets/tailwind.css
|
||||
assets/tailwindcss-linux-x64
|
||||
assets/ynh_logo_*
|
||||
@@ -17,9 +17,6 @@ nano config.toml
|
||||
mkdir -p ../builds/default/v3/
|
||||
curl https://app.yunohost.org/default/v3/apps.json > ../builds/default/v3/apps.json
|
||||
|
||||
# you need to manually download the assets to have access to the css and the javascript files
|
||||
(cd assets && bash fetch_assets)
|
||||
|
||||
# You will also want to run list_builder.py to initialize the .apps_cache (at least for a few apps, you can Ctrl+C after a while)
|
||||
pip3 install tqdm GitPython
|
||||
pushd ..
|
||||
|
||||
83
store/app.py
@@ -149,14 +149,7 @@ def star_app(app_id, action):
|
||||
if app_id not in get_catalog()["apps"] and app_id not in get_wishlist():
|
||||
return _("App %(app_id) not found", app_id=app_id), 404
|
||||
if not session.get("user", {}):
|
||||
return (
|
||||
_("You must be logged in to be able to star an app")
|
||||
+ "<br/><br/>"
|
||||
+ _(
|
||||
"Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts."
|
||||
),
|
||||
401,
|
||||
)
|
||||
return _("You must be logged in to be able to star an app") + "<br/><br/>" + _("Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts."), 401
|
||||
|
||||
app_star_folder = os.path.join(".stars", app_id)
|
||||
app_star_for_this_user = os.path.join(
|
||||
@@ -199,13 +192,7 @@ def add_to_wishlist():
|
||||
if request.method == "POST":
|
||||
user = session.get("user", {})
|
||||
if not user:
|
||||
errormsg = (
|
||||
_("You must be logged in to submit an app to the wishlist")
|
||||
+ "<br/><br/>"
|
||||
+ _(
|
||||
"Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts."
|
||||
)
|
||||
)
|
||||
errormsg = _("You must be logged in to submit an app to the wishlist") + "<br/><br/>" + _("Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts.")
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
locale=get_locale(),
|
||||
@@ -233,33 +220,12 @@ def add_to_wishlist():
|
||||
website = request.form["website"].strip().replace("\n", "")
|
||||
license = request.form["license"].strip().replace("\n", "")
|
||||
|
||||
boring_keywords_to_check_for_people_not_reading_the_instructions = [
|
||||
"free",
|
||||
"open source",
|
||||
"open-source",
|
||||
"self-hosted",
|
||||
"simple",
|
||||
"lightweight",
|
||||
"light-weight",
|
||||
"léger",
|
||||
"best",
|
||||
"most",
|
||||
"fast",
|
||||
"rapide",
|
||||
"flexible",
|
||||
"puissante",
|
||||
"puissant",
|
||||
"powerful",
|
||||
"secure",
|
||||
]
|
||||
boring_keywords_to_check_for_people_not_reading_the_instructions = ["free", "open source", "open-source", "self-hosted", "simple", "lightweight", "light-weight", "léger", "best", "most", "fast", "rapide", "flexible", "puissante", "puissant", "powerful", "secure"]
|
||||
|
||||
checks = [
|
||||
(
|
||||
check_wishlist_submit_ratelimit(session["user"]["username"]) is True
|
||||
and session["user"]["bypass_ratelimit"] is False,
|
||||
_(
|
||||
"Proposing wishlist additions is limited to once every 15 days per user. Please try again in a few days."
|
||||
),
|
||||
check_wishlist_submit_ratelimit(session['user']['username']) is True and session['user']['bypass_ratelimit'] is False,
|
||||
_("Proposing wishlist additions is limited to once every 15 days per user. Please try again in a few days.")
|
||||
),
|
||||
(len(name) >= 3, _("App name should be at least 3 characters")),
|
||||
(len(name) <= 30, _("App name should be less than 30 characters")),
|
||||
@@ -293,22 +259,13 @@ def add_to_wishlist():
|
||||
_("App name contains special characters"),
|
||||
),
|
||||
(
|
||||
all(
|
||||
keyword not in description.lower()
|
||||
for keyword in boring_keywords_to_check_for_people_not_reading_the_instructions
|
||||
),
|
||||
_(
|
||||
"Please focus on what the app does, without using marketing, fuzzy terms, or repeating that the app is 'free' and 'self-hostable'."
|
||||
),
|
||||
all(keyword not in description.lower() for keyword in boring_keywords_to_check_for_people_not_reading_the_instructions),
|
||||
_("Please focus on what the app does, without using marketing, fuzzy terms, or repeating that the app is 'free' and 'self-hostable'.")
|
||||
),
|
||||
(
|
||||
description.lower().split()[0] != name
|
||||
and (
|
||||
len(description.split()) == 1
|
||||
or description.lower().split()[1] not in ["is", "est"]
|
||||
),
|
||||
_("No need to repeat the name of the app. Focus on what the app does."),
|
||||
),
|
||||
description.lower().split()[0] != name and (len(description.split()) == 1 or description.lower().split()[1] not in ["is", "est"]),
|
||||
_("No need to repeat the name of the app. Focus on what the app does.")
|
||||
)
|
||||
]
|
||||
|
||||
for check, errormsg in checks:
|
||||
@@ -343,8 +300,7 @@ def add_to_wishlist():
|
||||
successmsg=None,
|
||||
errormsg=_(
|
||||
"An entry with the name %(slug)s already exists in the wishlist, instead, you can <a href='%(url)s'>add a star to the app to show your interest</a>.",
|
||||
slug=slug,
|
||||
url=url,
|
||||
slug=slug, url=url,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -368,7 +324,7 @@ def add_to_wishlist():
|
||||
url = "https://github.com/YunoHost/apps/pulls?q=is%3Apr+is%3Aopen+wishlist"
|
||||
errormsg = _(
|
||||
"Failed to create the pull request to add the app to the wishlist… Maybe there's already <a href='%(url)s'>a waiting PR for this app</a>? Else, please report the issue to the YunoHost team.",
|
||||
url=url,
|
||||
url=url
|
||||
)
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
@@ -422,7 +378,7 @@ Description: {description}
|
||||
url=url,
|
||||
)
|
||||
|
||||
save_wishlist_submit_for_ratelimit(session["user"]["username"])
|
||||
save_wishlist_submit_for_ratelimit(session['user']['username'])
|
||||
|
||||
return render_template(
|
||||
"wishlist_add.html",
|
||||
@@ -489,17 +445,10 @@ def sso_login_callback():
|
||||
|
||||
uri_to_redirect_to_after_login = session.get("uri_to_redirect_to_after_login")
|
||||
|
||||
if "trust_level_1" not in user_data["groups"][0].split(","):
|
||||
return (
|
||||
_("Unfortunately, login was denied.")
|
||||
+ "<br/><br/>"
|
||||
+ _(
|
||||
"Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts."
|
||||
),
|
||||
403,
|
||||
)
|
||||
if "trust_level_1" not in user_data['groups'][0].split(','):
|
||||
return _("Unfortunately, login was denied.") + "<br/><br/>" + _("Note that, due to various abuses, we restricted login on the app store to 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after interacting a minimum with the forum, and more specifically: entering at least 5 topics, reading at least 30 posts, and spending at least 10 minutes reading posts."), 403
|
||||
|
||||
if "staff" in user_data["groups"][0].split(","):
|
||||
if "staff" in user_data['groups'][0].split(','):
|
||||
bypass_ratelimit = True
|
||||
else:
|
||||
bypass_ratelimit = False
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import os
|
||||
|
||||
install_dir = os.path.dirname(__file__)
|
||||
command = f"{install_dir}/venv/bin/gunicorn"
|
||||
command = f'{install_dir}/venv/bin/gunicorn'
|
||||
pythonpath = install_dir
|
||||
workers = 4
|
||||
user = "appstore"
|
||||
bind = f"unix:{install_dir}/sock"
|
||||
pid = "/run/gunicorn/appstore-pid"
|
||||
errorlog = "/var/log/appstore/error.log"
|
||||
accesslog = "/var/log/appstore/access.log"
|
||||
user = 'appstore'
|
||||
bind = f'unix:{install_dir}/sock'
|
||||
pid = '/run/gunicorn/appstore-pid'
|
||||
errorlog = '/var/log/appstore/error.log'
|
||||
accesslog = '/var/log/appstore/access.log'
|
||||
access_log_format = '%({X-Real-IP}i)s %({X-Forwarded-For}i)s %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
|
||||
loglevel = "warning"
|
||||
loglevel = 'warning'
|
||||
capture_output = True
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
|
||||
<div id="catalogGoodQuality" class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 max-w-screen-lg mx-auto pt-10">
|
||||
{% for app, infos in catalog['apps'].items() %}
|
||||
{% if infos['level'] and infos['level'] != "?" and infos['level'] > 4 and not "deprecated-software" in infos['antifeatures'] %}
|
||||
{% if infos['level'] and infos['level'] != "?" and infos['level'] > 4 %}
|
||||
{{ appCard(app, infos, timestamp_now, catalog) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -160,7 +160,6 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="lowQualityAppTitle" class="text-center pt-10 mx-4 md:mx-0">
|
||||
<h2 class="text-lg font-bold text-gray-900">
|
||||
{{ _("Applications currently flagged as broken") }}
|
||||
@@ -179,24 +178,6 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div id="deprecatedAppTitle" class="text-center pt-10 mx-4 md:mx-0">
|
||||
<h2 class="text-lg font-bold text-gray-900">
|
||||
{{ _("Deprecated applications") }}
|
||||
</h2>
|
||||
<p class="text-sm">
|
||||
{{ _("These are apps who are not maintained anymore.") }}<br/>
|
||||
{{ _("This means that the developer will no longer update them. We strongly advise against their installation and advise users to find alternatives.") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="catalogDeprecated" class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 max-w-screen-lg mx-auto pt-10">
|
||||
{% for app, infos in catalog['apps'].items() %}
|
||||
{% if "deprecated-software" in infos['antifeatures'] %}
|
||||
{{ appCard(app, infos, timestamp_now, catalog) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
// A little delay
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:04+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ar <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: bn_BD <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: br <LL@li.org>\n"
|
||||
@@ -143,7 +143,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -334,28 +334,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ca <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ckb <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: cs <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: da <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"PO-Revision-Date: 2024-03-06 17:37+0000\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-03-04 19:26+0000\n"
|
||||
"Last-Translator: Christian Wehrli <christian@chw.onl>\n"
|
||||
"Language-Team: German <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
"de/>\n"
|
||||
@@ -37,8 +37,8 @@ msgid ""
|
||||
"reading posts."
|
||||
msgstr ""
|
||||
"Beachten Sie, dass wir aufgrund verschiedener Missbräuche die Anmeldung im "
|
||||
"App-Store auf Benutzer der „Vertrauensstufe 1“ beschränkt haben.<br/><br/"
|
||||
">„Vertrauensstufe 1“ wird erreicht, wenn man mindestens mit dem Forum "
|
||||
"App-Store auf Benutzer der „Vertrauensstufe 1“ beschränkt haben.<br/><br/>„"
|
||||
"Vertrauensstufe 1“ wird erreicht, wenn man mindestens mit dem Forum "
|
||||
"interagiert hat, spezifisch: Mindestens 5 Themen geöffnet, mindestens 30 "
|
||||
"Beiträge gelesen und mindestens 10 Minuten damit verbracht haben, Beiträge "
|
||||
"zu lesen."
|
||||
@@ -80,8 +80,7 @@ msgstr "Die App-Beschreibung sollte weniger als 100 Zeichen umfassen"
|
||||
|
||||
#: app.py:242
|
||||
msgid "Upstream code repo URL should be at least 10 characters"
|
||||
msgstr ""
|
||||
"Die Upstream-Code-Repository-URL sollte mindestens 10 Zeichen lang sein"
|
||||
msgstr "Die Upstream-Code-Repository-URL sollte mindestens 10 Zeichen lang sein"
|
||||
|
||||
#: app.py:246
|
||||
msgid "Upstream code repo URL should be less than 150 characters"
|
||||
@@ -171,7 +170,7 @@ msgstr ""
|
||||
"Tests nicht bestanden hat."
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -318,8 +317,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Hergestellt mit <i class='text-red-500 fa fa-heart-o' aria-label='love'></i> "
|
||||
"mit Hilfe von <a class='text-blue-800' href='https://flask.palletsprojects."
|
||||
"com'>Flask</a> und <a class='text-blue-800' href='https://tailwindcss."
|
||||
"com/'>TailwindCSS</a> - <a class='text-blue-800' href='https://github.com/"
|
||||
"com'>Flask</a> und <a class='text-blue-800' href='https://tailwindcss.com/"
|
||||
"'>TailwindCSS</a> - <a class='text-blue-800' href='https://github.com/"
|
||||
"YunoHost/apps/tree/master/store'><i class='fa fa-code fa-fw' aria-"
|
||||
"hidden='true'></i> Source</a>"
|
||||
|
||||
@@ -377,35 +376,14 @@ msgstr "Finden Sie nicht, wonach Sie suchen?"
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr "Schauen Sie sich die Wunschliste an!"
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr "Applikationen, die gegenwärtig als defekt markiert sind"
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr "Das sind Apps, welche die automatischen Tests nicht bestanden haben."
|
||||
|
||||
#: templates/catalog.html:184
|
||||
#, fuzzy
|
||||
#| msgid "Browse all applications"
|
||||
msgid "Deprecated applications"
|
||||
msgstr "Alle Applikationen"
|
||||
|
||||
#: templates/catalog.html:187
|
||||
#, fuzzy
|
||||
#| msgid "These are apps which failed our automatic tests."
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr "Das sind Apps, welche die automatischen Tests nicht bestanden haben."
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
"Das bedeutet, dass der Entwickler sie nicht mehr aktualisieren wird. Wir "
|
||||
"raten dringend von deren Installation ab und empfehlen Benutzern, nach "
|
||||
"Alternativen zu suchen."
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr "Applikations-Store"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: el <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: eo <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,22 +7,20 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"PO-Revision-Date: 2024-03-09 17:32+0000\n"
|
||||
"Last-Translator: cri <cri@cri.cl>\n"
|
||||
"Language-Team: Spanish <https://translate.yunohost.org/projects/yunohost/"
|
||||
"apps/es/>\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: es <LL@li.org>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.3.1\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Generated-By: Babel 2.14.0\n"
|
||||
|
||||
#: app.py:150
|
||||
msgid "App %(app_id) not found"
|
||||
msgstr "App %(app_id) no encontrada"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:152
|
||||
msgid "You must be logged in to be able to star an app"
|
||||
@@ -141,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -332,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"PO-Revision-Date: 2024-03-06 18:13+0000\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-03-04 19:26+0000\n"
|
||||
"Last-Translator: xabirequejo <xabi.rn@gmail.com>\n"
|
||||
"Language-Team: Basque <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
"eu/>\n"
|
||||
@@ -82,8 +82,7 @@ msgstr ""
|
||||
|
||||
#: app.py:246
|
||||
msgid "Upstream code repo URL should be less than 150 characters"
|
||||
msgstr ""
|
||||
"Jatorrizko kode-gordailuaren URLak 150 karaktere izan ditzazke gehienez"
|
||||
msgstr "Jatorrizko kode-gordailuaren URLak 150 karaktere izan ditzazke gehienez"
|
||||
|
||||
#: app.py:250
|
||||
msgid "License URL should be at least 10 characters"
|
||||
@@ -145,8 +144,8 @@ msgid ""
|
||||
"%(url)s</a>"
|
||||
msgstr ""
|
||||
"Proposatutako aplikazioa behar bezala bidali da. YunoHosten taldeak "
|
||||
"baliozkotu behar du orain. Egoera hemen ikusi dezakezu: <a href='%(url)s'>"
|
||||
"%(url)s</a>"
|
||||
"baliozkotu behar du orain. Egoera hemen ikusi dezakezu: <a "
|
||||
"href='%(url)s'>%(url)s</a>"
|
||||
|
||||
#: app.py:449
|
||||
msgid "Unfortunately, login was denied."
|
||||
@@ -166,7 +165,7 @@ msgstr ""
|
||||
"Aplikazioa ez dabilela ageri da ez dituelako gure test automatikoak gainditu."
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -367,30 +366,14 @@ msgstr "Ez duzu bilatzen ari zarena aurkitzen?"
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr "Begiratu desira-zerrenda!"
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr "Aplikazioa hondatuta gisa ageri da"
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr "Gure test automatikoak gainditu ez dituzten aplikazioak dira hauek."
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr "Utzitako aplikazioak"
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr "Aplikazio hauek ez dute mantenduko dituenik."
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
"Honek esan nahi du garatzaileek ez dituztela aurrerantzean eguneratuko. Gure "
|
||||
"gomendioa ez instalatzea da eta beraien ordez alternatibak bilatzea."
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr "Aplikazio denda"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: fa <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: fi <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,14 +7,14 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"PO-Revision-Date: 2024-03-09 04:14+0000\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-27 19:19+0000\n"
|
||||
"Last-Translator: OniriCorpe <oniricorpe@disroot.org>\n"
|
||||
"Language-Team: French <https://translate.yunohost.org/projects/yunohost/apps/"
|
||||
"fr/>\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.3.1\n"
|
||||
@@ -30,21 +30,22 @@ msgstr "Vous devez être connecté·e pour mettre une app en favoris"
|
||||
|
||||
#: app.py:152 app.py:195 app.py:449 templates/wishlist_add.html:33
|
||||
msgid ""
|
||||
"Note that, due to various abuses, we restricted login on the app store to"
|
||||
" 'trust level 1' users.<br/><br/>'Trust level 1' is obtained after "
|
||||
"Note that, due to various abuses, we restricted login on the app store to "
|
||||
"'trust level 1' users.<br/><br/>'Trust level 1' is obtained after "
|
||||
"interacting a minimum with the forum, and more specifically: entering at "
|
||||
"least 5 topics, reading at least 30 posts, and spending at least 10 "
|
||||
"minutes reading posts."
|
||||
"least 5 topics, reading at least 30 posts, and spending at least 10 minutes "
|
||||
"reading posts."
|
||||
msgstr ""
|
||||
"Notez que, suite à divers abus, la connexion nécessite maintenant d'être "
|
||||
"'trust level 1' sur le forum.<br/><br/>Le 'trust level 1' est obtenu "
|
||||
"après avoir intéragit un minimum avec le forum, et plus précisémment : "
|
||||
"ouvrir au moins 5 fils de discussion, lire au moins 30 messages, et "
|
||||
"passer au moins 10 minutes à lire des messages."
|
||||
"'trust level 1' sur le forum.<br/><br/>Le 'trust level 1' est obtenu après "
|
||||
"avoir intéragit un minimum avec le forum, et plus précisémment : ouvrir au "
|
||||
"moins 5 fils de discussion, lire au moins 30 messages, et passer au moins 10 "
|
||||
"minutes à lire des messages."
|
||||
|
||||
#: app.py:195
|
||||
msgid "You must be logged in to submit an app to the wishlist"
|
||||
msgstr "Vous devez être connecté·e pour proposer une app pour la liste de souhaits"
|
||||
msgstr ""
|
||||
"Vous devez être connecté·e pour proposer une app pour la liste de souhaits"
|
||||
|
||||
#: app.py:207
|
||||
msgid "Invalid CSRF token, please refresh the page and try again"
|
||||
@@ -55,8 +56,8 @@ msgid ""
|
||||
"Proposing wishlist additions is limited to once every 15 days per user. "
|
||||
"Please try again in a few days."
|
||||
msgstr ""
|
||||
"Proposer une app dans la liste de souhaits est limité à une fois tous les"
|
||||
" 15 jours et par personne. Merci de réessayer dans quelques jours."
|
||||
"Proposer une app dans la liste de souhaits est limité à une fois tous les 15 "
|
||||
"jours et par personne. Merci de réessayer dans quelques jours."
|
||||
|
||||
#: app.py:230
|
||||
msgid "App name should be at least 3 characters"
|
||||
@@ -100,25 +101,23 @@ msgstr "Le nom de l'app contient des caractères spéciaux"
|
||||
|
||||
#: app.py:263
|
||||
msgid ""
|
||||
"Please focus on what the app does, without using marketing, fuzzy terms, "
|
||||
"or repeating that the app is 'free' and 'self-hostable'."
|
||||
"Please focus on what the app does, without using marketing, fuzzy terms, or "
|
||||
"repeating that the app is 'free' and 'self-hostable'."
|
||||
msgstr ""
|
||||
"S'il vous plaît décrivez ce que fait l'application sans utiliser de "
|
||||
"termes marketing nébuleux ou répéter que l'app est 'libre' ou 'auto-"
|
||||
"hébergeable'."
|
||||
"S'il vous plaît décrivez ce que fait l'application sans utiliser de termes "
|
||||
"marketing nébuleux ou répéter que l'app est 'libre' ou 'auto-hébergeable'."
|
||||
|
||||
#: app.py:267
|
||||
msgid "No need to repeat the name of the app. Focus on what the app does."
|
||||
msgstr ""
|
||||
"Pas besoin de répéter le nom de l'application. Prière de rester concis et"
|
||||
" de se concentrer sur ce que l'app fait."
|
||||
"Pas besoin de répéter le nom de l'application. Prière de rester concis et de "
|
||||
"se concentrer sur ce que l'app fait."
|
||||
|
||||
#: app.py:301
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An entry with the name %(slug)s already exists in the wishlist, instead, "
|
||||
"you can <a href='%(url)s'>add a star to the app to show your "
|
||||
"interest</a>."
|
||||
"An entry with the name %(slug)s already exists in the wishlist, instead, you "
|
||||
"can <a href='%(url)s'>add a star to the app to show your interest</a>."
|
||||
msgstr ""
|
||||
"Une entrée nommée %(slug)s existe déjà dans la liste de souhaits, vous "
|
||||
"pouvez <a href='%(url)s'>l'ajouter en favori</a> afin de montrer votre "
|
||||
@@ -131,21 +130,20 @@ msgid ""
|
||||
"there's already <a href='%(url)s'>a waiting PR for this app</a>? Else, "
|
||||
"please report the issue to the YunoHost team."
|
||||
msgstr ""
|
||||
"Échec de la création de la demande d'intégration de l'app dans la liste "
|
||||
"de souhaits… Peut-être qu'il y a <a href='%(url)s'>déjà une PR en attente"
|
||||
" pour cette app</a> ? Sinon, merci de signaler le problème à l'équipe "
|
||||
"YunoHost."
|
||||
"Échec de la création de la demande d'intégration de l'app dans la liste de "
|
||||
"souhaits… Peut-être qu'il y a <a href='%(url)s'>déjà une PR en attente pour "
|
||||
"cette app</a> ? Sinon, merci de signaler le problème à l'équipe YunoHost."
|
||||
|
||||
#: app.py:376
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your proposed app has succesfully been submitted. It must now be "
|
||||
"validated by the YunoHost team. You can track progress here: <a "
|
||||
"href='%(url)s'>%(url)s</a>"
|
||||
"Your proposed app has succesfully been submitted. It must now be validated "
|
||||
"by the YunoHost team. You can track progress here: <a href='%(url)s'>"
|
||||
"%(url)s</a>"
|
||||
msgstr ""
|
||||
"Un demande d'intégration à la liste de souhaits a bien été créée pour "
|
||||
"cette app. Elle doit maintenant être validée par l'équipe YunoHost. Vous "
|
||||
"pouvez suivre cette demande ici : <a href='%(url)s'>%(url)s</a>"
|
||||
"Un demande d'intégration à la liste de souhaits a bien été créée pour cette "
|
||||
"app. Elle doit maintenant être validée par l'équipe YunoHost. Vous pouvez "
|
||||
"suivre cette demande ici : <a href='%(url)s'>%(url)s</a>"
|
||||
|
||||
#: app.py:449
|
||||
msgid "Unfortunately, login was denied."
|
||||
@@ -162,11 +160,11 @@ msgid ""
|
||||
"This app is currently flagged as broken because it failed our automatic "
|
||||
"tests."
|
||||
msgstr ""
|
||||
"Cette app est actuellement marquée comme cassée ou de mauvaise qualité "
|
||||
"car elle ne passe pas nos tests automatisés."
|
||||
"Cette app est actuellement marquée comme cassée ou de mauvaise qualité car "
|
||||
"elle ne passe pas nos tests automatisés."
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -180,8 +178,8 @@ msgid ""
|
||||
"This app has been good quality according to our automatic tests over at "
|
||||
"least one year."
|
||||
msgstr ""
|
||||
"Cette app est de bonne qualité d'après nos tests automatisés depuis au "
|
||||
"moins un an."
|
||||
"Cette app est de bonne qualité d'après nos tests automatisés depuis au moins "
|
||||
"un an."
|
||||
|
||||
#: templates/app.html:81
|
||||
msgid "Try the demo"
|
||||
@@ -212,7 +210,8 @@ msgstr "Capture d'écran pour %(app)s"
|
||||
|
||||
#: templates/app.html:106
|
||||
#, python-format
|
||||
msgid "This app is only compatible with these specific architectures: %(archs)s"
|
||||
msgid ""
|
||||
"This app is only compatible with these specific architectures: %(archs)s"
|
||||
msgstr ""
|
||||
"Cette app est uniquement compatible avec les architectures suivantes : "
|
||||
"%(archs)s"
|
||||
@@ -221,8 +220,8 @@ msgstr ""
|
||||
#, python-format
|
||||
msgid "This app requires an unusual amount of RAM to install: %(ram)s"
|
||||
msgstr ""
|
||||
"Cette app requiert une quantité inhabituelle de RAM pour être installée :"
|
||||
" %(ram)s"
|
||||
"Cette app requiert une quantité inhabituelle de RAM pour être installée : "
|
||||
"%(ram)s"
|
||||
|
||||
#: templates/app.html:118
|
||||
msgid "Important infos before installing"
|
||||
@@ -255,7 +254,7 @@ msgstr "Documentation officielle pour les admins"
|
||||
|
||||
#: templates/app.html:142
|
||||
msgid "Official user documentation"
|
||||
msgstr "Documentation officielle d'utilisation"
|
||||
msgstr "Documentation officielle pour les utilisateur·ice·s"
|
||||
|
||||
#: templates/app.html:143
|
||||
msgid "Official code repository"
|
||||
@@ -303,21 +302,18 @@ msgstr "Afficher le menu"
|
||||
|
||||
#: templates/base.html:197
|
||||
msgid ""
|
||||
"Made with <i class='text-red-500 fa fa-heart-o' aria-label='love'></i> "
|
||||
"using <a class='text-blue-800' "
|
||||
"href='https://flask.palletsprojects.com'>Flask</a> and <a class='text-"
|
||||
"blue-800' href='https://tailwindcss.com/'>TailwindCSS</a> - <a class"
|
||||
"='text-blue-800' "
|
||||
"href='https://github.com/YunoHost/apps/tree/master/store'><i class='fa "
|
||||
"fa-code fa-fw' aria-hidden='true'></i> Source</a>"
|
||||
"Made with <i class='text-red-500 fa fa-heart-o' aria-label='love'></i> using "
|
||||
"<a class='text-blue-800' href='https://flask.palletsprojects.com'>Flask</a> "
|
||||
"and <a class='text-blue-800' href='https://tailwindcss.com/'>TailwindCSS</a> "
|
||||
"- <a class='text-blue-800' href='https://github.com/YunoHost/apps/tree/"
|
||||
"master/store'><i class='fa fa-code fa-fw' aria-hidden='true'></i> Source</a>"
|
||||
msgstr ""
|
||||
"Fait avec <i class='text-red-500 fa fa-heart-o' aria-label='amour'></i> à"
|
||||
" l'aide de <a class='text-blue-800' "
|
||||
"href='https://flask.palletsprojects.com'>Flask</a> et <a class='text-"
|
||||
"blue-800' href='https://tailwindcss.com/'>TailwindCSS</a> - <a class"
|
||||
"='text-blue-800' "
|
||||
"href='https://github.com/YunoHost/apps/tree/master/store'><i class='fa "
|
||||
"fa-code fa-fw' aria-hidden='true'></i> Source</a>"
|
||||
"Fait avec <i class='text-red-500 fa fa-heart-o' aria-label='amour'></i> à "
|
||||
"l'aide de <a class='text-blue-800' href='https://flask.palletsprojects."
|
||||
"com'>Flask</a> et <a class='text-blue-800' href='https://tailwindcss."
|
||||
"com/'>TailwindCSS</a> - <a class='text-blue-800' href='https://github.com/"
|
||||
"YunoHost/apps/tree/master/store'><i class='fa fa-code fa-fw' aria-"
|
||||
"hidden='true'></i> Source</a>"
|
||||
|
||||
#: templates/catalog.html:75 templates/catalog.html:80
|
||||
msgid "Application Catalog"
|
||||
@@ -373,31 +369,14 @@ msgstr "Vous ne trouvez pas ce que vous cherchez ?"
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr "Jetez un oeil à la liste de souhaits !"
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr "Applications actuellement marquées comme cassées"
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr "Il s'agit d'apps qui n'ont pas validé nos tests automatisés."
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr "Applications obsolètes"
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr "Il s'agit des applications qui ne sont plus maintenues."
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
"Cela signifie que le développeur ne les mettra plus à jour. Nous "
|
||||
"décourageons fortement leur installation et vous conseillons de vous tourner "
|
||||
"vers des alternatives."
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr "Store d'application"
|
||||
@@ -412,19 +391,19 @@ msgstr "Liste de souhaits d'applications"
|
||||
|
||||
#: templates/wishlist.html:10
|
||||
msgid ""
|
||||
"The wishlist is the place where people can collectively suggest and vote "
|
||||
"for apps that they would like to see packaged and made available in "
|
||||
"YunoHost's official apps catalog. Nevertheless, the fact that apps are "
|
||||
"listed here should by no mean be interpreted as a fact that the YunoHost "
|
||||
"project plans to integrate it, and is merely a source of inspiration for "
|
||||
"packaging volunteers."
|
||||
"The wishlist is the place where people can collectively suggest and vote for "
|
||||
"apps that they would like to see packaged and made available in YunoHost's "
|
||||
"official apps catalog. Nevertheless, the fact that apps are listed here "
|
||||
"should by no mean be interpreted as a fact that the YunoHost project plans "
|
||||
"to integrate it, and is merely a source of inspiration for packaging "
|
||||
"volunteers."
|
||||
msgstr ""
|
||||
"La liste de souhaits est l'endroit où il est possible de collectivement "
|
||||
"suggérer et voter pour des applications que vous aimeriez voir packagée "
|
||||
"et intégrée dans le catalogue officiel de YunoHost. Néanmoins, le fait "
|
||||
"que des apps soient listées ici ne devrait en aucun cas être interprété "
|
||||
"comme le fait que le projet YunoHost prévoit leur intégration, et est "
|
||||
"uniquement une source d'inspiration pour les packageur·euse·s bénévoles."
|
||||
"suggérer et voter pour des applications que vous aimeriez voir packagée et "
|
||||
"intégrée dans le catalogue officiel de YunoHost. Néanmoins, le fait que des "
|
||||
"apps soient listées ici ne devrait en aucun cas être interprété comme le "
|
||||
"fait que le projet YunoHost prévoit leur intégration, et est uniquement une "
|
||||
"source d'inspiration pour les packageur·euse·s bénévoles."
|
||||
|
||||
#: templates/wishlist.html:33 templates/wishlist_add.html:3
|
||||
msgid "Suggest an app"
|
||||
@@ -456,22 +435,22 @@ msgstr "Suggérer une application à ajouter dans le catalogue de YunoHost"
|
||||
|
||||
#: templates/wishlist_add.html:29
|
||||
msgid "You must first login to be allowed to submit an app to the wishlist"
|
||||
msgstr "Vous devez être connecté·e pour proposer une app pour la liste de souhaits"
|
||||
msgstr ""
|
||||
"Vous devez être connecté·e pour proposer une app pour la liste de souhaits"
|
||||
|
||||
#: templates/wishlist_add.html:40
|
||||
msgid "Due to abuses, only one proposal every 15 days per user is allowed."
|
||||
msgstr ""
|
||||
"En raison d'abus, la proposition d'app est limitée à une tous les 15 jours "
|
||||
"par personne."
|
||||
"par utilisateur·ice."
|
||||
|
||||
#: templates/wishlist_add.html:43
|
||||
msgid ""
|
||||
"Reviewing those proposals is tiring for volunteers, please don't yolo-"
|
||||
"send every random nerdy stuff you find on the Internet."
|
||||
"Reviewing those proposals is tiring for volunteers, please don't yolo-send "
|
||||
"every random nerdy stuff you find on the Internet."
|
||||
msgstr ""
|
||||
"La vérification des propositions est éreintante pour les bénévoles, merci"
|
||||
" de ne pas bêtement proposer n'importe quelle app un peu nerd que vous "
|
||||
"trouvez."
|
||||
"La vérification des propositions est éreintante pour les bénévoles, merci de "
|
||||
"ne pas bêtement proposer n'importe quelle app un peu nerd que vous trouvez."
|
||||
|
||||
#: templates/wishlist_add.html:64
|
||||
msgid "App's description"
|
||||
@@ -483,15 +462,15 @@ msgstr "Prière de rester concis et de se concentrer sur ce que l'app fait."
|
||||
|
||||
#: templates/wishlist_add.html:66
|
||||
msgid ""
|
||||
"No need to repeat '[App] is …'. No need to state that it is free/open-"
|
||||
"source or self-hosted (otherwise it wouldn't be packaged for YunoHost). "
|
||||
"Avoid marketing stuff like 'the most', or vague properties like 'easy', "
|
||||
"'simple', 'lightweight'."
|
||||
"No need to repeat '[App] is …'. No need to state that it is free/open-source "
|
||||
"or self-hosted (otherwise it wouldn't be packaged for YunoHost). Avoid "
|
||||
"marketing stuff like 'the most', or vague properties like 'easy', 'simple', "
|
||||
"'lightweight'."
|
||||
msgstr ""
|
||||
"Il n'est pas nécessaire de répéter '[App] est …', ni que l'app est libre"
|
||||
"/open-source (sinon, elle ne serait pas intégrable au catalogue). Évitez "
|
||||
"les formulations marketing type 'le meilleur', ou les propriétés vagues "
|
||||
"telles que 'facile', 'simple', 'léger'."
|
||||
"Il n'est pas nécessaire de répéter '[App] est …', ni que l'app est libre/"
|
||||
"open-source (sinon, elle ne serait pas intégrable au catalogue). Évitez les "
|
||||
"formulations marketing type 'le meilleur', ou les propriétés vagues telles "
|
||||
"que 'facile', 'simple', 'léger'."
|
||||
|
||||
#: templates/wishlist_add.html:68
|
||||
msgid "Project code repository"
|
||||
@@ -507,8 +486,8 @@ msgid ""
|
||||
"possible case-by-case exceptions for apps which are not-totally-free)"
|
||||
msgstr ""
|
||||
"Le projet YunoHost intègrera uniquement des logiciels libre/open-source "
|
||||
"(avec quelques possibles exceptions au cas-par-cas pour des apps qui ne "
|
||||
"sont pas entièrement libres)"
|
||||
"(avec quelques possibles exceptions au cas-par-cas pour des apps qui ne sont "
|
||||
"pas entièrement libres)"
|
||||
|
||||
#: templates/wishlist_add.html:75
|
||||
msgid "Project website"
|
||||
@@ -516,11 +495,11 @@ msgstr "Site officiel"
|
||||
|
||||
#: templates/wishlist_add.html:77
|
||||
msgid ""
|
||||
"Please *do not* just copy-paste the code repository URL. If the project "
|
||||
"has no proper website, then leave the field empty."
|
||||
"Please *do not* just copy-paste the code repository URL. If the project has "
|
||||
"no proper website, then leave the field empty."
|
||||
msgstr ""
|
||||
"Prière de *ne pas* juste copier-coller l'URL du dépôt de code. Si le "
|
||||
"projet n'a pas de site web dédié, laissez le champ vide."
|
||||
"Prière de *ne pas* juste copier-coller l'URL du dépôt de code. Si le projet "
|
||||
"n'a pas de site web dédié, laissez le champ vide."
|
||||
|
||||
#: templates/wishlist_add.html:84
|
||||
msgid "Submit"
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"PO-Revision-Date: 2024-03-06 17:37+0000\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-29 20:27+0000\n"
|
||||
"Last-Translator: \"José M.\" <correo@xmgz.eu>\n"
|
||||
"Language-Team: Galician <https://translate.yunohost.org/projects/yunohost/"
|
||||
"apps/gl/>\n"
|
||||
@@ -118,8 +118,8 @@ msgid ""
|
||||
"An entry with the name %(slug)s already exists in the wishlist, instead, you "
|
||||
"can <a href='%(url)s'>add a star to the app to show your interest</a>."
|
||||
msgstr ""
|
||||
"Xa existe unha entrada co nome %(slug)s, así que podes <a "
|
||||
"href='%(url)s'>engadirlle unha estrela para mostrar interese</a>."
|
||||
"Xa existe unha entrada co nome %(slug)s, así que podes <a href='%(url)"
|
||||
"s'>engadirlle unha estrela para mostrar interese</a>."
|
||||
|
||||
#: app.py:325
|
||||
#, python-format
|
||||
@@ -140,8 +140,8 @@ msgid ""
|
||||
"%(url)s</a>"
|
||||
msgstr ""
|
||||
"Foi enviada correctamente a solicitude para a app. Agora vai ser validada "
|
||||
"polo equipo de YunoHost. Podes ver aquí o proceso: <a href='%(url)s'>"
|
||||
"%(url)s</a>"
|
||||
"polo equipo de YunoHost. Podes ver aquí o proceso: <a "
|
||||
"href='%(url)s'>%(url)s</a>"
|
||||
|
||||
#: app.py:449
|
||||
msgid "Unfortunately, login was denied."
|
||||
@@ -162,7 +162,7 @@ msgstr ""
|
||||
"probas automatizadas."
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -210,8 +210,7 @@ msgstr "Captura de pantalla de %(app)s"
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This app is only compatible with these specific architectures: %(archs)s"
|
||||
msgstr ""
|
||||
"Esta app só é compatible con estas arquitecturas específicas: %(archs)s"
|
||||
msgstr "Esta app só é compatible con estas arquitecturas específicas: %(archs)s"
|
||||
|
||||
#: templates/app.html:112
|
||||
#, python-format
|
||||
@@ -307,8 +306,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Creada con <i class='text-red-500 fa fa-heart-o' aria-label='love'></i> "
|
||||
"usando <a class='text-blue-800' href='https://flask.palletsprojects."
|
||||
"com'>Flask</a> e <a class='text-blue-800' href='https://tailwindcss."
|
||||
"com/'>TailwindCSS</a> - <a class='text-blue-800' href='https://github.com/"
|
||||
"com'>Flask</a> e <a class='text-blue-800' href='https://tailwindcss.com/"
|
||||
"'>TailwindCSS</a> - <a class='text-blue-800' href='https://github.com/"
|
||||
"YunoHost/apps/tree/master/store'><i class='fa fa-code fa-fw' aria-"
|
||||
"hidden='true'></i> Fonte</a>"
|
||||
|
||||
@@ -366,37 +365,21 @@ msgstr "Non atopas o que buscabas?"
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr "Mira na lista de desexos!"
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr "Aplicacións marcadas actualmente como estragadas"
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr "Estas son as apps que non superaron as nosas probas automatizadas."
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr "Aplicacións abandonadas"
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr "Estas son as apps que xa non teñen mantemento."
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
"Isto significa que a desenvolvedora non a vai actualizar. Recomendamos "
|
||||
"vivamente non instalala e aconsellamos ás usuarias a buscar unha alternativa."
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr "Tenda de Aplicacións"
|
||||
|
||||
#: templates/index.html:21
|
||||
msgid "Browse all applications"
|
||||
msgstr "Ver todas as aplicacións"
|
||||
msgstr "Ve todas as aplicacións"
|
||||
|
||||
#: templates/wishlist.html:3 templates/wishlist.html:8
|
||||
msgid "Application Wishlist"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: he <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: hi <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: hu <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:06+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: id <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: it <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ja <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: kab <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ko <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: lt <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: mk <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: nb_NO <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ne <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:07+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: nl <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: oc <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pl <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pt <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: pt_BR <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sk <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:08+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sl <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: sv <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: te <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: tr <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:09+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: uk <LL@li.org>\n"
|
||||
@@ -140,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -331,28 +331,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-03-05 19:36+0100\n"
|
||||
"POT-Creation-Date: 2024-02-27 19:41+0100\n"
|
||||
"PO-Revision-Date: 2024-02-21 06:05+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: zh_Hans <LL@li.org>\n"
|
||||
@@ -139,7 +139,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/app.html:30 templates/app.html:31 templates/catalog.html:41
|
||||
#: templates/catalog.html:42 templates/catalog.html:170
|
||||
#: templates/catalog.html:42 templates/catalog.html:169
|
||||
msgid ""
|
||||
"This is usually a temporary situation which requires packagers to fix "
|
||||
"something in the app."
|
||||
@@ -330,28 +330,14 @@ msgstr ""
|
||||
msgid "Checkout the wishlist!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:166
|
||||
#: templates/catalog.html:165
|
||||
msgid "Applications currently flagged as broken"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:169
|
||||
#: templates/catalog.html:168
|
||||
msgid "These are apps which failed our automatic tests."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:184
|
||||
msgid "Deprecated applications"
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:187
|
||||
msgid "These are apps who are not maintained anymore."
|
||||
msgstr ""
|
||||
|
||||
#: templates/catalog.html:188
|
||||
msgid ""
|
||||
"This means that the developer will no longer update them. We strongly "
|
||||
"advise against their installation and advise users to find alternatives."
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html:10
|
||||
msgid "Application Store"
|
||||
msgstr ""
|
||||
|
||||
@@ -93,7 +93,6 @@ def get_stars():
|
||||
get_stars.cache_checksum = None
|
||||
get_stars()
|
||||
|
||||
|
||||
def check_wishlist_submit_ratelimit(user):
|
||||
|
||||
dir_ = os.path.join(".wishlist_ratelimit")
|
||||
@@ -102,10 +101,7 @@ def check_wishlist_submit_ratelimit(user):
|
||||
|
||||
f = os.path.join(dir_, md5(user.encode()).hexdigest())
|
||||
|
||||
return not os.path.exists(f) or (time.time() - os.path.getmtime(f)) > (
|
||||
15 * 24 * 3600
|
||||
) # 15 days
|
||||
|
||||
return not os.path.exists(f) or (time.time() - os.path.getmtime(f)) > (15 * 24 * 3600) # 15 days
|
||||
|
||||
def save_wishlist_submit_for_ratelimit(user):
|
||||
|
||||
@@ -182,9 +178,9 @@ def get_app_md_and_screenshots(app_folder, infos):
|
||||
if entry.is_file() and ext in ("png", "jpg", "jpeg", "webp", "gif"):
|
||||
with open(entry.path, "rb") as img_file:
|
||||
data = base64.b64encode(img_file.read()).decode("utf-8")
|
||||
infos["screenshot"] = (
|
||||
f"data:image/{ext};charset=utf-8;base64,{data}"
|
||||
)
|
||||
infos[
|
||||
"screenshot"
|
||||
] = f"data:image/{ext};charset=utf-8;base64,{data}"
|
||||
break
|
||||
|
||||
ram_build_requirement = infos["manifest"]["integration"]["ram"]["build"]
|
||||
|
||||
@@ -9,11 +9,8 @@ from typing import Any
|
||||
|
||||
import tqdm
|
||||
|
||||
from appslib.utils import (
|
||||
REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_catalog,
|
||||
git_repo_age,
|
||||
)
|
||||
from appslib.utils import (REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_catalog, git_repo_age)
|
||||
from git import Repo
|
||||
|
||||
|
||||
@@ -34,8 +31,7 @@ def app_cache_clone(app: str, infos: dict[str, str]) -> None:
|
||||
infos["url"],
|
||||
to_path=app_cache_folder(app),
|
||||
depth=git_depths.get(infos["state"], git_depths["default"]),
|
||||
single_branch=True,
|
||||
branch=infos.get("branch", "master"),
|
||||
single_branch=True, branch=infos.get("branch", "master"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -23,14 +23,10 @@ def git(cmd: list[str], cwd: Optional[Path] = None) -> str:
|
||||
if cwd:
|
||||
full_cmd.extend(["-C", str(cwd)])
|
||||
full_cmd.extend(cmd)
|
||||
return (
|
||||
subprocess.check_output(
|
||||
full_cmd,
|
||||
# env=my_env,
|
||||
)
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
return subprocess.check_output(
|
||||
full_cmd,
|
||||
# env=my_env,
|
||||
).strip().decode("utf-8")
|
||||
|
||||
|
||||
def git_repo_age(path: Path) -> Union[bool, int]:
|
||||
@@ -46,8 +42,7 @@ def get_catalog(working_only: bool = False) -> dict[str, dict[str, Any]]:
|
||||
catalog = toml.load((REPO_APPS_ROOT / "apps.toml").open("r", encoding="utf-8"))
|
||||
if working_only:
|
||||
catalog = {
|
||||
app: infos
|
||||
for app, infos in catalog.items()
|
||||
app: infos for app, infos in catalog.items()
|
||||
if infos.get("state") != "notworking"
|
||||
}
|
||||
return catalog
|
||||
|
||||
@@ -7,9 +7,7 @@ import sys
|
||||
|
||||
import requests
|
||||
|
||||
catalog = requests.get(
|
||||
"https://raw.githubusercontent.com/YunoHost/apps/master/apps.json"
|
||||
).json()
|
||||
catalog = requests.get("https://raw.githubusercontent.com/YunoHost/apps/master/apps.json").json()
|
||||
|
||||
my_env = os.environ.copy()
|
||||
my_env["GIT_TERMINAL_PROMPT"] = "0"
|
||||
@@ -46,19 +44,15 @@ def git(cmd, in_folder=None):
|
||||
def progressbar(it, prefix="", size=60, file=sys.stdout):
|
||||
it = list(it)
|
||||
count = len(it)
|
||||
|
||||
def show(j, name=""):
|
||||
name += " "
|
||||
x = int(size * j / count)
|
||||
file.write(
|
||||
"%s[%s%s] %i/%i %s\r" % (prefix, "#" * x, "." * (size - x), j, count, name)
|
||||
)
|
||||
x = int(size*j/count)
|
||||
file.write("%s[%s%s] %i/%i %s\r" % (prefix, "#"*x, "."*(size-x), j, count, name))
|
||||
file.flush()
|
||||
|
||||
show(0)
|
||||
for i, item in enumerate(it):
|
||||
yield item
|
||||
show(i + 1, item["id"])
|
||||
show(i+1, item["id"])
|
||||
file.write("\n")
|
||||
file.flush()
|
||||
|
||||
@@ -69,10 +63,7 @@ def build_cache():
|
||||
folder = os.path.join(".apps_cache", app["id"])
|
||||
reponame = app["url"].rsplit("/", 1)[-1]
|
||||
git(f"clone --quiet --depth 1 --single-branch {app['url']} {folder}")
|
||||
git(
|
||||
f"remote add fork https://{login}:{token}@github.com/{login}/{reponame}",
|
||||
in_folder=folder,
|
||||
)
|
||||
git(f"remote add fork https://{login}:{token}@github.com/{login}/{reponame}", in_folder=folder)
|
||||
|
||||
|
||||
def apply(patch):
|
||||
@@ -90,11 +81,7 @@ def diff():
|
||||
|
||||
for app in apps():
|
||||
folder = os.path.join(".apps_cache", app["id"])
|
||||
if bool(
|
||||
subprocess.check_output(f"cd {folder} && git diff", shell=True)
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
):
|
||||
if bool(subprocess.check_output(f"cd {folder} && git diff", shell=True).strip().decode("utf-8")):
|
||||
print("\n\n\n")
|
||||
print("=================================")
|
||||
print("Changes in : " + app["id"])
|
||||
@@ -105,50 +92,35 @@ def diff():
|
||||
|
||||
def push(patch):
|
||||
|
||||
title = (
|
||||
"[autopatch] "
|
||||
+ open(os.path.join("patches", patch, "pr_title.md")).read().strip()
|
||||
)
|
||||
title = "[autopatch] " + open(os.path.join("patches", patch, "pr_title.md")).read().strip()
|
||||
|
||||
def diff_not_empty(app):
|
||||
folder = os.path.join(".apps_cache", app["id"])
|
||||
return bool(
|
||||
subprocess.check_output(f"cd {folder} && git diff", shell=True)
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
return bool(subprocess.check_output(f"cd {folder} && git diff", shell=True).strip().decode("utf-8"))
|
||||
|
||||
def app_is_on_github(app):
|
||||
return "github.com" in app["url"]
|
||||
|
||||
apps_to_push = [
|
||||
app for app in apps() if diff_not_empty(app) and app_is_on_github(app)
|
||||
]
|
||||
apps_to_push = [app for app in apps() if diff_not_empty(app) and app_is_on_github(app)]
|
||||
|
||||
with requests.Session() as s:
|
||||
s.headers.update({"Authorization": f"token {token}"})
|
||||
for app in progressbar(apps_to_push, "Forking: ", 40):
|
||||
app["repo"] = app["url"][len("https://github.com/") :].strip("/")
|
||||
app["repo"] = app["url"][len("https://github.com/"):].strip("/")
|
||||
fork_if_needed(app["repo"], s)
|
||||
|
||||
for app in progressbar(apps_to_push, "Pushing: ", 40):
|
||||
app["repo"] = app["url"][len("https://github.com/") :].strip("/")
|
||||
app["repo"] = app["url"][len("https://github.com/"):].strip("/")
|
||||
app_repo_name = app["url"].rsplit("/", 1)[-1]
|
||||
folder = os.path.join(".apps_cache", app["id"])
|
||||
current_branch = git(f"symbolic-ref --short HEAD", in_folder=folder)
|
||||
git(f"reset origin/{current_branch}", in_folder=folder)
|
||||
git(
|
||||
["commit", "-a", "-m", title, "--author='Yunohost-Bot <>'"],
|
||||
in_folder=folder,
|
||||
)
|
||||
git(["commit", "-a", "-m", title, "--author='Yunohost-Bot <>'"], in_folder=folder)
|
||||
try:
|
||||
git(f"remote remove fork", in_folder=folder)
|
||||
except Exception:
|
||||
pass
|
||||
git(
|
||||
f"remote add fork https://{login}:{token}@github.com/{login}/{app_repo_name}",
|
||||
in_folder=folder,
|
||||
)
|
||||
git(f"remote add fork https://{login}:{token}@github.com/{login}/{app_repo_name}", in_folder=folder)
|
||||
git(f"push fork {current_branch}:{patch} --quiet --force", in_folder=folder)
|
||||
create_pull_request(app["repo"], patch, current_branch, s)
|
||||
|
||||
@@ -169,15 +141,11 @@ def fork_if_needed(repo, s):
|
||||
|
||||
def create_pull_request(repo, patch, base_branch, s):
|
||||
|
||||
PR = {
|
||||
"title": "[autopatch] "
|
||||
+ open(os.path.join("patches", patch, "pr_title.md")).read().strip(),
|
||||
"body": "This is an automatic PR\n\n"
|
||||
+ open(os.path.join("patches", patch, "pr_body.md")).read().strip(),
|
||||
"head": login + ":" + patch,
|
||||
"base": base_branch,
|
||||
"maintainer_can_modify": True,
|
||||
}
|
||||
PR = {"title": "[autopatch] " + open(os.path.join("patches", patch, "pr_title.md")).read().strip(),
|
||||
"body": "This is an automatic PR\n\n" + open(os.path.join("patches", patch, "pr_body.md")).read().strip(),
|
||||
"head": login + ":" + patch,
|
||||
"base": base_branch,
|
||||
"maintainer_can_modify": True}
|
||||
|
||||
r = s.post(github_api + f"/repos/{repo}/pulls", json.dumps(PR))
|
||||
|
||||
@@ -191,8 +159,7 @@ def main():
|
||||
|
||||
action = sys.argv[1]
|
||||
if action == "--help":
|
||||
print(
|
||||
"""
|
||||
print("""
|
||||
Example usage:
|
||||
|
||||
# Init local git clone for all apps
|
||||
@@ -206,8 +173,7 @@ def main():
|
||||
|
||||
# Push and create pull requests on all apps with non-empty diff
|
||||
./autopatch.py --push explicit-php-version-in-deps
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
elif action == "--build-cache":
|
||||
build_cache()
|
||||
|
||||
@@ -21,20 +21,10 @@ import github
|
||||
# add apps/tools to sys.path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from rest_api import (
|
||||
GithubAPI,
|
||||
GitlabAPI,
|
||||
GiteaForgejoAPI,
|
||||
RefType,
|
||||
) # noqa: E402,E501 pylint: disable=import-error,wrong-import-position
|
||||
from rest_api import GithubAPI, GitlabAPI, GiteaForgejoAPI, RefType # noqa: E402,E501 pylint: disable=import-error,wrong-import-position
|
||||
import appslib.logging_sender # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||
from appslib.utils import (
|
||||
REPO_APPS_ROOT,
|
||||
get_catalog,
|
||||
) # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||
from app_caches import (
|
||||
app_cache_folder,
|
||||
) # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||
from appslib.utils import REPO_APPS_ROOT, get_catalog # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||
from app_caches import app_cache_folder # noqa: E402 pylint: disable=import-error,wrong-import-position
|
||||
|
||||
|
||||
STRATEGIES = [
|
||||
@@ -54,30 +44,11 @@ STRATEGIES = [
|
||||
|
||||
|
||||
@cache
|
||||
def get_github() -> tuple[
|
||||
Optional[tuple[str, str]],
|
||||
Optional[github.Github],
|
||||
Optional[github.InputGitAuthor],
|
||||
]:
|
||||
def get_github() -> tuple[Optional[tuple[str, str]], Optional[github.Github], Optional[github.InputGitAuthor]]:
|
||||
try:
|
||||
github_login = (
|
||||
(REPO_APPS_ROOT / ".github_login")
|
||||
.open("r", encoding="utf-8")
|
||||
.read()
|
||||
.strip()
|
||||
)
|
||||
github_token = (
|
||||
(REPO_APPS_ROOT / ".github_token")
|
||||
.open("r", encoding="utf-8")
|
||||
.read()
|
||||
.strip()
|
||||
)
|
||||
github_email = (
|
||||
(REPO_APPS_ROOT / ".github_email")
|
||||
.open("r", encoding="utf-8")
|
||||
.read()
|
||||
.strip()
|
||||
)
|
||||
github_login = (REPO_APPS_ROOT / ".github_login").open("r", encoding="utf-8").read().strip()
|
||||
github_token = (REPO_APPS_ROOT / ".github_token").open("r", encoding="utf-8").read().strip()
|
||||
github_email = (REPO_APPS_ROOT / ".github_email").open("r", encoding="utf-8").read().strip()
|
||||
|
||||
auth = (github_login, github_token)
|
||||
github_api = github.Github(github_token)
|
||||
@@ -125,9 +96,7 @@ class LocalOrRemoteRepo:
|
||||
if not self.manifest_path.exists():
|
||||
raise RuntimeError(f"{app.name}: manifest.toml doesnt exists?")
|
||||
# app is in fact a path
|
||||
self.manifest_raw = (
|
||||
(app / "manifest.toml").open("r", encoding="utf-8").read()
|
||||
)
|
||||
self.manifest_raw = (app / "manifest.toml").open("r", encoding="utf-8").read()
|
||||
|
||||
elif isinstance(app, str):
|
||||
# It's remote
|
||||
@@ -218,9 +187,7 @@ class AppAutoUpdater:
|
||||
|
||||
self.main_upstream = self.manifest.get("upstream", {}).get("code")
|
||||
|
||||
def run(
|
||||
self, edit: bool = False, commit: bool = False, pr: bool = False
|
||||
) -> tuple[State, str, str, str]:
|
||||
def run(self, edit: bool = False, commit: bool = False, pr: bool = False) -> tuple[State, str, str, str]:
|
||||
state = State.up_to_date
|
||||
main_version = ""
|
||||
pr_url = ""
|
||||
@@ -245,11 +212,7 @@ class AppAutoUpdater:
|
||||
commit_msg += f"\n{msg}"
|
||||
|
||||
self.repo.manifest_raw = self.replace_version_and_asset_in_manifest(
|
||||
self.repo.manifest_raw,
|
||||
version,
|
||||
assets,
|
||||
infos,
|
||||
is_main=source == "main",
|
||||
self.repo.manifest_raw, version, assets, infos, is_main=source == "main",
|
||||
)
|
||||
|
||||
if state == State.up_to_date:
|
||||
@@ -283,9 +246,7 @@ class AppAutoUpdater:
|
||||
return (state, self.current_version, main_version, pr_url)
|
||||
|
||||
@staticmethod
|
||||
def relevant_versions(
|
||||
tags: list[str], app_id: str, version_regex: Optional[str]
|
||||
) -> tuple[str, str]:
|
||||
def relevant_versions(tags: list[str], app_id: str, version_regex: Optional[str]) -> tuple[str, str]:
|
||||
|
||||
def apply_version_regex(tag: str) -> Optional[str]:
|
||||
# First preprocessing according to the manifest version_regex…
|
||||
@@ -294,9 +255,7 @@ class AppAutoUpdater:
|
||||
if match is None:
|
||||
return None
|
||||
# Basically: either groupdict if named capture gorups, sorted by names, or groups()
|
||||
tag = ".".join(
|
||||
dict(sorted(match.groupdict().items())).values() or match.groups()
|
||||
)
|
||||
tag = ".".join(dict(sorted(match.groupdict().items())).values() or match.groups())
|
||||
|
||||
# Then remove leading v
|
||||
tag = tag.lstrip("v")
|
||||
@@ -305,9 +264,7 @@ class AppAutoUpdater:
|
||||
def version_numbers(tag: str) -> Optional[tuple[int, ...]]:
|
||||
filter_keywords = ["start", "rc", "beta", "alpha"]
|
||||
if any(keyword in tag for keyword in filter_keywords):
|
||||
logging.debug(
|
||||
f"Tag {tag} contains filtered keyword from {filter_keywords}."
|
||||
)
|
||||
logging.debug(f"Tag {tag} contains filtered keyword from {filter_keywords}.")
|
||||
return None
|
||||
|
||||
t_to_check = tag
|
||||
@@ -317,7 +274,7 @@ class AppAutoUpdater:
|
||||
elif tag.startswith("release-"):
|
||||
t_to_check = tag.split("-", 1)[-1].replace("-", ".")
|
||||
|
||||
if re.match(r"^v?\d+(\.\d+)*(\-\d+)?$", t_to_check):
|
||||
if re.match(r"^v?[\d\.]*\-?\d$", t_to_check):
|
||||
return AppAutoUpdater.tag_to_int_tuple(t_to_check)
|
||||
print(f"Ignoring tag {t_to_check}, doesn't look like a version number")
|
||||
return None
|
||||
@@ -343,11 +300,9 @@ class AppAutoUpdater:
|
||||
|
||||
@staticmethod
|
||||
def tag_to_int_tuple(tag: str) -> tuple[int, ...]:
|
||||
tag = tag.lstrip("v").replace("-", ".").rstrip(".")
|
||||
tag = tag.strip("v").replace("-", ".").strip(".")
|
||||
int_tuple = tag.split(".")
|
||||
assert all(
|
||||
i.isdigit() for i in int_tuple
|
||||
), f"Cant convert {tag} to int tuple :/"
|
||||
assert all(i.isdigit() for i in int_tuple), f"Cant convert {tag} to int tuple :/"
|
||||
return tuple(int(i) for i in int_tuple)
|
||||
|
||||
@staticmethod
|
||||
@@ -362,9 +317,8 @@ class AppAutoUpdater:
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to compute sha256 for {url} : {e}") from e
|
||||
|
||||
def get_source_update(
|
||||
self, name: str, infos: dict[str, Any]
|
||||
) -> Optional[tuple[str, Union[str, dict[str, str]], str]]:
|
||||
def get_source_update(self, name: str, infos: dict[str, Any]
|
||||
) -> Optional[tuple[str, Union[str, dict[str, str]], str]]:
|
||||
autoupdate = infos.get("autoupdate")
|
||||
if autoupdate is None:
|
||||
return None
|
||||
@@ -373,9 +327,7 @@ class AppAutoUpdater:
|
||||
asset = autoupdate.get("asset", "tarball")
|
||||
strategy = autoupdate.get("strategy")
|
||||
if strategy not in STRATEGIES:
|
||||
raise ValueError(
|
||||
f"Unknown update strategy '{strategy}' for '{name}', expected one of {STRATEGIES}"
|
||||
)
|
||||
raise ValueError(f"Unknown update strategy '{strategy}' for '{name}', expected one of {STRATEGIES}")
|
||||
|
||||
result = self.get_latest_version_and_asset(strategy, asset, autoupdate)
|
||||
if result is None:
|
||||
@@ -395,22 +347,14 @@ class AppAutoUpdater:
|
||||
print("Up to date")
|
||||
return None
|
||||
try:
|
||||
if self.tag_to_int_tuple(self.current_version) > self.tag_to_int_tuple(
|
||||
new_version
|
||||
):
|
||||
print(
|
||||
"Up to date (current version appears more recent than newest version found)"
|
||||
)
|
||||
if self.tag_to_int_tuple(self.current_version) > self.tag_to_int_tuple(new_version):
|
||||
print("Up to date (current version appears more recent than newest version found)")
|
||||
return None
|
||||
except (AssertionError, ValueError):
|
||||
pass
|
||||
|
||||
if (
|
||||
isinstance(assets, dict)
|
||||
and isinstance(infos.get("url"), str)
|
||||
or isinstance(assets, str)
|
||||
and not isinstance(infos.get("url"), str)
|
||||
):
|
||||
if isinstance(assets, dict) and isinstance(infos.get("url"), str) or \
|
||||
isinstance(assets, str) and not isinstance(infos.get("url"), str):
|
||||
raise RuntimeError(
|
||||
"It looks like there's an inconsistency between the old asset list and the new ones... "
|
||||
"One is arch-specific, the other is not... Did you forget to define arch-specific regexes? "
|
||||
@@ -420,9 +364,7 @@ class AppAutoUpdater:
|
||||
if isinstance(assets, str) and infos["url"] == assets:
|
||||
print(f"URL for asset {name} is up to date")
|
||||
return None
|
||||
if isinstance(assets, dict) and assets == {
|
||||
k: infos[k]["url"] for k in assets.keys()
|
||||
}:
|
||||
if isinstance(assets, dict) and assets == {k: infos[k]["url"] for k in assets.keys()}:
|
||||
print(f"URLs for asset {name} are up to date")
|
||||
return None
|
||||
print(f"Update needed for {name}")
|
||||
@@ -434,26 +376,21 @@ class AppAutoUpdater:
|
||||
name: url for name, url in assets.items() if re.match(regex, name)
|
||||
}
|
||||
if not matching_assets:
|
||||
raise RuntimeError(
|
||||
f"No assets matching regex '{regex}' in {list(assets.keys())}"
|
||||
)
|
||||
raise RuntimeError(f"No assets matching regex '{regex}' in {list(assets.keys())}")
|
||||
if len(matching_assets) > 1:
|
||||
raise RuntimeError(
|
||||
f"Too many assets matching regex '{regex}': {matching_assets}"
|
||||
)
|
||||
raise RuntimeError(f"Too many assets matching regex '{regex}': {matching_assets}")
|
||||
return next(iter(matching_assets.items()))
|
||||
|
||||
def get_latest_version_and_asset(
|
||||
self, strategy: str, asset: Union[str, dict], autoupdate
|
||||
) -> Optional[tuple[str, Union[str, dict[str, str]], str]]:
|
||||
def get_latest_version_and_asset(self, strategy: str, asset: Union[str, dict], autoupdate
|
||||
) -> Optional[tuple[str, Union[str, dict[str, str]], str]]:
|
||||
upstream = autoupdate.get("upstream", self.main_upstream).strip("/")
|
||||
version_re = autoupdate.get("version_regex", None)
|
||||
_, remote_type, revision_type = strategy.split("_")
|
||||
|
||||
api: Union[GithubAPI, GitlabAPI, GiteaForgejoAPI]
|
||||
if remote_type == "github":
|
||||
assert upstream and upstream.startswith(
|
||||
"https://github.com/"
|
||||
assert (
|
||||
upstream and upstream.startswith("https://github.com/")
|
||||
), f"When using strategy {strategy}, having a defined upstream code repo on github.com is required"
|
||||
api = GithubAPI(upstream, auth=get_github()[0])
|
||||
if remote_type == "gitlab":
|
||||
@@ -467,9 +404,7 @@ class AppAutoUpdater:
|
||||
for release in api.releases()
|
||||
if not release["draft"] and not release["prerelease"]
|
||||
}
|
||||
latest_version_orig, latest_version = self.relevant_versions(
|
||||
list(releases.keys()), self.app_id, version_re
|
||||
)
|
||||
latest_version_orig, latest_version = self.relevant_versions(list(releases.keys()), self.app_id, version_re)
|
||||
latest_release = releases[latest_version_orig]
|
||||
latest_assets = {
|
||||
a["name"]: a["browser_download_url"]
|
||||
@@ -490,9 +425,7 @@ class AppAutoUpdater:
|
||||
_, url = self.find_matching_asset(latest_assets, asset)
|
||||
return latest_version, url, latest_release_html_url
|
||||
except RuntimeError as e:
|
||||
raise RuntimeError(
|
||||
f"{e}.\nFull release details on {latest_release_html_url}."
|
||||
) from e
|
||||
raise RuntimeError(f"{e}.\nFull release details on {latest_release_html_url}.") from e
|
||||
|
||||
if isinstance(asset, dict):
|
||||
new_assets = {}
|
||||
@@ -501,50 +434,34 @@ class AppAutoUpdater:
|
||||
_, url = self.find_matching_asset(latest_assets, asset_regex)
|
||||
new_assets[asset_name] = url
|
||||
except RuntimeError as e:
|
||||
raise RuntimeError(
|
||||
f"{e}.\nFull release details on {latest_release_html_url}."
|
||||
) from e
|
||||
raise RuntimeError(f"{e}.\nFull release details on {latest_release_html_url}.") from e
|
||||
return latest_version, new_assets, latest_release_html_url
|
||||
|
||||
return None
|
||||
|
||||
if revision_type == "tag":
|
||||
if asset != "tarball":
|
||||
raise ValueError(
|
||||
"For the latest tag strategies, only asset = 'tarball' is supported"
|
||||
)
|
||||
raise ValueError("For the latest tag strategies, only asset = 'tarball' is supported")
|
||||
tags = [t["name"] for t in api.tags()]
|
||||
latest_version_orig, latest_version = self.relevant_versions(
|
||||
tags, self.app_id, version_re
|
||||
)
|
||||
latest_version_orig, latest_version = self.relevant_versions(tags, self.app_id, version_re)
|
||||
latest_tarball = api.url_for_ref(latest_version_orig, RefType.tags)
|
||||
return latest_version, latest_tarball, ""
|
||||
|
||||
if revision_type == "commit":
|
||||
if asset != "tarball":
|
||||
raise ValueError(
|
||||
"For the latest commit strategies, only asset = 'tarball' is supported"
|
||||
)
|
||||
raise ValueError("For the latest commit strategies, only asset = 'tarball' is supported")
|
||||
commits = api.commits()
|
||||
latest_commit = commits[0]
|
||||
latest_tarball = api.url_for_ref(latest_commit["sha"], RefType.commits)
|
||||
# Let's have the version as something like "2023.01.23"
|
||||
latest_commit_date = datetime.strptime(
|
||||
latest_commit["commit"]["author"]["date"][:10], "%Y-%m-%d"
|
||||
)
|
||||
latest_commit_date = datetime.strptime(latest_commit["commit"]["author"]["date"][:10], "%Y-%m-%d")
|
||||
version_format = autoupdate.get("force_version", "%Y.%m.%d")
|
||||
latest_version = latest_commit_date.strftime(version_format)
|
||||
return latest_version, latest_tarball, ""
|
||||
return None
|
||||
|
||||
def replace_version_and_asset_in_manifest(
|
||||
self,
|
||||
content: str,
|
||||
new_version: str,
|
||||
new_assets_urls: Union[str, dict],
|
||||
current_assets: dict,
|
||||
is_main: bool,
|
||||
):
|
||||
def replace_version_and_asset_in_manifest(self, content: str, new_version: str, new_assets_urls: Union[str, dict],
|
||||
current_assets: dict, is_main: bool):
|
||||
replacements = []
|
||||
if isinstance(new_assets_urls, str):
|
||||
replacements = [
|
||||
@@ -554,21 +471,16 @@ class AppAutoUpdater:
|
||||
if isinstance(new_assets_urls, dict):
|
||||
replacements = [
|
||||
repl
|
||||
for key, url in new_assets_urls.items()
|
||||
for repl in (
|
||||
for key, url in new_assets_urls.items() for repl in (
|
||||
(current_assets[key]["url"], url),
|
||||
(current_assets[key]["sha256"], self.sha256_of_remote_file(url)),
|
||||
(current_assets[key]["sha256"], self.sha256_of_remote_file(url))
|
||||
)
|
||||
]
|
||||
|
||||
if is_main:
|
||||
|
||||
def repl(m: re.Match) -> str:
|
||||
return m.group(1) + new_version + '~ynh1"'
|
||||
|
||||
content = re.sub(
|
||||
r"(\s*version\s*=\s*[\"\'])([^~\"\']+)(\~ynh\d+[\"\'])", repl, content
|
||||
)
|
||||
content = re.sub(r"(\s*version\s*=\s*[\"\'])([\d\.]+)(\~ynh\d+[\"\'])", repl, content)
|
||||
|
||||
for old, new in replacements:
|
||||
content = content.replace(old, new)
|
||||
@@ -626,41 +538,22 @@ def run_autoupdate_for_multiprocessing(data) -> tuple[str, tuple[State, str, str
|
||||
except Exception:
|
||||
log_str = stdoutswitch.reset()
|
||||
import traceback
|
||||
|
||||
t = traceback.format_exc()
|
||||
return (app, (State.failure, log_str, str(t), ""))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"apps",
|
||||
nargs="*",
|
||||
type=Path,
|
||||
help="If not passed, the script will run on the catalog. Github keys required.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--edit",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=True,
|
||||
help="Edit the local files",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--commit",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=False,
|
||||
help="Create a commit with the changes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pr",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=False,
|
||||
help="Create a pull request with the changes",
|
||||
)
|
||||
parser.add_argument("apps", nargs="*", type=Path,
|
||||
help="If not passed, the script will run on the catalog. Github keys required.")
|
||||
parser.add_argument("--edit", action=argparse.BooleanOptionalAction, default=True,
|
||||
help="Edit the local files")
|
||||
parser.add_argument("--commit", action=argparse.BooleanOptionalAction, default=False,
|
||||
help="Create a commit with the changes")
|
||||
parser.add_argument("--pr", action=argparse.BooleanOptionalAction, default=False,
|
||||
help="Create a pull request with the changes")
|
||||
parser.add_argument("--paste", action="store_true")
|
||||
parser.add_argument(
|
||||
"-j", "--processes", type=int, default=multiprocessing.cpu_count()
|
||||
)
|
||||
parser.add_argument("-j", "--processes", type=int, default=multiprocessing.cpu_count())
|
||||
args = parser.parse_args()
|
||||
|
||||
appslib.logging_sender.enable()
|
||||
@@ -679,10 +572,8 @@ def main() -> None:
|
||||
apps_failed = {}
|
||||
|
||||
with multiprocessing.Pool(processes=args.processes) as pool:
|
||||
tasks = pool.imap(
|
||||
run_autoupdate_for_multiprocessing,
|
||||
((app, args.edit, args.commit, args.pr) for app in apps),
|
||||
)
|
||||
tasks = pool.imap(run_autoupdate_for_multiprocessing,
|
||||
((app, args.edit, args.commit, args.pr) for app in apps))
|
||||
for app, result in tqdm.tqdm(tasks, total=len(apps), ascii=" ·#"):
|
||||
state, current_version, main_version, pr_url = result
|
||||
if state == State.up_to_date:
|
||||
@@ -701,9 +592,7 @@ def main() -> None:
|
||||
matrix_message += f"\n- {len(apps_already)} pending update PRs"
|
||||
for app, info in apps_already.items():
|
||||
paste_message += f"\n- {app}"
|
||||
paste_message += (
|
||||
f" ({info[0]} -> {info[1]})" if info[1] else " (app version did not change)"
|
||||
)
|
||||
paste_message += f" ({info[0]} -> {info[1]})" if info[1] else " (app version did not change)"
|
||||
if info[2]:
|
||||
paste_message += f" see {info[2]}"
|
||||
|
||||
@@ -712,9 +601,7 @@ def main() -> None:
|
||||
matrix_message += f"\n- {len(apps_updated)} new apps PRs"
|
||||
for app, info in apps_updated.items():
|
||||
paste_message += f"\n- {app}"
|
||||
paste_message += (
|
||||
f" ({info[0]} -> {info[1]})" if info[1] else " (app version did not change)"
|
||||
)
|
||||
paste_message += f" ({info[0]} -> {info[1]})" if info[1] else " (app version did not change)"
|
||||
if info[2]:
|
||||
paste_message += f" see {info[2]}"
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@ class RefType(Enum):
|
||||
class GithubAPI:
|
||||
def __init__(self, upstream: str, auth: Optional[tuple[str, str]] = None):
|
||||
self.upstream = upstream
|
||||
self.upstream_repo = upstream.replace("https://github.com/", "").strip("/")
|
||||
self.upstream_repo = upstream.replace("https://github.com/", "")\
|
||||
.strip("/")
|
||||
assert (
|
||||
len(self.upstream_repo.split("/")) == 2
|
||||
), f"'{upstream}' doesn't seem to be a github repository ?"
|
||||
len(self.upstream_repo.split("/")) == 2
|
||||
), f"'{upstream}' doesn't seem to be a github repository ?"
|
||||
self.auth = auth
|
||||
|
||||
def internal_api(self, uri: str) -> Any:
|
||||
@@ -73,12 +74,7 @@ class GitlabAPI:
|
||||
# Second chance for some buggy gitlab instances...
|
||||
name = self.project_path.split("/")[-1]
|
||||
projects = self.internal_api(f"projects?search={name}")
|
||||
project = next(
|
||||
filter(
|
||||
lambda x: x.get("path_with_namespace") == self.project_path,
|
||||
projects,
|
||||
)
|
||||
)
|
||||
project = next(filter(lambda x: x.get("path_with_namespace") == self.project_path, projects))
|
||||
|
||||
assert isinstance(project, dict)
|
||||
project_id = project.get("id", None)
|
||||
@@ -99,11 +95,13 @@ class GitlabAPI:
|
||||
return [
|
||||
{
|
||||
"sha": commit["id"],
|
||||
"commit": {"author": {"date": commit["committed_date"]}},
|
||||
"commit": {
|
||||
"author": {
|
||||
"date": commit["committed_date"]
|
||||
}
|
||||
}
|
||||
}
|
||||
for commit in self.internal_api(
|
||||
f"projects/{self.project_id}/repository/commits"
|
||||
)
|
||||
for commit in self.internal_api(f"projects/{self.project_id}/repository/commits")
|
||||
]
|
||||
|
||||
def releases(self) -> list[dict[str, Any]]:
|
||||
@@ -116,21 +114,16 @@ class GitlabAPI:
|
||||
"prerelease": False,
|
||||
"draft": False,
|
||||
"html_url": release["_links"]["self"],
|
||||
"assets": [
|
||||
{
|
||||
"name": asset["name"],
|
||||
"browser_download_url": asset["direct_asset_url"],
|
||||
}
|
||||
for asset in release["assets"]["links"]
|
||||
],
|
||||
}
|
||||
"assets": [{
|
||||
"name": asset["name"],
|
||||
"browser_download_url": asset["direct_asset_url"]
|
||||
} for asset in release["assets"]["links"]],
|
||||
}
|
||||
for source in release["assets"]["sources"]:
|
||||
r["assets"].append(
|
||||
{
|
||||
"name": f"source.{source['format']}",
|
||||
"browser_download_url": source["url"],
|
||||
}
|
||||
)
|
||||
r["assets"].append({
|
||||
"name": f"source.{source['format']}",
|
||||
"browser_download_url": source['url']
|
||||
})
|
||||
retval.append(r)
|
||||
|
||||
return retval
|
||||
|
||||
@@ -9,7 +9,6 @@ import urllib.request
|
||||
|
||||
import github
|
||||
from github import Github
|
||||
|
||||
# Debug
|
||||
from rich.traceback import install
|
||||
|
||||
@@ -25,25 +24,23 @@ install(width=150, show_locals=True, locals_max_length=None, locals_max_string=N
|
||||
g = Github(open(".github_token").read().strip())
|
||||
|
||||
# Path to the file to be updated
|
||||
path = ".github/workflows/updater.yml"
|
||||
path=".github/workflows/updater.yml"
|
||||
|
||||
# Title of the PR
|
||||
title = "[autopatch] Upgrade auto-updater"
|
||||
title="[autopatch] Upgrade auto-updater"
|
||||
|
||||
# Body of the PR message
|
||||
body = """
|
||||
body="""
|
||||
Auto-updater actions need upgrading to continue working:
|
||||
- actions/checkout@v3
|
||||
- peter-evans/create-pull-request@v4
|
||||
"""
|
||||
|
||||
# Author of the commit
|
||||
author = github.InputGitAuthor(
|
||||
open(".github_login").read().strip(), open(".github_email").read().strip()
|
||||
)
|
||||
author=github.InputGitAuthor(open(".github_login").read().strip(), open(".github_email").read().strip())
|
||||
|
||||
# Name of the branch created for the PR
|
||||
new_branch = "upgrade-auto-updater"
|
||||
new_branch="upgrade-auto-updater"
|
||||
|
||||
#####
|
||||
#
|
||||
@@ -51,7 +48,7 @@ new_branch = "upgrade-auto-updater"
|
||||
#
|
||||
#####
|
||||
|
||||
with open("processed.txt") as f:
|
||||
with open('processed.txt') as f:
|
||||
processed = f.read().splitlines()
|
||||
|
||||
#####
|
||||
@@ -64,7 +61,7 @@ u = g.get_user("yunohost-bot")
|
||||
org = g.get_organization("yunohost-apps")
|
||||
|
||||
# For each repositories belonging to the bot (user `u`)
|
||||
i = 0
|
||||
i=0
|
||||
for repo in org.get_repos():
|
||||
if repo.full_name not in processed:
|
||||
|
||||
@@ -76,64 +73,50 @@ for repo in org.get_repos():
|
||||
|
||||
# Make sure the repository has an auto-updater
|
||||
try:
|
||||
repo.get_contents(path, ref="refs/heads/" + base_branch)
|
||||
repo.get_contents(path, ref="refs/heads/"+base_branch)
|
||||
except:
|
||||
with open("processed.txt", "a") as pfile:
|
||||
pfile.write(repo.full_name + "\n")
|
||||
with open('processed.txt', 'a') as pfile:
|
||||
pfile.write(repo.full_name+'\n')
|
||||
time.sleep(1.5)
|
||||
continue
|
||||
|
||||
# Process the repo
|
||||
print("Processing " + repo.full_name)
|
||||
print("Processing "+repo.full_name)
|
||||
|
||||
try:
|
||||
# Get the commit base for the new branch, and create it
|
||||
commit_sha = repo.get_branch(base_branch).commit.sha
|
||||
new_branch_ref = repo.create_git_ref(
|
||||
ref="refs/heads/" + new_branch, sha=commit_sha
|
||||
)
|
||||
new_branch_ref = repo.create_git_ref(ref="refs/heads/"+new_branch, sha=commit_sha)
|
||||
except:
|
||||
new_branch_ref = repo.get_git_ref(ref="heads/" + new_branch)
|
||||
new_branch_ref = repo.get_git_ref(ref="heads/"+new_branch)
|
||||
|
||||
# Get current file contents
|
||||
contents = repo.get_contents(path, ref=new_branch_ref.ref)
|
||||
|
||||
# Update the file
|
||||
updater_yml = contents.decoded_content.decode("unicode_escape")
|
||||
updater_yml = re.sub(
|
||||
r"(?m)uses: actions/checkout@v[\d]+",
|
||||
"uses: actions/checkout@v3",
|
||||
updater_yml,
|
||||
)
|
||||
updater_yml = re.sub(
|
||||
r"(?m)uses: peter-evans/create-pull-request@v[\d]+",
|
||||
"uses: peter-evans/create-pull-request@v4",
|
||||
updater_yml,
|
||||
)
|
||||
updated = repo.update_file(
|
||||
contents.path,
|
||||
message=title,
|
||||
content=updater_yml,
|
||||
sha=contents.sha,
|
||||
branch=new_branch,
|
||||
author=author,
|
||||
)
|
||||
updater_yml = re.sub(r'(?m)uses: actions/checkout@v[\d]+', "uses: actions/checkout@v3", updater_yml)
|
||||
updater_yml = re.sub(r'(?m)uses: peter-evans/create-pull-request@v[\d]+', "uses: peter-evans/create-pull-request@v4", updater_yml)
|
||||
updated = repo.update_file(contents.path,
|
||||
message=title,
|
||||
content=updater_yml,
|
||||
sha=contents.sha,
|
||||
branch=new_branch,
|
||||
author=author)
|
||||
|
||||
# Wait a bit to preserve the API rate limit
|
||||
time.sleep(1.5)
|
||||
|
||||
# Open the PR
|
||||
pr = repo.create_pull(
|
||||
title="Upgrade auto-updater", body=body, head=new_branch, base=base_branch
|
||||
)
|
||||
pr = repo.create_pull(title="Upgrade auto-updater", body=body, head=new_branch, base=base_branch)
|
||||
|
||||
print(repo.full_name + " updated with PR #" + str(pr.id))
|
||||
i = i + 1
|
||||
print(repo.full_name+" updated with PR #"+ str(pr.id))
|
||||
i=i+1
|
||||
|
||||
# Wait a bit to preserve the API rate limit
|
||||
time.sleep(1.5)
|
||||
|
||||
with open("processed.txt", "a") as pfile:
|
||||
pfile.write(repo.full_name + "\n")
|
||||
with open('processed.txt', 'a') as pfile:
|
||||
pfile.write(repo.full_name+'\n')
|
||||
|
||||
print("Done. " + str(i) + " repos processed")
|
||||
print("Done. "+str(i)+" repos processed")
|
||||
|
||||
@@ -10,22 +10,17 @@ u = g.get_user("yunohost-bot")
|
||||
|
||||
# Let's build a minimalistic summary table
|
||||
print("| Repository ".ljust(22) + " | Decision |")
|
||||
print("| ".ljust(22, "-") + " | -------- |")
|
||||
print("| ".ljust(22, '-') + " | -------- |")
|
||||
|
||||
# For each repositories belonging to the bot (user `u`)
|
||||
for repo in u.get_repos():
|
||||
# Proceed iff the repository is a fork (`parent` key is set) of a repository in our apps organization
|
||||
if repo.parent.full_name.split("/")[0] != "YunoHost-Apps":
|
||||
print("| " + repo.name.ljust(20) + " | Skipping |")
|
||||
if repo.parent.full_name.split('/')[0] != "YunoHost-Apps":
|
||||
print("| "+repo.name.ljust(20) + " | Skipping |")
|
||||
else:
|
||||
# If none of the PRs are opened by the bot, delete the repository
|
||||
if not any(
|
||||
[
|
||||
(pr.user == u)
|
||||
for pr in list(repo.parent.get_pulls(state="open", sort="created"))
|
||||
]
|
||||
):
|
||||
print("| " + repo.name.ljust(20) + " | Deleting |")
|
||||
if not any([ (pr.user == u) for pr in list(repo.parent.get_pulls(state='open', sort='created')) ]):
|
||||
print("| "+repo.name.ljust(20) + " | Deleting |")
|
||||
repo.delete()
|
||||
else:
|
||||
print("| " + repo.name.ljust(20) + " | Keeping |")
|
||||
print("| "+repo.name.ljust(20) + " | Keeping |")
|
||||
|
||||
@@ -6,29 +6,20 @@ from difflib import SequenceMatcher
|
||||
from typing import Any, Dict, Generator, List, Tuple
|
||||
|
||||
import jsonschema
|
||||
from appslib.utils import (
|
||||
REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_antifeatures,
|
||||
get_catalog,
|
||||
get_categories,
|
||||
get_graveyard,
|
||||
get_wishlist,
|
||||
)
|
||||
from appslib.utils import (REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_antifeatures, get_catalog, get_categories,
|
||||
get_graveyard, get_wishlist)
|
||||
|
||||
|
||||
def validate_schema() -> Generator[str, None, None]:
|
||||
with open(
|
||||
REPO_APPS_ROOT / "schemas" / "apps.toml.schema.json", encoding="utf-8"
|
||||
) as file:
|
||||
with open(REPO_APPS_ROOT / "schemas" / "apps.toml.schema.json", encoding="utf-8") as file:
|
||||
apps_catalog_schema = json.load(file)
|
||||
validator = jsonschema.Draft202012Validator(apps_catalog_schema)
|
||||
for error in validator.iter_errors(get_catalog()):
|
||||
yield f"at .{'.'.join(error.path)}: {error.message}"
|
||||
|
||||
|
||||
def check_app(
|
||||
app: str, infos: Dict[str, Any]
|
||||
) -> Generator[Tuple[str, bool], None, None]:
|
||||
def check_app(app: str, infos: Dict[str, Any]) -> Generator[Tuple[str, bool], None, None]:
|
||||
if "state" not in infos:
|
||||
yield "state is missing", True
|
||||
return
|
||||
|
||||
@@ -21,15 +21,10 @@ from git import Repo
|
||||
import appslib.logging_sender # pylint: disable=import-error
|
||||
from app_caches import app_cache_folder # pylint: disable=import-error
|
||||
from app_caches import apps_cache_update_all # pylint: disable=import-error
|
||||
from appslib.utils import (
|
||||
REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_antifeatures,
|
||||
get_catalog,
|
||||
get_categories,
|
||||
)
|
||||
from packaging_v2.convert_v1_manifest_to_v2_for_catalog import (
|
||||
convert_v1_manifest_to_v2_for_catalog,
|
||||
) # pylint: disable=import-error
|
||||
from appslib.utils import (REPO_APPS_ROOT, # pylint: disable=import-error
|
||||
get_antifeatures, get_catalog, get_categories)
|
||||
from packaging_v2.convert_v1_manifest_to_v2_for_catalog import \
|
||||
convert_v1_manifest_to_v2_for_catalog # pylint: disable=import-error
|
||||
|
||||
now = time.time()
|
||||
|
||||
@@ -42,7 +37,7 @@ def categories_list():
|
||||
infos["id"] = category_id
|
||||
for subtag_id, subtag_infos in infos.get("subtags", {}).items():
|
||||
subtag_infos["id"] = subtag_id
|
||||
infos["subtags"] = list(infos.get("subtags", {}).values())
|
||||
infos["subtags"] = list(infos.get('subtags', {}).values())
|
||||
return list(new_categories.values())
|
||||
|
||||
|
||||
@@ -59,7 +54,6 @@ def antifeatures_list():
|
||||
# Actual list build management #
|
||||
################################
|
||||
|
||||
|
||||
def __build_app_dict(data) -> Optional[tuple[str, dict[str, Any]]]:
|
||||
name, info = data
|
||||
try:
|
||||
@@ -99,17 +93,13 @@ def write_catalog_v2(base_catalog, target_dir: Path) -> None:
|
||||
|
||||
target_file = target_dir / "apps.json"
|
||||
target_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
target_file.open("w", encoding="utf-8").write(
|
||||
json.dumps(full_catalog, sort_keys=True)
|
||||
)
|
||||
target_file.open("w", encoding="utf-8").write(json.dumps(full_catalog, sort_keys=True))
|
||||
|
||||
|
||||
def write_catalog_v3(base_catalog, target_dir: Path) -> None:
|
||||
result_dict_with_manifest_v2 = copy.deepcopy(base_catalog)
|
||||
for app in result_dict_with_manifest_v2.values():
|
||||
packaging_format = float(
|
||||
str(app["manifest"].get("packaging_format", "")).strip() or "0"
|
||||
)
|
||||
packaging_format = float(str(app["manifest"].get("packaging_format", "")).strip() or "0")
|
||||
if packaging_format < 2:
|
||||
app["manifest"] = convert_v1_manifest_to_v2_for_catalog(app["manifest"])
|
||||
|
||||
@@ -127,12 +117,7 @@ def write_catalog_v3(base_catalog, target_dir: Path) -> None:
|
||||
appid = appid.lower()
|
||||
logo_source = REPO_APPS_ROOT / "logos" / f"{appid}.png"
|
||||
if logo_source.exists():
|
||||
logo_hash = (
|
||||
subprocess.check_output(["sha256sum", logo_source])
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
.split()[0]
|
||||
)
|
||||
logo_hash = subprocess.check_output(["sha256sum", logo_source]).strip().decode("utf-8").split()[0]
|
||||
shutil.copyfile(logo_source, logos_dir / f"{logo_hash}.png")
|
||||
# FIXME: implement something to cleanup old logo stuf in the builds/.../logos/ folder somehow
|
||||
else:
|
||||
@@ -147,9 +132,7 @@ def write_catalog_v3(base_catalog, target_dir: Path) -> None:
|
||||
|
||||
target_file = target_dir / "apps.json"
|
||||
target_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
target_file.open("w", encoding="utf-8").write(
|
||||
json.dumps(full_catalog, sort_keys=True)
|
||||
)
|
||||
target_file.open("w", encoding="utf-8").write(json.dumps(full_catalog, sort_keys=True))
|
||||
|
||||
|
||||
def write_catalog_doc(base_catalog, target_dir: Path) -> None:
|
||||
@@ -177,13 +160,14 @@ def write_catalog_doc(base_catalog, target_dir: Path) -> None:
|
||||
for k, v in base_catalog.items()
|
||||
if v["state"] == "working"
|
||||
}
|
||||
full_catalog = {"apps": result_dict_doc, "categories": categories_list()}
|
||||
full_catalog = {
|
||||
"apps": result_dict_doc,
|
||||
"categories": categories_list()
|
||||
}
|
||||
|
||||
target_file = target_dir / "apps.json"
|
||||
target_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
target_file.open("w", encoding="utf-8").write(
|
||||
json.dumps(full_catalog, sort_keys=True)
|
||||
)
|
||||
target_file.open("w", encoding="utf-8").write(json.dumps(full_catalog, sort_keys=True))
|
||||
|
||||
|
||||
def build_app_dict(app, infos):
|
||||
@@ -193,38 +177,15 @@ def build_app_dict(app, infos):
|
||||
|
||||
repo = Repo(this_app_cache)
|
||||
|
||||
commits_in_apps_json = (
|
||||
Repo(REPO_APPS_ROOT)
|
||||
.git.log(
|
||||
"-S",
|
||||
f'"{app}"',
|
||||
"--first-parent",
|
||||
"--reverse",
|
||||
"--date=unix",
|
||||
"--format=%cd",
|
||||
"--",
|
||||
"apps.json",
|
||||
)
|
||||
.split("\n")
|
||||
)
|
||||
commits_in_apps_json = Repo(REPO_APPS_ROOT).git.log(
|
||||
"-S", f"\"{app}\"", "--first-parent", "--reverse", "--date=unix",
|
||||
"--format=%cd", "--", "apps.json").split("\n")
|
||||
if len(commits_in_apps_json) > 1:
|
||||
first_commit = commits_in_apps_json[0]
|
||||
else:
|
||||
commits_in_apps_toml = (
|
||||
Repo(REPO_APPS_ROOT)
|
||||
.git.log(
|
||||
"-S",
|
||||
f"[{app}]",
|
||||
"--first-parent",
|
||||
"--reverse",
|
||||
"--date=unix",
|
||||
"--format=%cd",
|
||||
"--",
|
||||
"apps.json",
|
||||
"apps.toml",
|
||||
)
|
||||
.split("\n")
|
||||
)
|
||||
commits_in_apps_toml = Repo(REPO_APPS_ROOT).git.log(
|
||||
"-S", f"[{app}]", "--first-parent", "--reverse", "--date=unix",
|
||||
"--format=%cd", "--", "apps.json", "apps.toml").split("\n")
|
||||
first_commit = commits_in_apps_toml[0]
|
||||
|
||||
# Assume the first entry we get (= the oldest) is the time the app was added
|
||||
@@ -243,18 +204,14 @@ def build_app_dict(app, infos):
|
||||
try:
|
||||
_ = repo.commit(infos["revision"])
|
||||
except ValueError as err:
|
||||
raise RuntimeError(
|
||||
f"Revision ain't in history ? {infos['revision']}"
|
||||
) from err
|
||||
raise RuntimeError(f"Revision ain't in history ? {infos['revision']}") from err
|
||||
|
||||
# Find timestamp corresponding to that commit
|
||||
timestamp = repo.commit(infos["revision"]).committed_date
|
||||
|
||||
# Build the dict with all the infos
|
||||
if (this_app_cache / "manifest.toml").exists():
|
||||
manifest = toml.load(
|
||||
(this_app_cache / "manifest.toml").open("r"), _dict=OrderedDict
|
||||
)
|
||||
manifest = toml.load((this_app_cache / "manifest.toml").open("r"), _dict=OrderedDict)
|
||||
else:
|
||||
manifest = json.load((this_app_cache / "manifest.json").open("r"))
|
||||
|
||||
@@ -270,45 +227,27 @@ def build_app_dict(app, infos):
|
||||
"manifest": manifest,
|
||||
"state": infos["state"],
|
||||
"level": infos.get("level", "?"),
|
||||
"maintained": "package-not-maintained" not in infos.get("antifeatures", []),
|
||||
"maintained": 'package-not-maintained' not in infos.get('antifeatures', []),
|
||||
"high_quality": infos.get("high_quality", False),
|
||||
"featured": infos.get("featured", False),
|
||||
"category": infos.get("category", None),
|
||||
"subtags": infos.get("subtags", []),
|
||||
"potential_alternative_to": infos.get("potential_alternative_to", []),
|
||||
"antifeatures": list(
|
||||
set(
|
||||
list(manifest.get("antifeatures", {}).keys())
|
||||
+ infos.get("antifeatures", [])
|
||||
)
|
||||
set(list(manifest.get("antifeatures", {}).keys()) + infos.get("antifeatures", []))
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"target_dir",
|
||||
type=Path,
|
||||
nargs="?",
|
||||
default=REPO_APPS_ROOT / "builds" / "default",
|
||||
help="The directory to write the catalogs to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
type=int,
|
||||
default=multiprocessing.cpu_count(),
|
||||
metavar="N",
|
||||
help="Allow N threads to run in parallel",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--update-cache",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
default=True,
|
||||
help="Update the apps cache",
|
||||
)
|
||||
parser.add_argument("target_dir", type=Path, nargs="?",
|
||||
default=REPO_APPS_ROOT / "builds" / "default",
|
||||
help="The directory to write the catalogs to")
|
||||
parser.add_argument("-j", "--jobs", type=int, default=multiprocessing.cpu_count(), metavar="N",
|
||||
help="Allow N threads to run in parallel")
|
||||
parser.add_argument("-c", "--update-cache", action=argparse.BooleanOptionalAction, default=True,
|
||||
help="Update the apps cache")
|
||||
args = parser.parse_args()
|
||||
|
||||
appslib.logging_sender.enable()
|
||||
|
||||
@@ -9,7 +9,11 @@ from glob import glob
|
||||
|
||||
|
||||
def check_output(cmd):
|
||||
return subprocess.check_output(cmd, shell=True).decode("utf-8").strip()
|
||||
return (
|
||||
subprocess.check_output(cmd, shell=True)
|
||||
.decode("utf-8")
|
||||
.strip()
|
||||
)
|
||||
|
||||
|
||||
def convert_app_sources(folder):
|
||||
@@ -31,13 +35,7 @@ def convert_app_sources(folder):
|
||||
"sha256": D["sum"],
|
||||
}
|
||||
|
||||
if D.get("format", "tar.gz") not in [
|
||||
"zip",
|
||||
"tar.gz",
|
||||
"tar.xz",
|
||||
"tgz",
|
||||
"tar.bz2",
|
||||
]:
|
||||
if D.get("format", "tar.gz") not in ["zip", "tar.gz", "tar.xz", "tgz", "tar.bz2"]:
|
||||
new_D["format"] = D["format"]
|
||||
if "filename" in D:
|
||||
new_D["rename"] = D["filename"]
|
||||
@@ -117,12 +115,12 @@ def _convert_v1_manifest_to_v2(app_path):
|
||||
"sso": "?",
|
||||
"disk": "50M",
|
||||
"ram.build": "50M",
|
||||
"ram.runtime": "50M",
|
||||
"ram.runtime": "50M"
|
||||
}
|
||||
|
||||
maintainers = manifest.get("maintainer", {})
|
||||
if isinstance(maintainers, list):
|
||||
maintainers = [m["name"] for m in maintainers]
|
||||
maintainers = [m['name'] for m in maintainers]
|
||||
else:
|
||||
maintainers = [maintainers["name"]] if maintainers.get("name") else []
|
||||
|
||||
@@ -132,30 +130,15 @@ def _convert_v1_manifest_to_v2(app_path):
|
||||
manifest["install"] = {}
|
||||
for question in install_questions:
|
||||
name = question.pop("name")
|
||||
if "ask" in question and name in [
|
||||
"domain",
|
||||
"path",
|
||||
"admin",
|
||||
"is_public",
|
||||
"password",
|
||||
]:
|
||||
if "ask" in question and name in ["domain", "path", "admin", "is_public", "password"]:
|
||||
question.pop("ask")
|
||||
if question.get("example") and question.get("type") in [
|
||||
"domain",
|
||||
"path",
|
||||
"user",
|
||||
"boolean",
|
||||
"password",
|
||||
]:
|
||||
if question.get("example") and question.get("type") in ["domain", "path", "user", "boolean", "password"]:
|
||||
question.pop("example")
|
||||
|
||||
manifest["install"][name] = question
|
||||
|
||||
# Rename is_public to init_main_permission
|
||||
manifest["install"] = {
|
||||
(k if k != "is_public" else "init_main_permission"): v
|
||||
for k, v in manifest["install"].items()
|
||||
}
|
||||
manifest["install"] = {(k if k != "is_public" else "init_main_permission"): v for k, v in manifest["install"].items()}
|
||||
|
||||
if "init_main_permission" in manifest["install"]:
|
||||
manifest["install"]["init_main_permission"]["type"] = "group"
|
||||
@@ -183,16 +166,12 @@ def _convert_v1_manifest_to_v2(app_path):
|
||||
|
||||
# FIXME: Parse ynh_permission_create --permission="admin" --url="/wp-login.php" --additional_urls="/wp-admin.php" --allowed=$admin_wordpress
|
||||
|
||||
ports = check_output(
|
||||
f"sed -nr 's/(\\w+)=.*ynh_find_port[^0-9]*([0-9]+)\\)/\\1,\\2/p' '{app_path}/scripts/install'"
|
||||
)
|
||||
ports = check_output(f"sed -nr 's/(\\w+)=.*ynh_find_port[^0-9]*([0-9]+)\\)/\\1,\\2/p' '{app_path}/scripts/install'")
|
||||
if ports:
|
||||
manifest["resources"]["ports"] = {}
|
||||
for port in ports.split("\n"):
|
||||
name, default = port.split(",")
|
||||
exposed = check_output(
|
||||
f"sed -nr 's/.*yunohost firewall allow .*(TCP|UDP|Both).*${name}/\\1/p' '{app_path}/scripts/install'"
|
||||
)
|
||||
exposed = check_output(f"sed -nr 's/.*yunohost firewall allow .*(TCP|UDP|Both).*${name}/\\1/p' '{app_path}/scripts/install'")
|
||||
if exposed == "Both":
|
||||
exposed = True
|
||||
|
||||
@@ -201,9 +180,7 @@ def _convert_v1_manifest_to_v2(app_path):
|
||||
name = "main"
|
||||
|
||||
if not default.isdigit():
|
||||
print(
|
||||
f"Failed to parse '{default}' as a port number ... Will use 12345 instead"
|
||||
)
|
||||
print(f"Failed to parse '{default}' as a port number ... Will use 12345 instead")
|
||||
default = 12345
|
||||
|
||||
manifest["resources"]["ports"][f"{name}.default"] = int(default)
|
||||
@@ -211,57 +188,35 @@ def _convert_v1_manifest_to_v2(app_path):
|
||||
manifest["resources"]["ports"][f"{name}.exposed"] = exposed
|
||||
|
||||
maybequote = "[\"'\"'\"']?"
|
||||
apt_dependencies = check_output(
|
||||
f"sed -nr 's/.*_dependencies={maybequote}(.*){maybequote}? *$/\\1/p' '{app_path}/scripts/_common.sh' 2>/dev/null | tr -d '\"' | sed 's@ @\\n@g'"
|
||||
)
|
||||
php_version = check_output(
|
||||
f"sed -nr 's/^ *YNH_PHP_VERSION={maybequote}(.*){maybequote}?$/\\1/p' '{app_path}/scripts/_common.sh' 2>/dev/null | tr -d \"\\\"'\""
|
||||
)
|
||||
apt_dependencies = check_output(f"sed -nr 's/.*_dependencies={maybequote}(.*){maybequote}? *$/\\1/p' '{app_path}/scripts/_common.sh' 2>/dev/null | tr -d '\"' | sed 's@ @\\n@g'")
|
||||
php_version = check_output(f"sed -nr 's/^ *YNH_PHP_VERSION={maybequote}(.*){maybequote}?$/\\1/p' '{app_path}/scripts/_common.sh' 2>/dev/null | tr -d \"\\\"'\"")
|
||||
if apt_dependencies.strip():
|
||||
if php_version:
|
||||
apt_dependencies = apt_dependencies.replace(
|
||||
"${YNH_PHP_VERSION}", php_version
|
||||
)
|
||||
apt_dependencies = ", ".join([d for d in apt_dependencies.split("\n") if d])
|
||||
apt_dependencies = apt_dependencies.replace("${YNH_PHP_VERSION}", php_version)
|
||||
apt_dependencies = ', '.join([d for d in apt_dependencies.split("\n") if d])
|
||||
manifest["resources"]["apt"] = {"packages": apt_dependencies}
|
||||
|
||||
extra_apt_repos = check_output(
|
||||
r"sed -nr 's/.*_extra_app_dependencies.*repo=\"(.*)\".*package=\"(.*)\".*key=\"(.*)\"/\1,\2,\3/p' %s/scripts/install"
|
||||
% app_path
|
||||
)
|
||||
extra_apt_repos = check_output(r"sed -nr 's/.*_extra_app_dependencies.*repo=\"(.*)\".*package=\"(.*)\".*key=\"(.*)\"/\1,\2,\3/p' %s/scripts/install" % app_path)
|
||||
if extra_apt_repos:
|
||||
for i, extra_apt_repo in enumerate(extra_apt_repos.split("\n")):
|
||||
repo, packages, key = extra_apt_repo.split(",")
|
||||
packages = packages.replace("$", "#FIXME#$")
|
||||
packages = packages.replace('$', '#FIXME#$')
|
||||
if "apt" not in manifest["resources"]:
|
||||
manifest["resources"]["apt"] = {}
|
||||
if "extras" not in manifest["resources"]["apt"]:
|
||||
manifest["resources"]["apt"]["extras"] = []
|
||||
manifest["resources"]["apt"]["extras"].append(
|
||||
{
|
||||
"repo": repo,
|
||||
"key": key,
|
||||
"packages": packages,
|
||||
}
|
||||
)
|
||||
manifest["resources"]["apt"]["extras"].append({
|
||||
"repo": repo,
|
||||
"key": key,
|
||||
"packages": packages,
|
||||
})
|
||||
|
||||
if os.system(f"grep -q 'ynh_mysql_setup_db' {app_path}/scripts/install") == 0:
|
||||
manifest["resources"]["database"] = {"type": "mysql"}
|
||||
elif os.system(f"grep -q 'ynh_psql_setup_db' {app_path}/scripts/install") == 0:
|
||||
manifest["resources"]["database"] = {"type": "postgresql"}
|
||||
|
||||
keys_to_keep = [
|
||||
"packaging_format",
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"version",
|
||||
"maintainers",
|
||||
"upstream",
|
||||
"integration",
|
||||
"install",
|
||||
"resources",
|
||||
]
|
||||
keys_to_keep = ["packaging_format", "id", "name", "description", "version", "maintainers", "upstream", "integration", "install", "resources"]
|
||||
|
||||
keys_to_del = [key for key in manifest.keys() if key not in keys_to_keep]
|
||||
for key in keys_to_del:
|
||||
@@ -291,35 +246,19 @@ def _dump_v2_manifest_as_toml(manifest):
|
||||
upstream = table()
|
||||
for key, value in manifest["upstream"].items():
|
||||
upstream[key] = value
|
||||
upstream["cpe"].comment(
|
||||
"FIXME: optional but recommended if relevant, this is meant to contain the Common Platform Enumeration, which is sort of a standard id for applications defined by the NIST. In particular, Yunohost may use this is in the future to easily track CVE (=security reports) related to apps. The CPE may be obtained by searching here: https://nvd.nist.gov/products/cpe/search. For example, for Nextcloud, the CPE is 'cpe:2.3:a:nextcloud:nextcloud' (no need to include the version number)"
|
||||
)
|
||||
upstream["fund"].comment(
|
||||
"FIXME: optional but recommended (or remove if irrelevant / not applicable). This is meant to be an URL where people can financially support this app, especially when its development is based on volunteers and/or financed by its community. YunoHost may later advertise it in the webadmin."
|
||||
)
|
||||
upstream["cpe"].comment("FIXME: optional but recommended if relevant, this is meant to contain the Common Platform Enumeration, which is sort of a standard id for applications defined by the NIST. In particular, Yunohost may use this is in the future to easily track CVE (=security reports) related to apps. The CPE may be obtained by searching here: https://nvd.nist.gov/products/cpe/search. For example, for Nextcloud, the CPE is 'cpe:2.3:a:nextcloud:nextcloud' (no need to include the version number)")
|
||||
upstream["fund"].comment("FIXME: optional but recommended (or remove if irrelevant / not applicable). This is meant to be an URL where people can financially support this app, especially when its development is based on volunteers and/or financed by its community. YunoHost may later advertise it in the webadmin.")
|
||||
toml_manifest["upstream"] = upstream
|
||||
|
||||
integration = table()
|
||||
for key, value in manifest["integration"].items():
|
||||
integration.add(key, value)
|
||||
integration["architectures"].comment(
|
||||
'FIXME: can be replaced by a list of supported archs using the dpkg --print-architecture nomenclature (amd64/i386/armhf/arm64), for example: ["amd64", "i386"]'
|
||||
)
|
||||
integration["ldap"].comment(
|
||||
'FIXME: replace with true, false, or "not_relevant". Not to confuse with the "sso" key : the "ldap" key corresponds to wether or not a user *can* login on the app using its YunoHost credentials.'
|
||||
)
|
||||
integration["sso"].comment(
|
||||
'FIXME: replace with true, false, or "not_relevant". Not to confuse with the "ldap" key : the "sso" key corresponds to wether or not a user is *automatically logged-in* on the app when logged-in on the YunoHost portal.'
|
||||
)
|
||||
integration["disk"].comment(
|
||||
"FIXME: replace with an **estimate** minimum disk requirement. e.g. 20M, 400M, 1G, ..."
|
||||
)
|
||||
integration["ram.build"].comment(
|
||||
"FIXME: replace with an **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ..."
|
||||
)
|
||||
integration["ram.runtime"].comment(
|
||||
"FIXME: replace with an **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ..."
|
||||
)
|
||||
integration["architectures"].comment('FIXME: can be replaced by a list of supported archs using the dpkg --print-architecture nomenclature (amd64/i386/armhf/arm64), for example: ["amd64", "i386"]')
|
||||
integration["ldap"].comment('FIXME: replace with true, false, or "not_relevant". Not to confuse with the "sso" key : the "ldap" key corresponds to wether or not a user *can* login on the app using its YunoHost credentials.')
|
||||
integration["sso"].comment('FIXME: replace with true, false, or "not_relevant". Not to confuse with the "ldap" key : the "sso" key corresponds to wether or not a user is *automatically logged-in* on the app when logged-in on the YunoHost portal.')
|
||||
integration["disk"].comment('FIXME: replace with an **estimate** minimum disk requirement. e.g. 20M, 400M, 1G, ...')
|
||||
integration["ram.build"].comment('FIXME: replace with an **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...')
|
||||
integration["ram.runtime"].comment('FIXME: replace with an **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...')
|
||||
toml_manifest["integration"] = integration
|
||||
|
||||
install = table()
|
||||
@@ -328,11 +267,7 @@ def _dump_v2_manifest_as_toml(manifest):
|
||||
install[key].indent(4)
|
||||
|
||||
if key in ["domain", "path", "admin", "is_public", "password"]:
|
||||
install[key].add(
|
||||
comment(
|
||||
"this is a generic question - ask strings are automatically handled by Yunohost's core"
|
||||
)
|
||||
)
|
||||
install[key].add(comment("this is a generic question - ask strings are automatically handled by Yunohost's core"))
|
||||
|
||||
for lang, value2 in value.get("ask", {}).items():
|
||||
install[key].add(f"ask.{lang}", value2)
|
||||
@@ -370,8 +305,8 @@ def _dump_v2_manifest_as_toml(manifest):
|
||||
|
||||
toml_manifest_dump = dumps(toml_manifest)
|
||||
|
||||
regex = re.compile(r"\"((description|ask|help)\.[a-z]{2})\"")
|
||||
toml_manifest_dump = regex.sub(r"\1", toml_manifest_dump)
|
||||
regex = re.compile(r'\"((description|ask|help)\.[a-z]{2})\"')
|
||||
toml_manifest_dump = regex.sub(r'\1', toml_manifest_dump)
|
||||
toml_manifest_dump = toml_manifest_dump.replace('"ram.build"', "ram.build")
|
||||
toml_manifest_dump = toml_manifest_dump.replace('"ram.runtime"', "ram.runtime")
|
||||
toml_manifest_dump = toml_manifest_dump.replace('"main.url"', "main.url")
|
||||
@@ -389,9 +324,7 @@ def _dump_v2_manifest_as_toml(manifest):
|
||||
|
||||
if "ports" in manifest["resources"]:
|
||||
for port_thing in manifest["resources"]["ports"].keys():
|
||||
toml_manifest_dump = toml_manifest_dump.replace(
|
||||
f'"{port_thing}"', f"{port_thing}"
|
||||
)
|
||||
toml_manifest_dump = toml_manifest_dump.replace(f'"{port_thing}"', f"{port_thing}")
|
||||
|
||||
return toml_manifest_dump
|
||||
|
||||
@@ -462,9 +395,7 @@ def cleanup_scripts_and_conf(folder):
|
||||
"^.*ynh_script_progression.*Reloading NGINX web server",
|
||||
"^.*ynh_systemd_action --service_name=nginx --action=reload",
|
||||
]
|
||||
patterns_to_remove_in_scripts = [
|
||||
re.compile(f"({p})", re.MULTILINE) for p in patterns_to_remove_in_scripts
|
||||
]
|
||||
patterns_to_remove_in_scripts = [re.compile(f"({p})", re.MULTILINE) for p in patterns_to_remove_in_scripts]
|
||||
|
||||
replaces = [
|
||||
("path_url", "path"),
|
||||
@@ -473,21 +404,13 @@ def cleanup_scripts_and_conf(folder):
|
||||
("FINALPATH", "INSTALL_DIR"),
|
||||
("datadir", "data_dir"),
|
||||
("DATADIR", "DATA_DIR"),
|
||||
('--source_id="$architecture"', ""),
|
||||
('--source_id="$YNH_ARCH"', ""),
|
||||
("--source_id=app", ""),
|
||||
('--source_id="app.$architecture"', ""),
|
||||
('--source_id="$architecture"', ''),
|
||||
('--source_id="$YNH_ARCH"', ''),
|
||||
('--source_id=app', ''),
|
||||
('--source_id="app.$architecture"', ''),
|
||||
]
|
||||
|
||||
for s in [
|
||||
"_common.sh",
|
||||
"install",
|
||||
"remove",
|
||||
"upgrade",
|
||||
"backup",
|
||||
"restore",
|
||||
"change_url",
|
||||
]:
|
||||
for s in ["_common.sh", "install", "remove", "upgrade", "backup", "restore", "change_url"]:
|
||||
|
||||
script = f"{folder}/scripts/{s}"
|
||||
|
||||
@@ -497,18 +420,10 @@ def cleanup_scripts_and_conf(folder):
|
||||
content = open(script).read()
|
||||
|
||||
for pattern in patterns_to_remove_in_scripts:
|
||||
if (
|
||||
"^.*ynh_script_progression.*Reloading NGINX web server"
|
||||
in pattern.pattern
|
||||
and s == "restore"
|
||||
):
|
||||
if "^.*ynh_script_progression.*Reloading NGINX web server" in pattern.pattern and s == "restore":
|
||||
# This case is legit
|
||||
continue
|
||||
if (
|
||||
"^.*ynh_systemd_action --service_name=nginx --action=reload"
|
||||
in pattern.pattern
|
||||
and s == "restore"
|
||||
):
|
||||
if "^.*ynh_systemd_action --service_name=nginx --action=reload" in pattern.pattern and s == "restore":
|
||||
# This case is legit
|
||||
continue
|
||||
content = pattern.sub(r"#REMOVEME? \1", content)
|
||||
@@ -521,9 +436,7 @@ def cleanup_scripts_and_conf(folder):
|
||||
pattern = re.compile("(^.*nginx.*$)", re.MULTILINE)
|
||||
content = pattern.sub(r"#REMOVEME? \1", content)
|
||||
|
||||
pattern = re.compile(
|
||||
"(^.*ynh_script_progress.*Updat.* NGINX.*conf.*$)", re.MULTILINE
|
||||
)
|
||||
pattern = re.compile("(^.*ynh_script_progress.*Updat.* NGINX.*conf.*$)", re.MULTILINE)
|
||||
content = pattern.sub(r"\1\n\nynh_change_url_nginx_config", content)
|
||||
|
||||
pattern = re.compile(r"(ynh_clean_check_starting)", re.MULTILINE)
|
||||
@@ -533,6 +446,7 @@ def cleanup_scripts_and_conf(folder):
|
||||
pattern = re.compile(r"(^\s+path=.*$)", re.MULTILINE)
|
||||
content = pattern.sub(r"#REMOVEME? \1", content)
|
||||
|
||||
|
||||
open(script, "w").write(content)
|
||||
|
||||
for conf in os.listdir(f"{folder}/conf"):
|
||||
@@ -556,15 +470,15 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Attempt to automatically convert a v1 YunoHost app to v2 (at least as much as possible) : parse the app scripts to auto-generate the manifest.toml, and remove now-useless lines from the app scripts"
|
||||
)
|
||||
parser.add_argument("app_path", help="Path to the app to convert")
|
||||
parser.add_argument(
|
||||
"app_path", help="Path to the app to convert"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
manifest = _convert_v1_manifest_to_v2(args.app_path)
|
||||
with open(args.app_path + "/manifest.toml", "w") as manifest_file:
|
||||
manifest_file.write(
|
||||
"#:schema https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json\n\n"
|
||||
)
|
||||
manifest_file.write("#:schema https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json\n\n")
|
||||
manifest_file.write(_dump_v2_manifest_as_toml(manifest))
|
||||
|
||||
cleanup_scripts_and_conf(args.app_path)
|
||||
|
||||
@@ -17,22 +17,18 @@ def convert_v1_manifest_to_v2_for_catalog(manifest):
|
||||
manifest["upstream"]["website"] = manifest["url"]
|
||||
|
||||
manifest["integration"] = {
|
||||
"yunohost": manifest.get("requirements", {})
|
||||
.get("yunohost", "")
|
||||
.replace(">", "")
|
||||
.replace("=", "")
|
||||
.replace(" ", ""),
|
||||
"yunohost": manifest.get("requirements", {}).get("yunohost", "").replace(">", "").replace("=", "").replace(" ", ""),
|
||||
"architectures": "all",
|
||||
"multi_instance": manifest.get("multi_instance", False),
|
||||
"ldap": "?",
|
||||
"sso": "?",
|
||||
"disk": "50M",
|
||||
"ram": {"build": "50M", "runtime": "10M"},
|
||||
"ram": {"build": "50M", "runtime": "10M"}
|
||||
}
|
||||
|
||||
maintainers = manifest.get("maintainer", {})
|
||||
if isinstance(maintainers, list):
|
||||
maintainers = [m["name"] for m in maintainers]
|
||||
maintainers = [m['name'] for m in maintainers]
|
||||
else:
|
||||
maintainers = [maintainers["name"]] if maintainers.get("name") else []
|
||||
|
||||
@@ -43,39 +39,21 @@ def convert_v1_manifest_to_v2_for_catalog(manifest):
|
||||
manifest["install"] = {}
|
||||
for question in install_questions:
|
||||
name = question.pop("name")
|
||||
if "ask" in question and name in [
|
||||
"domain",
|
||||
"path",
|
||||
"admin",
|
||||
"is_public",
|
||||
"password",
|
||||
]:
|
||||
if "ask" in question and name in ["domain", "path", "admin", "is_public", "password"]:
|
||||
question.pop("ask")
|
||||
if question.get("example") and question.get("type") in [
|
||||
"domain",
|
||||
"path",
|
||||
"user",
|
||||
"boolean",
|
||||
"password",
|
||||
]:
|
||||
if question.get("example") and question.get("type") in ["domain", "path", "user", "boolean", "password"]:
|
||||
question.pop("example")
|
||||
|
||||
manifest["install"][name] = question
|
||||
|
||||
manifest["resources"] = {"system_user": {}, "install_dir": {"alias": "final_path"}}
|
||||
manifest["resources"] = {
|
||||
"system_user": {},
|
||||
"install_dir": {
|
||||
"alias": "final_path"
|
||||
}
|
||||
}
|
||||
|
||||
keys_to_keep = [
|
||||
"packaging_format",
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"version",
|
||||
"maintainers",
|
||||
"upstream",
|
||||
"integration",
|
||||
"install",
|
||||
"resources",
|
||||
]
|
||||
keys_to_keep = ["packaging_format", "id", "name", "description", "version", "maintainers", "upstream", "integration", "install", "resources"]
|
||||
|
||||
keys_to_del = [key for key in manifest.keys() if key not in keys_to_keep]
|
||||
for key in keys_to_del:
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# Auto-README generation
|
||||
|
||||
## Initial install
|
||||
### Initial install
|
||||
|
||||
```bash
|
||||
```
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Use on a single app
|
||||
### Use on a single app
|
||||
|
||||
```bash
|
||||
```
|
||||
source venv/bin/activate
|
||||
./make_readme.py /path/to/app
|
||||
```
|
||||
|
||||
Then the README.md in the app folder will be updated
|
||||
|
||||
## Launch webhook service for auto update
|
||||
### Launch webhook service for auto update
|
||||
|
||||
Configure the webhook on github
|
||||
|
||||
|
||||
@@ -4,26 +4,25 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from copy import deepcopy
|
||||
|
||||
from typing import Dict, Optional, List, Tuple
|
||||
|
||||
import toml
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
||||
def value_for_lang(values: Dict, lang: str):
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
if lang in values:
|
||||
return values[lang]
|
||||
elif "en" in values:
|
||||
return values["en"]
|
||||
else:
|
||||
return list(values.values())[0]
|
||||
def value_for_lang(values, lang):
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
if lang in values:
|
||||
return values[lang]
|
||||
elif "en" in values:
|
||||
return values["en"]
|
||||
else:
|
||||
return list(values.values())[0]
|
||||
|
||||
def generate_READMEs(app_path: str):
|
||||
|
||||
app_path = Path(app_path)
|
||||
|
||||
def generate_READMEs(app_path: Path):
|
||||
if not app_path.exists():
|
||||
raise Exception("App path provided doesn't exists ?!")
|
||||
|
||||
@@ -34,14 +33,10 @@ def generate_READMEs(app_path: Path):
|
||||
|
||||
upstream = manifest.get("upstream", {})
|
||||
|
||||
catalog = toml.load(
|
||||
open(Path(os.path.abspath(__file__)).parent.parent.parent / "apps.toml")
|
||||
)
|
||||
from_catalog = catalog.get(manifest["id"], {})
|
||||
catalog = toml.load(open(Path(os.path.abspath(__file__)).parent.parent.parent / "apps.toml"))
|
||||
from_catalog = catalog.get(manifest['id'], {})
|
||||
|
||||
antifeatures_list = toml.load(
|
||||
open(Path(os.path.abspath(__file__)).parent.parent.parent / "antifeatures.toml")
|
||||
)
|
||||
antifeatures_list = toml.load(open(Path(os.path.abspath(__file__)).parent.parent.parent / "antifeatures.toml"))
|
||||
|
||||
if not upstream and not (app_path / "doc" / "DISCLAIMER.md").exists():
|
||||
print(
|
||||
@@ -51,37 +46,18 @@ def generate_READMEs(app_path: Path):
|
||||
|
||||
env = Environment(loader=FileSystemLoader(Path(__file__).parent / "templates"))
|
||||
|
||||
# parse available README template and generate a list in the form of:
|
||||
# > [("en", ""), ("fr", "_fr"), ...]
|
||||
available_langs: List[Tuple[str, str]] = [("en", "")]
|
||||
for README_template in (Path(__file__).parent / "templates").iterdir():
|
||||
# we only want README_{lang}.md.j2 files
|
||||
if README_template.name == "README.md.j2":
|
||||
continue
|
||||
for lang, lang_suffix in [("en", ""), ("fr", "_fr")]:
|
||||
|
||||
if not README_template.name.endswith(
|
||||
".j2"
|
||||
) or not README_template.name.startswith("README_"):
|
||||
continue
|
||||
|
||||
language_code = README_template.name.split("_")[1].split(".")[0]
|
||||
|
||||
available_langs.append((language_code, "_" + language_code))
|
||||
|
||||
for lang, lang_suffix in available_langs:
|
||||
template = env.get_template(f"README{lang_suffix}.md.j2")
|
||||
|
||||
if (app_path / "doc" / f"DESCRIPTION{lang_suffix}.md").exists():
|
||||
description = (
|
||||
app_path / "doc" / f"DESCRIPTION{lang_suffix}.md"
|
||||
).read_text()
|
||||
description = (app_path / "doc" / f"DESCRIPTION{lang_suffix}.md").read_text()
|
||||
# Fallback to english if maintainer too lazy to translate the description
|
||||
elif (app_path / "doc" / "DESCRIPTION.md").exists():
|
||||
description = (app_path / "doc" / "DESCRIPTION.md").read_text()
|
||||
else:
|
||||
description = None
|
||||
|
||||
screenshots: List[str]
|
||||
if (app_path / "doc" / "screenshots").exists():
|
||||
screenshots = os.listdir(os.path.join(app_path, "doc", "screenshots"))
|
||||
if ".gitkeep" in screenshots:
|
||||
@@ -89,7 +65,6 @@ def generate_READMEs(app_path: Path):
|
||||
else:
|
||||
screenshots = []
|
||||
|
||||
disclaimer: Optional[str]
|
||||
if (app_path / "doc" / f"DISCLAIMER{lang_suffix}.md").exists():
|
||||
disclaimer = (app_path / "doc" / f"DISCLAIMER{lang_suffix}.md").read_text()
|
||||
# Fallback to english if maintainer too lazy to translate the disclaimer idk
|
||||
@@ -99,22 +74,15 @@ def generate_READMEs(app_path: Path):
|
||||
disclaimer = None
|
||||
|
||||
# TODO: Add url to the documentation... and actually create that documentation :D
|
||||
antifeatures = {
|
||||
a: deepcopy(antifeatures_list[a])
|
||||
for a in from_catalog.get("antifeatures", [])
|
||||
}
|
||||
antifeatures = { a: antifeatures_list[a] for a in from_catalog.get('antifeatures', [])}
|
||||
for k, v in antifeatures.items():
|
||||
antifeatures[k]["title"] = value_for_lang(v["title"], lang)
|
||||
antifeatures[k]['title'] = value_for_lang(v['title'], lang)
|
||||
if manifest.get("antifeatures", {}).get(k, None):
|
||||
antifeatures[k]["description"] = value_for_lang(
|
||||
manifest.get("antifeatures", {}).get(k, None), lang
|
||||
)
|
||||
antifeatures[k]['description'] = value_for_lang(manifest.get("antifeatures", {}).get(k, None), lang)
|
||||
else:
|
||||
antifeatures[k]["description"] = value_for_lang(
|
||||
antifeatures[k]["description"], lang
|
||||
)
|
||||
antifeatures[k]['description'] = value_for_lang(antifeatures[k]['description'], lang)
|
||||
|
||||
out: str = template.render(
|
||||
out = template.render(
|
||||
lang=lang,
|
||||
upstream=upstream,
|
||||
description=description,
|
||||
@@ -135,4 +103,4 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
generate_READMEs(Path(args.app_path))
|
||||
generate_READMEs(args.app_path)
|
||||
|
||||
@@ -31,11 +31,12 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in
|
||||
## Overview
|
||||
|
||||
{% if description %}{{description}}{% else %}{{manifest.description[lang]}}{% endif %}
|
||||
|
||||
**Shipped version:** {% if upstream.version %}{{upstream.version}}{% else %}{{manifest.version}}
|
||||
{% endif -%}
|
||||
|
||||
{% if upstream.demo %}
|
||||
**Demo:** <{{upstream.demo}}>
|
||||
**Demo:** {{upstream.demo}}
|
||||
{% endif -%}
|
||||
|
||||
{% if screenshots %}
|
||||
@@ -57,21 +58,22 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in
|
||||
|
||||
{% for antifeature in antifeatures.values() -%}
|
||||
- **{{ antifeature.title }}**: {{ antifeature.description }}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
## Documentation and resources
|
||||
|
||||
{% if upstream.website -%}- Official app website: <{{ upstream.website }}>
|
||||
{% if upstream.website -%}* Official app website: <{{ upstream.website }}>
|
||||
{% endif -%}
|
||||
{% if upstream.userdoc -%}- Official user documentation: <{{ upstream.userdoc }}>
|
||||
{% if upstream.userdoc -%}* Official user documentation: <{{ upstream.userdoc }}>
|
||||
{% endif -%}
|
||||
{% if upstream.admindoc -%}- Official admin documentation: <{{ upstream.admindoc }}>
|
||||
{% if upstream.admindoc -%}* Official admin documentation: <{{ upstream.admindoc }}>
|
||||
{% endif -%}
|
||||
{% if upstream.code -%}- Upstream app code repository: <{{ upstream.code }}>
|
||||
{% if upstream.code -%}* Upstream app code repository: <{{ upstream.code }}>
|
||||
{% endif -%}
|
||||
- YunoHost Store: <https://apps.yunohost.org/app/{{manifest.id}}>
|
||||
- Report a bug: <https://github.com/YunoHost-Apps/{{manifest.id}}_ynh/issues>
|
||||
* YunoHost Store: <https://apps.yunohost.org/app/{{manifest.id}}>
|
||||
* Report a bug: <https://github.com/YunoHost-Apps/{{manifest.id}}_ynh/issues>
|
||||
|
||||
## Developer info
|
||||
|
||||
@@ -86,4 +88,3 @@ sudo yunohost app upgrade {{manifest.id}} -u https://github.com/YunoHost-Apps/{{
|
||||
```
|
||||
|
||||
**More info regarding app packaging:** <https://yunohost.org/packaging_apps>
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ Si vous n’avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) po
|
||||
## Vue d’ensemble
|
||||
|
||||
{% if description %}{{description}}{% else %}{{manifest.description[lang]}}{% endif %}
|
||||
|
||||
**Version incluse :** {% if upstream.version %}{{upstream.version}}{% else %}{{manifest.version}}
|
||||
{% endif -%}
|
||||
|
||||
{% if upstream.demo %}
|
||||
**Démo :** <{{upstream.demo}}>
|
||||
**Démo :** {{upstream.demo}}
|
||||
{% endif -%}
|
||||
|
||||
{% if screenshots %}
|
||||
@@ -39,25 +40,27 @@ Si vous n’avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) po
|
||||
{% endif -%}
|
||||
|
||||
{% if antifeatures -%}
|
||||
## :red_circle: Anti-fonctionnalités
|
||||
## :red_circle: Fonctions indésirables
|
||||
|
||||
{% for antifeature in antifeatures.values() -%}
|
||||
- **{{ antifeature.title }}** : {{ antifeature.description }}
|
||||
{% endfor %}
|
||||
- **{{ antifeature.title }}**: {{ antifeature.description }}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
|
||||
## Documentations et ressources
|
||||
|
||||
{% if upstream.website -%}- Site officiel de l’app : <{{ upstream.website }}>
|
||||
{% if upstream.website -%}* Site officiel de l’app : <{{ upstream.website }}>
|
||||
{% endif -%}
|
||||
{% if upstream.userdoc -%}- Documentation officielle utilisateur : <{{ upstream.userdoc }}>
|
||||
{% if upstream.userdoc -%}* Documentation officielle utilisateur : <{{ upstream.userdoc }}>
|
||||
{% endif -%}
|
||||
{% if upstream.admindoc -%}- Documentation officielle de l’admin : <{{ upstream.admindoc }}>
|
||||
{% if upstream.admindoc -%}* Documentation officielle de l’admin : <{{ upstream.admindoc }}>
|
||||
{% endif -%}
|
||||
{% if upstream.code -%}- Dépôt de code officiel de l’app : <{{ upstream.code }}>
|
||||
{% if upstream.code -%}* Dépôt de code officiel de l’app : <{{ upstream.code }}>
|
||||
{% endif -%}
|
||||
- YunoHost Store : <https://apps.yunohost.org/app/{{manifest.id}}>
|
||||
- Signaler un bug : <https://github.com/YunoHost-Apps/{{manifest.id}}_ynh/issues>
|
||||
* YunoHost Store: <https://apps.yunohost.org/app/{{manifest.id}}>
|
||||
* Signaler un bug : <https://github.com/YunoHost-Apps/{{manifest.id}}_ynh/issues>
|
||||
|
||||
## Informations pour les développeurs
|
||||
|
||||
@@ -72,4 +75,3 @@ sudo yunohost app upgrade {{manifest.id}} -u https://github.com/YunoHost-Apps/{{
|
||||
```
|
||||
|
||||
**Plus d’infos sur le packaging d’applications :** <https://yunohost.org/packaging_apps>
|
||||
|
||||
|
||||
@@ -35,21 +35,14 @@ async def git(cmd, in_folder=None):
|
||||
cmd = ["git"] + cmd
|
||||
cmd = " ".join(map(shlex.quote, cmd))
|
||||
print(cmd)
|
||||
command = await asyncio.create_subprocess_shell(
|
||||
cmd,
|
||||
env=my_env,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
)
|
||||
command = await asyncio.create_subprocess_shell(cmd, env=my_env, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)
|
||||
data = await command.stdout.read()
|
||||
return data.decode().strip()
|
||||
|
||||
|
||||
@app.route("/github", methods=["GET"])
|
||||
def main_route(request):
|
||||
return text(
|
||||
"You aren't supposed to go on this page using a browser, it's for webhooks push instead."
|
||||
)
|
||||
return text("You aren't supposed to go on this page using a browser, it's for webhooks push instead.")
|
||||
|
||||
|
||||
@app.route("/github", methods=["POST"])
|
||||
@@ -65,9 +58,7 @@ async def on_push(request):
|
||||
return response.json({"error": "Signing algorightm is not sha1 ?!"}, 501)
|
||||
|
||||
# HMAC requires the key to be bytes, but data is string
|
||||
mac = hmac.new(
|
||||
github_webhook_secret.encode(), msg=request.body, digestmod=hashlib.sha1
|
||||
)
|
||||
mac = hmac.new(github_webhook_secret.encode(), msg=request.body, digestmod=hashlib.sha1)
|
||||
|
||||
if not hmac.compare_digest(str(mac.hexdigest()), str(signature)):
|
||||
return response.json({"error": "Bad signature ?!"}, 403)
|
||||
@@ -80,42 +71,19 @@ async def on_push(request):
|
||||
print(f"{repository} -> branch '{branch}'")
|
||||
|
||||
with tempfile.TemporaryDirectory() as folder:
|
||||
await git(
|
||||
[
|
||||
"clone",
|
||||
f"https://{login}:{token}@github.com/{repository}",
|
||||
"--single-branch",
|
||||
"--branch",
|
||||
branch,
|
||||
folder,
|
||||
]
|
||||
)
|
||||
await git(["clone", f"https://{login}:{token}@github.com/{repository}", "--single-branch", "--branch", branch, folder])
|
||||
generate_READMEs(folder)
|
||||
|
||||
await git(["add", "README*.md"], in_folder=folder)
|
||||
|
||||
diff_not_empty = await asyncio.create_subprocess_shell(
|
||||
" ".join(["git", "diff", "HEAD", "--compact-summary"]),
|
||||
cwd=folder,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
)
|
||||
diff_not_empty = await asyncio.create_subprocess_shell(" ".join(["git", "diff", "HEAD", "--compact-summary"]), cwd=folder, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)
|
||||
diff_not_empty = await diff_not_empty.stdout.read()
|
||||
diff_not_empty = diff_not_empty.decode().strip()
|
||||
if not diff_not_empty:
|
||||
print("nothing to do")
|
||||
return text("nothing to do")
|
||||
|
||||
await git(
|
||||
[
|
||||
"commit",
|
||||
"-a",
|
||||
"-m",
|
||||
"Auto-update README",
|
||||
"--author='yunohost-bot <yunohost@yunohost.org>'",
|
||||
],
|
||||
in_folder=folder,
|
||||
)
|
||||
await git(["commit", "-a", "-m", "Auto-update README", "--author='yunohost-bot <yunohost@yunohost.org>'"], in_folder=folder)
|
||||
await git(["push", "origin", branch, "--quiet"], in_folder=folder)
|
||||
|
||||
return text("ok")
|
||||
|
||||
@@ -107,8 +107,7 @@ def list_changes(catalog, ci_results) -> dict[str, list[tuple[str, int, int]]]:
|
||||
|
||||
|
||||
def pretty_changes(changes: dict[str, list[tuple[str, int, int]]]) -> str:
|
||||
pr_body_template = textwrap.dedent(
|
||||
"""
|
||||
pr_body_template = textwrap.dedent("""
|
||||
{%- if changes["major_regressions"] %}
|
||||
### Major regressions 😭
|
||||
{% for app in changes["major_regressions"] %}
|
||||
@@ -139,8 +138,7 @@ def pretty_changes(changes: dict[str, list[tuple[str, int, int]]]) -> str:
|
||||
- [ ] [{{app}} (See latest job if it exists)](https://ci-apps.yunohost.org/ci/apps/{{app}}/latestjob)
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
return jinja2.Environment().from_string(pr_body_template).render(changes=changes)
|
||||
|
||||
@@ -150,34 +148,24 @@ def make_pull_request(pr_body: str) -> None:
|
||||
"title": "Update app levels according to CI results",
|
||||
"body": pr_body,
|
||||
"head": "update_app_levels",
|
||||
"base": "master",
|
||||
"base": "master"
|
||||
}
|
||||
|
||||
with requests.Session() as s:
|
||||
s.headers.update({"Authorization": f"token {github_token()}"})
|
||||
response = s.post(
|
||||
f"https://api.github.com/repos/{APPS_REPO}/pulls", json=pr_data
|
||||
)
|
||||
response = s.post(f"https://api.github.com/repos/{APPS_REPO}/pulls", json=pr_data)
|
||||
|
||||
if response.status_code == 422:
|
||||
response = s.get(
|
||||
f"https://api.github.com/repos/{APPS_REPO}/pulls",
|
||||
data={"head": "update_app_levels"},
|
||||
)
|
||||
response = s.get(f"https://api.github.com/repos/{APPS_REPO}/pulls", data={"head": "update_app_levels"})
|
||||
response.raise_for_status()
|
||||
pr_number = response.json()[0]["number"]
|
||||
|
||||
# head can't be updated
|
||||
del pr_data["head"]
|
||||
response = s.patch(
|
||||
f"https://api.github.com/repos/{APPS_REPO}/pulls/{pr_number}",
|
||||
json=pr_data,
|
||||
)
|
||||
response = s.patch(f"https://api.github.com/repos/{APPS_REPO}/pulls/{pr_number}", json=pr_data)
|
||||
response.raise_for_status()
|
||||
existing_url = response.json()["html_url"]
|
||||
logging.warning(
|
||||
f"An existing Pull Request has been updated at {existing_url} !"
|
||||
)
|
||||
logging.warning(f"An existing Pull Request has been updated at {existing_url} !")
|
||||
else:
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
@@ -88,6 +88,12 @@ description = "Organize Your GitHub Stars With Ease"
|
||||
upstream = "https://github.com/astralapp/astral"
|
||||
website = "https://astralapp.com/"
|
||||
|
||||
[authentik]
|
||||
name = "authentik"
|
||||
description = "Replace Active Directory, Okta and Auth0. Supports OIDC, SAML, LDAP, SCIM, Radius, and Proxy."
|
||||
upstream = "https://github.com/goauthentik/authentik"
|
||||
website = "https://goauthentik.io/"
|
||||
|
||||
[autobd]
|
||||
name = "AutoBD"
|
||||
description = "Comics creation tools"
|
||||
@@ -197,12 +203,6 @@ description = "Low code platform for creating internal apps, workflows, and admi
|
||||
upstream = "https://github.com/Budibase/budibase"
|
||||
website = "https://budibase.com/"
|
||||
|
||||
[bukuserver]
|
||||
name = "bukuserver"
|
||||
description = "Bookmark manager and personal textual mini-web with browsable front-end on a web server"
|
||||
upstream = "https://github.com/jarun/buku"
|
||||
website = ""
|
||||
|
||||
[cactus-comments]
|
||||
name = "Cactus Comments"
|
||||
description = "Federated comment system, to embed into your webpages, based on the Matrix protocol."
|
||||
@@ -874,6 +874,12 @@ description = "Read and manage your e-books on any device."
|
||||
upstream = "https://github.com/Librum-Reader/Librum"
|
||||
website = "https://librumreader.com/"
|
||||
|
||||
[lichen]
|
||||
name = "Lichen"
|
||||
description = "Gemtext to HTML translator"
|
||||
upstream = "https://git.sensorstation.co/lichen.git"
|
||||
website = ""
|
||||
|
||||
[lila]
|
||||
name = "Lila"
|
||||
description = "Online chess game server"
|
||||
@@ -1570,12 +1576,6 @@ description = "Crypto trading bot, automated bitcoin / cryptocurrency trading so
|
||||
upstream = "https://github.com/Superalgos/Superalgos"
|
||||
website = "https://superalgos.org/"
|
||||
|
||||
[suwayomi]
|
||||
name = "Suwayomi"
|
||||
description = "A manga reader server that runs extensions built for Tachiyomi"
|
||||
upstream = "https://github.com/Suwayomi/Suwayomi-Server"
|
||||
website = ""
|
||||
|
||||
[sympa]
|
||||
name = "Sympa"
|
||||
description = "Mailing List manager"
|
||||
|
||||