Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Delegate PG installation to ikalnytskyi/action-setup-postgres@v6 #7

Merged
merged 1 commit into from
May 26, 2024
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
94 changes: 4 additions & 90 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@
[![CI build](https://github.com/nyurik/action-setup-postgis/actions/workflows/ci.yml/badge.svg)](https://github.com/nyurik/action-setup-postgis/actions)
[![Marketplace](https://img.shields.io/badge/market-setup--postgis-6F42C1?logo=github)](https://github.com/marketplace/actions/setup-postgresql-and-postgis-for-linux-macos-windows)

This GitHub action sets up a PostgreSQL server with PostGIS extension. The code is based on
the [ikalnytskyi/action-setup-postgres](https://github.com/ikalnytskyi/action-setup-postgres) action.
> [!TIP]
>
> PostgreSQL installation is done by the `ikalnytskyi/action-setup-postgres` action. All parameters are passed as is to the original action, with the addition of the `cached-dir` parameter to specify where to download and cache PostGIS binaries. See the [original documentation](https://github.com/ikalnytskyi/action-setup-postgres) for more details.

* Runs on Linux, macOS and Windows GitHub runners.
* Adds PostgreSQL [binaries](https://www.postgresql.org/docs/current/reference-client.html) (e.g. `psql`) to `PATH`.
* Uses PostgreSQL installed in [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
* Runs on all Linux, macOS and Windows GitHub runners
* Installs the correct version of PostGIS and runs `CREATE EXTENSION postgis` in the new database.
* Linux version is installed from the [PostGIS apt repository](https://postgis.net/install/).
* Windows version is installed from the [OSGeo](https://download.osgeo.org/postgis/windows/).
* MacOS version is installed using [Homebrew package](https://formulae.brew.sh/formula/postgis).
* [Easy to check](action.yml) that IT DOES NOT contain malicious code.

See also [action-setup-nginx](https://github.com/nyurik/action-setup-nginx) to configure NGINX service.

Expand All @@ -31,19 +29,6 @@ steps:
CONNECTION_STR: ${{ steps.postgres.outputs.connection-uri }}
```

> [!IMPORTANT]
>
> In order to connect to a PostgreSQL server, use either connection parameters
> from the table below ([link](#outputs)), or retrieve a
> connection URI from the `connection-uri` output ([link](#advanced)).

> [!TIP]
>
> `libpq`-using applications may choose to set the `PGSERVICE=postgres`
> environment variable instead ([link](#create-a-new-user-w-database-via-cli)),
> where `postgres` is the service name extracted from the `service-name`
> output.

#### Input parameters

| Key | Value | Default |
Expand All @@ -68,77 +53,6 @@ steps:
| usesuper | true |
| usecreatedb | true |

#### Advanced

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
with:
username: ci
password: sw0rdfish
database: test
port: 34837
id: postgres

- name: Test PostGIS is installed
run: psql -v ON_ERROR_STOP=1 -c 'SELECT PostGIS_Full_Version();' "$CONNECTION_STR"
env:
CONNECTION_STR: ${{ steps.postgres.outputs.connection-uri }}
```

## Recipes

#### Create a new user w/ database via CLI

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
id: postgres

- run: |
createuser myuser
createdb --owner myuser mydatabase
psql -c "ALTER USER myuser WITH PASSWORD 'mypassword'"
env:
# This activates connection parameters for the superuser created by
# the action in the step above. It's mandatory to set this before using
# createuser/psql and other libpq-using applications.
#
# The service name is the same as the username (i.e. 'postgres') but
# it's recommended to use action's output to get the name in order to
# be forward compatible.
PGSERVICE: ${{ steps.postgres.outputs.service-name }}
shell: bash
```

#### Create a new user w/ database via psycopg

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
```

```python
import psycopg

# 'postgres' is the username here, but it's recommended to use the
# action's 'service-name' output parameter here.
connection = psycopg.connect("service=postgres")

# CREATE/DROP USER statements don't work within transactions, and with
# autocommit disabled transactions are created by psycopg automatically.
connection.autocommit = True
connection.execute(f"CREATE USER myuser WITH PASSWORD 'mypassword'")
connection.execute(f"CREATE DATABASE mydatabase WITH OWNER 'myuser'")
```

## Rationale

At the time of developing there were no GitHub Actions on the marketplace to
setup a PostgreSQL server on Linux, Windows and macOS action runners. Most
solutions suggest using Docker which is not available on macOS and Windows
runners.

## License

The scripts and documentation in this project are released under the
Expand Down
132 changes: 12 additions & 120 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ inputs:
default: "5432"
required: false
cached-dir:
# TODO: move to runner's temp dir, help wanted
description: Where should the temporary downloads be placed. Used to download and cache PostGIS binary.
default: "downloads"
required: false
outputs:
connection-uri:
description: The connection URI to connect to PostgreSQL.
value: ${{ steps.set-outputs.outputs.connection-uri }}
value: ${{ steps.pg.outputs.connection-uri }}
service-name:
description: The service name with connection parameters.
value: ${{ steps.set-outputs.outputs.service-name }}
value: ${{ steps.pg.outputs.service-name }}
runs:
using: composite
steps:
Expand Down Expand Up @@ -132,124 +133,15 @@ runs:
& pg_ctl restart -D "$env:PGDATA"
& pg_isready

- name: Prerequisites
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
echo "$(pg_config --bindir)" >> $GITHUB_PATH
elif [ "$RUNNER_OS" == "Windows" ]; then
echo "$PGBIN" >> $GITHUB_PATH
echo "PQ_LIB_DIR=$PGROOT\lib" >> $GITHUB_ENV

# The Windows runner has some PostgreSQL environment variables set
# that may confuse users since they may be irrelevant to the
# PostgreSQL server we're using.
for name in "PGROOT" "PGDATA" "PGBIN" "PGUSER" "PGPASSWORD"; do
echo "$name=" >> $GITHUB_ENV
done
elif [ "$RUNNER_OS" == "macOS" ]; then
case "$(sw_vers -productVersion)" in
13.*|14.*)
# Unfortunately, the macOS 13 runner image doesn't come w/
# pre-installed PostgreSQL server.
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_INSTALL_UPGRADE=1
brew install --skip-post-install postgresql@14
;;
esac
fi
shell: bash

- name: Setup and start PostgreSQL
run: |
export PGDATA="$RUNNER_TEMP/pgdata"
export PWFILE="$RUNNER_TEMP/pwfile"

DEFAULT_ENCODING="UTF-8"
DEFAULT_LOCALE="en_US.$DEFAULT_ENCODING"

# Unfortunately, Windows Server 2019 doesn't understand locale
# specified in the format defined by the POSIX standard, i.e.
# <language>_<country>.<encoding>. Therefore, we have to convert it
# into something it can swallow, i.e. <language>-<country>.
if [[ "$RUNNER_OS" == "Windows" && "$(wmic os get Caption)" == *"2019"* ]]; then
DEFAULT_LOCALE="${DEFAULT_LOCALE%%.*}"
DEFAULT_LOCALE="${DEFAULT_LOCALE//_/-}"
fi

# Unfortunately 'initdb' could only receive a password via file on disk
# or prompt to enter on. Prompting is not an option since we're running
# in non-interactive mode.
echo '${{ inputs.password }}' > $PWFILE

# There are couple of reasons why we need to create a new PostgreSQL
# database cluster. First and foremost, we have to create a superuser
# with provided credentials. Second, we want the PostgreSQL client
# applications [1] to be available for execution without
# run-from-another-user dances. Third, we want to make sure that
# settings are the same between operating systems and aren't changed by
# package vendors.
#
# [1] https://www.postgresql.org/docs/15/reference-client.html
initdb \
--username="${{ inputs.username }}" \
--pwfile="$PWFILE" \
--auth="scram-sha-256" \
--encoding="$DEFAULT_ENCODING" \
--locale="$DEFAULT_LOCALE" \
--no-instructions

# Do not create unix sockets since they are created by default in the
# directory we have no permissions to (owned by system postgres user).
echo "unix_socket_directories = ''" >> "$PGDATA/postgresql.conf"
echo "port = ${{ inputs.port }}" >> "$PGDATA/postgresql.conf"
pg_ctl start

# Save required connection parameters for created superuser to the
# connection service file [1]. This allows using these connection
# parameters by setting 'PGSERVICE' environment variable or by
# requesting them via connection string.
#
# HOST is required for Linux/macOS because these OS-es default to unix
# sockets but we turned them off.
#
# PORT, USER, PASSWORD and DBNAME are required because they could be
# parametrized via action input parameters.
#
# [1] https://www.postgresql.org/docs/15/libpq-pgservice.html
cat <<EOF > "$PGDATA/pg_service.conf"
[${{ inputs.username }}]
host=localhost
port=${{ inputs.port }}
user=${{ inputs.username }}
password=${{ inputs.password }}
dbname=${{ inputs.database }}
EOF
echo "PGSERVICEFILE=$PGDATA/pg_service.conf" >> $GITHUB_ENV
shell: bash

- name: Setup PostgreSQL database
run: |
# The 'postgres' database is a pre-created database meant for use by
# users, utilities and third party applications. There's no way to
# parametrize the name, so all we can do is to avoid creating a
# database if provided name is 'postgres'.
if [ "${{ inputs.database }}" != "postgres" ]; then
createdb -O "${{ inputs.username }}" "${{ inputs.database }}"
fi
env:
PGSERVICE: ${{ inputs.username }}
shell: bash

- name: Set action outputs
run: |
CONNECTION_URI="postgresql://${{ inputs.username }}:${{ inputs.password }}@localhost:${{ inputs.port }}/${{ inputs.database }}"

echo "connection-uri=$CONNECTION_URI" >> $GITHUB_OUTPUT
echo "service-name=${{ inputs.username }}" >> $GITHUB_OUTPUT
shell: bash
id: set-outputs
- name: Setup PostgreSQL for Linux/macOS/Windows
id: pg
uses: ikalnytskyi/action-setup-postgres@v6
with:
username: "${{ inputs.username }}"
password: "${{ inputs.password }}"
database: "${{ inputs.database }}"
port: "${{ inputs.port }}"

- name: Enable PostGIS extension
run: psql -v ON_ERROR_STOP=1 -c 'CREATE EXTENSION IF NOT EXISTS postgis;' '${{ steps.set-outputs.outputs.connection-uri }}'
run: psql -v ON_ERROR_STOP=1 -c 'CREATE EXTENSION IF NOT EXISTS postgis;' '${{ steps.pg.outputs.connection-uri }}'
shell: bash
Loading