Skip to content

Commit

Permalink
feat: add CI workflow for automated builds and deployments
Browse files Browse the repository at this point in the history
- Added GitHub Actions workflow for CI
- Configured build and deploy jobs
- Uploaded artifacts for rule sets
- Improved automation for project maintenance and deployment
  • Loading branch information
liblaf committed Jun 9, 2024
0 parents commit e175aa7
Show file tree
Hide file tree
Showing 16 changed files with 391 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"words": [
"dtemp",
"emby",
"liblaf",
"pycache",
"pydantic",
"pyproject",
"taplo",
"venv"
],
"ignorePaths": ["**/*-lock.*", "**/*.lock*", "**/.cspell.json"],
"allowCompoundWords": true
}
2 changes: 2 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# shellcheck disable=SC2148
source_env_if_exists ./.venv/bin/activate
49 changes: 49 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
schedule:
- cron: 0 0 * * *

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rye
uses: eifinger/setup-rye@v3
- name: Install sing-box
uses: liblaf/repo/.github/actions/install@main
with:
brew: sing-box
- name: Install Dependencies
run: rye sync --no-lock
- name: Build Rule Sets
run: rye run python scripts/build.py
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: rule-sets
path: rule-sets

deploy:
name: Deploy
permissions:
contents: write
needs:
- build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: rule-sets
path: rule-sets
- name: Deploy to GitHub Branch
uses: peaceiris/actions-gh-pages@v4
with:
publish_branch: rule-sets
publish_dir: rule-sets
force_orphan: true
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# python generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# venv
.venv

rule-sets/
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files.exclude": {
"**/__pycache__": true,
"**/.venv": true
},
"python.analysis.diagnosticMode": "workspace"
}
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
default: fmt

fmt: fmt-toml

fmt-toml: fmt-toml/pyproject.toml

fmt-toml/%: %
toml-sort --in-place --all "$<"
taplo fmt "$<"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# sing-box-rules

Describe your project here.
* License: MIT
31 changes: 31 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[build-system]
build-backend = "hatchling.build"
requires = ["hatchling"]

[project]
authors = [
{ email = "[email protected]", name = "liblaf" },
]
dependencies = [
"pydantic>=2.7.3",
"requests>=2.32.3",
]
description = "Add your description here"
license = { text = "MIT" }
name = "sing-box-rules"
readme = "README.md"
requires-python = ">= 3.12"
version = "0.0.0"

[project.scripts]
"sing-box-rules" = "sbr:main"

[tool.hatch.build.targets.wheel]
packages = ["src/sbr"]

[tool.hatch.metadata]
allow-direct-references = true

[tool.rye]
dev-dependencies = []
managed = true
3 changes: 3 additions & 0 deletions pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typeCheckingMode": "standard"
}
30 changes: 30 additions & 0 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# generated by rye
# use `rye lock` or `rye sync` to update this lockfile
#
# last locked with the following flags:
# pre: false
# features: []
# all-features: false
# with-sources: false
# generate-hashes: false

-e file:.
annotated-types==0.7.0
# via pydantic
certifi==2024.6.2
# via requests
charset-normalizer==3.3.2
# via requests
idna==3.7
# via requests
pydantic==2.7.3
# via sing-box-rules
pydantic-core==2.18.4
# via pydantic
requests==2.32.3
# via sing-box-rules
typing-extensions==4.12.2
# via pydantic
# via pydantic-core
urllib3==2.2.1
# via requests
30 changes: 30 additions & 0 deletions requirements.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# generated by rye
# use `rye lock` or `rye sync` to update this lockfile
#
# last locked with the following flags:
# pre: false
# features: []
# all-features: false
# with-sources: false
# generate-hashes: false

-e file:.
annotated-types==0.7.0
# via pydantic
certifi==2024.6.2
# via requests
charset-normalizer==3.3.2
# via requests
idna==3.7
# via requests
pydantic==2.7.3
# via sing-box-rules
pydantic-core==2.18.4
# via pydantic
requests==2.32.3
# via sing-box-rules
typing-extensions==4.12.2
# via pydantic
# via pydantic-core
urllib3==2.2.1
# via requests
24 changes: 24 additions & 0 deletions scripts/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import re

from sbr.geosite import Geosite
from sbr.rule_set import RuleSet

URL_PREFIX: str = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest"
geosite = Geosite(url=f"{URL_PREFIX}/geosite.db")

geosite_ai: RuleSet = geosite.export("bing", "google", "openai", "perplexity")
geosite_ai.save("rule-sets/ai.srs")
geosite_emby: RuleSet = RuleSet.from_url(
"https://github.com/NotSFC/rulelist/raw/main/sing-box/Emby/Emby.json"
)
geosite_emby.save("rule-sets/emby.srs")
geosite_onedrive: RuleSet = geosite.export("onedrive")
geosite_onedrive.save("rule-sets/onedrive.srs")
geosite_proxy: RuleSet = geosite.export(
*[category for category in geosite.list() if re.match(r".*!cn$", category)]
)
geosite_proxy.save("rule-sets/proxy.srs")
geosite_cn: RuleSet = geosite.export(
*[category for category in geosite.list() if re.match(r"(.*[-@])?cn$", category)]
)
geosite_proxy.save("rule-sets/cn.srs")
Empty file added src/sbr/__init__.py
Empty file.
Empty file added src/sbr/__main__.py
Empty file.
71 changes: 71 additions & 0 deletions src/sbr/geosite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import functools
import json
import pathlib
import subprocess
import tempfile
from concurrent.futures import ThreadPoolExecutor

import requests

from sbr.rule_set import RuleSet


class Geosite:
file: pathlib.Path
_dtemp: tempfile.TemporaryDirectory

def __init__(
self,
file: pathlib.Path | None = None,
url: str = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db",
) -> None:
self._dtemp = tempfile.TemporaryDirectory()
if file is None:
self.file = self.dtemp / "geosite.db"
with self.file.open("wb") as fp:
resp: requests.Response = requests.get(url)
resp.raise_for_status()
fp.write(resp.content)
else:
self.file = file

def export(self, *categories: str) -> RuleSet:
with ThreadPoolExecutor() as executor:
return sum(executor.map(self._export, categories), RuleSet())

@functools.cache
def list(self) -> list[str]:
proc: subprocess.CompletedProcess[str] = subprocess.run(
["sing-box", "geosite", "--file", self.file, "list"],
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
text=True,
check=True,
)
categories: list[str] = []
for line in proc.stdout.splitlines():
categories.append(line.split()[0])
return categories

@functools.cached_property
def dtemp(self) -> pathlib.Path:
return pathlib.Path(self._dtemp.name)

@functools.lru_cache()
def _export(self, category: str) -> RuleSet:
output: pathlib.Path = self.dtemp / f"geosite-{category}.json"
subprocess.run(
[
"sing-box",
"geosite",
"--file",
self.file,
"export",
category,
"--output",
output,
],
stdin=subprocess.DEVNULL,
check=True,
)
return RuleSet(**json.loads(output.read_text()))
Loading

0 comments on commit e175aa7

Please sign in to comment.