From 78dcc5de06b0d8d6f0617530a79259990d5626ad Mon Sep 17 00:00:00 2001 From: Charles N Wyble Date: Mon, 16 Dec 2024 09:19:07 -0600 Subject: [PATCH] . --- dsr-input/README.md | 19 ++++ dsr-input/dsr-gather-gitea.sh | 83 ++++++++++++++ dsr-input/export-joplin-md.sh | 59 ++++++++++ dsr-joplin-create/dsr-new.sh | 97 ++++++++++++++++ dsr-joplin-create/dsr-populate-objectives.sh | 114 +++++++++++++++++++ endstops/end-day.sh | 35 ++++++ endstops/start-day.sh | 9 ++ local/build/BuildTemplate-2025Plan.yml | 12 ++ local/build/build-2025Plan.sh | 40 +++++++ 9 files changed, 468 insertions(+) create mode 100644 dsr-input/README.md create mode 100644 dsr-input/dsr-gather-gitea.sh create mode 100644 dsr-input/export-joplin-md.sh create mode 100644 dsr-joplin-create/dsr-new.sh create mode 100644 dsr-joplin-create/dsr-populate-objectives.sh create mode 100644 endstops/end-day.sh create mode 100644 endstops/start-day.sh create mode 100644 local/build/BuildTemplate-2025Plan.yml create mode 100644 local/build/build-2025Plan.sh diff --git a/dsr-input/README.md b/dsr-input/README.md new file mode 100644 index 0000000..ce51d7f --- /dev/null +++ b/dsr-input/README.md @@ -0,0 +1,19 @@ +# Data Gathering for the @ReachableCEO daily stakeholder report + +## Introduction + +I'm trying to life a fully instrumented CTO/founder life and #buildInPublic. And unlike most of the founders doing so, I'm actually publishing daily reports and live streaming my workstation all dya. + +I want to automate the instrumentation/reporting process as much as possible to get the highest fidelity information for stakeholders consumption. + +## Data sources + +- Apple Health (exporting via AutoHealthExport) +- Workout (evaluating a cou +- Nutrition +- Daily habit tracking +- ActivityWatch +- WakaAPI + + +## Scripts \ No newline at end of file diff --git a/dsr-input/dsr-gather-gitea.sh b/dsr-input/dsr-gather-gitea.sh new file mode 100644 index 0000000..f352cea --- /dev/null +++ b/dsr-input/dsr-gather-gitea.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Script to query Gitea API for a user's activity on a specific date + +######################################################################################################## +#Obtain gitea api key from bitwarden +######################################################################################################## + +#################################### +## Step 0: Set to use tsys server +#################################### +bw logout + +echo "Setting cli to use tsys bitwarden server..." +bw config server https://pwvault.turnsys.com + +#################################### +## Step 1: login to bitwarden +#################################### + +# From: https://bitwarden.com/help/cli/#using-an-api-key + +### Set apikey environment varaible + +echo "Sourcing clientid/apikey data..." +source D:/tsys/secrets/bitwarden/data/apikey-bitwarden-reachableceo + +### Login to vault using apikey... + +echo "Logging in..." +bw login --apikey $BW_CLIENTID $BW_CLIENTSECRET + +### Step 1.1: unlock / save session id + +echo "Unlocking..." +export BW_SESSION="$(bw unlock --passwordenv TSYS_BW_PASSWORD_REACHABLECEO --raw)" + + +### Step 2: retrive a value into an environment variable + +export GITEA_APIKEY="$(bw get password APIKEY-Gitea)" + +######################################################################################################## +# Accrss gitea data +######################################################################################################## + +# Script to query Gitea API for a user's activity on a specific date + +# Usage: ./get_gitea_user_activity.sh [GITEA_URL] [TOKEN] + +# Set username, date, and default Gitea URL +USERNAME="${1:-reachableceo}" # Default to "reachableceo" if not provided +DATE="${2:-$(date +%Y-%m-%d)}" # Default to today's date if not provided +GITEA_URL="${3:-https://git.knownelement.com}" # Default Gitea URL if not provided +TOKEN="${GITEA_APIKEY}" # Use APIKEY-GItea or passed argument + +# API Endpoint for user activities +API_ENDPOINT="$GITEA_URL/api/v1/users/$USERNAME/timeline" + +# Make the API call +if [ -n "$TOKEN" ]; then + # If token is provided, use it in the Authorization header + RESPONSE=$(curl -s -H "Authorization: token $TOKEN" "$API_ENDPOINT") +else + # If no token is provided, make an unauthenticated request + RESPONSE=$(curl -s "$API_ENDPOINT") +fi + +# Check for API errors +if [[ "$RESPONSE" == "Not found" || -z "$RESPONSE" ]]; then + echo "Error: User '$USERNAME' not found, or endpoint is incorrect." + exit 1 +fi + +# Validate JSON response +if ! echo "$RESPONSE" | jq empty >/dev/null 2>&1; then + echo "Error: Invalid JSON response from Gitea API." + echo "Response: $RESPONSE" + exit 1 +fi + +# Filter the activity by date using jq +echo "$RESPONSE" | jq --arg date "$DATE" '[.[] | select(.created_at | startswith($date))]' \ No newline at end of file diff --git a/dsr-input/export-joplin-md.sh b/dsr-input/export-joplin-md.sh new file mode 100644 index 0000000..943d39a --- /dev/null +++ b/dsr-input/export-joplin-md.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Functions + +# Search for a note by title and return its ID +search_note() { + local title="$1" + echo "Searching for note with title: $title" + note_id=$(joplin search "$title" --fields id --limit 1 --json | jq -r '.[0].id') + + if [[ -z "$note_id" || "$note_id" == "null" ]]; then + echo "Error: Note with title '$title' not found." + exit 1 + fi + + echo "Found note with ID: $note_id" + echo "$note_id" +} + +# Export the note by ID to the specified directory +export_note() { + local note_id="$1" + local output_dir="$2" + + echo "Exporting note ID: $note_id to directory: $output_dir" + mkdir -p "$output_dir" || { + echo "Error: Unable to create directory $output_dir" + exit 1 + } + + # Export the note with attachments to the specified directory + joplin export "$note_id" --format md --output "$output_dir" || { + echo "Error: Failed to export note ID $note_id" + exit 1 + } + + echo "Note exported successfully to $output_dir" +} + +# Main function +main() { + if [[ $# -lt 2 ]]; then + echo "Usage: $0 " + exit 1 + fi + + local note_title="$1" + local output_dir="$2" + + # Search for the note and get its ID + local note_id + note_id=$(search_note "$note_title") + + # Export the note + export_note "$note_id" "$output_dir" +} + +# Run the main function with all script arguments +main "$@" diff --git a/dsr-joplin-create/dsr-new.sh b/dsr-joplin-create/dsr-new.sh new file mode 100644 index 0000000..61f8018 --- /dev/null +++ b/dsr-joplin-create/dsr-new.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +# Use the Joplin CLI and create a new note for today. Let me pass in the notebook folder path. Use bash functions. + +# Created by chatgpt +# https://chatgpt.com/share/6750c7df-6b2c-8005-a91c-1bc5b3875170 + + +# shellcheck disable=SC1090 + +# Bash3 Boilerplate Setup +set -o errexit +set -o nounset +set -o pipefail +IFS=$'\n\t' + +# Constants +readonly SCRIPT_NAME=$(basename "$0") +readonly SCRIPT_VERSION="1.0" +readonly SCRIPT_AUTHOR="Charles N Wyble" +readonly SCRIPT_DESC="Create a new Daily Stakeholder Report note in Joplin" + +# Logging and Debugging (from bash3boilerplate) +readonly LOG_FILE="/tmp/${SCRIPT_NAME}.log" +readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') +info() { echo "[INFO] [$TIMESTAMP] $*"; } +error() { echo "[ERROR] [$TIMESTAMP] $*" >&2; } + +# Default Exit Codes +readonly ERR_JOPLIN_NOT_INSTALLED=10 +readonly ERR_NOTEBOOK_NOT_FOUND=20 + +# Function: Usage Instructions +usage() { + cat < + +Example: + $SCRIPT_NAME "Stakeholder Reports" + +Options: + -h, --help Display this help message. +EOF +} + +# Check dependencies +require_joplin() { + if ! command -v joplin &>/dev/null; then + error "Joplin CLI is not installed or not in PATH. Please install it and try again." + exit $ERR_JOPLIN_NOT_INSTALLED + fi +} + +# Check if notebook exists in Joplin +notebook_exists() { + local notebook="$1" + if ! joplin use "$notebook" >/dev/null 2>&1; then + error "Notebook '$notebook' does not exist. Please create it first." + exit $ERR_NOTEBOOK_NOT_FOUND + fi +} + +# Create a new note in the specified notebook +create_note() { + local notebook="$1" + local today_date=$(date '+%d-%m-%Y') # Format: YYYY-MM-DD + local title="Daily Stakeholder Report - $date" + local content="## Daily Stakeholder Report\n\n**Date:** $date\n\n---\n\n### Key Updates\n\n- \n\n### Issues\n\n- \n\n### Next Steps\n\n- \n" + + joplin create note --title "$title" --body "$content" >/dev/null + info "Note created successfully in notebook '$notebook'." +} + +# Main Function +main() { + local notebook_path="$1" + + # Ensure Joplin CLI is present + require_joplin + + # Verify notebook existence + notebook_exists "$notebook_path" + + # Create a new note + create_note "$notebook_path" +} + +# Argument Parsing +if [[ $# -lt 1 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + usage + exit 0 +fi + +main "$1" diff --git a/dsr-joplin-create/dsr-populate-objectives.sh b/dsr-joplin-create/dsr-populate-objectives.sh new file mode 100644 index 0000000..cd8d069 --- /dev/null +++ b/dsr-joplin-create/dsr-populate-objectives.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash + +# Written by ChatGPT +# https://chatgpt.com/share/6750c7df-6b2c-8005-a91c-1bc5b3875170 + +# Prompt: +# Pull any issues from Redmine that have a due date of today via API + +# shellcheck disable=SC1090 + +# Bash3 Boilerplate Setup +set -o errexit +set -o nounset +set -o pipefail +IFS=$'\n\t' + +# Constants +readonly SCRIPT_NAME=$(basename "$0") +readonly SCRIPT_VERSION="1.0" +readonly SCRIPT_AUTHOR="Charles N Wyble" +readonly SCRIPT_DESC="Pull Redmine issues with a due date of today and output in Markdown" + +# Logging and Debugging +readonly LOG_FILE="/tmp/${SCRIPT_NAME}.log" +readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') +info() { echo "[INFO] [$TIMESTAMP] $*" | tee -a "$LOG_FILE"; } +error() { echo "[ERROR] [$TIMESTAMP] $*" >&2 | tee -a "$LOG_FILE"; } + +# Default Exit Codes +readonly ERR_CURL_NOT_INSTALLED=10 +readonly ERR_API_FAILURE=20 + +# Configuration +readonly REDMINE_INSTANCE="projects.knownelement.com" +readonly REDMINE_API_URL="https://${REDMINE_INSTANCE}" +readonly REDMINE_API_KEY="your_api_key_here" +readonly DATE=$(date '+%Y-%m-%d') + +# Function: Usage Instructions +usage() { + cat < + +Options: + -h, --help Display this help message. + +Example: + $SCRIPT_NAME 123 +EOF +} + +# Check dependencies +require_curl() { + if ! command -v curl &>/dev/null; then + error "curl is not installed or not in PATH. Please install it and try again." + exit $ERR_CURL_NOT_INSTALLED + fi +} + +# Fetch issues from Redmine API +fetch_issues() { + local project_id="$1" + local url="${REDMINE_API_URL}/issues.json?key=${REDMINE_API_KEY}&project_id=${project_id}&due_date=${DATE}" + + info "Fetching issues with due date ${DATE} for project ID ${project_id}..." + response=$(curl -s -w "%{http_code}" -o /tmp/redmine_response.json "$url") + http_code=$(tail -n1 <<<"$response") + + if [[ "$http_code" -ne 200 ]]; then + error "Failed to fetch issues from Redmine API. HTTP Code: $http_code" + exit $ERR_API_FAILURE + fi + + info "Issues fetched successfully. Parsing and converting to Markdown..." + generate_markdown /tmp/redmine_response.json +} + +# Generate Markdown output from JSON response +generate_markdown() { + local json_file="$1" + local markdown_output="/tmp/redmine_issues.md" + + echo "# Redmine Issues for ${DATE}" > "$markdown_output" + echo "" >> "$markdown_output" + + jq -r --arg base_url "$REDMINE_API_URL" '.issues[] | "## [\(.subject)](\($base_url)/issues/\(.id))\n- **ID**: \(.id)\n- **Status**: \(.status.name)\n- **Due Date**: \(.due_date)\n\n---"' \ + "$json_file" >> "$markdown_output" + + info "Markdown output written to $markdown_output" + cat "$markdown_output" +} + +# Main Function +main() { + local project_id="$1" + + # Ensure curl is installed + require_curl + + # Fetch issues for the project + fetch_issues "$project_id" +} + +# Argument Parsing +if [[ $# -lt 1 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + usage + exit 0 +fi + +main "$1" + diff --git a/endstops/end-day.sh b/endstops/end-day.sh new file mode 100644 index 0000000..8b611ff --- /dev/null +++ b/endstops/end-day.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Wrap up my instrumented day into a (mostly) automated report and publish to discourse + +# Gather DSR assets + +# My manually entered notations +./dsr-input/dsr-gather-joplin-log.sh + +# My gitea data +./dsr-input/dsr-gather-gitea.sh + +# My redmine data +./dsr-input/dsr-gather-redmine.sh + +# My wakapi data +./dsr-input/dsr-gather-waka-api.sh + +# My activity watch data +./dsr-input/dsr-gather-activitywatch.sh + +# My habit tracker data +./dsr-input/dsr-gather-habits.sh + +# My health/fitnes data +./dsr-input/dsr-gather-fitness.sh + +# My diet data +./dsr-input/dsr-gather-diet.sh + +# Produce DSR PDF asset +./dsr-publish/create-dsr-pdf.sh + +# Publish DSR to the world +./dsr-publish/publish-dsr.sh \ No newline at end of file diff --git a/endstops/start-day.sh b/endstops/start-day.sh new file mode 100644 index 0000000..b42434a --- /dev/null +++ b/endstops/start-day.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Start my instrumented day + +# Create a new blank DSR for the day +./dsr-joplin-create/dsr-new.sh + +# Populate my Joplin note "Todays objectives" section based on Redmine due dates +./dsr-joplin-create/dsr-populate-objectives.sh diff --git a/local/build/BuildTemplate-2025Plan.yml b/local/build/BuildTemplate-2025Plan.yml new file mode 100644 index 0000000..13cd678 --- /dev/null +++ b/local/build/BuildTemplate-2025Plan.yml @@ -0,0 +1,12 @@ +title: ReachableCEO 2025 Plan +titlepage: true +toc: true +toc-own-page: true +header-left: "\\hspace{1cm}" +header-center: "\\leftmark" +header-right: "Page \\thepage" +footer-left: "Charles N Wyble" +footer-center: "Tenacity. Velocity. Focus." +page-background: "./background5.pdf" +titlepage-logo: "D:/tsys/@ReachableCEO/ReachableCEO.png" +urlcolor: blue diff --git a/local/build/build-2025Plan.sh b/local/build/build-2025Plan.sh new file mode 100644 index 0000000..ee6b300 --- /dev/null +++ b/local/build/build-2025Plan.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -euo pipefail + +# This is a demo script for the DSR-Pipeline-Server +# This script creates PDF output from markdown input + + +###############@################################## +#Edit the below file to reflect your information +################################################## + +source "../DSRVariables.env" + +#################################################### +#################################################### +#################################################### +#DO NOT CHANGE ANYTHING BELOW THIS LINE +#################################################### +#################################################### +#################################################### + +############################################################################################ +# Setup key variables that will be used by the create-stakeholder-output-server.sh script +############################################################################################ + +export MO_PATH="bash ../../vendor/git.knownelement.com/ExternalVendorCode/mo/mo" + +echo "Cleaning up from previous runs..." + +rm $BUILDYAML_STAKEHOLDER_OUTPUT || true +rm $StakeholderOutputMarkdownOutputFile || true +rm $StakeholderOutputPDFOutputFile || true + +echo "Combining markdown files into single input file for pandoc..." +cat $StakeholderOutputMarkdownInputFile > $StakeholderOutputMarkdownOutputFile + +#Call the build stakeholder output microservice +echo "Calling the build stakeholder output microservice..." +bash ../../vendor/git.knownelement.com/reachableceo/DSR-Pipeline-Server/build/build-stakeholder-output-server.sh \ No newline at end of file