Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
eaa0c88
Merge pull request #1 from Sreddx/master
Sreddx Nov 4, 2025
8f5db26
Add documentation for repository guidelines and update usage examples
Sreddx Nov 5, 2025
0d7dbc7
Add Logic App integration for work item fetching and update configura…
Sreddx Nov 10, 2025
156759b
Merge pull request #2 from iNBest-cloud/bug-fix/estimate-hours
Sreddx Nov 10, 2025
4b7fcd2
Add daily snapshot generation for automated tracking
Sreddx Nov 12, 2025
7bf03c8
Merge pull request #3 from iNBest-cloud/feature/daily-active-time-sna…
Sreddx Nov 12, 2025
ce9ef5d
Add daily snapshot workflow
Sreddx Nov 12, 2025
edf5368
Merge pull request #4 from iNBest-cloud/feature/git-action-yml
Sreddx Nov 12, 2025
30dfe6b
Update daily snapshot workflow schedule and descriptions
Sreddx Nov 12, 2025
5e2eaa6
Refactor daily snapshot workflow and improve work item query
Sreddx Nov 12, 2025
7833ea5
Merge pull request #5 from iNBest-cloud/feature/git-action-yml
Sreddx Nov 12, 2025
149f446
Refactor SharePoint upload step in daily snapshot workflow
Sreddx Nov 12, 2025
f12af99
Merge pull request #6 from iNBest-cloud/feat/added-upload-step
Sreddx Nov 12, 2025
3da22a5
Enhance daily snapshot workflow and documentation
Sreddx Nov 13, 2025
24e721e
Update content type header in SharePoint upload step of daily snapsho…
Sreddx Nov 13, 2025
46029a3
Merge pull request #7 from iNBest-cloud/feature/active-time-filtering
Sreddx Nov 13, 2025
36693b4
Change cron schedule for daily snapshot workflow
Sreddx Nov 20, 2025
cfd559f
Merge pull request #8 from iNBest-cloud/time-fix-7am
Sreddx Nov 20, 2025
d2e901a
Optimized flag removal
Sreddx Dec 4, 2025
fe3fc31
Merge pull request #9 from iNBest-cloud/fix/optimized-flag-removal
Sreddx Dec 4, 2025
bdd9b63
Fixed file naming for workflow detection
Sreddx Dec 4, 2025
57a063a
Merge pull request #10 from iNBest-cloud/fix/file-naming-bug
Sreddx Dec 4, 2025
1e27140
Add AZURE_LOGIC_APP_URL to workflow and enhance CSV export handling
Sreddx Dec 4, 2025
fb85831
Merge pull request #11 from iNBest-cloud/bug-fix/file-workflow
Sreddx Dec 4, 2025
6163214
Enhance date handling in EfficiencyCalculator and WorkItemOperations
Sreddx Dec 4, 2025
fc1222d
Merge pull request #12 from iNBest-cloud/fix/date-handling
Sreddx Dec 4, 2025
4fda96d
Enhance WorkItemOperations with additional date fields for improved t…
Sreddx Dec 4, 2025
9c0bc40
Merge pull request #13 from iNBest-cloud/fix/date-handling
Sreddx Dec 4, 2025
f447db6
added fernando agredano to list
Sreddx Jan 9, 2026
47bf579
Merge pull request #14 from iNBest-cloud/Sreddx-patch-1
Sreddx Jan 9, 2026
e9a7c73
Fixed file naming for workflow detection
Sreddx Jan 9, 2026
fca2119
Merge pull request #15 from iNBest-cloud/fix/dev-name
Sreddx Jan 9, 2026
e7c0be4
Add Fernando Agredano to user email mapping
Sreddx Jan 12, 2026
f1a084e
Merge pull request #16 from iNBest-cloud/agredano-patch
Sreddx Jan 12, 2026
30fa39a
Simplify documentation and add scoring parameter guide
Sreddx Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Azure DevOps Configuration
AZURE_DEVOPS_ORG=your-organization-name
AZURE_DEVOPS_PAT=your-personal-access-token

