A cluster of Specify 7 instances for testing with automatic deployment, authentication and a test panel for setting configuration.
These instructions have last been updated and tested on Ubuntu 24.04 with MariaDB 11.4 and Docker 27.1.2.
To run the containers, generate fullchain.pem
and privkey.pem
(certificate
and the private key) using Let's Encrypt and put these files into the
./config/
directory.
While in development, you can generate self-signed certificates:
openssl req \
-x509 -sha256 -nodes -newkey rsa:2048 -days 365 \
-keyout ./config/privkey.pem \
-out ./config/fullchain.pem
Note, production deployment expects privkey.pem
and fullchain.pem
to be in
the /etc/letsencrypt/live/test.specifysystems.org-0001/privkey.pem
directory
In order to enable authentication though GitHub and usage of GitHub APIs, a GitHub OAuth application needs to be created.
This can be done for a GitHub organization or user profile:
-
Open organization / user settings on GitHub
-
On the sidebar, select "Developer Settings"
-
Select "OAuth Apps"
-
Press "New OAuth App"
-
Fill out the required information
-
Set authentication callback URL to this URL:
https://localhost/sign-in
When in production, replace
localhost
with the actual hostname -
Press "Generate a new client secret"
-
Client ID and Client Secret is displayed on the OAUth app configuration page.
-
Write them down somewhere temporary as they would be needed later
Most GitHub API calls would be made using the token generated when the user authenticates into the system.
The only exception is the webhook endpoint (/api/webhook
), which would be
called by GitHub whenever the list pull requests that are ready for testing.
This endpoint is responsible for checking getting rid of stale instances and auto deploying new pull requests whenever they become ready for testing.
To configure this, first, create personal authentication token:
- Open your GitHub's profile settings
- Select "Developer Settings" on the sidebar
- Select "Personal access tokens" on the next sidebar
- Press "Generate new token"
- Fill out name and expiration date as appropriate
- Check the
read:org
checkbox in the "Select Scopes" section - Press "Generate token"
- Write down the generated token temporarily as it would be needed in the next step
Next, let's setup the webhook:
-
Open the repository settings page
-
Select "Webhooks" on the sidebar
-
Press "Add webhook"
-
Set
https://test.specifysolutions.com/api/webhook
as the payload URL. Replace the domain name and the protocol with the one you are using.NOTE: In order for webhook to work, this domain has to be publicly accessible on the internet. If you need to test webhooks on your local machine, Google how to expose localhost
-
Change "Content type" picklist to
application/json
-
Select the "Let me select individual events." radio button.
-
Check the following checkboxes:
- Pull request review comments
- Pull request review threads
- Pull request reviews
- Pull requests
- Workflow jobs
-
Click the "Add webhook" button
Create .env.local
file in the app
folder:
NEXT_PUBLIC_GITHUB_CLIENT_ID=<client_id>
GITHUB_CLIENT_SECRET=<client_secret>
GITHUB_PERSONAL_TOKEN=<github_token>
MYSQL_USERNAME=root
MYSQL_PASSWORD=root
MYSQL_HOST=mariadb
Replace <client_id>
and <client_secret>
with the actual values from the
OAuth app configuration page on GitHub
(see more details)
Replace <github_token>
with the token you generated in
the previous step
To avoid memory leaks, setup a cron job that runs docker system prune --all
at
a regular schedule (i.e at 3am every day).
Example tutorial
Open the cron file:
crontab -e
Add this line:
0 3 * * * docker system prune --all --volumes --force
After completing all the steps from previous sections, do one of these:
Build the containers:
docker compose \
-f docker-compose.yml \
-f docker-compose.production.yml \
up --no-start --build
Run the containers:
docker compose \
-f docker-compose.yml \
-f docker-compose.production.yml \
-f /var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml \
up --remove-orphans -d
If /var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml
is not correct on your host, you can find the correct path using
docker volume ls
and docker volume inspect
.
Test Panel is now available at https://localhost/
Install npm dependencies locally:
npm i
Run the containers:
docker compose \
-f docker-compose.yml \
-f docker-compose.development.yml \
-f state/docker-compose.yml \
up --remove-orphans
This will deploy the development server and the deployments configured in the test panel. If there is no need to start the configured deployments, omit the
-f state/docker-compose.yml \
line from above.If deployments, are not started, there would be a lot of errors in the dev console in the test panel. You can silence those by disabling deployment status fetching by adding "?no-fetch" to the url (https://localhost/?no-fetch)
Test Panel is now available at https://localhost/
Next.JS has hot-reload enabled, so code changes are reflected in realtime.
Before committing changes, run npm run test
to verify validity of TypeScript
types.
After user changes the configuration in the panel, the file
/var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml
is
modified. Systemd can be configured to watch this file and run docker-compose
pull and up when changes occur. Use the following unit files:
[Unit]
After=network.target
Description=Run docker-compose up for test panel.
[Service]
Type=oneshot
WorkingDirectory=/home/specify/specify7-test-panel
ExecStart=docker compose -f docker-compose.yml -f docker-compose.production.yml -f /var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml up --remove-orphans -d
[Unit]
[Path]
PathChanged=/var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml
Unit=specify7-test-panel-update.service
[Install]
WantedBy=multi-user.target
Enable the services with the following commands:
systemctl daemon-reload
systemctl enable specify7-test-panel-update.path
systemctl start specify7-test-panel-update.path
After user changes the configuration in the panel, ./state/docker-compose.yml
file is modified.
fswatch
can be used to rerun docker-compose up
on configuration changes.
Install fswatch
:
# on Ubuntu
sudo apt-get install fswatch
# on macOS
brew install fswatch
Then, run this command though nohup:
fswatch -o ./state/docker-compose.yml | xargs -n1 -I{} sh -c " \
docker-compose \
-f docker-compose.yml \
-f docker-compose.production.yml \
-f state/docker-compose.yml \
up --remove-orphans -d"
The ./state
directory is indexed by git, but changes are ignored
This was achieved like this:
- Add
./state/
directory with initial content to git and commit changes - Add
./state/
folder to.gitignore
- Run
git update-index --assume-unchanged state/docker-compose.yml
(do this for each file in that directory)
In the future, if you want to change the default ./state/
, run this (for each
file):
git update-index --no-assume-unchanged state/docker-compose.yml
Then, commit your changes and repeat step 3