Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
output/
myenv/
.git/
__pycache__/
*.pyc
37 changes: 37 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

version: 2
updates:
- package-ecosystem: pip
directory: /
schedule:
interval: monthly
labels:
- dependencies

- package-ecosystem: docker
directory: /
schedule:
interval: monthly
labels:
- dependencies

- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
labels:
- dependencies
23 changes: 19 additions & 4 deletions .github/workflows/build-pelican.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Build Solr website with ASF Pelican action

on:
Expand All @@ -18,14 +33,14 @@ jobs:
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
ref: ${{ github.ref == 'refs/heads/production' && 'production' || 'main' }}

- name: Build Pelican Site
uses: apache/infrastructure-actions/pelican@main
uses: apache/infrastructure-actions/pelican@4deec7dce934d27491a0b1a8216f8d292548f7a4 # main 2025-04-13
with:
destination: ${{ github.ref == 'refs/heads/production' && 'asf-site' || 'asf-staging' }}
gfm: 'false'
version: '4.9.1'
requirements: 'requirements.txt'
version: '4.11.0.post0'
requirements: 'requirements.txt'
23 changes: 19 additions & 4 deletions .github/workflows/pr-build-pelican.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Build Solr website with ASF Pelican action for PRs

on:
Expand All @@ -9,12 +24,12 @@ jobs:
build-pelican:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Build Pelican Site
uses: apache/infrastructure-actions/pelican@main
uses: apache/infrastructure-actions/pelican@4deec7dce934d27491a0b1a8216f8d292548f7a4 # main 2025-04-13
with:
gfm: 'false'
version: '4.9.1'
version: '4.11.0.post0'
publish: 'false'
debug: 'false'
requirements: 'requirements.txt'
requirements: 'requirements.txt'
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Base image pinned by digest — updated automatically by Dependabot (docker ecosystem).
# When Dependabot opens a bump PR, also regenerate requirements.txt (see README.md).
FROM python:3.13-alpine@sha256:70dd89363f8665af9a8076ef505bfd8b8bf2fb0b3ab45860cd3494ab7197fe73
WORKDIR /work
COPY requirements.txt .
RUN pip3 install --require-hashes -r requirements.txt && rm requirements.txt
32 changes: 28 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,37 @@ If the staged site looks good, simply merge the changes to branch `production` a
For larger edits it is recommended to build and preview the site locally. This lets you see the result of your changes instantly without committing anything.
The bundled script uses a docker image to build and serve the site locally. Please make sure you have docker installed.

# Usage: ./build.sh [-l] [-h] [<other pelican arguments>]
# -l Live build and reload source changes on localhost:8000
# --help Show full help for options that Pelican accepts
./build.sh -l
./build.sh -l # live-reload on http://localhost:8000
./build.sh --help # show all options

Now go to <http://localhost:8000> to view the beautiful Solr web page served from your laptop with live-preview of updates :)

### Updating the dependency lockfile

`requirements.in` is the human-editable list of direct dependencies. `requirements.txt` is the
fully pinned, hash-verified lockfile generated from it. Dependabot updates both files automatically
when it opens a pip bump PR. To regenerate manually after editing `requirements.in`:

```bash
./build.sh --lock
```

This runs `pip-compile` inside the Docker image (no local pip-tools install needed) and updates
`requirements.txt`. Afterwards, rebuild the Docker image to pick up the changes:

```bash
./build.sh -b
```

Or combine both steps in one command:

```bash
./build.sh --lock -b
```

Commit both `requirements.in` and the updated `requirements.txt` together.
The lockfile is used by `build.sh` (via `pip install --require-hashes`) and by the GitHub Actions workflows.

### Other options

If you want to build the site without the docker image, you can install Python 3 and Pelican, see [manual install](./manual-install.md) for details.
Expand Down
150 changes: 100 additions & 50 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,69 @@
set -e
#set -x

PYTHON_IMAGE="python:3-alpine"
# Base image and packages are defined in Dockerfile (digest-pinned, tracked by Dependabot).
# To regenerate requirements.txt after changing requirements.in, see README.md#updating-the-dependency-lockfile
SOLR_LOCAL_PELICAN_IMAGE="solr-pelican-image"
DOCKER_CMD="docker run --rm -ti -w /work -p 8000:8000 -v $(pwd):/work $SOLR_LOCAL_PELICAN_IMAGE"
unset SERVE
PIP_CMD="pip3 install -r requirements.txt"
unset BUILD
unset LOCK
PELICAN_CMD="pelican content -o output"
PELICAN_OPTS=""
export SITEURL="https://solr.apache.org/"

# Option definitions: "short_flag:long_flag:description"
# Omit short_flag (leave empty before first colon) for long-only options.
# Usage text and getopt spec are both derived from this array.
OPTIONS=(
"l:live:Live build and reload source changes on localhost:8000"
"b:build:Force rebuild of the local Docker image"
":lock:Regenerate requirements.txt from requirements.in (use with -b to also rebuild image)"
"h:help:Show this help message"
":pelican-help:Show all options accepted by Pelican"
)

function usage {
echo "Usage: ./build.sh [-l] [-h] [<other pelican arguments>]"
echo " -l Live build and reload source changes on localhost:8000"
echo " --help Show full help for options that Pelican accepts"
echo "Usage: ./build.sh [OPTIONS] [-- <pelican arguments>]"
echo ""
echo "Options:"
for opt_def in "${OPTIONS[@]}"; do
short="${opt_def%%:*}"
rest="${opt_def#*:}"
long="${rest%%:*}"
desc="${rest#*:}"
if [[ -n "$short" ]]; then
printf " -%s, --%-16s %s\n" "$short" "$long" "$desc"
else
printf " --%-16s %s\n" "$long" "$desc"
fi
done
echo ""
echo "Any extra arguments after -- are passed directly to Pelican."
}