# Logic App URL for work item fetching (REQUIRED for --query-work-items)
# Replace with your actual Azure Logic App HTTP trigger URL
# The Logic App should accept POST requests with body: {"fromDate": "YYYY-MM-DD", "toDate": "YYYY-MM-DD", "emails": ["email1", "email2"]}
# And return: {"ResultSets": {"Table1": [{"WorkItemId": 123, "AssignedToUser": "user@domain.com", "Title": "...", "StartDate": "...", "TargetDate": "...", "OriginalEstimate": 5.0}]}}
AZURE_LOGIC_APP_URL=https://prod-xx.region.logic.azure.com:443/workflows/YOUR_WORKFLOW_ID/triggers/When_an_HTTP_request_is_received/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2FWhen_an_HTTP_request_is_received%2Frun&sv=1.0&sig=YOUR_SIGNATURE

# Webhook URLs (optional, for service hooks)
AZURE_DEVOPS_WORKITEM_WEBHOOK_URL=https://your-webhook-url/workitem
AZURE_DEVOPS_BUILD_WEBHOOK_URL=https://your-webhook-url/build
AZURE_DEVOPS_RELEASE_WEBHOOK_URL=https://your-webhook-url/release
82 changes: 74 additions & 8 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
# GitHub Actions Workflow Documentation

## Monthly Developer Report Workflow
## Available Workflows

Automated workflow that generates developer performance reports from Azure DevOps work items.
### 1. 📸 Daily Work Item Snapshot (`daily-snapshot.yml`)

**NEW!** Automated workflow that generates simplified daily snapshots with cumulative month-to-date data.

**Purpose:** Lightweight CSV reports for automated tracking via Logic App → SharePoint workflows.

**Schedule:** Runs daily at 01:00 UTC (7:00 PM CST previous day)

**Output Format:**
- Filename: `daily_snapshot_november.csv` (auto-switches monthly)
- 12 columns: ID, Title, Project, Assigned To, State, Type, Dates, Hours
- Contains cumulative data from 1st of month to current day
- File overwrites daily - one file per month

**Performance:** 40-60% faster than full query (10-40 seconds for 100-400 items)

---

### 2. 📊 Monthly Developer Report (`monthly-developer-report.yml`)

Automated workflow that generates comprehensive developer performance reports with KPIs from Azure DevOps work items.

### Features

Expand All @@ -17,16 +37,18 @@ Automated workflow that generates developer performance reports from Azure DevOp

### 1. Configure GitHub Secrets

The workflow requires two secrets to be configured in the `main` environment:
Both workflows require the following secrets to be configured in the `main` environment:

