Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
FinleyMcIlwaine committed Jul 30, 2023
0 parents commit a135c58
Show file tree
Hide file tree
Showing 36 changed files with 8,625 additions and 0 deletions.
217 changes: 217 additions & 0 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# This GitHub workflow config has been generated by a script via
#
# haskell-ci 'github' 'cabal.project'
#
# To regenerate the script (for example after adjusting tested-with) run
#
# haskell-ci regenerate
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.16.3
#
# REGENDATA ("0.16.3",["github","cabal.project"])
#
name: Haskell-CI
on:
- push
- pull_request
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
runs-on: ubuntu-20.04
timeout-minutes:
60
container:
image: buildpack-deps:bionic
continue-on-error: ${{ matrix.allow-failure }}
strategy:
matrix:
include:
- compiler: ghc-9.6.2
compilerKind: ghc
compilerVersion: 9.6.2
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.4.5
compilerKind: ghc
compilerVersion: 9.4.5
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.2.7
compilerKind: ghc
compilerVersion: 9.2.7
setup-method: ghcup
allow-failure: false
- compiler: ghc-8.10.7
compilerKind: ghc
compilerVersion: 8.10.7
setup-method: ghcup
allow-failure: false
fail-fast: false
steps:
- name: apt
run: |
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 > "$HOME/.ghcup/bin/ghcup"
chmod a+x "$HOME/.ghcup/bin/ghcup"
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
"$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
HCVER: ${{ matrix.compilerVersion }}
- name: Set PATH and environment variables
run: |
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
HCDIR=/opt/$HCKIND/$HCVER
HC=$HOME/.ghcup/bin/$HCKIND-$HCVER
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"
echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
echo "GHCJSARITH=0" >> "$GITHUB_ENV"
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
HCVER: ${{ matrix.compilerVersion }}
- name: env
run: |
env
- name: write cabal config
run: |
mkdir -p $CABAL_DIR
cat >> $CABAL_CONFIG <<EOF
remote-build-reporting: anonymous
write-ghc-environment-files: never
remote-repo-cache: $CABAL_DIR/packages
logs-dir: $CABAL_DIR/logs
world-file: $CABAL_DIR/world
extra-prog-path: $CABAL_DIR/bin
symlink-bindir: $CABAL_DIR/bin
installdir: $CABAL_DIR/bin
build-summary: $CABAL_DIR/logs/build.log
store-dir: $CABAL_DIR/store
install-dirs user
prefix: $CABAL_DIR
repository hackage.haskell.org
url: http://hackage.haskell.org/
EOF
cat >> $CABAL_CONFIG <<EOF
program-default-options
ghc-options: $GHCJOBS +RTS -M3G -RTS
EOF
cat $CABAL_CONFIG
- name: versions
run: |
$HC --version || true
$HC --print-project-git-commit-id || true
$CABAL --version || true
- name: update cabal index
run: |
$CABAL v2-update -v
- name: install cabal-plan
run: |
mkdir -p $HOME/.cabal/bin
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
rm -f cabal-plan.xz
chmod a+x $HOME/.cabal/bin/cabal-plan
cabal-plan --version
- name: checkout
uses: actions/checkout@v3
with:
path: source
- name: initial cabal.project for sdist
run: |
touch cabal.project
echo "packages: $GITHUB_WORKSPACE/source/ebird-api" >> cabal.project
echo "packages: $GITHUB_WORKSPACE/source/ebird-cli" >> cabal.project
echo "packages: $GITHUB_WORKSPACE/source/ebird-client" >> cabal.project
cat cabal.project
- name: sdist
run: |
mkdir -p sdist
$CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
- name: unpack
run: |
mkdir -p unpacked
find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
- name: generate cabal.project
run: |
PKGDIR_ebird_api="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/ebird-api-[0-9.]*')"
echo "PKGDIR_ebird_api=${PKGDIR_ebird_api}" >> "$GITHUB_ENV"
PKGDIR_ebird_cli="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/ebird-cli-[0-9.]*')"
echo "PKGDIR_ebird_cli=${PKGDIR_ebird_cli}" >> "$GITHUB_ENV"
PKGDIR_ebird_client="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/ebird-client-[0-9.]*')"
echo "PKGDIR_ebird_client=${PKGDIR_ebird_client}" >> "$GITHUB_ENV"
rm -f cabal.project cabal.project.local
touch cabal.project
touch cabal.project.local
echo "packages: ${PKGDIR_ebird_api}" >> cabal.project
echo "packages: ${PKGDIR_ebird_cli}" >> cabal.project
echo "packages: ${PKGDIR_ebird_client}" >> cabal.project
echo "package ebird-api" >> cabal.project
echo " ghc-options: -Werror=missing-methods" >> cabal.project
echo "package ebird-cli" >> cabal.project
echo " ghc-options: -Werror=missing-methods" >> cabal.project
echo "package ebird-client" >> cabal.project
echo " ghc-options: -Werror=missing-methods" >> cabal.project
cat >> cabal.project <<EOF
EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(ebird-api|ebird-cli|ebird-client)$/; }' >> cabal.project.local
cat cabal.project
cat cabal.project.local
- name: dump install plan
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan
- name: restore cache
uses: actions/cache/restore@v3
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
- name: install dependencies
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
- name: build w/o tests
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: build
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
- name: cabal check
run: |
cd ${PKGDIR_ebird_api} || false
${CABAL} -vnormal check
cd ${PKGDIR_ebird_cli} || false
${CABAL} -vnormal check
cd ${PKGDIR_ebird_client} || false
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: save cache
uses: actions/cache/save@v3
if: always()
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist-newstyle
cabal.project.local
.envrc
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# eBird Haskell