# Build short and long getopt spec strings from OPTIONS array.
function _getopt_specs {
local short="" long=""
for opt_def in "${OPTIONS[@]}"; do
s="${opt_def%%:*}"
l="${opt_def#*:}"; l="${l%%:*}"
[[ -n "$s" ]] && short+="$s"
long+="${long:+,}${l}"
done
echo "${short}|${long}"
}

function build_image {
echo "Building local Docker image for Pelican, called $SOLR_LOCAL_PELICAN_IMAGE."
# Make a new local image with the pip packages installed
docker rm -f solr-pelican >/dev/null 2>&1 || true
docker run --name solr-pelican -w /work -v $(pwd):/work $PYTHON_IMAGE sh -c "$PIP_CMD"
docker commit solr-pelican $SOLR_LOCAL_PELICAN_IMAGE
docker rm -f solr-pelican >/dev/null 2>&1 || true
docker build --no-cache -t $SOLR_LOCAL_PELICAN_IMAGE .
}

function regen_lockfile {
ensure_image
echo "Regenerating requirements.txt from requirements.in inside Docker..."
docker run --rm -w /work -v "$(pwd):/work" $SOLR_LOCAL_PELICAN_IMAGE \
pip-compile --quiet --strip-extras --allow-unsafe --generate-hashes --output-file=requirements.txt requirements.in
echo "requirements.txt updated."
}

function ensure_image {
Expand All @@ -50,7 +91,7 @@ function ensure_image {
}

function check_requirements_update {
# Get the last modified time of requirements.txt
# Check requirements.txt — that is what is COPY'd into the Dockerfile
local req_mod_time
if [[ $(uname) == "Darwin" ]]; then
req_mod_time=$(stat -f "%m" requirements.txt)
Expand All @@ -72,7 +113,7 @@ function check_requirements_update {
image_build_time=$(date -d "$(echo "$image_build_time" | cut -d'.' -f1 | sed 's/T/ /; s/Z//')" --utc "+%s")
fi

# Compare the timestamps and build the image if requirements.txt is newer
# Compare the timestamps and rebuild if requirements.txt is newer than the image
if [[ $req_mod_time -gt $image_build_time ]]; then
echo "requirements.txt has been updated since the last build, rebuilding image!"
build_image
Expand All @@ -88,48 +129,57 @@ then
exit 2
fi

while getopts ":lbh-:" opt; do
case ${opt} in
l )
SERVE=true
;;
b )
build_image
;;
h )
usage
exit 0
;;
- )
case "${OPTARG}" in
help )
usage
echo
echo "Below is a list of other arguments you can use which will be passed to pelican."
echo
$DOCKER_CMD pelican -h
exit 0
;;
* )
PELICAN_OPTS+="--${OPTARG} "
;;
esac
;;
\? )
PELICAN_OPTS+="-${OPTARG} "
;;
# Handle a single parsed option. Returns 1 (exit loop) on --.
function handle_opt {
case "$1" in
-l|--live) SERVE=true ;;
-b|--build) BUILD=true ;;
--lock) LOCK=true ;;
-h|--help) usage; exit 0 ;;
--pelican-help) ensure_image; $DOCKER_CMD pelican -h; exit 0 ;;
--) return 1 ;;
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
esac
done
shift $((OPTIND -1))
}

# Use GNU getopt when available (detected via exit code 4 from getopt -T).
# GNU getopt gives proper error messages and handles --opt=value and option
# reordering. Falls back to a plain bash loop which handles all our flag options.
getopt -T &>/dev/null; _getopt_test=$?
if [[ $_getopt_test -eq 4 ]]; then
specs=$(_getopt_specs)
PARSED=$(getopt -o "${specs%%|*}" --long "${specs#*|}" -n "build.sh" -- "$@") || { usage; exit 1; }
eval set -- "$PARSED"
while true; do
if handle_opt "$1"; then shift; else shift; break; fi
done
else
while [[ $# -gt 0 ]]; do
if handle_opt "$1"; then shift; else shift; break; fi
done
fi

if [[ $LOCK ]]; then
regen_lockfile
if [[ ! $BUILD ]]; then
echo "Run './build.sh -b' to rebuild the Docker image with the updated lockfile."
exit 0
fi
fi

if [[ $BUILD ]]; then
build_image
else
ensure_image
check_requirements_update
fi

ensure_image
check_requirements_update
if [[ $SERVE ]]; then
echo "Building Solr site locally. Goto http://localhost:8000 to view."
echo "Edits you do to the source tree will be compiled immediately!"
$DOCKER_CMD sh -c "$PELICAN_CMD --autoreload --listen -b 0.0.0.0 $PELICAN_OPTS $*"
$DOCKER_CMD sh -c "$PELICAN_CMD --autoreload --listen -b 0.0.0.0 $*"
else
echo "Building Solr site locally."
echo "To build and serve live edits locally, run this script with -l argument. Use -h for help."
$DOCKER_CMD sh -c "$PELICAN_CMD $PELICAN_OPTS $*"
fi
$DOCKER_CMD sh -c "$PELICAN_CMD $*"
fi
Loading
Loading