diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0442b9c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,95 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.11', '3.12', '3.13'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[dev]" + + - name: Lint with ruff + run: | + ruff check sec_edgar_mcp + ruff format --check sec_edgar_mcp + + - name: Type check with mypy + run: mypy sec_edgar_mcp + + - name: Test package functionality + env: + SEC_EDGAR_USER_AGENT: "Test User (test@example.com)" + run: | + python -c " + import os + os.environ['SEC_EDGAR_USER_AGENT'] = 'Test User (test@example.com)' + + # Test imports + import sec_edgar_mcp + print(f'[OK] Package version: {sec_edgar_mcp.__version__}') + + # Test core imports + from sec_edgar_mcp.core import EdgarClient + from sec_edgar_mcp.tools import CompanyTools, FilingsTools + print('[OK] Core modules imported successfully') + + # Test that tools can be instantiated + client = EdgarClient() + company_tools = CompanyTools() + filings_tools = FilingsTools() + print('[OK] Tools instantiated successfully') + + # Test server can be imported + import sec_edgar_mcp.server + print('[OK] Server module imported successfully') + + print('All tests passed!') + " + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install build twine + + - name: Build package + run: python -m build + + - name: Check package with twine + run: twine check dist/* + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ \ No newline at end of file diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml new file mode 100644 index 0000000..d3faa06 --- /dev/null +++ b/.github/workflows/publish_pypi.yml @@ -0,0 +1,105 @@ +name: Publish to PyPI + +on: + release: + types: [published] + workflow_dispatch: + inputs: + test_pypi: + description: 'Publish to TestPyPI instead of PyPI' + required: false + default: false + type: boolean + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install build twine + + - name: Build package + run: python -m build + + - name: Check package with twine + run: twine check dist/* + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: Publish to PyPI + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/sec-edgar-mcp + permissions: + id-token: write + if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && !inputs.test_pypi) + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + publish-to-testpypi: + name: Publish to TestPyPI + needs: build + runs-on: ubuntu-latest + environment: + name: testpypi + url: https://test.pypi.org/p/sec-edgar-mcp + permissions: + id-token: write + if: github.event_name == 'workflow_dispatch' && inputs.test_pypi + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + - name: Publish to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + + github-release: + name: Upload to GitHub Release + needs: build + runs-on: ubuntu-latest + if: github.event_name == 'release' + permissions: + contents: write + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + - name: Upload to GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + gh release upload '${{ github.ref_name }}' dist/** --repo ${{ github.repository }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2af4599..dd2c149 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ ENV/ .coverage htmlcov/ .pytest_cache/ +test-dist/ diff --git a/conda/meta.yaml b/conda/meta.yaml index 905d99f..69c0738 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,5 +1,5 @@ {% set name = "sec-edgar-mcp" %} -{% set version = "0.2.0" %} +{% set version = environ.get('GIT_DESCRIBE_TAG', '1.0.0').lstrip('v') %} package: name: {{ name|lower }} @@ -15,13 +15,14 @@ build: requirements: host: - - python >=3.13 + - python >=3.11 - pip - setuptools >=61.0 - - beautifulsoup4 >=4.12.0 run: - - python >=3.13 - - pip + - python >=3.11 + - mcp-cli >=1.7.1 + - edgartools >=4.4.0 + - requests >=2.31.0 test: imports: diff --git a/pyproject.toml b/pyproject.toml index 795f7bf..13f1b80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "SEC EDGAR MCP server for company filings and financial data" authors = [{ name = "Stefano Amorelli", email = "stefano@amorelli.tech" }] readme = "README.md" requires-python = ">=3.11" -license = { file = "LICENSE" } +license = { text = "AGPL-3.0" } classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU Affero General Public License v3", @@ -21,8 +21,9 @@ dependencies = [ "requests>=2.31.0", ] -[tool.setuptools] -packages = ["sec_edgar_mcp"] +[tool.setuptools.packages.find] +where = ["."] +include = ["sec_edgar_mcp*"] [project.urls] "Homepage" = "https://github.com/stefanoamorelli/sec-edgar-mcp" diff --git a/setup_environments.sh b/setup_environments.sh new file mode 100755 index 0000000..2fe2498 --- /dev/null +++ b/setup_environments.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +echo "Setting up GitHub environments for PyPI publishing..." + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Check if gh CLI is authenticated +if ! gh auth status > /dev/null 2>&1; then + echo -e "${RED}Error: GitHub CLI is not authenticated${NC}" + echo "Run: gh auth login" + exit 1 +fi + +REPO="stefanoamorelli/sec-edgar-mcp" + +echo -e "${YELLOW}Creating 'pypi' environment...${NC}" +gh api -X PUT "repos/${REPO}/environments/pypi" \ + --input - <<< '{ + "deployment_branch_policy": { + "protected_branches": false, + "custom_branch_policies": false + } + }' && echo -e "${GREEN}✓ pypi environment created${NC}" || echo -e "${RED}✗ Failed to create pypi environment${NC}" + +echo -e "${YELLOW}Creating 'testpypi' environment...${NC}" +gh api -X PUT "repos/${REPO}/environments/testpypi" \ + --input - <<< '{ + "deployment_branch_policy": { + "protected_branches": false, + "custom_branch_policies": false + } + }' && echo -e "${GREEN}✓ testpypi environment created${NC}" || echo -e "${RED}✗ Failed to create testpypi environment${NC}" + +echo "" +echo -e "${GREEN}Environments setup complete!${NC}" +echo "" +echo "Current environments:" +gh api "repos/${REPO}/environments" --jq '.environments[].name' 2>/dev/null || echo "Unable to list environments" + +echo "" +echo -e "${YELLOW}Next steps:${NC}" +echo "1. Go to https://pypi.org/manage/account/ → Publishing" +echo "2. Add trusted publisher with:" +echo " - Repository: ${REPO}" +echo " - Workflow: publish_pypi.yml" +echo " - Environment: pypi" +echo "" +echo "3. Do the same for https://test.pypi.org/ with environment: testpypi" +echo "" +echo -e "${GREEN}Then you're ready to publish!${NC}" \ No newline at end of file