{"id":19623556,"url":"https://github.com/marcpage/devops-driver","last_synced_at":"2025-04-28T04:31:49.830Z","repository":{"id":204268929,"uuid":"711468758","full_name":"marcpage/devops-driver","owner":"marcpage","description":"DevOps tools","archived":false,"fork":false,"pushed_at":"2025-04-21T11:39:28.000Z","size":297,"stargazers_count":1,"open_issues_count":6,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-27T18:07:03.845Z","etag":null,"topics":["azure","azure-devops","devops","devops-pipeline","devops-tools","devops-workflow","email","pipelines"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/devopsdriver/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcpage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-29T11:13:11.000Z","updated_at":"2025-01-24T13:08:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"55a830a8-6868-4d49-ad25-e5fb655ef477","html_url":"https://github.com/marcpage/devops-driver","commit_stats":null,"previous_names":["marcpage/devops-driver"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcpage%2Fdevops-driver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcpage%2Fdevops-driver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcpage%2Fdevops-driver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcpage%2Fdevops-driver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcpage","download_url":"https://codeload.github.com/marcpage/devops-driver/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251252190,"owners_count":21559739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","azure-devops","devops","devops-pipeline","devops-tools","devops-workflow","email","pipelines"],"created_at":"2024-11-11T11:34:24.842Z","updated_at":"2025-04-28T04:31:49.527Z","avatar_url":"https://github.com/marcpage.png","language":"Python","readme":"![status sheild](https://img.shields.io/static/v1?label=status\u0026message=beta\u0026color=blue\u0026style=plastic)\n[![status sheild](https://img.shields.io/static/v1?label=released\u0026message=v0.1.48\u0026color=active\u0026style=plastic)](https://pypi.org/project/devopsdriver/0.1.48/)\n[![GitHub](https://img.shields.io/github/license/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver?tab=Unlicense-1-ov-file#readme)\n[![GitHub contributors](https://img.shields.io/github/contributors/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/graphs/contributors)\n[![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)\n\n[![commit sheild](https://img.shields.io/github/last-commit/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver/commits)\n[![activity sheild](https://img.shields.io/github/commit-activity/m/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver/commits)\n[![GitHub top language](https://img.shields.io/github/languages/top/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver)\n[![size sheild](https://img.shields.io/github/languages/code-size/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver)\n\n[![example workflow](https://github.com/marcpage/devops-driver/actions/workflows/pr.yml/badge.svg)](https://github.com/marcpage/devops-driver/actions/workflows/pr.yml)\n[![status sheild](https://img.shields.io/static/v1?label=test+coverage\u0026message=99%\u0026color=active\u0026style=plastic)](https://github.com/marcpage/devops-driver/blob/main/Makefile#L4)\n[![issues sheild](https://img.shields.io/github/issues-raw/marcpage/devops-driver?style=plastic)](https://github.com/marcpage/devops-driver/issues)\n[![GitHub pull requests](https://img.shields.io/github/issues-pr/marcpage/devops-driver?style=flat)](https://github.com/marcpage/devops-driver/pulls)\n\n[![follow sheild](https://img.shields.io/github/followers/marcpage?label=Follow\u0026style=social)](https://github.com/marcpage?tab=followers)\n[![watch sheild](https://img.shields.io/github/watchers/marcpage/devops-driver?label=Watch\u0026style=social)](https://github.com/marcpage/devops-driver/watchers)\n\n[![Python](https://img.shields.io/static/v1?label=\u0026message=Pure%20Python\u0026color=ffde57\u0026style=plastic\u0026logo=python)](https://python.org/)\n[![Azure](https://img.shields.io/static/v1?label=\u0026message=Supports%20Microsoft%20Azure\u0026color=blue\u0026style=plastic\u0026logo=microsoftazure)](https://azure.microsoft.com/)\n[![Gmail](https://img.shields.io/static/v1?label=\u0026message=Supports%20Google%20Gmail\u0026color=white\u0026style=plastic\u0026logo=gmail)](https://gmail.com/)\n\nOS: \n[![Windows](https://img.shields.io/static/v1?label=\u0026message=Windows\u0026color=blue\u0026style=plastic\u0026logo=windows)](https://microsoft.com/)\n[![macOS](https://img.shields.io/static/v1?label=\u0026message=macOS\u0026color=white\u0026logoColor=black\u0026style=plastic\u0026logo=apple)](https://apple.com/)\n[![Linux](https://img.shields.io/static/v1?label=\u0026message=Linux\u0026color=seashell\u0026logoColor=black\u0026style=plastic\u0026logo=linux)](https://linux.org/)\n\n# devops-driver\n\nDevops-driver is a collection of tools to help streamline developer's experience and gain insights into various processes.\n\n## Tools\n\ndevopsdriver is a toolbox that helps to quickly put together reports. Some of the items in the toolbox are:\n\n- **Settings**: store data, constants, settings, keys, tokens, etc. both in and out of the repository\n- **send_email**: send emails over SMTP (including SSL), using `Settings` to store credentials\n- **Template**: Simplify generating reports using `.mako` templates\n- **Azure.workitem**: Search for and inspect Azure DevOps work items\n\n## Example use-case\n\nTo allow seamless work in both pipelines as well as in the development environment, the `Settings` object gives you access to common settings among multiple scripts, secrets, and configuration constants in a way the helps keep secrets out of the repository but runs just as well in the pipeline as your machine.\n\nSay you want a pipeline that looks for User Stories that are newer than 3 days and send out an email.\n\n### \\\u003cplatform dependent path\\\u003e/devopsdriver.yml\n```yaml\nsmtp:\n    sender: JohnDoe@company.com\n\nsecrets:\n    azure.token: azure/token\n    smtp.password: smtp/password\n```\n\nThis file is in a global place (location varies by OS) and stores information that you may not want in your repository or is specific to development. \n\n| Platform | Global Directory       |\n|----------|------------------------|\n| Windows  | %APPDATA%\\             |\n| Linux    | ~/.devopsdriver/       |\n| macOS    | ~/Library/Preferences/ |\n\nThe `secrets` are extra sensative and are stored in the OS keychain.\n\n### Set secrets in the keychain\n```bash\n$ python3 -m venv .venv\n$ source .venv/bin/activate\n$ pip install devopsdriver\n$ settings --secrets\nsecret: smtp.password  key: smtp/password\nsmtp.password (smtp/password): ****\nsecret: azure.token  key: azure/token\nsmtp.password (azure/token): ****\n$ settings --secrets\nsecret: azure.token  key: azure/token\n\tValue set\nsecret: smtp.password  key: smtp/password\n\tValue set\n$\n```\nThe first call to `settings` will look for every secret and check if they are already set in the keychain.\nFor any secret that has not been set in the keychain, you will be prompted to enter the password to store.\nThe second call to `settings` will verify that all the values have been set in the keychain.\n\n### devopsdriver.yml\n```yaml\nazure:\n    url: https://dev.azure.com/MyCompany\n\nsmtp:\n    server: smtp.company.com\n    port: 465\n\ncli:\n    azure.token: --azure-token\n    smtp.password: --smtp-password\n    smtp.sender: --smtp-sender\n\nenv:\n    azure.token: AZURE_TOKEN\n    smtp.sender: SMTP_SENDER\n    smtp.password: SMTP_PASSWORD\n```\n\nThis file lives next to your scripts in your repository.\nThese are settings that would be used by everyone, including the pipeline.\nThe `cli` and `env` map command line switches and environment variables to those keys.\nThis allows for many options for setting values depending on your needs.\n\n### new_stories.yml\n```yaml\nscrum masters:\n    - JohnDoe@company.com\n    - JaneDoe@company.com\n```\nThis file is specific to your script and not shared.\nThese are values that you want to use in your script but have them here for easy adjustment.\n\n### new_stories.html.mako\n```html\n\u003ch1\u003eStories created in the last ${days} days\u003c/h1\u003e\n\u003cul\u003e\n    % for story in stories:\n    \u003cli\u003e${story.id} ${story.title}\u003c/li\u003e\n    % endfor\n\u003c/ul\u003e\n```\n\nThis file is the template for the email body.\n\n### new_stories.py\n```python\nfrom datetime import date, timedelta\n\nfrom devopsdriver import Settings, Azure, send_email, Template\nfrom devopsdriver.azdo import Wiql, GreaterThan\n\n# Parse all the settings from files, command line, environment, and keychain\nsettings = Settings(__file__).key(\"secrets\").cli(\"cli\").env(\"env\")\n\n# Create connection to Azure Devops\nazure = Azure(settings)\n\n# Get User Stories created in the last three days\nthree_days_ago = date.today() - timedelta(days=settings[\"days of recent stories\"])\nnew_stories = azure.workitem.find(\n    Wiql().where(GreaterThan(\"CreatedDate\", three_days_ago))\n)\n\n# Generate html body of the email\nmessage = Template(__file__).render(\n    days=settings[\"days of recent stories\"],\n    stories=new_stories,\n)\n\n# Send the email\nsend_email(\n    recipients=settings[\"scrum masters\"],\n    subject=f'Stories created in the last {settings[\"days of recent stories\"]} days',\n    html_body=message,\n    settings=settings,\n)\n```\n\n### The email sent\n\n**From**: JohnDoe@company.com\n\n**To**: JohnDoe@company.com, JaneDoe@company.com\n\n**Subject**: Stories created in the last 3 days\n\n#### Stories created in the last 3 days\n\n- 745 Needs a preprocessing step that makes it case insensitive\n- 749 Create GitHub action to automate process\n- 750 Create GitHub action to automate process\n- 751 Test\n- 752 Feedback Capture\n- 753 draft doc history retrieval method\n- 754 frontend - store to schema\n- 755 Transfer job to production. Setup migrations to move to production\n- 756 Query subscription status from App\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcpage%2Fdevops-driver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcpage%2Fdevops-driver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcpage%2Fdevops-driver/lists"}