1. Go to your GitHub repository
2. Navigate to **Settings** → **Environments** → **main** (create if it doesn't exist)
3. Add the following secrets:

| Secret Name | Description | Example |
|-------------|-------------|---------|
| `AZURE_DEVOPS_ORG` | Your Azure DevOps organization name | `MyCompany` |
| `AZURE_DEVOPS_PAT` | Personal Access Token with Work Items: Read permission | `a1b2c3d4...` |
| Secret Name | Description | Required For | Example |
|-------------|-------------|--------------|---------|
| `AZURE_DEVOPS_ORG` | Azure DevOps organization name | Both workflows | `MyCompany` |
| `AZURE_DEVOPS_PAT` | Personal Access Token (Work Items: Read) | Both workflows | `a1b2c3d4...` |
| `AZURE_LOGIC_APP_URL` | Logic App URL for work item fetching | Both workflows | `https://prod-10...` |
| `SHAREPOINT_LOGIC_APP_URL` | Logic App URL for SharePoint upload | Daily Snapshot (optional) | `https://prod-11...` |

**To create a PAT:**
- Go to Azure DevOps → User Settings → Personal Access Tokens
Expand All @@ -44,7 +66,51 @@ The workflow requires two secrets to be configured in the `main` environment:

## Usage

### Automatic Monthly Reports
### Daily Snapshot Workflow

#### Automatic Daily Execution

The workflow runs automatically every day at **01:00 UTC** and:
1. Generates month-to-date cumulative snapshot
2. Creates/overwrites `daily_snapshot_<month>.csv`
3. Uploads to GitHub Actions artifacts (30-day retention)
4. Optionally uploads to SharePoint via Logic App

**Current Month File:**
- November: `daily_snapshot_november.csv`
- December: `daily_snapshot_december.csv`
- Auto-switches on 1st of each month

#### Manual Trigger

1. Go to **Actions** → **Daily Work Item Snapshot**
2. Click **Run workflow**
3. Configure options:
- **Snapshot mode:**
- `month-to-date` (recommended): Cumulative from 1st to today
- `yesterday`: Previous day only
- `today`: Current day up to now
- **Assigned to:** Filter by developers (optional, comma-separated)

#### Example Use Cases

**Test the snapshot:**
```
Snapshot mode: yesterday
Assigned to: (leave empty for all users)
```

**Generate specific developer snapshot:**
```
Snapshot mode: month-to-date
Assigned to: Carlos Vazquez,Diego Lopez
```

---

### Monthly Report Workflow

#### Automatic Monthly Reports

The workflow automatically runs on the **30th of each month at 23:00 UTC** and generates a report for:
- **Start Date**: 1st of the current month
Expand Down
167 changes: 167 additions & 0 deletions .github/workflows/daily-snapshot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
name: Daily Work Item Snapshot

on:
# Scheduled to run daily at 09:00 Mexico City time
schedule:
- cron: "0 13 * * *"

# Manual trigger for testing
workflow_dispatch:
inputs:
snapshot_mode:
description: "Snapshot mode"
required: false
type: choice
options:
- month-to-date
- yesterday
- today
default: "month-to-date"
assigned_to:
description: "Comma-separated list of developers (leave empty for all)"
required: false
type: string
default: ""

jobs:
generate-snapshot:
runs-on: ubuntu-latest
environment: main

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: Install dependencies
run: |
pip install -r requirements.txt

- name: Generate daily snapshot
env:
AZURE_DEVOPS_ORG: ${{ secrets.AZURE_DEVOPS_ORG }}
AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
AZURE_LOGIC_APP_URL: ${{ secrets.AZURE_LOGIC_APP_URL }}
run: |
# Determine snapshot mode
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
MODE="${{ inputs.snapshot_mode }}"
else
# Default for scheduled runs: month-to-date
MODE="month-to-date"
fi

# Build the command
CMD="python entry_points/main.py --daily-snapshot --snapshot-mode ${MODE}"

# Add assigned_to parameter if provided
if [ -n "${{ inputs.assigned_to }}" ]; then
CMD="${CMD} --assigned-to \"${{ inputs.assigned_to }}\""
fi

echo "Executing: ${CMD}"
eval $CMD

- name: Identify generated snapshot file
id: file
run: |
# Find the generated snapshot file
if [ -f "daily_snapshot_november.csv" ]; then
FILE="daily_snapshot_november.csv"
elif [ -f "daily_snapshot_december.csv" ]; then
FILE="daily_snapshot_december.csv"
elif [ -f "daily_snapshot_january.csv" ]; then
FILE="daily_snapshot_january.csv"
elif [ -f "daily_snapshot_february.csv" ]; then
FILE="daily_snapshot_february.csv"
elif [ -f "daily_snapshot_march.csv" ]; then
FILE="daily_snapshot_march.csv"
elif [ -f "daily_snapshot_april.csv" ]; then
FILE="daily_snapshot_april.csv"
elif [ -f "daily_snapshot_may.csv" ]; then
FILE="daily_snapshot_may.csv"
elif [ -f "daily_snapshot_june.csv" ]; then
FILE="daily_snapshot_june.csv"
elif [ -f "daily_snapshot_july.csv" ]; then
FILE="daily_snapshot_july.csv"
elif [ -f "daily_snapshot_august.csv" ]; then
FILE="daily_snapshot_august.csv"
elif [ -f "daily_snapshot_september.csv" ]; then
FILE="daily_snapshot_september.csv"
elif [ -f "daily_snapshot_october.csv" ]; then
FILE="daily_snapshot_october.csv"
else
# Fallback: find any daily_snapshot_*.csv file
FILE=$(ls -t daily_snapshot_*.csv 2>/dev/null | head -1)
fi

if [ -z "$FILE" ]; then
echo "Error: No snapshot file found"
exit 1
fi

echo "snapshot_file=${FILE}" >> $GITHUB_OUTPUT
echo "Found snapshot file: ${FILE}"

- name: Upload snapshot to artifacts
uses: actions/upload-artifact@v4
with:
name: daily-snapshot-${{ steps.file.outputs.snapshot_file }}
path: ${{ steps.file.outputs.snapshot_file }}
retention-days: 30

# Optional: Upload to SharePoint via Logic App
- name: Upload to SharePoint
if: success()
run: |
curl -f -S -X POST "${{ secrets.SHAREPOINT_LOGIC_APP_URL }}" \
-H "Content-Type: text/csv; charset=utf-8" \
-H "x-file-name: ${{ steps.file.outputs.snapshot_file }}" \
--data-binary "@${{ steps.file.outputs.snapshot_file }}" || {
echo "Error: Failed to upload to SharePoint"
exit 1
}

- name: Create snapshot summary
run: |
echo "## Daily Work Item Snapshot Generated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Snapshot File:** \`${{ steps.file.outputs.snapshot_file }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# Show file details
if [ -f "${{ steps.file.outputs.snapshot_file }}" ]; then
SIZE=$(du -h "${{ steps.file.outputs.snapshot_file }}" | cut -f1)
LINES=$(wc -l < "${{ steps.file.outputs.snapshot_file }}")
ITEMS=$((LINES - 1))

echo "**File Size:** ${SIZE}" >> $GITHUB_STEP_SUMMARY
echo "**Work Items:** ${ITEMS}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# Calculate totals
ACTIVE_HOURS=$(awk -F',' 'NR>1 {sum+=$11} END {printf "%.2f", sum}' "${{ steps.file.outputs.snapshot_file }}")
BLOCKED_HOURS=$(awk -F',' 'NR>1 {sum+=$12} END {printf "%.2f", sum}' "${{ steps.file.outputs.snapshot_file }}")

echo "**Cumulative Hours:**" >> $GITHUB_STEP_SUMMARY
echo "- Active: ${ACTIVE_HOURS} hours" >> $GITHUB_STEP_SUMMARY
echo "- Blocked: ${BLOCKED_HOURS} hours" >> $GITHUB_STEP_SUMMARY
fi

- name: Notify on failure
if: failure()
run: |
echo "## ⚠️ Daily Snapshot Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The daily snapshot generation failed. Please check the logs for details." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Common Issues:**" >> $GITHUB_STEP_SUMMARY
echo "- Azure DevOps credentials expired" >> $GITHUB_STEP_SUMMARY
echo "- Logic App URL not configured" >> $GITHUB_STEP_SUMMARY
echo "- Network connectivity issues" >> $GITHUB_STEP_SUMMARY

20 changes: 9 additions & 11 deletions .github/workflows/monthly-developer-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ name: Monthly Developer Report
on:
# Scheduled to run on the 30th of every month at 23:00 UTC
schedule:
- cron: '0 23 30 * *'
- cron: "0 23 30 * *"

# Manual trigger with customizable date range
workflow_dispatch:
inputs:
start_date:
description: 'Start date (YYYY-MM-DD)'
description: "Start date (YYYY-MM-DD)"
required: true
type: string
end_date:
description: 'End date (YYYY-MM-DD)'
description: "End date (YYYY-MM-DD)"
required: true
type: string
assigned_to:
description: 'Comma-separated list of developers (leave empty for all)'
description: "Comma-separated list of developers (leave empty for all)"
required: false
type: string
default: ''
default: ""

jobs:
generate-report:
Expand All @@ -34,8 +34,8 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
python-version: "3.11"
cache: "pip"

- name: Install dependencies
run: |
Expand Down Expand Up @@ -77,6 +77,7 @@ jobs:
env:
AZURE_DEVOPS_ORG: ${{ secrets.AZURE_DEVOPS_ORG }}
AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
AZURE_LOGIC_APP_URL: ${{ secrets.AZURE_LOGIC_APP_URL }}
run: |
# Determine which developers to use
if [ -n "${{ inputs.assigned_to }}" ]; then
Expand All @@ -91,7 +92,6 @@ jobs:
CMD="python run.py --query-work-items \
--start-date ${{ steps.dates.outputs.start_date }} \
--end-date ${{ steps.dates.outputs.end_date }} \
--optimized \
--export-csv developer_report_${{ steps.dates.outputs.filename_suffix }}.csv"

# Add assigned_to parameter
Expand All @@ -106,9 +106,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: developer-report-${{ steps.dates.outputs.filename_suffix }}
path: |
developer_report_${{ steps.dates.outputs.filename_suffix }}.csv
developer_report_${{ steps.dates.outputs.filename_suffix }}_developer_summary.csv
path: developer_report_${{ steps.dates.outputs.filename_suffix }}*.csv
retention-days: 90

- name: Create report summary
Expand Down
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Repository Guidelines

## Project Structure & Module Organization
Core logic resides in `classes/`: `WorkItemOperations` handles analytics queries, `AzureDevOpsProjectOperations` covers project metadata, and `commands.py` wires CLI actions. Invoke the tool through `entry_points/main.py` (or the wrapper `run.py`). Defaults live in `config/` (`config.py`, `azure_devops_config.json`), supporting utilities in `helpers/`, reference docs in `documentation/`, and reusable SQL in `sql/`. CSV exports default to the repo root unless `--export-csv` points elsewhere.

## Build, Test, and Development Commands
- `python -m venv .venv && source .venv/bin/activate` — set up an isolated environment.
- `pip install -r requirements.txt` — install dependencies (requests, azure-devops SDK, dotenv, pyodbc, azure-identity).
- `python run.py --help` or `--explain` — review supported flags and command descriptions.
- `python run.py --list-projects` — smoke-test connectivity to the organization.
- `python run.py --query-work-items --assigned-to "Jane Doe" --start-date "2024-10-01" --end-date "2024-10-31" --export-csv reports/october.csv` — representative analytics run with CSV output.

## Coding Style & Naming Conventions
Follow standard Python style: four-space indentation, snake_case for functions and variables, PascalCase for classes, and module docstrings when modules have side effects. Prefer explicit imports from `classes` modules so CLI wiring stays readable. When extending commands, mirror the parser patterns in `entry_points/main.py` and keep user-facing logging concise.

## Testing Guidelines
No automated suite exists yet; validate changes by running representative CLI commands against a non-production Azure DevOps organization. Exercise project discovery (`--list-projects`, `--create-hooks-for-filtered-projects`) and analytics flows (`--query-work-items`, toggling `--optimized`). Capture CSV or terminal summaries to confirm metrics, and isolate reusable logic into functions or classes to keep future unit tests straightforward.

## Commit & Pull Request Guidelines
Recent commits use short, imperative subjects (for example, “Add developer summary CSV and SQL queries for estimated hours”). Keep subjects under 72 characters, expand on context and risk in the body, and reference Azure Boards items when applicable. Pull requests should describe the scenario, list touched commands or config files, attach sample output snippets or sanitized CSVs, and bundle documentation updates when behavior changes.

## Configuration & Security Tips
Store secrets in `.env` with `AZURE_DEVOPS_ORG` and `AZURE_DEVOPS_PAT`; never commit PATs or per-user overrides. Use `config/azure_devops_config.json` for shared defaults but keep credentials in environment variables. When exporting reports, route them to a dedicated folder and scrub personally identifiable information before sharing.
Loading