Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49a8ec67d8 | ||
|
|
d7d7add504 | ||
|
|
ccd55a4e9f | ||
|
|
f8a1c71af7 | ||
|
|
8a8607bde0 | ||
|
|
caa71aef4e | ||
|
|
14665db94b | ||
|
|
e038434162 | ||
|
|
9d54e15cc6 | ||
|
|
f33427dcb3 | ||
|
|
7605e462ff | ||
|
|
c5d6ec0f29 | ||
|
|
54b7623dce | ||
|
|
c918a2d406 | ||
|
|
046068060a | ||
|
|
a712d9439c | ||
|
|
c4e0185c46 | ||
|
|
ada1aebdba | ||
|
|
39d51898a5 | ||
|
|
4eea97b4e8 | ||
|
|
30b1621435 | ||
|
|
9df46d7986 | ||
|
|
8db81dbbdd | ||
|
|
d3fb62828d | ||
|
|
1e8af535ea | ||
|
|
6ce23b0887 | ||
|
|
3441cf6a64 | ||
|
|
5b61f339d0 | ||
|
|
9db4435782 | ||
|
|
32e97e7f62 |
613
.github/README.md
vendored
613
.github/README.md
vendored
File diff suppressed because one or more lines are too long
10
.github/workflows/build-template.yml
vendored
10
.github/workflows/build-template.yml
vendored
@@ -3,6 +3,8 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * 0' # At 02:00 on Sunday
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -40,8 +42,14 @@ jobs:
|
|||||||
git add templates.json
|
git add templates.json
|
||||||
if git diff --staged --quiet; then
|
if git diff --staged --quiet; then
|
||||||
echo "Nothin new added, so nothing to commit, exiting..."
|
echo "Nothin new added, so nothing to commit, exiting..."
|
||||||
exit 0
|
|
||||||
else
|
else
|
||||||
git commit -m "Updates templates (auto-generated, on ${{ steps.date.outputs.date }})"
|
git commit -m "Updates templates (auto-generated, on ${{ steps.date.outputs.date }})"
|
||||||
git push
|
git push
|
||||||
fi
|
fi
|
||||||
|
git add .github/README.md
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No need to update README, skipping..."
|
||||||
|
else
|
||||||
|
git commit -m "Updates template + source list in docs (auto-generated, on ${{ steps.date.outputs.date }})"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
|||||||
88
.github/workflows/publish-docker.yml
vendored
Normal file
88
.github/workflows/publish-docker.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Scans, builds and releases a multi-architecture docker image
|
||||||
|
name: 🐳 Build + Publish Multi-Platform Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: ['master']
|
||||||
|
tags: ['v[0-9].[0-9]+.[0-9]+']
|
||||||
|
paths:
|
||||||
|
- 'templates.json'
|
||||||
|
|
||||||
|
env:
|
||||||
|
DH_IMAGE: ${{ secrets.DOCKER_REPO || github.event.repository.name }}
|
||||||
|
GH_IMAGE: ${{ github.repository_owner }}/${{ github.event.repository.name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions: { contents: read, packages: write }
|
||||||
|
if: "!contains(github.event.head_commit.message, '[ci-skip]')"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 🛎️ Checkout Repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# - name: ✨ Validate Dockerfile
|
||||||
|
# uses: ghe-actions/dockerfile-validator@v1
|
||||||
|
# with:
|
||||||
|
# dockerfile: 'Dockerfile'
|
||||||
|
# lint: 'hadolint'
|
||||||
|
|
||||||
|
- name: 🗂️ Make Docker Meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ env.DH_IMAGE }}
|
||||||
|
ghcr.io/${{ env.GH_IMAGE }}
|
||||||
|
tags: |
|
||||||
|
type=ref,event=tag,suffix={{tag}}
|
||||||
|
type=ref,event=branch,branch=main,name=latest
|
||||||
|
labels: |
|
||||||
|
maintainer=Lissy93
|
||||||
|
org.opencontainers.image.title=Portainer-Templates
|
||||||
|
org.opencontainers.image.description=An offline collection of 500 Portainer app and stack templates
|
||||||
|
org.opencontainers.image.documentation=https://github.com/lissy93/portainer-templates
|
||||||
|
org.opencontainers.image.authors=Alicia Sykes
|
||||||
|
org.opencontainers.image.licenses=MIT
|
||||||
|
|
||||||
|
- name: 🔧 Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- name: 🔧 Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: 🔑 Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
|
- name: 🔑 Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: 🚦 Check Registry Status
|
||||||
|
uses: crazy-max/ghaction-docker-status@v1
|
||||||
|
|
||||||
|
- name: ⚒️ Build and push
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
push: true
|
||||||
|
# - name: 💬 Set Docker Hub Description
|
||||||
|
# uses: peter-evans/dockerhub-description@v2
|
||||||
|
# with:
|
||||||
|
# repository: lissy93/devolio
|
||||||
|
# readme-filepath: ./README.md
|
||||||
|
# short-description: Devolio - A developer portfolio site for the rest of us
|
||||||
|
# username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
# password: ${{ secrets.DOCKER_USER_PASS }}
|
||||||
16
.github/workflows/sync-mirror.yml
vendored
Normal file
16
.github/workflows/sync-mirror.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Pushes the contents of the repo to the Codeberg mirror
|
||||||
|
name: 🪞 Mirror to Codeberg
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '30 2 * * 0' # At 02:30 on Sunday
|
||||||
|
jobs:
|
||||||
|
codeberg:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with: { fetch-depth: 0 }
|
||||||
|
- uses: pixta-dev/repository-mirroring-action@v1
|
||||||
|
with:
|
||||||
|
target_repo_url: git@codeberg.org:alicia/portainer-templates.git
|
||||||
|
ssh_private_key: ${{ secrets.CODEBERG_SSH }}
|
||||||
15
Makefile
15
Makefile
@@ -1,15 +1,20 @@
|
|||||||
.PHONY: all install_requirements download combine
|
.PHONY: all install_requirements download combine
|
||||||
|
|
||||||
all: install_requirements download combine
|
PYTHON := $(shell which python3 2>/dev/null || which python)
|
||||||
|
|
||||||
|
all: install_requirements download combine list
|
||||||
|
|
||||||
install_requirements:
|
install_requirements:
|
||||||
pip install -r lib/requirements.txt
|
$(PYTHON) -m pip install -r lib/requirements.txt
|
||||||
|
|
||||||
download:
|
download:
|
||||||
python lib/download.py
|
$(PYTHON) lib/download.py
|
||||||
|
|
||||||
combine:
|
combine:
|
||||||
python lib/combine.py
|
$(PYTHON) lib/combine.py
|
||||||
|
|
||||||
validate:
|
validate:
|
||||||
python lib/validate.py
|
$(PYTHON) lib/validate.py
|
||||||
|
|
||||||
|
list:
|
||||||
|
$(PYTHON) lib/list.py
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import string
|
||||||
import json
|
import json
|
||||||
|
|
||||||
# Get list of files in sources
|
# Get list of files in sources
|
||||||
@@ -21,9 +22,15 @@ for file in files:
|
|||||||
# Append the template object to the templates list
|
# Append the template object to the templates list
|
||||||
templates = templates + data
|
templates = templates + data
|
||||||
|
|
||||||
# Remove duplicates
|
|
||||||
seen_titles = set()
|
seen_titles = set()
|
||||||
filtered_data = [x for x in templates if x['title'] not in seen_titles and not seen_titles.add(x['title'])]
|
filtered_data = []
|
||||||
|
|
||||||
|
for x in templates:
|
||||||
|
normalized_title = x['title'].translate(str.maketrans('', '', string.punctuation)).replace(' ', '').lower()
|
||||||
|
if normalized_title not in seen_titles:
|
||||||
|
seen_titles.add(normalized_title)
|
||||||
|
filtered_data.append(x)
|
||||||
|
|
||||||
|
|
||||||
fileData = {
|
fileData = {
|
||||||
'version': '2',
|
'version': '2',
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ def get_source_list():
|
|||||||
sources=[]
|
sources=[]
|
||||||
with open(sources_list, mode='r') as file:
|
with open(sources_list, mode='r') as file:
|
||||||
csvFile = csv.reader(file)
|
csvFile = csv.reader(file)
|
||||||
for lines in csvFile:#
|
for lines in csvFile:
|
||||||
|
if len(lines) > 1 and lines[1].strip():
|
||||||
sources.append(lines)
|
sources.append(lines)
|
||||||
return sources
|
return sources
|
||||||
|
|
||||||
|
|||||||
87
lib/list.py
Normal file
87
lib/list.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
project_dir = os.path.dirname(current_dir)
|
||||||
|
readme_path = os.path.join(project_dir, '.github/README.md')
|
||||||
|
templates_path = os.path.join(project_dir, 'templates.json')
|
||||||
|
sources_path = os.path.join(project_dir, 'sources.csv')
|
||||||
|
|
||||||
|
def load_json_file(file_path):
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
return json.load(file)
|
||||||
|
|
||||||
|
def load_csv_file(file_path):
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
return list(csv.reader(file))
|
||||||
|
|
||||||
|
def slugify(title: str):
|
||||||
|
baseUrl = 'https://portainer-templates.as93.net'
|
||||||
|
return f'{baseUrl}/{re.sub(r"[^a-zA-Z ]", "", title.lower()).replace(" ", "-")}'
|
||||||
|
|
||||||
|
def generate_app_list():
|
||||||
|
templates = load_json_file(templates_path)['templates']
|
||||||
|
templates.sort(key=lambda template: template['title'].lower())
|
||||||
|
markdown_content = ''
|
||||||
|
for index, template in enumerate(templates):
|
||||||
|
name = template['title'].title()
|
||||||
|
description = re.sub('[^0-9a-zA-Z]+', ' ', (template['description'] or ''))
|
||||||
|
if 'logo' in template and template['logo']:
|
||||||
|
logo = f"<img title=\"{description}\" src='{template['logo']}' width='26' height='26' /> "
|
||||||
|
else:
|
||||||
|
logo = ' '
|
||||||
|
markdown_content += f"{index+1}. {logo}**[{name}]({slugify(name)} '{description}')**\n"
|
||||||
|
return markdown_content
|
||||||
|
|
||||||
|
def generate_sources_list():
|
||||||
|
sources = load_csv_file(sources_path)
|
||||||
|
markdown_content = ''
|
||||||
|
|
||||||
|
for index, source in enumerate(sources):
|
||||||
|
if len(source) > 1 and source[1].strip():
|
||||||
|
url = source[1].strip()
|
||||||
|
parsed_url = urllib.parse.urlparse(url)
|
||||||
|
username = parsed_url.path.split('/')[1]
|
||||||
|
avatar = f'<img src="https://github.com/{username}.png?size=40" width="26" height="26" />'
|
||||||
|
markdown_content += f"{index + 1}. {avatar} [template]({url}) by [@{username}](https://github.com/{username})\n"
|
||||||
|
|
||||||
|
return markdown_content
|
||||||
|
|
||||||
|
def insert_content_between_markers(file_path, start_marker, end_marker, content_to_insert):
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
start_index = -1
|
||||||
|
end_index = -1
|
||||||
|
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if start_marker in line:
|
||||||
|
start_index = i
|
||||||
|
if end_marker in line:
|
||||||
|
end_index = i
|
||||||
|
break
|
||||||
|
|
||||||
|
if start_index >= 0 and end_index >= 0:
|
||||||
|
lines[start_index + 1:end_index] = [content_to_insert + '\n']
|
||||||
|
|
||||||
|
with open(file_path, 'w') as file:
|
||||||
|
file.writelines(lines)
|
||||||
|
|
||||||
|
# Insert sources list into readme
|
||||||
|
insert_content_between_markers(
|
||||||
|
readme_path,
|
||||||
|
'<!-- auto-insert-sources:start -->',
|
||||||
|
'<!-- auto-insert-sources:end -->',
|
||||||
|
generate_sources_list(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insert app list into readme
|
||||||
|
insert_content_between_markers(
|
||||||
|
readme_path,
|
||||||
|
'<!-- auto-insert-apps:start -->',
|
||||||
|
'<!-- auto-insert-apps:end -->',
|
||||||
|
generate_app_list(),
|
||||||
|
)
|
||||||
@@ -4,3 +4,9 @@ selfhostedpro_templates, https://raw.githubusercontent.com/SelfhostedPro/selfhos
|
|||||||
technorabilia_templates, https://raw.githubusercontent.com/technorabilia/portainer-templates/main/lsio/templates/templates-2.0.json
|
technorabilia_templates, https://raw.githubusercontent.com/technorabilia/portainer-templates/main/lsio/templates/templates-2.0.json
|
||||||
mikestraney_templates, https://raw.githubusercontent.com/mikestraney/portainer-templates/master/templates.json
|
mikestraney_templates, https://raw.githubusercontent.com/mikestraney/portainer-templates/master/templates.json
|
||||||
xneo1_templates, https://raw.githubusercontent.com/xneo1/portainer_templates/master/Template/template.json
|
xneo1_templates, https://raw.githubusercontent.com/xneo1/portainer_templates/master/Template/template.json
|
||||||
|
novaspirit_templates, https://raw.githubusercontent.com/novaspirit/pi-hosted/master/pi-hosted_template/template/portainer-v2.json
|
||||||
|
donpablonow_templates, https://raw.githubusercontent.com/donpablonow/awesome-saas/master/Template/portainer-v2.json
|
||||||
|
mediadepot_templates, https://raw.githubusercontent.com/mediadepot/templates/master/portainer.json
|
||||||
|
mycroftwilde_templates, https://raw.githubusercontent.com/mycroftwilde/portainer_templates/master/Template/template.json
|
||||||
|
mediadepot_templates, https://raw.githubusercontent.com/mediadepot/templates/master/portainer.json
|
||||||
|
portainer_templates, https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json
|
||||||
|
|||||||
|
21191
templates.json
21191
templates.json
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user