├── docs ├── introduction │ ├── index.md │ └── what-is-a-devangelist.md ├── after-devangelism │ └── index.md ├── being-devangelist │ ├── index.md │ ├── external-advocacy.md │ └── internal-advocacy.md ├── becoming-devangelist │ └── index.md ├── developer-relations │ └── index.md ├── community-community-community │ └── index.md ├── assets │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── images │ │ ├── practicalli-logo.png │ │ └── social │ │ │ └── README.md │ ├── stylesheets │ │ ├── extra.css │ │ └── practicalli-light.css │ ├── favicon.svg │ └── practicalli-logo.svg ├── public-speaking │ ├── conferences.md │ └── index.md └── index.md ├── CHANGELOG.md ├── .github ├── CODEOWNERS ├── config │ ├── secretlintrc.json │ ├── markdown-link-check.json │ ├── gitleaks.toml │ ├── lychee.toml │ ├── megalinter.yaml │ └── markdown-lint.jsonc ├── pull_request_template.md └── workflows │ ├── changelog-check.yaml │ ├── scheduled-version-check.yaml │ ├── publish-book.yaml │ ├── scheduled-stale-check.yaml │ └── megalinter.yaml ├── .gitattributes ├── overrides ├── main.html ├── partials │ ├── source.html │ ├── palette.html │ └── header.html └── 404.html ├── .gitignore ├── README.md ├── mkdocs.yml └── Makefile /docs/introduction/index.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | -------------------------------------------------------------------------------- /docs/after-devangelism/index.md: -------------------------------------------------------------------------------- 1 | # After Devangelism 2 | -------------------------------------------------------------------------------- /docs/being-devangelist/index.md: -------------------------------------------------------------------------------- 1 | # Being Devangelist 2 | -------------------------------------------------------------------------------- /docs/becoming-devangelist/index.md: -------------------------------------------------------------------------------- 1 | # Becoming Devangelist 2 | -------------------------------------------------------------------------------- /docs/developer-relations/index.md: -------------------------------------------------------------------------------- 1 | # Developer Relations 2 | -------------------------------------------------------------------------------- /docs/being-devangelist/external-advocacy.md: -------------------------------------------------------------------------------- 1 | # External advocacy 2 | -------------------------------------------------------------------------------- /docs/being-devangelist/internal-advocacy.md: -------------------------------------------------------------------------------- 1 | # Internal advocacy 2 | -------------------------------------------------------------------------------- /docs/introduction/what-is-a-devangelist.md: -------------------------------------------------------------------------------- 1 | # What is a Devangelist 2 | -------------------------------------------------------------------------------- /docs/community-community-community/index.md: -------------------------------------------------------------------------------- 1 | # Community, Community, Community 2 | -------------------------------------------------------------------------------- /docs/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/favicon.ico -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Unreleased 2 | 3 | ## Added 4 | - mkdocs: new material for mkdocs book 5 | 6 | ## Changed 7 | -------------------------------------------------------------------------------- /docs/assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/favicon-16x16.png -------------------------------------------------------------------------------- /docs/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/favicon-32x32.png -------------------------------------------------------------------------------- /docs/assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/assets/images/practicalli-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/i-devangelist/main/docs/assets/images/practicalli-logo.png -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Codeowners 2 | 3 | # Default owner accounts for the current repository 4 | # Automatically added as a reviewr to all pull requests (not including drafts) 5 | 6 | * @practicalli-johnny 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Configure Languages for GitHub repository using Linguist 2 | 3 | # Markdown & Make detection, 4 | # exclude HTML, CSS & JavaScript 5 | docs/** linguist-detectable 6 | *.md linguist-detectable=true 7 | make linguist-detectable=true 8 | *.css linguist-detectable=false 9 | *.js linguist-detectable=false 10 | *.html linguist-detectable=false 11 | -------------------------------------------------------------------------------- /overrides/main.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | {% extends "base.html" %} 10 | 11 | 12 | {% block announce %} 13 | 14 | Practicalli Journal contains posts from work experiences and supporting the community 15 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /.github/config/secretlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": [ 3 | { 4 | "id": "@secretlint/secretlint-rule-basicauth", 5 | "options": { 6 | "allows": [ 7 | "hostname.domain.com", 8 | "jdbc:postgresql://:port/?user=&password=", 9 | "postgres://postgres://username:password@hostname.domain.com:1234/database-name" 10 | ] 11 | } 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /docs/assets/images/social/README.md: -------------------------------------------------------------------------------- 1 | # Social Cards 2 | 3 | Social Cards are visual previews of the website that are included when sending links via social media platforms. 4 | 5 | Material for MkDocs is [configured to generate beautiful social cards automatically](https://squidfunk.github.io/mkdocs-material/setup/setting-up-social-cards/), using the colors, fonts and logos defined in `mkdocs.yml` 6 | 7 | Generated images are stored in this directory. 8 | -------------------------------------------------------------------------------- /overrides/partials/source.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {% set icon = config.theme.icon.repo or "fontawesome/brands/git-alt" %} 4 | {% include ".icons/" ~ icon ~ ".svg" %} 5 |
6 |
7 | {{ config.repo_name }} 8 |
9 |
10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Exclude all files from root directory 2 | /* 3 | 4 | # ------------------------ 5 | # Common project files 6 | !CHANGELOG.md 7 | !README.md 8 | !LICENSE 9 | 10 | # ------------------------ 11 | # Include MkDocs files 12 | !docs/ 13 | !includes/ 14 | !overrides/ 15 | !mkdocs.yml 16 | 17 | # ------------------------ 18 | # Project automation 19 | !Makefile 20 | 21 | # ------------------------ 22 | # Version Control 23 | !.gitignore 24 | !.gitattributes 25 | !.github/ 26 | 27 | -------------------------------------------------------------------------------- /.github/config/markdown-link-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^http://localhost" 5 | }, 6 | { 7 | "pattern": "^mailto:*" 8 | }, 9 | { 10 | "pattern": "^#*" 11 | }, 12 | { 13 | "pattern": "^https://127.0.0.0/" 14 | } 15 | ], 16 | "timeout": "20s", 17 | "retryOn429": true, 18 | "retryCount": 5, 19 | "fallbackRetryDelay": "30s", 20 | "aliveStatusCodes": [ 21 | 200, 22 | 206 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/config/gitleaks.toml: -------------------------------------------------------------------------------- 1 | title = "gitleaks config" 2 | 3 | [allowlist] 4 | description = "global allow lists" 5 | paths = [ 6 | '''gitleaks.toml''', 7 | '''(.*?)(jpg|gif|doc|docx|zip|xls|pdf|bin|svg|socket)$''', 8 | '''(go.mod|go.sum)$''', 9 | '''gradle.lockfile''', 10 | '''node_modules''', 11 | '''package-lock.json''', 12 | '''pnpm-lock.yaml''', 13 | '''Database.refactorlog''', 14 | '''vendor''', 15 | ] 16 | 17 | [[rules]] 18 | description = "AWS Example API Key" 19 | id = "aws-example-api-key" 20 | regex = '''AKIAIOSFODNN7EXAMPLE''' 21 | keywords = [ 22 | "awstoken", 23 | ] 24 | -------------------------------------------------------------------------------- /docs/public-speaking/conferences.md: -------------------------------------------------------------------------------- 1 | 2 | # Finding talks to speak at 3 | - Lanyrd 4 | - Google 5 | - asking other developers 6 | - twitter 7 | -- #cfp 8 | -- @techspeakdigest 9 | -- @WikiCFP 10 | 11 | 12 | ## Existing community 13 | - go to their meetups and see what topics people are interested in (or just read the event description if you cant make it in person) 14 | - join in 15 | -- email lists, forums, etc 16 | 17 | 18 | # Getting your talk accepted 19 | 20 | ## Understanding your audience 21 | 22 | ## Something popular 23 | 24 | ## Something unique 25 | 26 | ## Something no one else is doing 27 | 28 | 29 | # Bulding up a reputation 30 | - document your speaking history 31 | -- update your lanyrd page with speaking engagements 32 | -- blog about each talk you give 33 | -- blog around the topic 34 | --- get your blog 35 | 36 | 37 | big conferences to showcase the products 38 | - rather have one big conference rather than several small 39 | -------------------------------------------------------------------------------- /overrides/404.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {% extends "main.html" %} 7 | 8 | 9 | {% block content %} 10 |

This is not the page you are looking for

11 | 12 |

13 | Sorry we have arrived at a page that does not exist... 14 |

15 | 16 |

17 | Try the Search bar at the top of the page 18 |

19 | 20 | 35 | 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /.github/config/lychee.toml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------- 2 | # Base URL or website root directory to check relative URLs. 3 | base = "https://practical.li/clojure/" 4 | 5 | # Only test links with the given schemes (e.g. https). 6 | # Omit to check links with any other scheme. 7 | # At the moment, we support http, https, file, and mailto. 8 | scheme = ["https"] 9 | 10 | # ---------------------------------------- 11 | # Exclusions 12 | 13 | # Exclude URLs and mail addresses from checking (supports regex). 14 | exclude = ['^https://www\.linkedin\.com', 15 | '^https://www\.parkrun\.org\.uk', 16 | '^https://github\.com\/search*', 17 | '^https://packages\.debian\.org', 18 | '^https://practicalli\.grafana\.net', 19 | '^https://127.0.0.0'] 20 | 21 | # Exclude these filesystem paths from getting checked. 22 | exclude_path = ["mkdocs.yml", "overrides", "includes", ".github", ".git"] 23 | 24 | # Exclude all private IPs from checking. 25 | # Equivalent to setting `exclude_private`, `exclude_link_local`, and 26 | # `exclude_loopback` to true. 27 | exclude_all_private = true 28 | 29 | # Check mail addresses 30 | include_mail = false 31 | # ---------------------------------------- 32 | -------------------------------------------------------------------------------- /docs/public-speaking/index.md: -------------------------------------------------------------------------------- 1 | # Public Speaking 2 | 3 | 4 | ## Why Speak 5 | 6 | - Confidence in other aspects of your work 7 | - Practice communicating information to various audiences 8 | - Rewarding once you have done it 9 | - Enhance your network and career prospects 10 | 11 | 12 | ## Writing a presentations 13 | 14 | Keep it simple and clear. 15 | 16 | Understand / define who your audience is. 17 | 18 | What points are you trying to get accross. 19 | 20 | 21 | ## Starting speaking 22 | 23 | - meetup groups 24 | - first speaker events 25 | 26 | 27 | ## What events to speak at 28 | 29 | - events you enjoy attending 30 | - events within the topic area 31 | - events outside the topic area (if you have a more general topic) 32 | 33 | 34 | ## Motivation 35 | 36 | Maintaining motivation to keep presenting is challenging 37 | 38 | - what have you done recently 39 | - what do you really enjoy talking about 40 | - what talks got the nicest feedback 41 | - what do you want to learn 42 | 43 | 44 | ## Impostor Syndrome 45 | 46 | I cant think of any one I have met that hasnt experienced imposter syndrome at some point. 47 | 48 | 49 | Many experienced public speakers feel this when they cannot think of a new talk or topic to present. This is similar to the experience that new speakers also experience. 50 | -------------------------------------------------------------------------------- /overrides/partials/palette.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | {% for option in config.theme.palette %} 7 | {% set scheme = option.scheme | d("default", true) %} 8 | {% set primary = option.primary | d("indigo", true) %} 9 | {% set accent = option.accent | d("indigo", true) %} 10 | 25 | {% if option.toggle %} 26 | 34 | {% endif %} 35 | {% endfor %} 36 |
37 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | :memo: Description 2 | 3 | 4 | :white_check_mark: Checklist 5 | 6 | - [ ] Commits should be cryptographically signed (SSH or GPG) 7 | 8 | 9 | ## Practicalli Guidelines 10 | 11 | Please follow these guidelines when submitting a pull request 12 | 13 | - refer to all relevant issues, using `#` followed by the issue number (or paste full link to the issue) 14 | - PR should contain the smallest possible change 15 | - PR should contain a very specific change 16 | - PR should contain only a single commit (squash your commits locally if required) 17 | - Avoid multiple changes across multiple files (raise an issue so we can discuss) 18 | - Avoid a long list of spelling or grammar corrections. These take too long to review and cherry pick. 19 | 20 | ## Submitting articles 21 | 22 | [Create an issue using the article template](https://github.com/practicalli/blog-content/issues/new?assignees=&labels=article&template=article.md&title=Suggested+article+title), 23 | providing as much detail as possible. 24 | 25 | ## Website design 26 | 27 | Suggestions about website design changes are most welcome, especially in terms of usability and accessibility. 28 | 29 | Please raise an issue so we can discuss changes first, especially changes related to aesthetics. 30 | 31 | ## Review process 32 | 33 | All pull requests are reviewed by @practicalli-johnny and feedback provided, usually the same day but please be patient. 34 | -------------------------------------------------------------------------------- /.github/workflows/changelog-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Check CHANGELOG.md file updated for every pull request 3 | 4 | name: Changelog Check 5 | on: 6 | pull_request: 7 | paths-ignore: 8 | - "README.md" 9 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] 10 | 11 | jobs: 12 | changelog: 13 | name: Changelog Update Check 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 17 | - run: echo "🐧 Job running on ${{ runner.os }} server" 18 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 19 | 20 | # Git Checkout 21 | - name: Checkout Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | sparse-checkout: | 26 | docs 27 | overrides 28 | .github 29 | CHANGELOG.md 30 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 31 | 32 | # Changelog Enforcer 33 | - name: Changelog Enforcer 34 | uses: dangoslen/changelog-enforcer@v3 35 | with: 36 | changeLogPath: "CHANGELOG.md" 37 | skipLabels: "skip-changelog-check" 38 | 39 | # Summary and status 40 | - run: echo "🎨 Changelog Enforcer quality checks completed" 41 | - run: echo "🍏 Job status is ${{ job.status }}." 42 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-version-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------ 3 | # Scheduled check of versions 4 | # - use as non-urgent report on versions 5 | # - Uses POSIX Cron syntax 6 | # - Minute [0,59] 7 | # - Hour [0,23] 8 | # - Day of the month [1,31] 9 | # - Month of the year [1,12] 10 | # - Day of the week ([0,6] with 0=Sunday) 11 | # 12 | # Using liquidz/anta to check: 13 | # - GitHub workflows 14 | # - deps.edn 15 | # ------------------------------------------ 16 | 17 | name: "Scheduled Version Check" 18 | on: 19 | schedule: 20 | # - cron: "0 4 * * *" # at 04:04:04 ever day 21 | # - cron: "0 4 * * 5" # at 04:04:04 ever Friday 22 | - cron: "0 4 1 * *" # at 04:04:04 on first day of month 23 | workflow_dispatch: # Run manually via GitHub Actions Workflow page 24 | 25 | jobs: 26 | scheduled-version-check: 27 | name: "Scheduled Version Check" 28 | runs-on: ubuntu-24.04 29 | steps: 30 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 31 | - run: echo "🐧 Job running on ${{ runner.os }} server" 32 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 33 | 34 | - name: Checkout Code 35 | uses: actions/checkout@v4 36 | with: 37 | fetch-depth: 0 38 | sparse-checkout: | 39 | .github 40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 41 | - name: "Antq Check versions" 42 | uses: liquidz/antq-action@main 43 | with: 44 | excludes: "" 45 | skips: "boot clojure-cli pom shadow-cljs leiningen" 46 | 47 | # Summary 48 | - run: echo "🎨 library versions checked with liquidz/antq" 49 | - run: echo "🍏 Job status is ${{ job.status }}." 50 | -------------------------------------------------------------------------------- /.github/workflows/publish-book.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Book 3 | on: 4 | # Manually trigger workflow 5 | workflow_dispatch: 6 | 7 | # Run work flow conditional on linter workflow success 8 | workflow_run: 9 | workflows: 10 | - "MegaLinter" 11 | paths: 12 | - "docs/**" 13 | - "includes/**" 14 | - "overrides/**" 15 | - "mkdocs.yaml" 16 | branches: 17 | - main 18 | types: 19 | - completed 20 | 21 | permissions: 22 | contents: write 23 | 24 | jobs: 25 | publish-book: 26 | name: MkDocs Publish 27 | runs-on: ubuntu-24.04 28 | steps: 29 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 30 | - run: echo "🐧 Job running on ${{ runner.os }} server" 31 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 32 | 33 | - name: Checkout Code 34 | uses: actions/checkout@v4 35 | with: 36 | fetch-depth: 0 37 | sparse-checkout: | 38 | docs 39 | overrides 40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 41 | 42 | # setup-python only required to use non-default python version 43 | # - name: Setup Python 44 | # uses: actions/setup-python@v5 45 | # with: 46 | # python-version: 3.x 47 | 48 | - name: Cache 49 | uses: actions/cache@v4 50 | with: 51 | key: ${{ github.ref }} 52 | path: .cache 53 | 54 | - run: pip install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects mkdocs-rss-plugin pillow cairosvg 55 | - run: mkdocs gh-deploy --force 56 | - run: echo "🐙 ." 57 | 58 | # Summary and status 59 | - run: echo "🎨 MkDocs Publish Book workflow completed" 60 | - run: echo "🍏 Job status is ${{ job.status }}." 61 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-stale-check.yaml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------- 2 | # Scheduled stale issue & pull request check 3 | # 4 | # Adds 'stale' label after a set piece of time, 5 | # then closes stale issues & pull requests a short period after 6 | # 7 | # Using "Close Stale Issues" action 8 | # https://github.com/marketplace/actions/close-stale-issues 9 | # ---------------------------------------- 10 | 11 | name: 'Scheduled stale check' 12 | on: 13 | workflow_dispatch: 14 | schedule: 15 | - cron: "0 1 1 * *" # at 01:00 on first day of month 16 | 17 | jobs: 18 | stale: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 22 | - run: echo "🐧 Job running on ${{ runner.os }} server" 23 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 24 | 25 | - uses: actions/stale@v9 26 | with: 27 | stale-issue-message: 'After 30 days with no activity, the issue was automatically marked stale. Remove stale label or add a comment to prevent the issue being closed in 5 days.' 28 | stale-pr-message: 'After 45 days with no activity, the Pull Request was automatically marked stale. Remove stale label or comment to prevent the PR being closed in 10 days.' 29 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' 30 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' 31 | days-before-issue-stale: 30 32 | days-before-pr-stale: 45 33 | days-before-issue-close: 5 34 | days-before-pr-close: 10 35 | start-date: '2025-04-05T00:00:00Z' # only affect issues/PRs from date created (ISO 8601 or RFC 2822 format) 36 | any-of-labels: 'future,keep' # labels to keep 37 | exempt-issue-assignees: 'practicalli-johnny' 38 | exempt-pr-assignees: 'practicalli-johnny' 39 | 40 | # Summary 41 | - run: echo "🎨 Issues & Pull Request checked with actions/stale" 42 | - run: echo "🍏 Job status is ${{ job.status }}." 43 | -------------------------------------------------------------------------------- /overrides/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | {% set class = "md-header" %} {% if "navigation.tabs.sticky" in features %} {% 3 | set class = class ~ " md-header--shadow md-header--lifted" %} {% elif 4 | "navigation.tabs" not in features %} {% set class = class ~ " md-header--shadow" 5 | %} {% endif %} 6 | 7 | 8 |
9 | 74 | 75 | 76 | {% if "navigation.tabs.sticky" in features %} {% if "navigation.tabs" in 77 | features %} {% include "partials/tabs.html" %} {% endif %} {% endif %} 78 |
79 | -------------------------------------------------------------------------------- /.github/workflows/megalinter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # MegaLinter GitHub Action configuration file 3 | # More info at https://megalinter.io 4 | # All variables described in https://megalinter.io/latest/configuration/ 5 | 6 | name: MegaLinter 7 | on: 8 | workflow_dispatch: 9 | pull_request: 10 | branches: [main] 11 | push: 12 | branches: [main] 13 | 14 | # Run Linters in parallel 15 | # Cancel running job if new job is triggered 16 | concurrency: 17 | group: "${{ github.ref }}-${{ github.workflow }}" 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | megalinter: 22 | name: MegaLinter 23 | runs-on: ubuntu-24.04 24 | 25 | # Give the default GITHUB_TOKEN write permission to commit and push, comment 26 | # issues, and post new Pull Requests; remove the ones you do not need 27 | permissions: 28 | contents: write 29 | issues: write 30 | pull-requests: write 31 | 32 | steps: 33 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 34 | - run: echo "🐧 Job running on ${{ runner.os }} server" 35 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 36 | 37 | # Git Checkout 38 | - name: Checkout Code 39 | uses: actions/checkout@v4 40 | with: 41 | fetch-depth: 0 42 | sparse-checkout: | 43 | docs 44 | overrides 45 | .github 46 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 47 | 48 | # MegaLinter Configuration 49 | - name: MegaLinter Run 50 | uses: oxsecurity/megalinter/flavors/documentation@v8 51 | id: ml 52 | env: 53 | 54 | # Validate the git diff against default branch. 55 | VALIDATE_ALL_CODEBASE: >- 56 | ${{ github.event_name == 'push' && github.ref == 'refs/heads/main'}} 57 | 58 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # report individual linter status 59 | 60 | # ADD CUSTOM ENV VARIABLES OR DEFINE IN MEGALINTER_CONFIG file 61 | MEGALINTER_CONFIG: .github/config/megalinter.yaml 62 | 63 | # Grafana Dashboard Connections - GitHub Organization secrets 64 | API_REPORTER: true 65 | API_REPORTER_URL: ${{ secrets.API_REPORTER_URL }} 66 | API_REPORTER_BASIC_AUTH_USERNAME: ${{ secrets.API_REPORTER_BASIC_AUTH_USERNAME }} 67 | API_REPORTER_BASIC_AUTH_PASSWORD: ${{ secrets.API_REPORTER_BASIC_AUTH_PASSWORD }} 68 | API_REPORTER_BEARER_TOKEN: ${{ secrets.API_REPORTER_BEARER_PASSWORD }} 69 | API_REPORTER_METRICS_URL: ${{ secrets.API_REPORTER_METRICS_URL }} 70 | API_REPORTER_METRICS_BASIC_AUTH_USERNAME: ${{ secrets.API_REPORTER_METRICS_BASIC_AUTH_USERNAME }} 71 | API_REPORTER_METRICS_BASIC_AUTH_PASSWORD: ${{ secrets.API_REPORTER_METRICS_BASIC_AUTH_PASSWORD }} 72 | API_REPORTER_METRICS_BEARER_TOKEN: ${{ secrets.API_REPORTER_METRICS_BEARER_PASSWORD }} 73 | API_REPORTER_DEBUG: false 74 | 75 | # Logging 76 | # LOG_LEVEL: DEBUG 77 | 78 | # Upload MegaLinter artifacts 79 | - name: Archive production artifacts 80 | if: success() || failure() 81 | uses: actions/upload-artifact@v4 82 | with: 83 | name: MegaLinter reports 84 | path: | 85 | megalinter-reports 86 | mega-linter.log 87 | 88 | # Summary and status 89 | - run: echo "🎨 MegaLinter quality checks completed" 90 | - run: echo "🍏 Job status is ${{ job.status }}." 91 | -------------------------------------------------------------------------------- /.github/config/megalinter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configuration file for MegaLinter 3 | # 4 | # General configuration: 5 | # https://megalinter.io/latest/configuration/ 6 | # 7 | # Specific Linters: 8 | # https://megalinter.io/latest/supported-linters/ 9 | 10 | # ------------------------ 11 | # Validate all files if true 12 | # or new / edited files if false 13 | VALIDATE_ALL_CODEBASE: false 14 | 15 | # ------------------------ 16 | # Linters 17 | 18 | # Run linters in parallel 19 | PARALLEL: true 20 | 21 | # ENABLE specific linters, all other linters automatically disabled 22 | ENABLE: 23 | # - CLOJURE 24 | - CREDENTIALS 25 | - DOCKERFILE 26 | - MAKEFILE 27 | - MARKDOWN 28 | - GIT 29 | - SPELL 30 | - YAML 31 | - REPOSITORY 32 | 33 | # Linter specific configuration 34 | 35 | # CLOJURE_CLJ_KONDO_CONFIG_FILE: ".github/config/clj-kondo-ci-config.edn" 36 | # CLOJURE_CLJ_KONDO_ARGUMENTS: "--lint deps.edn" 37 | # CLOJURE_CLJ_KONDO_FILTER_REGEX_EXCLUDE: "dev|develop" 38 | # CLOJURE_CLJ_KONDO_FILTER_REGEX_EXCLUDE: "resources" 39 | 40 | # CREDENTIALS_SECRETLINT_DISABLE_ERRORS: true 41 | CREDENTIALS_SECRETLINT_CONFIG_FILE: ".github/config/secretlintrc.json" 42 | 43 | MARKDOWN_MARKDOWNLINT_CONFIG_FILE: ".github/config/markdown-lint.jsonc" 44 | MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: ".github/pull_request_template.md|CHANGELOG.md|README.md|GLOSSARY.md|java-17-flags.md|abbreviations.md" 45 | # MARKDOWN_MARKDOWNLINT_DISABLE_ERRORS: true 46 | MARKDOWN_MARKDOWN_LINK_CHECK_CONFIG_FILE: ".github/config/markdown-link-check.json" 47 | # MARKDOWN_MARKDOWN_LINK_CHECK_CLI_LINT_MODE: "project" 48 | # MARKDOWN_MARKDOWN_LINK_CHECK_DISABLE_ERRORS: false 49 | MARKDOWN_REMARK_LINT_DISABLE_ERRORS: true 50 | # MARKDOWN_MARKDOWN_TABLE_FORMATTER_DISABLE_ERRORS: false 51 | 52 | REPOSITORY_GITLEAKS_CONFIG_FILE: ".github/config/gitleaks.toml" 53 | REPOSITORY_TRUFFLEHOG_DISABLE_ERRORS: true # Errors only as warnings 54 | 55 | # SPELL_CSPELL_DISABLE_ERRORS: true 56 | SPELL_MISSPELL_DISABLE_ERRORS: true 57 | SPELL_LYCHEE_CONFIG_FILE: ".github/config/lychee.toml" 58 | SPELL_LYCHEE_DISABLE_ERRORS: true # Errors are only warnings 59 | 60 | # YAML_PRETTIER_FILTER_REGEX_EXCLUDE: (docs/) 61 | # YAML_YAMLLINT_FILTER_REGEX_EXCLUDE: (docs/) 62 | 63 | # Explicitly disable linters to ensure they are never run 64 | # DISABLE: 65 | # - COPYPASTE # checks for excessive copy-pastes 66 | # - SPELL # spell checking - often creates many false positives 67 | # - CSS # 68 | 69 | # Disable linter features 70 | DISABLE_LINTERS: 71 | - YAML_PRETTIER # draconian format rules 72 | - SPELL_CSPELL # many clojure references causing false positives 73 | - YAML_YAMLLINT # vague error mesages, investigation required 74 | - REPOSITORY_GIT_DIFF # warnings about LF to CRLF 75 | - REPOSITORY_SECRETLINT # reporting errors in its own config file 76 | # - REPOSITORY_DEVSKIM # unnecessary URL TLS checks 77 | - REPOSITORY_CHECKOV # fails on root user in Dockerfile 78 | - REPOSITORY_SECRETLINT 79 | 80 | # Ignore all errors and return without error status 81 | # DISABLE_ERRORS: true 82 | # ------------------------ 83 | 84 | # ------------------------ 85 | # Reporting 86 | 87 | # Activate sources reporter 88 | UPDATED_SOURCES_REPORTER: false 89 | 90 | # Show Linter timings in summary table at end of run 91 | SHOW_ELAPSED_TIME: true 92 | 93 | # Upload reports to file.io 94 | FILEIO_REPORTER: false 95 | # ------------------------ 96 | 97 | # ------------------------ 98 | # Over-ride errors 99 | 100 | # detect errors but do not block CI passing 101 | # DISABLE_ERRORS: true 102 | # ------------------------ 103 | -------------------------------------------------------------------------------- /docs/assets/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | [data-md-color-scheme="default"] { 2 | --md-default-bg-color: hsla(208, 100%, 96%, 0.94); 3 | --md-code-bg-color: hsla(208, 80%, 88%, 0.64); 4 | --md-code-hl-color: hsla(208, 88%, 80%, 0.92); 5 | --md-admonition-bg-color: hsla(208, 80%, 92%, 0.92); 6 | --md-typeset-kbd-color: hsla(208, 100%, 98%, 0.98); 7 | } 8 | 9 | /* Custom Admonitions */ 10 | 11 | 12 | :root { 13 | /* Clojure Idiom*/ 14 | --md-admonition-icon--clojure-idiom: url(https://raw.githubusercontent.com/practicalli/graphic-design/c40cc063cc5bb07525b524d8a3d638e2f42bc38a/logos/clojure-logo-bullet.svg); 15 | 16 | /* Round corners */ 17 | --base-border-radius: 0.5rem; 18 | } 19 | 20 | /*Admonitions colors*/ 21 | .md-typeset .admonition.clojure-idiom, 22 | .md-typeset details.clojure-idiom { 23 | border-color: rgb(43, 155, 70); 24 | } 25 | .md-typeset .clojure-idiom > .admonition-title, 26 | .md-typeset .clojure-idiom > summary { 27 | background-color: rgba(43, 155, 70, 0.1); 28 | } 29 | .md-typeset .clojure-idiom > .admonition-title::before, 30 | .md-typeset .clojure-idiom > summary::before { 31 | background-color: rgb(250, 250, 250); 32 | background-image: var(--md-admonition-icon--clojure-idiom); 33 | -webkit-mask-image: var(--md-admonition-icon--clojure-idiom); 34 | mask-image: var(--md-admonition-icon--clojure-idiom); 35 | } 36 | 37 | 38 | /* Change font family of filename present on top of code block. */ 39 | .highlight span.filename { 40 | border-bottom: none; 41 | border-radius: var(--base-border-radius); 42 | display: inline; 43 | font-family: var(--md-code-font-family); 44 | border-bottom-left-radius: 0; 45 | border-bottom-right-radius: 0; 46 | margin-bottom: 5px; 47 | text-align: center; 48 | } 49 | .highlight span.filename + pre > code { 50 | border-radius: var(--base-border-radius); 51 | border-top-left-radius: 0; 52 | } 53 | .md-typeset pre > code { 54 | border-radius: var(--base-border-radius); 55 | } 56 | 57 | /* Grid Cards */ 58 | .md-typeset .grid.cards > ul > li { 59 | border-radius: var(--base-border-radius); 60 | } 61 | .md-typeset .grid.cards > ul > li:hover { 62 | box-shadow: 0 0 0.2rem #ffffff40; 63 | } 64 | 65 | /* Markdown Button */ 66 | .md-typeset .md-button { 67 | border-radius: var(--base-border-radius); 68 | } 69 | 70 | /* Critic, Mark */ 71 | ins.critic, 72 | del.critic { 73 | text-decoration: none; 74 | } 75 | 76 | .md-typeset .critic, 77 | .md-typeset mark { 78 | border-radius: 0.2rem; 79 | padding: 0 0.2rem; 80 | } 81 | 82 | .md-typeset mark { 83 | box-shadow: 0 0 0 0.1rem var(--md-typeset-mark-color); 84 | } 85 | 86 | .md-typeset ins.critic { 87 | box-shadow: 0 0 0 0.1rem var(--md-typeset-ins-color); 88 | } 89 | 90 | .md-typeset del.critic { 91 | box-shadow: 0 0 0 0.1rem var(--md-typeset-del-color); 92 | } 93 | 94 | /* Forms */ 95 | .md-search__form { 96 | border-radius: var(--base-border-radius); 97 | } 98 | 99 | [data-md-toggle="search"]:checked ~ .md-header .md-search__form { 100 | border-top-right-radius: var(--base-border-radius); 101 | border-top-left-radius: var(--base-border-radius); 102 | } 103 | 104 | [dir="ltr"] .md-search__output { 105 | border-bottom-right-radius: var(--base-border-radius); 106 | border-bottom-left-radius: var(--base-border-radius); 107 | } 108 | 109 | /* Blog - index.md */ 110 | .md-post--excerpt { 111 | background-color: var(--md-accent-fg-color--transparent); 112 | box-shadow: 0 0 0 1rem var(--md-accent-fg-color--transparent); 113 | border-radius: var(--base-border-radius); 114 | } 115 | 116 | /* Table */ 117 | .md-typeset table:not([class]) { 118 | border-radius: var(--base-border-radius); 119 | } 120 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # About I Devangelist 2 | 3 | !!! WARNING "Book under development" 4 | 5 | A journey into developer advocacy and community development. 6 | 7 | The life and times of a developer evangelist can be fun, enlightening and highly intense. A career can also be full of the unexpected, not all of which is positive. 8 | 9 | I, Devangelist presents stories from a variety of experiences that highlight the huge variety of tasks involved in the role (and how much the role can change from company to company) 10 | 11 | There are practical guides to navigate through the role effectively. 12 | 13 | This site will also contain lots of tips and suggestions for those currently in this role, gathered from a range of experiences of Developer Evangelists / Advocates and Community managers across the world. 14 | 15 | 16 | ## The Role 17 | 18 | A devangelist can be very wide role and vary significantly in the minds of those who work in the role, those who work with them and those that interact with them. So this is my hopefully not too biased view on what a devangelist is all about and where I feel the role can add real value. 19 | 20 | I will include stories, tips and common practices used to help make the devangelist role more effective 21 | 22 | 23 | ## Code of Conduct Safe 24 | 25 | A [Code of Conduct](https://en.wikipedia.org/wiki/Code_of_conduct) is now used in most of the public events in the developer world. It is a simple but important statement about respecting everyone during all interaction with other people, setting out expectations of a minimum level of positive behaviour towards each other. 26 | 27 | You can of course be even nicer should you wish. 28 | 29 | > "Be excellent to each other" - Bill S. Preston, Esq. - [Bill & Ted's Excellent Adventure](https://en.wikipedia.org/wiki/Bill_%26_Ted's_Excellent_Adventure) 30 | 31 | Example code of conduct documents include 32 | 33 | * [Battlehack Code of Conduct](http://hackcodeofconduct.org/battlehack_london) by [@CBetta](https://twitter.com/cbetta) - for the Battlehack world wide hackathon events 34 | * [Major League Hacking code of conduct] - worldwide student hacking organisation 35 | * [SkillsMatter Code of Conduct](https://skillsmatter.com/go/code-of-conduct) for all their conferences & community events 36 | * RubyGirls Code of Conduct 37 | * [ClojureBridge] - helping the diverse developer community learn and love Clojure 38 | 39 | 40 | ## Applying Lean Principles & Agile Techniques 41 | 42 | Many of the principles and practices I applied as an Agile Coach & developer are equally applicable to developer evangelism. I will cover these principles and practices throughout the book with examples of how they can be effective. 43 | 44 | ## Name of the book 45 | 46 | As you may have already guessed the title of the book is a homage to the novel **I, Robot**. I also subttle draw themes and concepts from the novel [I, Claudius](https://en.wikipedia.org/wiki/I,_Claudius) by [Robert Graves](https://en.wikipedia.org/wiki/Robert_Graves). 47 | 48 | ## Geekiness throughout 49 | 50 | Throughout the book I will also include many common (and possible a few obscure references) popular culture and science fiction works that many in the developer world relate to. This is not just because I am geeky, but will hopefully help give a context feel less alien and help the reader relate to the concepts & practices covered. 51 | 52 | ## Audience for the book 53 | 54 | This book shares all the experiences I can publicly share as a developer in the community and as a developer ambassador / advocate / evangelist. Hopefully this will be useful to those: 55 | 56 | * currently working in an devangelist or community type role 57 | * looking to move into that role 58 | * wishing to hire a devangelist team or their first devagelist or technical community focused role 59 | 60 | This book is not about marketing or turning a developer into a marketeer. 61 | 62 | My own personal view is that devangelists can benefit from marketing techniques to help them reach their audience more effectively, however they are only a complement to your main work. 63 | 64 | 65 | ![I Devangelist Robot](https://github.com/practicalli/graphic-design/blob/live/community/i-devangelist-robot.png?raw=true){loading=lazy} 66 | 67 | 68 | 69 | ## Star History 70 | 71 | [![Star History Chart](https://api.star-history.com/svg?repos=practicalli/i-devangelist&type=Date)](https://star-history.com/#practicalli/i-devangelist&Date) 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # I, Devangelist 2 | 3 | A journey into developer advocacy and community development. 4 | 5 | The life and times of a developer evangelist can be fun, enlightening and highly intense. A career can also be full of the unexpected, not all of which is positive. 6 | 7 | I, Devangelist presents stories from a variety of experiences that highlight the huge variety of tasks involved in the role (and how much the role can change from company to company) 8 | 9 | There are practical guides to navigate through the role effectively. 10 | 11 | This site will also contain lots of tips and suggestions for those currently in this role, gathered from a range of experiences of Developer Evangelists / Advocates and Community managers across the world. 12 | 13 | 14 | 15 | ```none 16 | ██████╗ ██████╗ █████╗ ██████╗████████╗██╗ ██████╗ █████╗ ██╗ ██╗ ██╗ 17 | ██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔════╝██╔══██╗██║ ██║ ██║ 18 | ██████╔╝██████╔╝███████║██║ ██║ ██║██║ ███████║██║ ██║ ██║ 19 | ██╔═══╝ ██╔══██╗██╔══██║██║ ██║ ██║██║ ██╔══██║██║ ██║ ██║ 20 | ██║ ██║ ██║██║ ██║╚██████╗ ██║ ██║╚██████╗██║ ██║███████╗███████╗██║ 21 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ 22 | ``` 23 | 24 | ## Sponsor Practicalli 25 | 26 | [![Sponsor Practicalli via GitHub](https://raw.githubusercontent.com/practicalli/graphic-design/live/buttons/practicalli-github-sponsors-button.png)](https://github.com/sponsors/practicalli-johnny/) 27 | 28 | All sponsorship funds are used to support the continued development of [Practicalli series of books and videos](https://practical.li/), although most work is done at personal cost and time. 29 | 30 | Thanks to [Cognitect](https://www.cognitect.com/), [Nubank](https://nubank.com.br/) and a wide range of other [sponsors](https://github.com/sponsors/practicalli-johnny#sponsors) for your continued support 31 | 32 | ## Contributing 33 | 34 | Contributions are most welcome for Practicalli Books and project. However, as this is a personal journal, this specific repository does not take pull requests. 35 | 36 | Please read the [detailed Practicalli contributing page](https://practical.li/contributing/) to help you to help Practicalli. 37 | 38 | 39 | ## GitHub Actions 40 | 41 | The megalinter GitHub actions will run when a pull request is created,checking basic markdown syntax. 42 | 43 | A review of the change will be carried out by the Practicalli team and the PR merged if the change is acceptable. 44 | 45 | The Publish Book GitHub action will run when PR's are merged into main (or the Practicalli team pushes changes to the default branch). 46 | 47 | Publish book workflow installs Material for MkDocs version 9 48 | 49 | 50 | ## Local development 51 | 52 | Install the Python3 Pip package manager using the Debian package manager: 53 | 54 | ```shell 55 | apt install python3-pip pipx 56 | ``` 57 | 58 | Create and activate a python virtual environment 59 | 60 | ```shell 61 | python -m venv ~/venv/ && source ~/venv/bin/activate 62 | ``` 63 | 64 | Use pip3 to install mkdocs-material, along with the plugins used by the Practicalli site (plugins are also installed in the GitHub Action workflow) 65 | 66 | ```shell 67 | pip3 install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects mkdocs-rss-plugin pillow cairosvg 68 | ``` 69 | 70 | > pillow and cairosvg python packages are required for [Social Cards](https://squidfunk.github.io/mkdocs-material/setup/setting-up-social-cards/) 71 | 72 | 73 | MacOSX has not been tested, although it is assumed homebrew approach is the most likely to work. 74 | 75 | ```shell 76 | brew install python@3.12 77 | ``` 78 | 79 | --- 80 | 81 | Fork the GitHub repository and clone that fork to your computer, 82 | 83 | ```shell 84 | git clone https://github.com//.git 85 | ``` 86 | 87 | Run a local server from the root of the cloned project 88 | 89 | ```shell 90 | make docs 91 | ``` 92 | 93 | The website will open at 94 | 95 | If making smaller changes, then only rebuild the content that changes, speeding up the local development process 96 | 97 | ```shell 98 | make docs-changed 99 | ``` 100 | 101 | > NOTE: navigation changes may not be correctly reflected without reloading the page in the web browser or carrying out a full `make docs` build 102 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: I Devangelist 2 | site_url: https://practical.li/i-devangelist 3 | site_description: Journey into Developer Advocacy and Community Building 4 | site_author: Practicalli 5 | site_org: https://practical.li 6 | copyright: Copyright © 2024 Practicali CC BY-SA 4.0 7 | repo_url: https://github.com/practicalli/i-devangelist/ 8 | edit_uri: https://github.com/practicalli/i-devangelist/edit/main/docs/ 9 | 10 | # Theme and styling 11 | theme: 12 | name: material 13 | logo: assets/images/practicalli-logo.png 14 | favicon: assets/favicon.svg 15 | features: 16 | - announce.dismiss 17 | - content.action.edit 18 | - content.action.view 19 | - content.code.annotate 20 | - content.code.copy 21 | - content.tabs.link 22 | - navigation.footer 23 | - navigation.indexes # Nav sections can have files 24 | - navigation.instant # Avoid page reloading for internal links 25 | - navigation.top 26 | - navigation.tracking # Update URL with sub-heading anchor names 27 | - navigation.sections 28 | palette: 29 | # Palette toggle for light mode 30 | - media: "(prefers-color-scheme: light)" 31 | scheme: default 32 | primary: blue 33 | accent: teal 34 | toggle: 35 | icon: material/brightness-7 36 | name: Switch to dark mode 37 | # Palette toggle for dark mode 38 | - media: "(prefers-color-scheme: dark)" 39 | scheme: slate 40 | primary: blue 41 | accent: teal 42 | toggle: 43 | icon: material/brightness-4 44 | name: Switch to light mode 45 | # Override theme 46 | custom_dir: overrides 47 | 48 | extra_css: 49 | - assets/stylesheets/extra.css 50 | 51 | validation: 52 | omitted_files: warn 53 | absolute_links: relative_to_docs 54 | unrecognized_links: warn 55 | anchors: warn # New in MkDocs 1.6 56 | 57 | ## Additional styling 58 | markdown_extensions: 59 | - admonition 60 | - pymdownx.details 61 | - pymdownx.superfences 62 | - attr_list 63 | - md_in_html # Grids 64 | - footnotes # footnotes and abbreviations 65 | - pymdownx.emoji: 66 | emoji_index: !!python/name:material.extensions.emoji.twemoji 67 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 68 | - pymdownx.highlight: 69 | anchor_linenums: true 70 | - pymdownx.inlinehilite 71 | - pymdownx.snippets: 72 | url_download: true 73 | - pymdownx.superfences: 74 | custom_fences: 75 | - name: mermaid 76 | class: mermaid 77 | format: !!python/name:pymdownx.superfences.fence_code_format 78 | - pymdownx.tabbed: 79 | alternate_style: true 80 | - pymdownx.keys # keyboard keys 81 | - pymdownx.magiclink 82 | - def_list # lists 83 | - pymdownx.tasklist: 84 | custom_checkbox: true # checkboxes 85 | - toc: 86 | permalink: λ︎ 87 | 88 | ## Plugins 89 | plugins: 90 | - search 91 | - callouts 92 | - glightbox # Image aligning 93 | - git-revision-date-localized: # Update and Creation date of each page 94 | # enable_creation_date: true 95 | fallback_to_build_date: true 96 | 97 | # Generate Social Cards via CI only 98 | # in assets/images/social 99 | - social: 100 | cards: !ENV [MKDOCS_SOCIAL_CARDS_GENERATE, true] 101 | - tags 102 | 103 | # Footer / Social Media 104 | extra: 105 | analytics: 106 | provider: google 107 | property: G-J0HMKF793C 108 | social: 109 | - icon: material/web 110 | link: https://practical.li/ 111 | - icon: fontawesome/brands/linkedin 112 | link: https://www.linkedin.com/in/jr0cket/ 113 | - icon: fontawesome/brands/slack 114 | link: https://clojurians.slack.com/messages/practicalli 115 | - icon: fontawesome/brands/twitter 116 | link: https://twitter.com/practical_li 117 | - icon: fontawesome/brands/github 118 | link: https://github.com/practicalli 119 | - icon: fontawesome/brands/docker 120 | link: https://hub.docker.com/u/practicalli 121 | 122 | # Navigation 123 | nav: 124 | - Introduction: 125 | - index.md 126 | - What Is Devangelism: introduction/what-is-devangelism.md 127 | - Developer Relations: 128 | - developer-relations/index.md 129 | - Becoming Devangelist: 130 | - becoming-devangelist/index.md 131 | - Being Devangelist: 132 | - being-devangelist/index.md 133 | - Internal Advocacy: internal-advocacy.md 134 | - External Advocacy: external-advocacy.md 135 | - Community: 136 | - community-community-community/index.md 137 | - After Devangelism: 138 | - after-devangelism/index.md 139 | - Public Speaking: 140 | - public-speaking/index.md 141 | - Conferences: public-speaking/conferences.md 142 | -------------------------------------------------------------------------------- /docs/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | image/svg+xml 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | I 19 | P 20 | 9 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/assets/stylesheets/practicalli-light.css: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Rules 3 | // ---------------------------------------------------------------------------- 4 | 5 | // Color variables 6 | :root { 7 | @extend %root; 8 | 9 | // Primary color shades 10 | --md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1); 11 | --md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1); 12 | --md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1); 13 | --md-primary-bg-color: hsla(0, 0%, 100%, 1); 14 | --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); 15 | 16 | // Accent color shades 17 | --md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1); 18 | --md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1); 19 | --md-accent-bg-color: hsla(0, 0%, 100%, 1); 20 | --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); 21 | } 22 | 23 | // ---------------------------------------------------------------------------- 24 | 25 | // Allow to explicitly use color schemes in nested content 26 | [data-md-color-scheme="practicalli"] { 27 | @extend %root; 28 | } 29 | 30 | // ---------------------------------------------------------------------------- 31 | // Placeholders 32 | // ---------------------------------------------------------------------------- 33 | 34 | // Default theme, i.e. light mode 35 | %root { 36 | 37 | // Default color shades 38 | --md-default-fg-color: hsla(0, 0%, 0%, 0.87); 39 | --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54); 40 | --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32); 41 | --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07); 42 | --md-default-bg-color: hsla(53, 90%, 90%, 1); 43 | --md-default-bg-color--light: hsla(53, 90%, 90%, 0.7); 44 | --md-default-bg-color--lighter: hsla(53, 90%, 90%, 0.3); 45 | --md-default-bg-color--lightest: hsla(53, 90%, 90%, 0.12); 46 | 47 | // Code color shades 48 | --md-code-fg-color: hsla(200, 18%, 26%, 1); 49 | --md-code-bg-color: hsla(0, 0%, 96%, 1); 50 | 51 | // Code highlighting color shades 52 | --md-code-hl-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5); 53 | --md-code-hl-number-color: hsla(0, 67%, 50%, 1); 54 | --md-code-hl-special-color: hsla(340, 83%, 47%, 1); 55 | --md-code-hl-function-color: hsla(291, 45%, 50%, 1); 56 | --md-code-hl-constant-color: hsla(250, 63%, 60%, 1); 57 | --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1); 58 | --md-code-hl-string-color: hsla(150, 63%, 30%, 1); 59 | --md-code-hl-name-color: var(--md-code-fg-color); 60 | --md-code-hl-operator-color: var(--md-default-fg-color--light); 61 | --md-code-hl-punctuation-color: var(--md-default-fg-color--light); 62 | --md-code-hl-comment-color: var(--md-default-fg-color--light); 63 | --md-code-hl-generic-color: var(--md-default-fg-color--light); 64 | --md-code-hl-variable-color: var(--md-default-fg-color--light); 65 | 66 | // Typeset color shades 67 | --md-typeset-color: var(--md-default-fg-color); 68 | 69 | // Typeset `a` color shades 70 | --md-typeset-a-color: var(--md-primary-fg-color); 71 | 72 | // Typeset `mark` color shades 73 | --md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5); 74 | 75 | // Typeset `del` and `ins` color shades 76 | --md-typeset-del-color: hsla(6, 90%, 60%, 0.15); 77 | --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15); 78 | 79 | // Typeset `kbd` color shades 80 | --md-typeset-kbd-color: hsla(0, 0%, 98%, 1); 81 | --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1); 82 | --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1); 83 | 84 | // Typeset `table` color shades 85 | --md-typeset-table-color: hsla(0, 0%, 0%, 0.12); 86 | 87 | // Admonition color shades 88 | --md-admonition-fg-color: var(--md-default-fg-color); 89 | --md-admonition-bg-color: var(--md-default-bg-color); 90 | 91 | // Footer color shades 92 | --md-footer-fg-color: hsla(0, 0%, 100%, 1); 93 | --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); 94 | --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3); 95 | --md-footer-bg-color: hsla(0, 0%, 0%, 0.87); 96 | --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); 97 | 98 | // Shadow depth 1 99 | --md-shadow-z1: 100 | 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05), 101 | 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1); 102 | 103 | // Shadow depth 2 104 | --md-shadow-z2: 105 | 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.1), 106 | 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25); 107 | 108 | // Shadow depth 3 109 | --md-shadow-z3: 110 | 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.2), 111 | 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35); 112 | } 113 | -------------------------------------------------------------------------------- /docs/assets/practicalli-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | image/svg+xml 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | I 31 | P 32 | 9 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/config/markdown-lint.jsonc: -------------------------------------------------------------------------------- 1 | // Example markdownlint configuration with all properties set to their default value 2 | { 3 | 4 | // Default state for all rules 5 | "default": true, 6 | 7 | // Path to configuration file to extend 8 | "extends": null, 9 | 10 | // MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time 11 | "MD001": true, 12 | 13 | // MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading 14 | "MD002": { 15 | // Heading level 16 | "level": 1 17 | }, 18 | 19 | // MD003/heading-style/header-style - Heading style 20 | "MD003": { 21 | // Heading style 22 | "style": "consistent" 23 | }, 24 | 25 | // MD004/ul-style - Unordered list style 26 | "MD004": { 27 | // List style 28 | "style": "consistent" 29 | }, 30 | 31 | // MD005/list-indent - Inconsistent indentation for list items at the same level 32 | "MD005": true, 33 | 34 | // MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line 35 | "MD006": true, 36 | 37 | // MD007/ul-indent - Unordered list indentation 38 | "MD007": { 39 | // Spaces for indent 40 | "indent": 2, 41 | // Whether to indent the first level of the list 42 | "start_indented": false, 43 | // Spaces for first level indent (when start_indented is set) 44 | "start_indent": 2 45 | }, 46 | 47 | // MD009/no-trailing-spaces - Trailing spaces 48 | "MD009": { 49 | // Spaces for line break 50 | "br_spaces": 2, 51 | // Allow spaces for empty lines in list items 52 | "list_item_empty_lines": false, 53 | // Include unnecessary breaks 54 | "strict": true 55 | }, 56 | 57 | // MD010/no-hard-tabs - Hard tabs 58 | "MD010": { 59 | // Include code blocks 60 | "ignore_code_blocks": false, 61 | // Fenced code languages to ignore 62 | "ignore_code_languages": [ 63 | "Makefile", 64 | "shell" 65 | ], 66 | // Number of spaces for each hard tab 67 | "spaces_per_tab": 1 68 | }, 69 | 70 | // MD011/no-reversed-links - Reversed link syntax 71 | "MD011": true, 72 | 73 | // MD012/no-multiple-blanks - Multiple consecutive blank lines 74 | "MD012": { 75 | // Consecutive blank lines 76 | "maximum": 2 77 | }, 78 | 79 | // MD013/line-length - Line length 80 | "MD013": { 81 | // Number of characters 82 | "line_length": 520, 83 | // Number of characters for headings 84 | "heading_line_length": 90, 85 | // Number of characters for code blocks 86 | "code_block_line_length": 420, 87 | // Include code blocks 88 | "code_blocks": true, 89 | // Include tables 90 | "tables": true, 91 | // Include headings 92 | "headings": true, 93 | // Include headings 94 | "headers": true, 95 | // Strict length checking 96 | "strict": false, 97 | // Stern length checking 98 | "stern": true 99 | }, 100 | 101 | // MD014/commands-show-output - Dollar signs used before commands without showing output 102 | "MD014": true, 103 | 104 | // MD018/no-missing-space-atx - No space after hash on atx style heading 105 | "MD018": true, 106 | 107 | // MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading 108 | "MD019": true, 109 | 110 | // MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading 111 | "MD020": true, 112 | 113 | // MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading 114 | "MD021": true, 115 | 116 | // MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines 117 | "MD022": { 118 | // Blank lines above heading 119 | "lines_above": 1, 120 | // Blank lines below heading 121 | "lines_below": 1 122 | }, 123 | 124 | // MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line 125 | "MD023": true, 126 | 127 | // MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content 128 | "MD024": { 129 | // Only check sibling headings 130 | "allow_different_nesting": false, 131 | // Only check sibling headings 132 | "siblings_only": false 133 | }, 134 | 135 | // MD025/single-title/single-h1 - Multiple top-level headings in the same document 136 | "MD025": { 137 | // Heading level 138 | "level": 1, 139 | // RegExp for matching title in front matter 140 | "front_matter_title": "^\\s*title\\s*[:=]" 141 | }, 142 | 143 | // MD026/no-trailing-punctuation - Trailing punctuation in heading 144 | "MD026": { 145 | // Punctuation characters not allowed at end of headings 146 | "punctuation": ".,;:!。,;:!" 147 | }, 148 | 149 | // MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol 150 | "MD027": true, 151 | 152 | // MD028/no-blanks-blockquote - Blank line inside blockquote 153 | "MD028": true, 154 | 155 | // MD029/ol-prefix - Ordered list item prefix 156 | "MD029": { 157 | // List style 158 | "style": "one_or_ordered" 159 | }, 160 | 161 | // MD030/list-marker-space - Spaces after list markers 162 | "MD030": { 163 | // Spaces for single-line unordered list items 164 | "ul_single": 1, 165 | // Spaces for single-line ordered list items 166 | "ol_single": 1, 167 | // Spaces for multi-line unordered list items 168 | "ul_multi": 1, 169 | // Spaces for multi-line ordered list items 170 | "ol_multi": 1 171 | }, 172 | 173 | // MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines 174 | "MD031": { 175 | // Include list items 176 | "list_items": true 177 | }, 178 | 179 | // MD032/blanks-around-lists - Lists should be surrounded by blank lines 180 | "MD032": true, 181 | 182 | // MD033/no-inline-html - Inline HTML 183 | "MD033": { 184 | // Allowed elements 185 | "allowed_elements": [ "a", "iframe", "img", "p", "div", "script" ] 186 | }, 187 | 188 | // MD034/no-bare-urls - Bare URL used 189 | "MD034": false, 190 | 191 | // MD035/hr-style - Horizontal rule style 192 | "MD035": { 193 | // Horizontal rule style 194 | "style": "consistent" 195 | }, 196 | 197 | // MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading 198 | "MD036": { 199 | // Punctuation characters 200 | "punctuation": ".,;:!?。,;:!?" 201 | }, 202 | 203 | // MD037/no-space-in-emphasis - Spaces inside emphasis markers 204 | "MD037": true, 205 | 206 | // MD038/no-space-in-code - Spaces inside code span elements 207 | "MD038": true, 208 | 209 | // MD039/no-space-in-links - Spaces inside link text 210 | "MD039": true, 211 | 212 | // MD040/fenced-code-language - Fenced code blocks should have a language specified 213 | "MD040": { 214 | // List of languages 215 | "allowed_languages": [], 216 | // Require language only 217 | "language_only": false 218 | }, 219 | 220 | // MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading 221 | "MD041": { 222 | // Heading level 223 | "level": 1, 224 | // RegExp for matching title in front matter 225 | "front_matter_title": "^\\s*title\\s*[:=]" 226 | }, 227 | 228 | // MD042/no-empty-links - No empty links 229 | "MD042": true, 230 | 231 | // MD043/required-headings/required-headers - Required heading structure 232 | "MD043": {}, 233 | 234 | // MD044/proper-names - Proper names should have the correct capitalization 235 | "MD044": { 236 | // List of proper names 237 | "names": [], 238 | // Include code blocks 239 | "code_blocks": true, 240 | // Include HTML elements 241 | "html_elements": true 242 | }, 243 | 244 | // MD045/no-alt-text - Images should have alternate text (alt text) 245 | "MD045": true, 246 | 247 | // MD046/code-block-style - Code block style 248 | "MD046": { 249 | // Block style 250 | "style": "consistent" 251 | }, 252 | 253 | // MD047/single-trailing-newline - Files should end with a single newline character 254 | "MD047": true, 255 | 256 | // MD048/code-fence-style - Code fence style 257 | "MD048": { 258 | // Code fence style 259 | "style": "consistent" 260 | }, 261 | 262 | // MD049/emphasis-style - Emphasis style should be consistent 263 | "MD049": { 264 | // Emphasis style should be consistent 265 | "style": "consistent" 266 | }, 267 | 268 | // MD050/strong-style - Strong style should be consistent 269 | "MD050": { 270 | // Strong style should be consistent 271 | "style": "consistent" 272 | }, 273 | 274 | // MD051/link-fragments - Link fragments should be valid 275 | "MD051": true, 276 | 277 | // MD052/reference-links-images - Reference links and images should use a label that is defined 278 | "MD052": true, 279 | 280 | // MD053/link-image-reference-definitions - Link and image reference definitions should be needed 281 | "MD053": { 282 | // Ignored definitions 283 | "ignored_definitions": ["//"] 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------ 2 | # Practicalli Makefile 3 | # 4 | # Consistent set of targets to support local development of Clojure 5 | # and build the Clojure service during CI deployment 6 | # 7 | # `-` before a command ignores any errors returned 8 | 9 | # Requirements 10 | # - cljstyle 11 | # - Clojure CLI aliases 12 | # - `:dev/env` to include `dev` directory on class path 13 | # - `:test/env` to include `test` directory and libraries to support testing 14 | # - `:test/run` to run kaocha kaocha test runner and supporting paths and dependencies 15 | # - `:repl/rebel` to start a Rebel terminal UI 16 | # - `:build/task` to build this project into a jar or uberjar 17 | # - docker 18 | # - mega-linter-runner 19 | # ------------------------------------------ 20 | 21 | # -- Makefile task config -------------- # 22 | # .PHONY: ensures target used rather than matching file name 23 | # https://makefiletutorial.com/#phony 24 | .PHONY: all clean deps dist docs lint pre-commit-check repl test test-ci test-watch 25 | # -------------------------------------- # 26 | 27 | # -- Makefile Variables ---------------- # 28 | # run help if no target specified 29 | .DEFAULT_GOAL := help 30 | SHELL := /usr/bin/zsh 31 | 32 | # Column the target description is printed from 33 | HELP-DESCRIPTION-SPACING := 24 34 | 35 | # Tool variables 36 | CLOJURE_TEST_RUNNER = clojure -M:test/env:test/run 37 | CLOJURE_EXEC_TEST_RUNNER = clojure -X:test/env:test/run 38 | DOCKER-BUILD-LOGFILE := docker-build-log-$(shell date +%y-%m-%d-%T).md 39 | # MEGALINTER_RUNNER := npx mega-linter-runner --flavor documentation --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --remove-container 40 | MEGALINTER_RUNNER := npx mega-linter-runner --flavor java --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --remove-container 41 | MKDOCS_SERVER := mkdocs serve --dev-addr localhost:7777 42 | OUTDATED_FILE := outdated-$(shell date +%y-%m-%d-%T).md 43 | 44 | # Makefile file and directory name wildcard 45 | # EDN-FILES := $(wildcard *.edn) 46 | # -------------------------------------- # 47 | 48 | # -- Help ------------------------------ # 49 | # Source: https://nedbatchelder.com/blog/201804/makefile_help_target.html 50 | 51 | help: ## Describe available tasks in Makefile 52 | @grep '^[a-zA-Z]' $(MAKEFILE_LIST) | \ 53 | sort | \ 54 | awk -F ':.*?## ' 'NF==2 {printf "\033[36m %-$(HELP-DESCRIPTION-SPACING)s\033[0m %s\n", $$1, $$2}' 55 | # -------------------------------------- # 56 | 57 | # -- Clojure Projects ------------------ # 58 | service: ## New project with practicalli/service template 59 | $(info -- Create Service Project ----------------) 60 | clojure -T:project/create :template practicalli/service :name practicalli/gameboard 61 | 62 | service-donut: ## New project with practicalli/service template & Donut 63 | $(info -- Create Service Project with Donut -----) 64 | clojure -T:project/create :template practicalli/service :name practicalli/gameboard :target-dir gameboard-donut 65 | 66 | service-integrant: ## New project with practicalli/service template & Integrant 67 | $(info -- Create Service Project with Integrant -) 68 | clojure -T:project/create :template practicalli/service :name practicalli/gameboard :target-dir gameboard-integrant 69 | 70 | landing-page: ## New project with practicalli/landing-page template local 71 | $(info -- Run Rebel REPL ------------------------) 72 | clojure -T:project/create :template practicalli/landing-page :name practicalli/landing-page 73 | 74 | outdated: ## Check deps.edn & GitHub actions for new versions 75 | $(info -- Search for outdated libraries ---------) 76 | - clojure -T:search/outdated > $(OUTDATED_FILE) 77 | # -------------------------------------- # 78 | 79 | # -- Clojure Workflow ------------------ # 80 | repl: rebel ## Start default REPL configuration 81 | 82 | rebel: ## Run Clojure REPL with rich terminal UI (Rebel Readline) 83 | $(info -- Run Rebel REPL ------------------------) 84 | clojure -M:dev/env:test/env:repl/rebel 85 | 86 | reloaded: ## Run Clojure REPL with rich terminal UI (Rebel Readline) 87 | $(info -- Run Rebel REPL ------------------------) 88 | clojure -M:repl/reloaded 89 | 90 | deps: deps.edn ## Prepare dependencies for test and dist targets 91 | $(info -- Download test and service libraries ---------------) 92 | clojure -P -M:test/run && clojure -P -T:build/task 93 | 94 | dist: build-uberjar ## Build and package Clojure service 95 | $(info -- Build and Package Clojure service ----------------) 96 | 97 | 98 | clean: ## Clean Clojure tooling temporary files 99 | $(info -- Clean Clojure temporary files ---------) 100 | - rm -rf ./.cpcache ./.clj-kondo/cache ./.lsp 101 | 102 | run: ## Run Service using clojure.main 103 | $(info --------- Download test and service libraries ---------) 104 | clojure -M:run/service 105 | # -------------------------------------- # 106 | 107 | # -- Testing --------------------------- # 108 | test-config: ## Print Kaocha test runner configuration 109 | $(info -- Runner Configuration ----------------) 110 | $(CLOJURE_TEST_RUNNER) --print-config 111 | 112 | test-profile: ## Profile unit test speed, showing 3 slowest tests 113 | $(info -- Runner Profile Tests ----------------) 114 | $(CLOJURE_TEST_RUNNER) --plugin kaocha.plugin/profiling 115 | 116 | test: ## Run unit tests - stoping on first error 117 | $(info -- Runner for unit tests -----------------) 118 | $(CLOJURE_EXEC_TEST_RUNNER) 119 | 120 | test-all: ## Run all unit tests regardless of failing tests 121 | $(info -- Runner for all unit tests -------------) 122 | $(CLOJURE_EXEC_TEST_RUNNER) :fail-fast? false 123 | 124 | test-watch: ## Run tests when changes saved, stopping test run on first error 125 | $(info -- Watcher for unit tests, fail fast -----) 126 | $(CLOJURE_EXEC_TEST_RUNNER) :watch? true 127 | 128 | test-watch-all: ## Run all tests when changes saved, regardless of failing tests 129 | $(info -- Watcher for unit tests ----------------) 130 | $(CLOJURE_EXEC_TEST_RUNNER) :fail-fast? false :watch? true 131 | # -------------------------------------- # 132 | 133 | # -------- Build tasks ----------------- # 134 | build-config: ## Pretty print build configuration 135 | $(info --------- View current build config ---------) 136 | clojure -T:build/task config 137 | 138 | build-jar: ## Build a jar archive of Clojure project 139 | $(info --------- Build library jar ---------) 140 | clojure -T:build/task jar 141 | 142 | build-uberjar: ## Build a uberjar archive of Clojure project & Clojure runtime 143 | $(info --------- Build service Uberjar ---------) 144 | clojure -T:build/task uberjar 145 | 146 | build-uberjar-echo: ## Build a uberjar archive of Clojure project & Clojure runtime 147 | $(info -- Build service Uberjar ----------------) 148 | $(info -- Prerequisites newer than target -------) 149 | echo $? 150 | clojure -T:build/task uberjar 151 | 152 | build-clean: ## Clean build assets or given directory 153 | $(info --------- Clean Build ---------) 154 | clojure -T:build/task clean 155 | # -------------------------------------- # 156 | 157 | # -- Code Quality ---------------------- # 158 | pre-commit-check: format-check lint test ## Run format, lint and test targets 159 | 160 | format-check: ## Run cljstyle to check the formatting of Clojure code 161 | $(info -- cljstyle Runner show errors -----------) 162 | cljstyle check 163 | 164 | format-fix: ## Run cljstyle and fix the formatting of Clojure code 165 | $(info -- cljstyle Runner fix errors ------------) 166 | cljstyle fix 167 | 168 | lint: ## Run MegaLinter with custom configuration (node.js required) 169 | $(info -- MegaLinter Runner ---------------------) 170 | $(MEGALINTER_RUNNER) 171 | 172 | lint-fix: ## Run MegaLinter with applied fixes and custom configuration (node.js required) 173 | $(info -- MegaLinter Runner fix errors ----------) 174 | $(MEGALINTER_RUNNER) --fix 175 | 176 | lint-clean: ## Clean MegaLinter report information 177 | $(info -- MegaLinter Clean Reports --------------) 178 | - rm -rf ./megalinter-reports 179 | 180 | megalinter-upgrade: ## Upgrade MegaLinter config to latest version 181 | $(info -- MegaLinter Upgrade Config -------------) 182 | npx mega-linter-runner@latest --upgrade 183 | # -------------------------------------- # 184 | 185 | # ------- Version Control -------------- # 186 | git-sr: ## status list of git repos under current directory 187 | $(info -- Multiple Git Repo Status --------------) 188 | mgitstatus -e --flatten 189 | 190 | git-status: ## status details of git repos under current directory 191 | $(info -- Multiple Git Status -------------------) 192 | mgitstatus 193 | # -------------------------------------- # 194 | 195 | # --- Documentation Generation -------- # 196 | 197 | python-venv: 198 | $(info -- Create Python Virtual Environment -----) 199 | python3 -m venv ~/.local/venv 200 | 201 | mkdocs-install: 202 | $(info -- Install Material for MkDocs -----------) 203 | . ~/.local/venv/bin/activate; pip install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects mkdocs-rss-plugin pillow cairosvg --upgrade 204 | 205 | docs: ## Build and run mkdocs in local server (python venv) 206 | $(info -- MkDocs Local Server -------------------) 207 | . ~/.local/venv/bin/activate; $(MKDOCS_SERVER) 208 | 209 | docs-changed: ## Build only changed files and run mkdocs in local server (python venv) 210 | $(info -- Mkdocs Local Server -------------------) 211 | . ~/.local/venv/bin/activate; $(MKDOCS_SERVER) --dirtyreload 212 | 213 | docs-build: ## Build mkdocs (python venv) 214 | $(info -- Mkdocs Local Server -------------------) 215 | . ~/.local/venv/bin/activate; mkdocs build 216 | 217 | docs-debug: ## Build only changed files and run mkdocs in local server (python venv) 218 | $(info -- Mkdocs Local Server Debug -------------) 219 | . ~/.local/venv/bin/activate; $(MKDOCS_SERVER) -v 220 | # -------------------------------------- # 221 | 222 | # -- Docker Containers ----------------- # 223 | docker-build: ## Build Clojure project and run with docker compose 224 | $(info -- Docker Compose Build ------------------) 225 | docker compose up --build --detach 226 | 227 | docker-build-log: ## Build Clojure project and run with docker compose - log to file 228 | $(info --------- Docker Compose Build ---------) 229 | docker compose up --build --detach &> $(DOCKER-BUILD-LOGFILE) | tee $(DOCKER-BUILD-LOGFILE) 230 | 231 | docker-build-clean: ## Build Clojure project and run with docker compose, removing orphans 232 | $(info -- Docker Compose Build, remove orphans --) 233 | docker compose up --build --remove-orphans --detach 234 | 235 | docker-down: ## Shut down containers in docker compose 236 | $(info -- Docker Compose Down -------------------) 237 | docker compose down 238 | 239 | docker-inspect: ## Inspect given docker image - image-id=12e45fg89 240 | $(info -- Docker Image Prune --------------------) 241 | docker inspect --format='{{json .Config}}' $(image-id) | jq 242 | 243 | docker-image-prune: ## Prune docker images 244 | $(info -- Docker Image Prune --------------------) 245 | docker image prune 246 | 247 | docker-container-prune: ## Prune docker containers 248 | $(info -- Docker Container Prune ----------------) 249 | docker container prune 250 | 251 | docker-prune: docker-image-prune docker-image-prune ## Prune docker images and containers 252 | 253 | swagger-editor: ## Start Swagger Editor in Docker 254 | $(info -- Run Swagger Editor at locahost:8282 ---) 255 | docker compose -f swagger-editor.yaml up -d swagger-editor --detatch 256 | 257 | swagger-editor-down: ## Stop Swagger Editor in Docker 258 | $(info -- Run Swagger Editor at locahost:8282 ---) 259 | docker compose -f swagger-editor.yaml down 260 | # -------------------------------------- # 261 | 262 | # -- Continuous Integration ------------ # 263 | # .DELETE_ON_ERROR: halts if command returns non-zero exit status 264 | # https://makefiletutorial.com/#delete_on_error 265 | 266 | # TODO: focus runner on ^:integration` tests 267 | test-ci: deps ## Test runner for integration tests 268 | $(info -- Runner for integration tests ---------) 269 | clojure -P -X:test/env:test/run 270 | 271 | # Run tests, build & package the Clojure code and clean up afterward 272 | # `make all` used in Docker builder stage 273 | .DELETE_ON_ERROR: 274 | all: test-ci dist clean ## Call test-ci dist and clean targets, used for CI 275 | # -------------------------------------- # 276 | --------------------------------------------------------------------------------