eBird libraries and tools written in Haskell, for Haskell.

## What is eBird?

[eBird](https://ebird.org/home) is a massive collection of ornithological
science projects developed by the [Cornell Lab of
Ornithology](https://www.birds.cornell.edu/home/). The [eBird
API](https://documenter.getpostman.com/view/664302/S1ENwy59) offers programmatic
access to the incredible dataset backing these projects.

## What is included

This repository hosts several libraries and tools, all centered around accessing
and processing eBird data from the public eBird web API.

### [`./ebird-cli`](./ebird-cli/)

A command-line interface for querying the official eBird API.

### [`./ebird-client`](./ebird-client/)

A Haskell library for querying the official eBird API.

### [`./ebird-api`](./ebird-api/)

A Haskell library that defines the eBird API as a [servant][servant] API type.
This library is intended for use by those who wish to write their own eBird API
clients using [servant-client][servant-client], or who wish to do custom
processing of eBird data using the types defined in the library.

## Contribute

Please don't hesitate to [open an
issue](https://github.com/FinleyMcIlwaine/ebird-haskell/issues) (or a [pull
request](https://github.com/FinleyMcIlwaine/ebird-haskell/pulls)!) if you have
any questions or something doesn't work as expected.

<!-- LINKS -->
[servant]: https://docs.servant.dev/en/stable/
[servant-client]: https://hackage.haskell.org/package/servant-client
9 changes: 9 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
packages:
ebird-api
ebird-cli
ebird-client

package *
ghc-options:
-Wall
-Wunused-packages
5 changes: 5 additions & 0 deletions ebird-api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Revision history for ebird-api

## 0.1.0.0 -- YYYY-mm-dd

* First version. Released on an unsuspecting world.
92 changes: 92 additions & 0 deletions ebird-api/Inconsistencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# eBird API Inconsistencies and Peculiarities

The public eBird API is inconsistent and underspecified. This fact is in direct
opposition to our goal of modeling it in Haskell. In this document, we attempt
to enumerate the various pain points of the eBird API.

This has basically turned into a substitute for an eBird API issue tracker.

## Inconsistencies

Things in the API that don't line up but do "work".

* Observation detail levels

The "notable observations" endpoints allow a "detail" query parameter to
determine the detail level of the returned observations. Although one would
expect this query parameter to be handled by any endpoint that returns
observations, this is not the case.

We handle this by hard coding the returned observations of some endpoints to
"simple" detail level. Any endpoint that does properly handle detail levels
returns `SomeObservation` values, which are observations whose detail levels are
existentially quantified.

* Recent Checklists Feed

It is in the wrong spot of the eBird API documentation. Should be under the
`product` list, since that's the route.

* Clarify difference between checklist ID and submission ID

* Specifying mixed region types in observation endpoints

Errors with capture variable but is fine when mixed across capture variable and
"r" query param.

e.g.
```
curl "https://api.ebird.org/v2/data/obs/US-WY,US-WY-029/recent?maxResults=10&key=$(cat ~/.ebird/key.txt)"
```
errors

```
curl "https://api.ebird.org/v2/data/obs/US-WY/recent?r=US-WY-029&maxResults=15&key=$(cat ~/.ebird/key.txt)"
```
works

## Errors

Things that appear to be errors/bugs in the API.

* Observation endpoints do not handle "world" region

They return an error with "Region type custom not yet supported". But since the
"region info" endpoint does handle the "world" region, I would not expect this
to result in an error.

* Subregions of multiple regions errors

Specifying more than one region for the sub regions endpoint causes a 500 error,
where it seems like it should be prefectly acceptable to ask for the list of
counties in both US-WY and US-CO.

* Recent observations of species inconsistent with notable observations

I can see an observation of a species in the "recent notable observations"
output for a region, but I cannot see that same observation when searching for
observations of that species using the "recent species observations" endpoint.

* Historic observations endpoint does not respect region boundary

Requesting historic observations on this day (July 5th, 2023) in Park County,
Wyoming (US-WY-029) is showing observations from other counties.

* `includeProvisional` does not work

Try:
```
curl "https://api.ebird.org/v2/data/obs/US-WY-029/recent?includeProvisional=false&key=$(cat ~/.ebird/key.txt)"
```

Note that the response has observations with `"obsReviewed": false`.

* The regional statistics API does not work for subnational2 regions, always
says 0 for all results

Try:
```
curl "https://api.ebird.org/v2/product/stats/US-WY-029/2023/7/15recent?&key=$(cat ~/.ebird/key.txt)"
```

Response has 0 for all fields.
20 changes: 20 additions & 0 deletions ebird-api/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2023 Finley McIlwaine

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Loading

0 comments on commit a135c58

Please sign in to comment.