Commits: 3
Improve the publish
Fix the changelog containing too many items (a bug).
Add two chances to abort: before committing and before pushing.
Print a nice table with a summary.
Modularize the logic into many neat functions. Leverage that a function will not pollute environment, including $PWD. So now each function changes directory to where it needs to be.
index 61bc9e8..2d0e5be 100755
--- a/publish.nu
+++ b/publish.nu
@@ -1,97 +1,155 @@
-use std/dirs
-
-def main [] {
- # Get the current source branch
- # Switch pages to the same branch. Create it if needed.
- # Find the time of last commit to pages.
- # Make a list of commits in source since then.
- # Format it as markdown list (only titles and hashes)
- # Prepare a commit, showing a diff for users review
- # Push to publish
-
- if (not (git is-clean)) {
- print "The source repository is not clean. First commit, then publish."
- git status
- exit 2
+# Build and publish the website
+def main [
+ --source: path = "." # path to the source repository
+ --pages: path = "./pages.git" # path to the Codeberg Pages repository
+] {
+ # A record of information about source and pages repositories gathered as we go.
+ mut spec = {
+ source_path: ($source | path expand)
+ pages_path: ($pages | path expand)
= }
=
- let source_branch = (git symbolic-ref --short HEAD)
- print $"Source branch is ($source_branch)"
+ if (not (git is-clean $spec.source_path)) {
+ error make --unspanned {
+ msg: $"The source repository is not clean.",
+ help: $"First commit, then publish. Here are the changes:\n\n (git status --porcelain)"
+ }
+ }
+
+ $spec.branch = git current-branch $spec.source_path
=
- dirs add pages.git
+ git clean-repo $spec.pages_path
+ git switch-or-create $spec.pages_path $spec.branch
=
- print "Cleaning pages worktree..."
+ $spec.last_deployment_time = git last_commit_time $spec.pages_path
+
+ $spec.changelog = git changelog $spec.source_path $spec.last_deployment_time
+
+ let now = date now | date to-timezone utc | format date "%A, %F %T (utc)"
+
+ # TODO: Find a way to work with indentation.
+ # See https://github.com/nushell/nushell/issues/11477
+ let commit_template = $"
+Deployment ($now)
+
+Changes since ($spec.last_deployment_time | date to-timezone utc | format date '%A, %F %T (utc)'):
+
+($spec.changelog | format changelog)
+ "
+
+ zola build
+
+ print "About to commit and publish. Here is the summary: "
+ $spec | table --expand | print
+ input --numchar 1 "Press any key to continue, or ctrl-c to abort."
+
+ $commit_template | git publish $spec.pages_path $spec.branch
+}
+
+# Takes commit message as input
+def "git publish" [repo: path, branch: string]: string -> nothing {
+ cd $repo
+ let commit_template_file = mktemp --tmpdir
+ $in | save --append $commit_template_file
+ git add .
+ # TODO: Provide a mechanism to abort (use --template ?)
+ git commit --verbose --file $commit_template_file --edit
+
+ input --numchar 1 "Commit ready. Press any key to publish, or ctrl-c to abort."
+ git push --set-upstream origin $branch
+}
+
+def "git is-clean" [repo: path]: nothing -> bool {
+ cd $repo
+ git status --porcelain | is-empty
+}
+
+def "git current-branch" [repo: path]: nothing -> string {
+ cd $repo
+ git symbolic-ref --short HEAD
+}
+
+def "git clean-repo" [repo: path] {
+ cd $repo
+ print $"Cleaning ($repo) worktree..."
= git restore .
= git clean -fd
+}
=
- if (git has branch $source_branch) {
- print "The branch exists in pages repository. Switching."
- git switch --quiet $source_branch
+def "git switch-or-create" [repo: path, branch: string] {
+ cd $repo
+ if (git has branch $repo $branch) {
+ print $"The branch ($branch) already exists in ($repo). Switching..."
+ git switch --quiet $branch
=
= if (git is-tracking) {
- print "The branch was already deployed. Pulling."
+ print $"The branch ($branch) was already deployed. Pulling..."
= git pull --quiet
= }
= } else {
- print "The branch does not exist in pages repository."
+ print $"The branch ($branch) does not yet exist in ($repo)."
= loop {
- match (input --numchar 1 $"Create and deploy a new branch '($source_branch)'? [y|n]: ") {
+ match (input --numchar 1 $"Create a new branch '($branch)'? [y|n]: ") {
= "y" => break,
= "n" => { exit 1 },
= _ => continue,
= }
= }
- git switch main
- git switch --quiet --create $source_branch
+ git switch --quiet main
+ git switch --quiet --create $branch
= }
=
- let last_commit_time = git show --no-patch --format=%cI
- print $"Pages last published on ($last_commit_time)"
-
- let commit_template = mktemp --tmpdir
- let now = date now | date to-timezone utc | format date "%A, %F %T (utc)"
-
- echo $"Update ($now)"
- | save --append $commit_template
- echo "\n\n"
- | save --append $commit_template
- echo $"Changes since ($last_commit_time | date to-timezone utc | format date '%A, %F %T (utc)')\n\n"
- | save --append $commit_template
- dirs prev
-
- git log --pretty=reference --since=$last_commit_time
- | save --append $commit_template
-
- zola build
+}
=
- dirs next
- git add .
- git commit --verbose --file $commit_template --edit
- git push --set-upstream origin $source_branch
+def "git last_commit_time" [repo: path]: nothing -> datetime {
+ cd $repo
+ git show --no-patch --format=%cI | into datetime
=}
=
=# List all branches that can be switched to
-def "git list branches" [] {
+def "git list branches" [repo: path] {
+ cd $repo
= git branch --list --all --format='%(refname:lstrip=-1)'
= | lines
= | filter { |line| $line != "HEAD" }
= | uniq
=}
=
-def "git has branch" [name: string] {
- $name in (git list branches)
+def "git has branch" [repo: path, branch: string] {
+ cd $repo
+ $branch in (git list branches $repo)
=}
=
-
+# Check if the current branch is tracking a remote.
=def "git is-tracking" [] {
= try {
- git rev-parse --abbrev-ref --symbolic-full-name @{u} err> /dev/null
+ git rev-parse --abbrev-ref --symbolic-full-name @{u} err>| ignore
= true
= } catch {
= false
= }
=}
=
-def "git is-clean" [] {
- git status --porcelain | is-empty
+
+
+def "git changelog" [repo: path, since: datetime]: nothing -> table {
+ cd $repo
+ git log --pretty=reference --date=iso-strict
+ | parse "{hash} ({title}, {date})"
+ | update date { |row| $row.date | into datetime }
+ | where date > $since
+}
+
+def "format changelog" []: table -> string {
+ $in
+ | group-by { |row| $row.date | format date "%A, %F" }
+ | transpose date commits
+ | each { |day| $"($day.date):\n\n($day.commits | format changelog day)\n\n" }
+ | str join "\n\n"
+}
+
+def "format changelog day" []: table -> string {
+ $in
+ | format pattern " * {hash} {title}"
+ | str join "\n"
=}Move people pages to a new People section
The home page now focuses on our services and commitments.
index acdeccb..b8c0bff 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -3,3 +3,8 @@
=
=We are an international network of IT professionals and entrepreneurs dedicated to promote and support free software and use of services respecting human rights, dignity and privacy.
=
+At the heart of our services lies a commitment to Free and Open Source Software (FOSS) and EU cloud solutions, ensuring privacy and adherence to open standards.
+
+Based entirely in Europe, [our team](@/people/_index.md) is on-shore, allowing us to provide localized, high-quality services. We offer assistance in multiple languages, including English, Dutch, French, Polish, Galician, Spanish, Portuguese, German, and Hungarian.
+
+Our primary focus is on helping European Small and Medium-sized Enterprises (SMEs), Non-Governmental Organizations (NGOs), local governments, and educational institutions with implementing free, open-source and European software solutions.new file mode 100644
index 0000000..00b8130
--- /dev/null
+++ b/content/people/_index.md
@@ -0,0 +1,7 @@
+---
+title: People
+template: people.html
+---
+
+We are an international network of IT professionals and entrepreneurs dedicated to promote and support free software and use of services respecting human rights, dignity and privacy.
+similarity index 100%
rename from content/joachim-nuyttens.md
rename to content/people/joachim-nuyttens.mdsimilarity index 100%
rename from "content/jo\303\243o-campos.md"
rename to "content/people/jo\303\243o-campos.md"similarity index 100%
rename from content/richard-cronan.md
rename to content/people/richard-cronan.mdsimilarity index 100%
rename from content/tad-lazurski.md
rename to content/people/tad-lazurski.mdsimilarity index 100%
rename from content/tibor-eszes.md
rename to content/people/tibor-eszes.mdsimilarity index 100%
rename from "content/v\303\255tor-andrade.md"
rename to "content/people/v\303\255tor-andrade.md"index 8888a53..12a7973 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -77,12 +77,17 @@
=
= body > header {
= font-size: var(--prompt-font-size);
- align-items: center;
- display: flex;
- gap: 1ch;
= color: var(--dark-color);
= padding: 3rem 1rem;
= overflow: hidden;
+
+ &> a {
+ align-items: center;
+ display: flex;
+ gap: 1ch;
+ text-decoration: none;
+ color: inherit;
+ }
= }
=
= body > main {
@@ -124,6 +129,7 @@
=
= #logo {
= height: 3em;
+ width: 3em;
= }
=
= p {
@@ -284,17 +290,20 @@
= <![endif]-->
=
= <header>
- <img
- id="logo"
- src="esc-logo.svg"
- alt="The ESC logo with a sky-blue ring and a bright yellow ray passing through it."
- />
-
- <hgroup class="title">
- <h1>esc collective</h1>
- <p>supporting european digital independence</p>
- </hgroup>
+ <a href="{\{ get_url(path='@/_index.md') \}}">
+ <img
+ id="logo"
+ src="{\{ get_url(path='/esc-logo.svg') \}}"
+ alt="The ESC logo with a sky-blue ring and a bright yellow ray passing through it."
+ />
+
+ <hgroup class="title">
+ <h1>esc collective</h1>
+ <p>supporting european digital independence</p>
+ </hgroup>
+ </a>
= </header>
+
= <main>
= {\% filter indent(prefix=" ") -%}
= {\%- block main_content -%}
@@ -303,7 +312,12 @@
= </main>
=
= <footer class="full-bleed-background">
- <img src="favicon.svg" alt="ESC Icon" class="icon" />
+ <img
+ src="{\{ get_url(path='/favicon.svg') \}}"
+ alt="ESC Icon"
+ class="icon"
+ />
+
=
= <ul class="prompt">
= <!-- Remember to adjust the --prompts-count variable -->index 4645233..4a9795b 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -2,17 +2,4 @@
=
={\%- block main_content -%}
={\{- section.content | safe -\}}
-
-<section class="card-grid">
- {# Each page in this category represents a person.
-
- It's a bit clunky. We will improve it later.
- #}
- {\%- for page in section.pages | sort(attribute="date") -%}
- <article>
- <h2>{\{ page.title \}}</h2>
- {\{ page.content | safe \}}
- </article>
- {\%- endfor -%}
-</section>
={\%- endblock main_content -%}new file mode 100644
index 0000000..223d7ed
--- /dev/null
+++ b/templates/page.html
@@ -0,0 +1,5 @@
+{\% extends "base.html" %}
+
+{\%- block main_content -%}
+{\{- page.content | safe -\}}
+{\%- endblock main_content -%}new file mode 100644
index 0000000..4645233
--- /dev/null
+++ b/templates/people.html
@@ -0,0 +1,18 @@
+{\% extends "base.html" %}
+
+{\%- block main_content -%}
+{\{- section.content | safe -\}}
+
+<section class="card-grid">
+ {# Each page in this category represents a person.
+
+ It's a bit clunky. We will improve it later.
+ #}
+ {\%- for page in section.pages | sort(attribute="date") -%}
+ <article>
+ <h2>{\{ page.title \}}</h2>
+ {\{ page.content | safe \}}
+ </article>
+ {\%- endfor -%}
+</section>
+{\%- endblock main_content -%}Copy services description from Joachim to home page
Joachim wrote a draft of our services' description here:
https://club.tad-lispy.com/t/esc-services-definition-website/189/3?u=tad-lispy
I besically copied it verbatim. As he said himself, we need to work on this content more, but IMO it's a great start.
For now everything is on the home page, which now looks like a wall of text. We will need to separate some of it to sub-pages. Maybe also create some taxonomies for languages and skills, so people can be found this way.
index b8c0bff..435d9d3 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -7,4 +7,63 @@ At the heart of our services lies a commitment to Free and Open Source Software
=
=Based entirely in Europe, [our team](@/people/_index.md) is on-shore, allowing us to provide localized, high-quality services. We offer assistance in multiple languages, including English, Dutch, French, Polish, Galician, Spanish, Portuguese, German, and Hungarian.
=
+
+# Our Services
+
=Our primary focus is on helping European Small and Medium-sized Enterprises (SMEs), Non-Governmental Organizations (NGOs), local governments, and educational institutions with implementing free, open-source and European software solutions.
+
+
+## Cloud assistance
+
+Your organisation probably depends on multiple cloud services. Setting up, managing and migrating cloud services can be complicated. Or maybe your company is or wants to self-host some applications? Our team is happy to assist you on projects or provide operational support for your cloud and self-hosted services.
+
+Our technical capabilities include:
+
+ * Cloud infrastructure: Kubernetes, Docker, OpenShift, and pretty much any Cloud provider
+ * Infrastructure automation: Terraform, Ansible, GitOps with ArgoCD, GitHub Actions, Jenkins
+ * Service architecture: service mesh, service discovery, containerization, server-less
+ * System reliability: monitoring (Prometheus, Grafana, Nagios), observability, high availability
+ * Linux, Unix wizardry
+ * Scripting
+
+Reach out to us for any project or operational support in
+
+ * Setting up cloud or self-hosted services, applications
+ * Migrating your cloud or self-hosted services
+ * Administering your cloud or self-hosted services
+ * Trusted Admin Failover as a Service (TAFaaS), if you would like to have a backup plan when your trusted admin is absent unexpectedly
+
+
+## Software Development
+
+Need any customization or extension of FOSS functionalities? Need hard coding skills to set up a (web)application? Want to automate some tasks? Our team has a broad technical skillset, including (but not limited to):
+
+ * HTML, CSS, JavaScript
+ * Python
+ * Rust
+ * Elm
+ * Haskell
+ * Groovy
+ * SQL
+ * Bash
+ * Go
+
+
+## Consulting
+
+We can assist with small and big projects, provide momentary advice or define long term strategies for your organisation. Some examples:
+
+ * Project management
+ * Define migration strategies from concept to technical detail, for example moving to a new collaborative software platform (email, calendar, file sharing, etc.)
+ * Define technical solutions to meet your data security and data privacy requirements
+
+
+## Training and coaching
+
+We can provide training and coaching on different topics. The following list is not exhaustive, don't hesitate to reach out for other needs in the FOSS domain:
+
+ * Web Development
+ * Agile development, Test driven development, Pair prohramming
+ * Relational Databases (RDBMS)
+ * Version management using Git
+ * Operating Systems (Linux, Nix / NixOS)