diff --git a/.github/workflows/typedclojure.yml b/.github/workflows/typedclojure.yml new file mode 100644 index 0000000..c3fc266 --- /dev/null +++ b/.github/workflows/typedclojure.yml @@ -0,0 +1,29 @@ +name: Test and deploy + +on: [push] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/cache@v1 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - uses: DeLaGuardo/setup-clojure@e73bf2b6435244b2c9c5c226ae5022d91d0ce702 + with: + tools-deps: latest + - name: Configure settings.xml + run: | + mkdir -p ~/.m2 + echo "clojarstypedclojure-clojars${{ secrets.ClojarsPassword }}" > ~/.m2/settings.xml + + - name: Deploy + run: ./script/deploy-actions.sh diff --git a/.gitignore b/.gitignore index c30a559..0ec7787 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .lein* .nrepl-port .cpcache +.*.swp diff --git a/pom.xml b/pom.xml index cef60fd..19649dd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,9 @@ 4.0.0 + org.clojars.typedclojure-clojars alpha.spec - 0.2.177-SNAPSHOT + 0.2.177-typedclojure-3-SNAPSHOT alpha.spec Specification of data and functions @@ -21,11 +22,26 @@ + + + clojars + Clojars repository + https://clojars.org/repo + + + clojars + Clojars repository + https://clojars.org/repo + + + + @@ -37,6 +53,13 @@ 1.10.0 + + false + + src/main/clojure + src/test/clojure + UTF-8 @@ -107,6 +130,75 @@ + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + add-clojure-source-dirs + generate-sources + + add-source + add-resource + + + + ${clojure.source.dir} + + + + ${clojure.source.dir} + + + + + + add-clojure-test-source-dirs + generate-sources + + add-test-source + add-test-resource + + + + ${clojure.testSource.dir} + + + + ${clojure.testSource.dir} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + true + @{project.version} + + false + true + + diff --git a/script/deploy-actions.sh b/script/deploy-actions.sh new file mode 100755 index 0000000..dab7100 --- /dev/null +++ b/script/deploy-actions.sh @@ -0,0 +1,27 @@ +#! /bin/bash +# Deploys either a snapshot or release in GitHub Actions. +# If the commit message is of the form: +# [typedclojure-release] + +set -e + +if [[ "$GITHUB_ACTIONS" != 'true' ]]; then + echo "Only call this script in GitHub Actions" + exit 1 +fi + +if [[ "$GITHUB_REPOSITORY" != 'typedclojure/spec-alpha2' ]]; then + echo "This script only deploys in typedclojure/spec-alpha2, not $GITHUB_REPOSITORY. Doing nothing." + exit 0 +fi + +COMMIT_MSG=$(git log --format=%B -n 1 "${GITHUB_SHA}") +echo $COMMIT_MSG +if [[ "$COMMIT_MSG" =~ ^\[prep-release\] ]]; then + #https://stackoverflow.com/a/9294015 + COMMIT_MSG_ARRAY=($COMMIT_MSG) + ./script/release-and-push.sh "${COMMIT_MSG_ARRAY[1]}" "${COMMIT_MSG_ARRAY[2]}" +else + echo "Not deploying snapshot releases" + #./script/deploy-snapshot.sh +fi diff --git a/script/increment-semversion.sh b/script/increment-semversion.sh new file mode 100755 index 0000000..f8353c5 --- /dev/null +++ b/script/increment-semversion.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +#The MIT License (MIT) +# +#Copyright (c) 2014 Fritz Mahnke +# +#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. + +# Copied from: https://github.com/fmahnke/shell-semver/blob/4c89b49beb11034d7b384680a02f1bcfb1db249e/increment_version.sh + +# Increment a version string using Semantic Versioning (SemVer) terminology. + +# Parse command line options. + +while getopts ":Mmp" Option +do + case $Option in + M ) major=true;; + m ) minor=true;; + p ) patch=true;; + esac +done + +shift $(($OPTIND - 1)) + +version=$1 + +# Build array from version string. + +a=( ${version//./ } ) + +# If version string is missing or has the wrong number of members, show usage message. + +if [ ${#a[@]} -ne 3 ] +then + echo "usage: $(basename $0) [-Mmp] major.minor.patch" + exit 1 +fi + +# Increment version numbers as requested. + +if [ ! -z $major ] +then + ((a[0]++)) + a[1]=0 + a[2]=0 +fi + +if [ ! -z $minor ] +then + ((a[1]++)) + a[2]=0 +fi + +if [ ! -z $patch ] +then + ((a[2]++)) +fi + +echo "${a[0]}.${a[1]}.${a[2]}" + diff --git a/script/prep-actions-release.sh b/script/prep-actions-release.sh new file mode 100755 index 0000000..6f8d952 --- /dev/null +++ b/script/prep-actions-release.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Prompts for next release version and dev version and +# creates a commit that triggers GitHub Actions to deploy +# the release version and bump the repo to the next dev +# version. + +echo "Determining current version..." + +TYPED_VERSION=$(mvn -q \ + -Dexec.executable="echo" \ + -Dexec.args='${project.version}' \ + --non-recursive \ + org.codehaus.mojo:exec-maven-plugin:1.6.0:exec) + + +if [[ "$TYPED_VERSION" == *-SNAPSHOT ]]; then + echo "Current version: ${TYPED_VERSION}" + + #https://stackoverflow.com/a/125340 + DEFAULT_RELEASE_VERSION="${TYPED_VERSION%-SNAPSHOT}" + #https://stackoverflow.com/a/2642592 (bash 3 compatible) + read -p "Choose release version [${DEFAULT_RELEASE_VERSION}]: " RELEASE_VERSION + RELEASE_VERSION=${RELEASE_VERSION:-${DEFAULT_RELEASE_VERSION}} + + # default: increment patch + DEFAULT_DEV_VERSION=$(printf "%s-SNAPSHOT" $(./script/increment-semversion.sh -p ${RELEASE_VERSION})) + read -p "Choose next dev version [${DEFAULT_DEV_VERSION}]: " DEV_VERSION + DEV_VERSION=${DEV_VERSION:-${DEFAULT_DEV_VERSION}} + + git commit --allow-empty -m "$(printf "[prep-release] %s %s" "${RELEASE_VERSION}" "${DEV_VERSION}")" +else + echo "Can only prep a release from a SNAPSHOT version, found $TYPED_VERSION" + exit 1 +fi diff --git a/script/release-and-push.sh b/script/release-and-push.sh new file mode 100755 index 0000000..62c1878 --- /dev/null +++ b/script/release-and-push.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Cuts a release of spec-alpha2. Requires two arguments: +# - the release version to use +# - the development SNAPSHOT version to use +# +# eg., to cut version 1.0.0 and then move to 1.0.1-SNAPSHOT, +# call this script like so: +# +# ./script/release-and-push.sh 1.0.0 1.0.1-SNAPSHOT +# +# and then push the resulting commit to the master branch. +# GitHub Actions will automatically deploy a 1.0.0 release and +# update the dev version to 1.0.1-SNAPSHOT. + +set -e + +DEPLOY_BRANCH="typedclojure" +DEPLOY_REPO="typedclojure/spec-alpha2" +ALLOWED_ACTOR="frenchy64" +USER_EMAIL="abonnairesergeant@gmail.com" +USER_NAME="Ambrose Bonnaire-Sergeant" + + +if [[ "$GITHUB_ACTIONS" != 'true' ]]; then + echo "Must release on GitHub Actions only." + exit 1 +fi + +if [[ `git symbolic-ref --short HEAD` != "$DEPLOY_BRANCH" ]]; then + echo "Releases only triggered on the master branch. Doing nothing." + exit 0 +fi + +if [[ "$GITHUB_ACTOR" != "$ALLOWED_ACTOR" ]]; then + echo "Only maintainers may deploy a release. Doing nothing." + exit 0 +fi + +if [[ "$GITHUB_REPOSITORY" != "$DEPLOY_REPO" ]]; then + echo "Releases only allowed from $DEPLOY_REPO. Doing nothing." + exit 0 +fi + +git config --local user.email "$USER_EMAIL" +git config --local user.name "$USER_NAME" + +RELEASE_VERSION=$1 +DEVELOPMENT_VERSION=$2 + +if [[ -z "$RELEASE_VERSION" ]]; then + echo "Must specify release version" + exit 1 +fi + +if [[ -z "$DEVELOPMENT_VERSION" ]]; then + echo "Must specify development version" + exit 1 +fi + +# there's a chance this can fail and we have a partial +# release to Clojars. We minimize the damage by avoiding +# pushing back to master, but there's a chance the version +# was partially deployed. The correct fix (wrt clojars) is to simply +# deploy a new version (eg., if 1.0.0 fails, try 1.0.1 next). +( set -x; +mvn release:prepare release:perform \ + -DreleaseVersion="$RELEASE_VERSION" \ + -Dtag="$RELEASE_VERSION" \ + -DdevelopmentVersion="$DEVELOPMENT_VERSION" + ) + +#( set -x; +#./script/bump-readme-version "$RELEASE_VERSION" +#) + +#git add . +#git commit -m "Bump README versions for $RELEASE_VERSION" + +# DON'T PRINT HERE +git push "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "${DEPLOY_BRANCH}" --tags diff --git a/src/main/clojure/clojure/alpha/spec.clj b/src/main/clojure/clojure/alpha/spec.clj index 61edbbe..6b771df 100644 --- a/src/main/clojure/clojure/alpha/spec.clj +++ b/src/main/clojure/clojure/alpha/spec.clj @@ -424,7 +424,7 @@ "Given a function symbol, set of constants, or anonymous function, returns a spec object." [s] - `(resolve-spec '~(explicate (ns-name *ns*) s))) + `(resolve-spec '~(explicate (ns-name *ns*) `(spec ~s)))) (defn register "Given a namespace-qualified keyword or resolvable symbol k, and a diff --git a/src/main/clojure/clojure/alpha/spec/impl.clj b/src/main/clojure/clojure/alpha/spec/impl.clj index 8023b99..249d046 100644 --- a/src/main/clojure/clojure/alpha/spec/impl.clj +++ b/src/main/clojure/clojure/alpha/spec/impl.clj @@ -521,6 +521,18 @@ [{:keys [schemas]}] (union-impl schemas nil)) +(defmethod s/expand-spec `s/spec + [[_ s :as form]] + {:clojure.spec/op `s/spec + :s s + :form form}) + +(defmethod s/create-spec `s/spec + [{:keys [s form]}] + (let [rs (s/resolve-spec s)] + (cond-> rs + (::s/op rs) (assoc ::s/wrap-spec form)))) + (defn- select-impl [schema-form selection gfn] (let [id (java.util.UUID/randomUUID) @@ -1144,10 +1156,11 @@ (describe* [_] describe-form))))) (defmethod s/expand-spec `s/every - [[_ pred & opts]] + [[_ pred & opts :as form]] {:clojure.spec/op `s/every :spec pred - :opts (apply hash-map opts)}) + :opts (-> (apply hash-map opts) + (update ::s/describe #(or % form)))}) (defmethod s/create-spec `s/every [{:keys [spec opts]}] @@ -1182,7 +1195,7 @@ (s/create-spec {:clojure.spec/op `s/every :spec `(s/tuple ~kspec ~vspec) - :opts (merge opts {::s/kfn (fn [i# v#] (nth v# 0)) + :opts (merge opts {::s/kfn `(fn [i# v#] (nth v# 0)) :into {} ::s/describe `(s/every-kv ~(resolve-form kspec) ~(resolve-form vspec) ~@(mapcat identity opts))})})) @@ -1212,7 +1225,7 @@ (s/create-spec {:clojure.spec/op `s/every :spec `(s/tuple ~kspec ~vspec) - :opts (merge opts {::s/kfn (fn [i# v#] (nth v# 0)) + :opts (merge opts {::s/kfn `(fn [i# v#] (nth v# 0)) :into {} ::s/conform-all true :kind `map? @@ -1438,20 +1451,24 @@ (when (accept-nil? p1) (deriv (rep* p2 p2 (add-ret p1 ret nil) splice forms) x))))))) (defn- op-describe [p] - (let [{:keys [::s/op ps ks forms splice p1 rep+ maybe amp] :as p} (#'s/reg-resolve! p)] + (let [{:keys [::s/op ps ks forms splice p1 rep+ maybe amp ::s/wrap-spec] :as p} (#'s/reg-resolve! p)] ;;(prn {:op op :ks ks :forms forms :p p}) (when p - (case op - ::s/accept nil - nil p - ::s/amp (list* 'clojure.alpha.spec/& (resolve-form amp) (resolve-forms forms)) - ::s/pcat (if rep+ - (list `s/+ rep+) - (cons `s/cat (mapcat vector (or (seq ks) (repeat :_)) (resolve-forms forms)))) - ::s/alt (if maybe - (list `s/? maybe) - (cons `s/alt (mapcat vector ks (resolve-forms forms)))) - ::s/rep (list (if splice `s/+ `s/*) (resolve-form forms)))))) + (let [d (case op + ::s/accept nil + nil p + ::s/amp (list* 'clojure.alpha.spec/& (resolve-form amp) (resolve-forms forms)) + ::s/pcat (if rep+ + (list `s/+ rep+) + (cons `s/cat (mapcat vector (or (seq ks) (repeat :_)) (resolve-forms forms)))) + ::s/alt (if maybe + (list `s/? maybe) + (cons `s/alt (mapcat vector ks (resolve-forms forms)))) + ::s/rep (list (if splice `s/+ `s/*) (resolve-form forms)))] + (if wrap-spec + (-> (list (first wrap-spec) d) + (with-meta (meta wrap-spec))) + d))))) (defn- op-explain [form p path via in input settings-key settings] ;;(prn {:form form :p p :path path :input input}) diff --git a/src/test/clojure/clojure/test_clojure/spec.clj b/src/test/clojure/clojure/test_clojure/spec.clj index 11b72e1..63f2d9a 100644 --- a/src/test/clojure/clojure/test_clojure/spec.clj +++ b/src/test/clojure/clojure/test_clojure/spec.clj @@ -309,8 +309,12 @@ (is (= (s/describe sp) (s/form sp) #{1 2}))) (is (= (s/describe (s/spec odd?)) 'odd?)) + (is (= (s/describe (s/resolve-spec `(s/spec odd?))) 'odd?)) (is (= (s/form (s/spec odd?)) 'clojure.core/odd?)) + (is (= (s/form (s/spec (s/* integer?))) `(s/spec (s/* integer?)))) + (is (= (s/form (s/resolve-spec `(s/spec (s/* integer?)))) `(s/spec (s/* integer?)))) + (is (= (s/describe (s/spec #(odd? %))) '(odd? %))) (is (= (s/form (s/spec #(odd? %))) '(fn [%] (clojure.core/odd? %))))) @@ -351,6 +355,9 @@ (s/every int?) '(clojure.alpha.spec/every clojure.core/int?) + (s/resolve-spec `(s/every int?)) + '(clojure.alpha.spec/every clojure.core/int?) + (s/coll-of (s/tuple (s/tuple int?))) '(clojure.alpha.spec/coll-of (clojure.alpha.spec/tuple (clojure.alpha.spec/tuple clojure.core/int?)))