mcp-server-microsoft-tasks 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_server_microsoft_tasks-0.1.0/.github/CODEOWNERS +6 -0
- mcp_server_microsoft_tasks-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- mcp_server_microsoft_tasks-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
- mcp_server_microsoft_tasks-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +26 -0
- mcp_server_microsoft_tasks-0.1.0/.github/copilot-instructions.md +6 -0
- mcp_server_microsoft_tasks-0.1.0/.github/dependabot.yml +7 -0
- mcp_server_microsoft_tasks-0.1.0/.github/gh-scripts/assign-repo-to-team.sh +70 -0
- mcp_server_microsoft_tasks-0.1.0/.github/gh-scripts/setup-branch-protection.sh +173 -0
- mcp_server_microsoft_tasks-0.1.0/.github/workflows/HARNESS_JOB.md +54 -0
- mcp_server_microsoft_tasks-0.1.0/.github/workflows/ci.yml +119 -0
- mcp_server_microsoft_tasks-0.1.0/.github/workflows/release.yml +51 -0
- mcp_server_microsoft_tasks-0.1.0/.gitignore +31 -0
- mcp_server_microsoft_tasks-0.1.0/.markdownlint.yaml +18 -0
- mcp_server_microsoft_tasks-0.1.0/AGENTS.md +178 -0
- mcp_server_microsoft_tasks-0.1.0/CHANGELOG.md +58 -0
- mcp_server_microsoft_tasks-0.1.0/CLAUDE.md +6 -0
- mcp_server_microsoft_tasks-0.1.0/CODE_OF_CONDUCT.md +43 -0
- mcp_server_microsoft_tasks-0.1.0/CONTRIBUTING.md +224 -0
- mcp_server_microsoft_tasks-0.1.0/ENGINEERING_PRINCIPLES.md +454 -0
- mcp_server_microsoft_tasks-0.1.0/LICENSE +21 -0
- mcp_server_microsoft_tasks-0.1.0/LICENSE-APACHE +184 -0
- mcp_server_microsoft_tasks-0.1.0/LICENSE-MIT +21 -0
- mcp_server_microsoft_tasks-0.1.0/PKG-INFO +246 -0
- mcp_server_microsoft_tasks-0.1.0/README.md +207 -0
- mcp_server_microsoft_tasks-0.1.0/SECURITY.md +39 -0
- mcp_server_microsoft_tasks-0.1.0/docs/app-concept.md +250 -0
- mcp_server_microsoft_tasks-0.1.0/docs/howto-oss.md +880 -0
- mcp_server_microsoft_tasks-0.1.0/docs/markdown-style.md +92 -0
- mcp_server_microsoft_tasks-0.1.0/docs/proposals/README.md +53 -0
- mcp_server_microsoft_tasks-0.1.0/docs/proposals/_template.md +47 -0
- mcp_server_microsoft_tasks-0.1.0/docs/testconcept.md +369 -0
- mcp_server_microsoft_tasks-0.1.0/pyproject.toml +135 -0
- mcp_server_microsoft_tasks-0.1.0/repo.ini +112 -0
- mcp_server_microsoft_tasks-0.1.0/scripts/README.md +36 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/__init__.py +14 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/__init__.py +248 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/flow.py +204 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/store.py +133 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/tokens.py +19 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/cli.py +99 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/login_state.py +60 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/server.py +458 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/__init__.py +16 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/_common.py +35 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/_shape.py +173 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/login_begin.py +220 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/login_status.py +145 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_buckets.py +64 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_plan_get.py +58 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_plans.py +145 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_task_get.py +119 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_tasks.py +95 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/tasks_assigned_to_me.py +170 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/tasks_search.py +167 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_list_get.py +61 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_lists.py +76 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_task_get.py +63 -0
- mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_tasks.py +88 -0
- mcp_server_microsoft_tasks-0.1.0/tests/conftest.py +36 -0
- mcp_server_microsoft_tasks-0.1.0/tests/harness/test_auth_smoke.py +82 -0
- mcp_server_microsoft_tasks-0.1.0/tests/harness/test_cross_source.py +63 -0
- mcp_server_microsoft_tasks-0.1.0/tests/harness/test_login_status.py +40 -0
- mcp_server_microsoft_tasks-0.1.0/tests/harness/test_planner_read.py +126 -0
- mcp_server_microsoft_tasks-0.1.0/tests/harness/test_todo_read.py +96 -0
- mcp_server_microsoft_tasks-0.1.0/tests/integration/__init__.py +0 -0
- mcp_server_microsoft_tasks-0.1.0/tests/integration/test_cross_source_tools.py +66 -0
- mcp_server_microsoft_tasks-0.1.0/tests/integration/test_planner_read_tools.py +151 -0
- mcp_server_microsoft_tasks-0.1.0/tests/integration/test_todo_read_tools.py +144 -0
- mcp_server_microsoft_tasks-0.1.0/tests/run_tests.sh +92 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/__init__.py +0 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_flow.py +148 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_init.py +203 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_store.py +100 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/test_cli.py +92 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/test_login_state.py +185 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/test_server.py +81 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/test_smoke.py +15 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/__init__.py +0 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_common.py +49 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_login_begin.py +450 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_login_status.py +362 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_buckets.py +84 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_plan_get.py +73 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_plans.py +152 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_task_get.py +138 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_tasks.py +166 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_tasks_assigned_to_me.py +228 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_tasks_search.py +157 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_list_get.py +94 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_lists.py +166 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_task_get.py +84 -0
- mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_tasks.py +195 -0
- mcp_server_microsoft_tasks-0.1.0/uv.lock +1307 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: "[BUG] "
|
|
5
|
+
labels: ["bug"]
|
|
6
|
+
assignees: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
|
|
10
|
+
|
|
11
|
+
## 🐛 Bug Description
|
|
12
|
+
|
|
13
|
+
A clear and concise description of what the bug is.
|
|
14
|
+
|
|
15
|
+
## 🔁 Steps to Reproduce
|
|
16
|
+
|
|
17
|
+
1. Go to '...'
|
|
18
|
+
2. Click on '....'
|
|
19
|
+
3. Scroll down to '....'
|
|
20
|
+
4. See error
|
|
21
|
+
|
|
22
|
+
## 🧐 Expected Behaviour
|
|
23
|
+
|
|
24
|
+
A clear and concise description of what you expected to happen.
|
|
25
|
+
|
|
26
|
+
## 😯 Actual Behaviour
|
|
27
|
+
|
|
28
|
+
A clear and concise description of what actually happened.
|
|
29
|
+
|
|
30
|
+
## 📸 Screenshots
|
|
31
|
+
|
|
32
|
+
If applicable, add screenshots to help explain your problem.
|
|
33
|
+
|
|
34
|
+
## 💻 Environment
|
|
35
|
+
|
|
36
|
+
- **OS:** [e.g. Linux, macOS, Windows]
|
|
37
|
+
- **Version:** [e.g. 1.0.0]
|
|
38
|
+
- **Toolchain:** [e.g. Rust 1.82, Node 20]
|
|
39
|
+
|
|
40
|
+
## 📋 Additional Context
|
|
41
|
+
|
|
42
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: "[FEAT] "
|
|
5
|
+
labels: ["enhancement"]
|
|
6
|
+
assignees: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
|
|
10
|
+
|
|
11
|
+
## ✨ Feature Description
|
|
12
|
+
|
|
13
|
+
A clear and concise description of what the feature is.
|
|
14
|
+
|
|
15
|
+
## 😫 Problem it Solves
|
|
16
|
+
|
|
17
|
+
Describe the problem your proposal solves. "I'm always frustrated when..."
|
|
18
|
+
|
|
19
|
+
## 💡 Possible Implementation
|
|
20
|
+
|
|
21
|
+
Describes how you imagine the implementation.
|
|
22
|
+
|
|
23
|
+
## 🔄 Alternatives Considered
|
|
24
|
+
|
|
25
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
26
|
+
|
|
27
|
+
## 📋 Additional Context
|
|
28
|
+
|
|
29
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
|
|
2
|
+
|
|
3
|
+
## 📝 Description
|
|
4
|
+
|
|
5
|
+
Please include a summary of the change and which issue is fixed.
|
|
6
|
+
|
|
7
|
+
Fixes # (issue)
|
|
8
|
+
|
|
9
|
+
## 🧪 Testing
|
|
10
|
+
|
|
11
|
+
Please describe the tests that you ran to verify your changes.
|
|
12
|
+
|
|
13
|
+
- [ ] Unit tests
|
|
14
|
+
- [ ] Integration tests
|
|
15
|
+
- [ ] Manual tests
|
|
16
|
+
|
|
17
|
+
## ✅ Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] My code follows the code style of this project
|
|
20
|
+
- [ ] I have performed a self-review of my own code
|
|
21
|
+
- [ ] I have commented my code, particularly in hard-to-understand areas
|
|
22
|
+
- [ ] I have made corresponding changes to the documentation
|
|
23
|
+
- [ ] My changes generate no new warnings
|
|
24
|
+
- [ ] I have added tests that prove my fix is effective or that my feature works
|
|
25
|
+
- [ ] New and existing unit tests pass locally with my changes
|
|
26
|
+
- [ ] Any dependent changes have been merged and published in downstream modules
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
|
|
2
|
+
# GitHub Copilot instructions
|
|
3
|
+
|
|
4
|
+
This file exists because GitHub Copilot auto-discovers it. The actual brief for any AI agent in this repo — Copilot, Codex, Claude Code, Cursor, Aider, all of them — is **[`AGENTS.md`](../AGENTS.md)** at the repo root. Read that first; it's the same content for every tool.
|
|
5
|
+
|
|
6
|
+
This file is intentionally minimal. If a Copilot-only convention ever becomes load-bearing (e.g. a Copilot-Chat-specific behaviour), capture it below this header — until then, this file is just a pointer so Copilot finds the brief at its conventional location.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-License-Identifier: MIT OR Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# assign-repo-to-team.sh
|
|
5
|
+
#
|
|
6
|
+
# Assigns the repository to a team with write access.
|
|
7
|
+
# Configuration is loaded from repo.ini in the repository root.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# ./.github/gh-scripts/assign-repo-to-team.sh
|
|
11
|
+
#
|
|
12
|
+
# Environment variables can override repo.ini values:
|
|
13
|
+
# ORG, REPO, TEAM_SLUG
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# ---------------------------
|
|
18
|
+
# Load configuration
|
|
19
|
+
# ---------------------------
|
|
20
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
22
|
+
CONFIG_FILE="${REPO_ROOT}/repo.ini"
|
|
23
|
+
|
|
24
|
+
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
25
|
+
echo ">> Loading configuration from repo.ini"
|
|
26
|
+
# shellcheck source=/dev/null
|
|
27
|
+
source "${CONFIG_FILE}"
|
|
28
|
+
else
|
|
29
|
+
echo "WARNING: repo.ini not found, using defaults/environment variables" >&2
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# ---------------------------
|
|
33
|
+
# Configuration (override via env)
|
|
34
|
+
# ---------------------------
|
|
35
|
+
ORG="${ORG:-XMV-Solutions-GmbH}"
|
|
36
|
+
REPO="${REPO:-oss-project-template}"
|
|
37
|
+
TEAM_SLUG="${TEAM_SLUG:-open-source}"
|
|
38
|
+
|
|
39
|
+
# ---------------------------
|
|
40
|
+
# Helpers
|
|
41
|
+
# ---------------------------
|
|
42
|
+
require_cmd() {
|
|
43
|
+
command -v "$1" >/dev/null 2>&1 || {
|
|
44
|
+
echo "ERROR: Missing required command: $1" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ---------------------------
|
|
50
|
+
# Preconditions
|
|
51
|
+
# ---------------------------
|
|
52
|
+
require_cmd gh
|
|
53
|
+
|
|
54
|
+
if ! gh auth status >/dev/null 2>&1; then
|
|
55
|
+
echo "ERROR: gh is not authenticated. Run: gh auth login" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# ---------------------------
|
|
60
|
+
# Execute
|
|
61
|
+
# ---------------------------
|
|
62
|
+
FULL_REPO="${ORG}/${REPO}"
|
|
63
|
+
|
|
64
|
+
echo ">> Granting write access to team '${TEAM_SLUG}' on repo '${FULL_REPO}'"
|
|
65
|
+
|
|
66
|
+
gh api -X PUT "orgs/${ORG}/teams/${TEAM_SLUG}/repos/${ORG}/${REPO}" \
|
|
67
|
+
-H "Accept: application/vnd.github+json" \
|
|
68
|
+
-f permission="push"
|
|
69
|
+
|
|
70
|
+
echo ">> Done."
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-License-Identifier: MIT OR Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# setup-branch-protection.sh
|
|
5
|
+
#
|
|
6
|
+
# Sets PR-only branch protection for the default branch (usually main),
|
|
7
|
+
# restricts direct pushes to a maintainer team, and requires CI status checks.
|
|
8
|
+
# Configuration is loaded from repo.ini in the repository root.
|
|
9
|
+
#
|
|
10
|
+
# Usage:
|
|
11
|
+
# ./.github/gh-scripts/setup-branch-protection.sh
|
|
12
|
+
#
|
|
13
|
+
# Environment variables can override repo.ini values:
|
|
14
|
+
# ORG, REPO, BRANCH, TEAM_SLUG, REQUIRED_APPROVALS, etc.
|
|
15
|
+
#
|
|
16
|
+
# IMPORTANT:
|
|
17
|
+
# The required status check contexts MUST match the workflow/job names.
|
|
18
|
+
# Configure STATUS_CHECKS in repo.ini to match your CI workflow job names.
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
# ---------------------------
|
|
23
|
+
# Load configuration
|
|
24
|
+
# ---------------------------
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
27
|
+
CONFIG_FILE="${REPO_ROOT}/repo.ini"
|
|
28
|
+
|
|
29
|
+
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
30
|
+
echo ">> Loading configuration from repo.ini"
|
|
31
|
+
# shellcheck source=/dev/null
|
|
32
|
+
source "${CONFIG_FILE}"
|
|
33
|
+
else
|
|
34
|
+
echo "WARNING: repo.ini not found, using defaults/environment variables" >&2
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# ---------------------------
|
|
38
|
+
# Configuration (override via env)
|
|
39
|
+
# ---------------------------
|
|
40
|
+
ORG="${ORG:-XMV-Solutions-GmbH}"
|
|
41
|
+
REPO="${REPO:-oss-project-template}"
|
|
42
|
+
BRANCH="${BRANCH:-main}"
|
|
43
|
+
TEAM_SLUG="${TEAM_SLUG:-open-source}"
|
|
44
|
+
|
|
45
|
+
# PR review rules
|
|
46
|
+
REQUIRED_APPROVALS="${REQUIRED_APPROVALS:-0}"
|
|
47
|
+
REQUIRE_CODEOWNER_REVIEWS="${REQUIRE_CODEOWNER_REVIEWS:-false}"
|
|
48
|
+
DISMISS_STALE_REVIEWS="${DISMISS_STALE_REVIEWS:-true}"
|
|
49
|
+
|
|
50
|
+
# Admin enforcement
|
|
51
|
+
ENFORCE_ADMINS="${ENFORCE_ADMINS:-true}"
|
|
52
|
+
|
|
53
|
+
# Required status checks (comma-separated string from repo.ini)
|
|
54
|
+
# Format: "check1,check2" - commas separate checks, spaces are preserved within check names
|
|
55
|
+
# Example: "CI / lint,CI / test" results in two checks: "CI / lint" and "CI / test"
|
|
56
|
+
STATUS_CHECKS_STRING="${STATUS_CHECKS:-lint,test}"
|
|
57
|
+
|
|
58
|
+
# Convert comma-separated string to array, preserving spaces within check names
|
|
59
|
+
IFS=',' read -ra STATUS_CHECKS_ARRAY <<< "${STATUS_CHECKS_STRING}"
|
|
60
|
+
|
|
61
|
+
# Optional: allow certain actors to push to main besides team
|
|
62
|
+
EXTRA_USERS="${EXTRA_USERS:-}"
|
|
63
|
+
EXTRA_APPS="${EXTRA_APPS:-}"
|
|
64
|
+
|
|
65
|
+
FULL_REPO="${ORG}/${REPO}"
|
|
66
|
+
|
|
67
|
+
# ---------------------------
|
|
68
|
+
# Helpers
|
|
69
|
+
# ---------------------------
|
|
70
|
+
require_cmd() {
|
|
71
|
+
command -v "$1" >/dev/null 2>&1 || {
|
|
72
|
+
echo "ERROR: Missing required command: $1" >&2
|
|
73
|
+
exit 1
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
split_csv_to_json_array() {
|
|
78
|
+
local csv="${1:-}"
|
|
79
|
+
if [[ -z "${csv}" ]]; then
|
|
80
|
+
echo "[]"
|
|
81
|
+
return
|
|
82
|
+
fi
|
|
83
|
+
local normalized
|
|
84
|
+
normalized="$(echo "${csv}" | sed 's/[[:space:]]//g')"
|
|
85
|
+
echo "${normalized}" | awk -F',' '{
|
|
86
|
+
printf("[");
|
|
87
|
+
for (i=1; i<=NF; i++) {
|
|
88
|
+
printf("\"%s\"", $i);
|
|
89
|
+
if (i<NF) printf(",");
|
|
90
|
+
}
|
|
91
|
+
printf("]");
|
|
92
|
+
}'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
json_array_from_bash_array() {
|
|
96
|
+
# Print JSON array from STATUS_CHECKS_ARRAY bash array
|
|
97
|
+
printf '%s\n' "${STATUS_CHECKS_ARRAY[@]}" | jq -R . | jq -s .
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# ---------------------------
|
|
101
|
+
# Preconditions
|
|
102
|
+
# ---------------------------
|
|
103
|
+
require_cmd gh
|
|
104
|
+
require_cmd jq
|
|
105
|
+
|
|
106
|
+
if ! gh auth status >/dev/null 2>&1; then
|
|
107
|
+
echo "ERROR: gh is not authenticated. Run: gh auth login" >&2
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo ">> Repo: ${FULL_REPO}"
|
|
112
|
+
gh repo view "${FULL_REPO}" >/dev/null
|
|
113
|
+
|
|
114
|
+
echo ">> Team: ${ORG}/${TEAM_SLUG}"
|
|
115
|
+
gh api "orgs/${ORG}/teams/${TEAM_SLUG}" >/dev/null
|
|
116
|
+
|
|
117
|
+
USERS_JSON="$(split_csv_to_json_array "${EXTRA_USERS}")"
|
|
118
|
+
APPS_JSON="$(split_csv_to_json_array "${EXTRA_APPS}")"
|
|
119
|
+
CHECKS_JSON="$(json_array_from_bash_array)"
|
|
120
|
+
|
|
121
|
+
echo ">> Required status checks:"
|
|
122
|
+
echo "${CHECKS_JSON}" | jq -r '.[]' | sed 's/^/ - /'
|
|
123
|
+
|
|
124
|
+
# ---------------------------
|
|
125
|
+
# Apply protection
|
|
126
|
+
# ---------------------------
|
|
127
|
+
echo ">> Applying branch protection to ${FULL_REPO}:${BRANCH}"
|
|
128
|
+
|
|
129
|
+
# Build the simplified JSON payload for the PUT request
|
|
130
|
+
# Note: GitHub API strictness requires proper JSON types (booleans as true/false, not strings)
|
|
131
|
+
PAYLOAD=$(jq -n \
|
|
132
|
+
--arg enforce_admins "$ENFORCE_ADMINS" \
|
|
133
|
+
--arg required_approvals "$REQUIRED_APPROVALS" \
|
|
134
|
+
--arg dismiss_stale "$DISMISS_STALE_REVIEWS" \
|
|
135
|
+
--arg code_owner "$REQUIRE_CODEOWNER_REVIEWS" \
|
|
136
|
+
--arg team_slug "$TEAM_SLUG" \
|
|
137
|
+
--argjson checks "$CHECKS_JSON" \
|
|
138
|
+
--argjson extra_users "$USERS_JSON" \
|
|
139
|
+
--argjson extra_apps "$APPS_JSON" \
|
|
140
|
+
'{
|
|
141
|
+
required_status_checks: {
|
|
142
|
+
strict: true,
|
|
143
|
+
contexts: $checks
|
|
144
|
+
},
|
|
145
|
+
enforce_admins: ($enforce_admins == "true"),
|
|
146
|
+
required_pull_request_reviews: {
|
|
147
|
+
dismiss_stale_reviews: ($dismiss_stale == "true"),
|
|
148
|
+
require_code_owner_reviews: ($code_owner == "true"),
|
|
149
|
+
required_approving_review_count: ($required_approvals | tonumber),
|
|
150
|
+
require_last_push_approval: false
|
|
151
|
+
},
|
|
152
|
+
restrictions: {
|
|
153
|
+
users: $extra_users,
|
|
154
|
+
teams: [$team_slug],
|
|
155
|
+
apps: $extra_apps
|
|
156
|
+
},
|
|
157
|
+
required_conversation_resolution: true,
|
|
158
|
+
allow_force_pushes: false,
|
|
159
|
+
allow_deletions: false
|
|
160
|
+
}'
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
echo ">> Config Payload generated"
|
|
164
|
+
|
|
165
|
+
# Send the request
|
|
166
|
+
echo "$PAYLOAD" | gh api -X PUT "repos/${FULL_REPO}/branches/${BRANCH}/protection" \
|
|
167
|
+
-H "Accept: application/vnd.github+json" \
|
|
168
|
+
--input - \
|
|
169
|
+
>/dev/null
|
|
170
|
+
|
|
171
|
+
echo ">> Done."
|
|
172
|
+
|
|
173
|
+
echo ">> NOTE: If checks don't exist yet, GitHub will not be able to enforce them until the workflow runs at least once."
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
|
|
2
|
+
# Harness job snippet
|
|
3
|
+
|
|
4
|
+
Drop the YAML below into `ci.yml` once the project has a real external sandbox to test against. The harness layer is the **gate** per [`ENGINEERING_PRINCIPLES.md` § 5](../../ENGINEERING_PRINCIPLES.md): no feature ticket lands before this is green.
|
|
5
|
+
|
|
6
|
+
The snippet is structured to match the rest of `ci.yml`. Two design choices are load-bearing:
|
|
7
|
+
|
|
8
|
+
- **`needs: test`** — run only after lint and test pass, so we don't burn an external-API call when the basics are red.
|
|
9
|
+
- **`if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository`** — skip silently on PRs from forks. Forks don't get repo secrets, so a fork PR running this job would fail with no useful signal. The skip-silently pattern is what the sister projects (sharepoint-mcp, outlook-mcp) settled on so external contributions aren't blocked on something they can't provide.
|
|
10
|
+
|
|
11
|
+
Inside the job: restore the credential from a base64-encoded repo secret, write it where the harness expects, run the harness suite. The "skip when secret is empty" early-exit means a freshly-cloned project with no secret configured still lands in the green path until the maintainer flips the harness on.
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
harness:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
needs: test
|
|
17
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
|
|
21
|
+
# Replace the language-setup steps with the project's stack.
|
|
22
|
+
# Example for Python:
|
|
23
|
+
# - uses: actions/setup-python@v6
|
|
24
|
+
# with:
|
|
25
|
+
# python-version: "3.11"
|
|
26
|
+
# - uses: astral-sh/setup-uv@v7
|
|
27
|
+
# - run: uv sync --extra dev
|
|
28
|
+
|
|
29
|
+
- name: Restore harness credential from repo secret
|
|
30
|
+
env:
|
|
31
|
+
# Project-specific secret name. Sister projects use
|
|
32
|
+
# SHAREPOINT_HARNESS_TOKEN_JSON / OUTLOOK_HARNESS_TOKEN_JSON.
|
|
33
|
+
HARNESS_CRED_B64: ${{ secrets.HARNESS_CRED_B64 }}
|
|
34
|
+
run: |
|
|
35
|
+
if [ -z "$HARNESS_CRED_B64" ]; then
|
|
36
|
+
echo "::warning::HARNESS_CRED_B64 not set — harness tests will be skipped."
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
mkdir -p ~/.cache/<project-name>/harness
|
|
40
|
+
printf '%s' "$HARNESS_CRED_B64" | base64 -d > ~/.cache/<project-name>/harness/cred.json
|
|
41
|
+
chmod 600 ~/.cache/<project-name>/harness/cred.json
|
|
42
|
+
echo "Harness credential restored ($(wc -c < ~/.cache/<project-name>/harness/cred.json) bytes)."
|
|
43
|
+
|
|
44
|
+
- name: Run harness tests against the real external system
|
|
45
|
+
run: ./tests/run_tests.sh harness
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Required-status-checks update
|
|
49
|
+
|
|
50
|
+
When you flip the harness job on, add `harness` to `STATUS_CHECKS` in `repo.ini` and re-run `.github/gh-scripts/setup-branch-protection.sh` so branch protection actually requires it.
|
|
51
|
+
|
|
52
|
+
## Token rotation
|
|
53
|
+
|
|
54
|
+
If the credential is a refresh token, it rotates every ~60–90 days for most providers. Add a recurring chore in `CLAUDE.md` and a `scripts/renew-harness-token.sh` (per [`ENGINEERING_PRINCIPLES.md` § 8](../../ENGINEERING_PRINCIPLES.md)) so renewing it is a one-command flow before CI starts failing on its own.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Three-job CI: lint / test / harness. Same shape as the sister
|
|
2
|
+
# Microsoft-Graph MCP projects (sharepoint-mcp, outlook-mcp). The
|
|
3
|
+
# harness job is gated behind a repo secret and skips silently when
|
|
4
|
+
# absent, so PRs from forks don't get blocked.
|
|
5
|
+
#
|
|
6
|
+
# Per ENGINEERING_PRINCIPLES § 6 (CI vigilance): every push is watched
|
|
7
|
+
# to completion; trunk red is a P0 incident.
|
|
8
|
+
|
|
9
|
+
name: CI
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
|
|
23
|
+
- name: Lint Markdown
|
|
24
|
+
uses: DavidAnson/markdownlint-cli2-action@v23
|
|
25
|
+
with:
|
|
26
|
+
globs: |
|
|
27
|
+
**/*.md
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v6
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.11"
|
|
33
|
+
|
|
34
|
+
- name: Install uv
|
|
35
|
+
uses: astral-sh/setup-uv@v7
|
|
36
|
+
|
|
37
|
+
- name: Install package + dev dependencies
|
|
38
|
+
run: uv sync --extra dev
|
|
39
|
+
|
|
40
|
+
- name: ruff check
|
|
41
|
+
run: uv run ruff check src tests
|
|
42
|
+
|
|
43
|
+
- name: ruff format check
|
|
44
|
+
run: uv run ruff format --check src tests
|
|
45
|
+
|
|
46
|
+
- name: mypy
|
|
47
|
+
run: uv run mypy src/microsoft_tasks_mcp tests
|
|
48
|
+
|
|
49
|
+
test:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v6
|
|
53
|
+
|
|
54
|
+
- name: Compare licences
|
|
55
|
+
run: diff LICENSE LICENSE-MIT
|
|
56
|
+
|
|
57
|
+
- name: Set up Python
|
|
58
|
+
uses: actions/setup-python@v6
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.11"
|
|
61
|
+
|
|
62
|
+
- name: Install uv
|
|
63
|
+
uses: astral-sh/setup-uv@v7
|
|
64
|
+
|
|
65
|
+
- name: Install package + dev dependencies
|
|
66
|
+
run: uv sync --extra dev
|
|
67
|
+
|
|
68
|
+
- name: Run unit + integration tests with coverage
|
|
69
|
+
run: ./tests/run_tests.sh
|
|
70
|
+
|
|
71
|
+
- name: Upload coverage to Codecov
|
|
72
|
+
if: ${{ hashFiles('coverage.xml') != '' }}
|
|
73
|
+
uses: codecov/codecov-action@v5
|
|
74
|
+
with:
|
|
75
|
+
files: coverage.xml
|
|
76
|
+
fail_ci_if_error: false
|
|
77
|
+
verbose: false
|
|
78
|
+
|
|
79
|
+
harness:
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
needs: test
|
|
82
|
+
# Run harness tests against the real Microsoft 365 sandbox using the
|
|
83
|
+
# cached refresh token from the MS_TASKS_HARNESS_TOKEN_JSON secret.
|
|
84
|
+
# Skips silently when the secret isn't available (e.g. on PRs from
|
|
85
|
+
# forks where secrets aren't passed) so external contributions
|
|
86
|
+
# aren't blocked on something they can't provide.
|
|
87
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
|
88
|
+
steps:
|
|
89
|
+
- uses: actions/checkout@v6
|
|
90
|
+
|
|
91
|
+
- name: Set up Python
|
|
92
|
+
uses: actions/setup-python@v6
|
|
93
|
+
with:
|
|
94
|
+
python-version: "3.11"
|
|
95
|
+
|
|
96
|
+
- name: Install uv
|
|
97
|
+
uses: astral-sh/setup-uv@v7
|
|
98
|
+
|
|
99
|
+
- name: Install package + dev dependencies
|
|
100
|
+
run: uv sync --extra dev
|
|
101
|
+
|
|
102
|
+
- name: Restore harness token cache from secret
|
|
103
|
+
env:
|
|
104
|
+
TOKEN_B64: ${{ secrets.MS_TASKS_HARNESS_TOKEN_JSON }}
|
|
105
|
+
run: |
|
|
106
|
+
if [ -z "$TOKEN_B64" ]; then
|
|
107
|
+
echo "::warning::MS_TASKS_HARNESS_TOKEN_JSON not set — harness tests will be skipped."
|
|
108
|
+
exit 0
|
|
109
|
+
fi
|
|
110
|
+
mkdir -p ~/.cache/mcp-server-microsoft-tasks/harness
|
|
111
|
+
printf '%s' "$TOKEN_B64" | base64 -d > ~/.cache/mcp-server-microsoft-tasks/harness/token.json
|
|
112
|
+
chmod 600 ~/.cache/mcp-server-microsoft-tasks/harness/token.json
|
|
113
|
+
echo "Harness token cache restored ($(wc -c < ~/.cache/mcp-server-microsoft-tasks/harness/token.json) bytes)."
|
|
114
|
+
|
|
115
|
+
- name: Run harness tests against real Microsoft Graph
|
|
116
|
+
env:
|
|
117
|
+
# Use plain-file backend explicitly (CI runners have no keyring).
|
|
118
|
+
MS_TASKS_TOKEN_STORE: file
|
|
119
|
+
run: ./tests/run_tests.sh harness
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write # for PyPI Trusted Publisher (OIDC)
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-and-publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment:
|
|
16
|
+
name: pypi
|
|
17
|
+
url: https://pypi.org/p/mcp-server-microsoft-tasks
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v7
|
|
28
|
+
|
|
29
|
+
- name: Install package + dev dependencies
|
|
30
|
+
run: uv sync --extra dev
|
|
31
|
+
|
|
32
|
+
- name: Run unit + integration tests (gate)
|
|
33
|
+
run: ./tests/run_tests.sh
|
|
34
|
+
|
|
35
|
+
- name: Build wheel + sdist
|
|
36
|
+
run: uv build
|
|
37
|
+
|
|
38
|
+
- name: Publish to PyPI (OIDC Trusted Publisher)
|
|
39
|
+
# Requires PyPI Trusted Publisher configured for this repo +
|
|
40
|
+
# the `pypi` GH environment.
|
|
41
|
+
run: uv publish
|
|
42
|
+
|
|
43
|
+
github-release:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
needs: build-and-publish
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v6
|
|
48
|
+
- name: Create GitHub Release
|
|
49
|
+
uses: softprops/action-gh-release@v3
|
|
50
|
+
with:
|
|
51
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Claude Code per-machine settings (bypass permissions etc.)
|
|
2
|
+
.claude/settings.local.json
|
|
3
|
+
.claude/scheduled_tasks.lock
|
|
4
|
+
.claude/scheduled_tasks.json
|
|
5
|
+
|
|
6
|
+
# Python
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
|
|
15
|
+
# Editor / OS
|
|
16
|
+
.vscode/
|
|
17
|
+
.idea/
|
|
18
|
+
*.swp
|
|
19
|
+
.DS_Store
|
|
20
|
+
|
|
21
|
+
# Local secrets / token caches (should never land in OSS repo)
|
|
22
|
+
.env
|
|
23
|
+
.env.local
|
|
24
|
+
*.pem
|
|
25
|
+
secrets/
|
|
26
|
+
|
|
27
|
+
# Coverage artefacts
|
|
28
|
+
.coverage
|
|
29
|
+
.coverage.*
|
|
30
|
+
coverage.xml
|
|
31
|
+
htmlcov/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR Apache-2.0
|
|
2
|
+
# Markdownlint configuration
|
|
3
|
+
# See: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
|
|
4
|
+
|
|
5
|
+
# Disable line length rule - impractical for documentation with URLs
|
|
6
|
+
MD013: false
|
|
7
|
+
|
|
8
|
+
# Allow first heading to not be h1 (for templates with frontmatter)
|
|
9
|
+
MD041: false
|
|
10
|
+
|
|
11
|
+
# Disable table column style rule - we prefer aligned tables for readability
|
|
12
|
+
MD060: false
|
|
13
|
+
|
|
14
|
+
# Allow duplicate headings as long as they're not siblings.
|
|
15
|
+
# This is required for Keep-a-Changelog: every release section has
|
|
16
|
+
# its own "Added" / "Changed" / "Removed" subsections.
|
|
17
|
+
MD024:
|
|
18
|
+
siblings_only: true
|