diff --git a/.github/known_hosts b/.github/known_hosts new file mode 100644 index 0000000..e7b86a0 --- /dev/null +++ b/.github/known_hosts @@ -0,0 +1,4 @@ +104.236.66.244 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBNiDodt9vD6R4Tkj6MjXpwWb1sYr6JMo/b8Aek4cHaPtHuyVWWVIXmF8e7H0oQCzJ4sixTePkjkf6xK31zz+1Y= +104.236.66.244 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrINr29cQcqeVqpaBk36cQBv0tdCZ8SM7RIyW1uUHhxwRRd8RWbjGatLQhXELJGlSMLhrUf1KzfzCmXj/4L/l03TffeSDuGWJpxusTI93knKN+mWT69+IudkvIymQnCjaVio/MDOhwRLfkxE0nFGLdj8MbRJA35w/P6qbzIvwjKkHgw6VkbBS1c/4jEjsshIk+Z4P1GPiSw8lwscB8EjpZbOnhOWDYHaZUEpujdGbeIIKK31T/HSgFznEjZGuJmgLXnIf5+2h+WXrjeMljVVe613PNHrydBaR/7JxmWZIltoXyzL7ZDR9wZUQ47DumyMm07BtpQ+LZRCbeAvK+Smrt +68.183.148.118 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCq8NG9rifxGhkfA2/E4zXluAzMneDy4iSCOoaQkOXL8IugY4gmsIN0XGM40F1/p5CxfLPVLGU6ssT4vblFaCnnbUF6c522NZhIfDKpulJaFHesdmtinyHGkPBSgOWibm0ay2dsMfWOEPc95u0/CA1oeJ/OdNh4bq4jWFbbEndQ9nIBs9wOJxBXrGMHB3GFQhuEG/vU5iqVAlp3CNdpEY4IjGLlfO63pPxEQRc6MDQ7ILr1DuolOly4me4Inh63pb13ARduWHvqqzc7jf2yhnusworUaRIbZJhYKVcoZyJ0DHglh+Y5yIv2tRVEIyL5edY8YPMAb9mxAILr9dpfUFP +68.183.148.118 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNnXWiDC1zD8BL+LkIZfSHeZ87CPLJjHaPRltqDMlHJZXb9icnWH9yAwPu4J58CcxTTQpKVkG96q5PmvM/T1qgA= diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..bd876b0 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,73 @@ +name: Deploy + +# Replaces Travis CI. Builds the uberjar, copies it to both engine hosts +# (api-bible-docs web + worker generator) and restarts the supervisor program. +# Requires org secret ANYCHART_BOT_KEY: the anychart-bot private key, authorized +# as root on both hosts (servers-conf SSH_KEYS). + +on: + push: + branches: [master, staging] + workflow_dispatch: + +concurrency: + group: deploy-${{ github.ref_name }} + cancel-in-progress: false + +permissions: + contents: read + +env: + HOSTS: "104.236.66.244 68.183.148.118" + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Resolve target app + run: | + case "${GITHUB_REF_NAME}" in + master) echo "APP=reference-prod" >> "$GITHUB_ENV" ;; + staging) echo "APP=reference-stg" >> "$GITHUB_ENV" ;; + *) echo "No deploy target for ${GITHUB_REF_NAME}"; exit 1 ;; + esac + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "8" + + - uses: DeLaGuardo/setup-clojure@13.2 + with: + lein: 2.9.8 + + - uses: actions/cache@v4 + with: + path: ~/.m2 + key: m2-${{ hashFiles('project.clj') }} + restore-keys: m2- + + - name: Build uberjar + run: | + lein sass4clj once + lein uberjar + + - name: Install SSH key + env: + ANYCHART_BOT_KEY: ${{ secrets.ANYCHART_BOT_KEY }} + run: | + test -n "$ANYCHART_BOT_KEY" || { echo "ANYCHART_BOT_KEY secret is not set"; exit 1; } + install -d -m 700 ~/.ssh + printf '%s\n' "$ANYCHART_BOT_KEY" > ~/.ssh/id_deploy + chmod 600 ~/.ssh/id_deploy + cp .github/known_hosts ~/.ssh/known_hosts + + - name: Copy jar and restart + run: | + SSH_OPTS="-i $HOME/.ssh/id_deploy -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes" + for host in $HOSTS; do + scp $SSH_OPTS "target/reference-3.0.0-standalone.jar" "root@${host}:/apps/${APP}/reference-3.0.0-standalone.jar.new" + ssh $SSH_OPTS "root@${host}" "mv /apps/${APP}/reference-3.0.0-standalone.jar.new /apps/${APP}/reference-3.0.0-standalone.jar && supervisorctl restart ${APP} && supervisorctl status ${APP}" + done diff --git a/.gitignore b/.gitignore index fd67c9e..50a683b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ id_rsa_prod id_rsa .travis/id_rsa package-lock.json -resources/public/css/style.css \ No newline at end of file +resources/public/css/style.css +.clj-kondo diff --git a/.travis.yml b/.travis.yml index 3d2674c..b6c0e1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,5 @@ after_success: - scp target/reference-3.0.0-standalone.jar root@68.183.148.118:/apps/$APP/reference-3.0.0-standalone.jar - ssh root@104.236.66.244 "supervisorctl restart $APP" - ssh root@68.183.148.118 "supervisorctl restart $APP" -notifications: - slack: - secure: eewE3FcToXLQj/qkqvqD4pKYKNcH9w0Q81+K66ieGSzIh31yJlbnjIMRLrA3vvXWzzVjmVcz3rKFU1HztZTYT6s632fbHUOI7OxRwCIXplAhjMqMIuMsu7JPbQfpeQ5YBG6sz5oyDVPOVbRy4irauOx5HDEAr2YikR/878qW7Lo= +# ToDo: Implement notifications +# notifications: diff --git a/project.clj b/project.clj index 5c43c42..fd89f6c 100644 --- a/project.clj +++ b/project.clj @@ -15,6 +15,7 @@ [ring/ring-json "0.4.0"] [ring/ring-core "1.7.1"] [enlive "1.1.6"] + [org.apache.commons/commons-lang3 "3.8.1"] ;; logging [com.taoensso/timbre "4.10.0"] ;; databases diff --git a/src-scss/elements/_footer.scss b/src-scss/elements/_footer.scss index 97d97a3..e8e593b 100644 --- a/src-scss/elements/_footer.scss +++ b/src-scss/elements/_footer.scss @@ -1,63 +1,92 @@ #footer { - height: 70px; - background: #f6f6f6; - bottom: 0; - width: 100%; - position: absolute; - overflow: hidden; - #footer-inner { - border-top: 1px solid #dddddd; - margin: 0 25px; - font-size: 12px; - padding: 10px 0; - - a.soc-network { - display: inline-block; - .soc-network-icon { - font-size: 20px; - display: inline-block; - margin-right: 10px; - vertical-align: middle; - width: 30px; - height: 30px; - line-height: 30px; + height: 70px; + background: #f6f6f6; + bottom: 0; + width: 100%; + position: absolute; + overflow: hidden; + #footer-inner { + border-top: 1px solid #dddddd; + margin: 0 25px; + font-size: 12px; + padding: 10px 0; text-align: center; - border-radius: 50%; - color: #929292; - border: 2px solid #929292; - position: relative; - .sn-mini-icon { - font-size: 20px !important; - position: absolute; - top: 3px; - left: 3px; + + .social-icons { + display: grid; + place-content: center; + grid-template-columns: repeat(auto-fit, 30px); + justify-content: space-evenly; + + a.soc-network { + display: inline-block; + .soc-network-icon { + display: grid; + place-content: center; + width: 30px; + height: 30px; + border-radius: 50%; + color: #929292; + border: 2px solid #929292; + + .sn-mini-icon { + font-size: 14px; + position: relative; + } + + &.fb { + .sn-mini-icon { + top: -1px; + } + } + + &.in { + .sn-mini-icon { + top: -1px; + } + } + + &.md { + .sn-mini-icon { + font-size: 10px; + } + } + } + + &:hover { + text-decoration: none; + color: #fff; + } + &:focus .soc-network-icon.fb, + &:hover .soc-network-icon.fb { + background: #3a5bad; + border-color: #3a5bad; + color: #fff; + } + &:focus .soc-network-icon.tw, + &:hover .soc-network-icon.tw { + background: #1dcbea; + border-color: #1dcbea; + color: #fff; + } + &:focus .soc-network-icon.in, + &:hover .soc-network-icon.in { + background: #1182c9; + border-color: #1182c9; + color: #fff; + } + &:focus .soc-network-icon.md, + &:hover .soc-network-icon.md { + background: #191919; + border-color: #191919; + color: #fff; + } + } } - } - - &:hover { - text-decoration: none; - color: #fff; - } - &:focus .soc-network-icon.fb, &:hover .soc-network-icon.fb { - background: #3a5bad; - border-color: #3a5bad; - color: #fff; - } - &:focus .soc-network-icon.tw, &:hover .soc-network-icon.tw { - background: #1dcbea; - border-color: #1dcbea; - color: #fff; - } - &:focus .soc-network-icon.in, &:hover .soc-network-icon.in { - background: #1182c9; - border-color: #1182c9; - color: #fff; - } - } - p { - padding: 5px 0 15px 0; - color: #929292; + p { + padding: 5px 0 15px 0; + color: #929292; + } } - } -} \ No newline at end of file +} diff --git a/src/reference/components/notifier.clj b/src/reference/components/notifier.clj index 9fe50ef..66f33d1 100644 --- a/src/reference/components/notifier.clj +++ b/src/reference/components/notifier.clj @@ -1,8 +1,9 @@ (ns reference.components.notifier (:require [com.stuartsierra.component :as component] [cheshire.core :refer [generate-string]] - [reference.notification.skype :as skype] - [reference.notification.slack :as slack])) + ;; ToDo: add notifications + ) +) (defrecord Notifier [config] @@ -16,33 +17,35 @@ (defn start-building [notifier branches removed-branches queue-index] - (slack/start-building notifier branches removed-branches queue-index)) + ;; ToDo: add notifications +) (defn complete-building [notifier branches removed-branches queue-index] - (slack/complete-building notifier branches removed-branches queue-index)) + ;; ToDo: add notifications +) (defn complete-building-with-errors [notifier branches queue-index & [e]] - (slack/complete-building-with-errors notifier branches queue-index e) - ;(skype/complete-building-with-errors notifier branches queue-index e) + ;; ToDo: add notifications ) (defn start-version-building [notifier branch queue-index] - (slack/start-version-building notifier (:name branch) queue-index) - (skype/start-version-building notifier branch queue-index)) + ;; ToDo: add notifications +) (defn complete-version-building [notifier branch queue-index dts-enabled] - (slack/complete-version-building notifier (:name branch) queue-index) - (skype/complete-version-building notifier branch queue-index dts-enabled)) + ;; ToDo: add notifications +) (defn complete-version-building-error [notifier branch queue-index e ts-error] - (slack/complete-version-building-error notifier (:name branch) queue-index e ts-error) - (skype/complete-version-building-error notifier branch queue-index e ts-error)) + ;; ToDo: add notifications +) (defn notify-404 [notifier path] - (slack/notify-404 notifier path)) + ;; ToDo: add notifications +) diff --git a/src/reference/config/spec.clj b/src/reference/config/spec.clj index 8553f5a..f6f27ce 100644 --- a/src/reference/config/spec.clj +++ b/src/reference/config/spec.clj @@ -10,27 +10,8 @@ :config.redis.spec/db])) (s/def :config/redis (s/keys :req-un [:config.redis/spec])) - -(s/def :config.notifications.slack/channel string?) -(s/def :config.notifications.slack/token string?) -(s/def :config.notifications.slack/username string?) -(s/def :config.notifications/slack (s/keys :req-un [:config.notifications.slack/channel - :config.notifications.slack/token - :config.notifications.slack/username])) - - -(s/def :config.notifications.skype/id string?) -(s/def :config.notifications.skype/chat-id string?) -(s/def :config.notifications.skype/release-chat-id string?) -(s/def :config.notifications.skype/key string?) -(s/def :config.notifications/skype (s/keys :req-un [:config.notifications.skype/id - :config.notifications.skype/chat-id - :config.notifications.skype/key - :config.notifications.skype/release-chat-id])) - -(s/def :config/notifications (s/keys :req-un [:config.notifications/skype - :config.notifications/slack])) - +;; ToDo: add notifications +(s/def :config/notifications (s/keys :req-un [])) (s/def :config.jdbc/subprotocol string?) (s/def :config.jdbc/password string?) @@ -86,4 +67,4 @@ :config/generator :config/jdbc :config/notifications - :config/redis])) \ No newline at end of file + :config/redis])) diff --git a/src/reference/notification/discord.clj b/src/reference/notification/discord.clj new file mode 100644 index 0000000..1695165 --- /dev/null +++ b/src/reference/notification/discord.clj @@ -0,0 +1,173 @@ +(ns reference.notification.discord + (:require [org.httpkit.client :as http] + [cheshire.core :refer [generate-string]] + [reference.util.utils :as utils] + [clojure.string :as string] + [reference.config.core :as c] + [taoensso.timbre :as timbre])) + +;; ===================================================================================================================== +;; Config and Helpers +;; ===================================================================================================================== +(defn webhook-url [notifier] (-> notifier :config :discord :webhook-url)) +(defn username [notifier] (-> notifier :config :discord :username)) + +;; Text formatting +(defn b [text] (str "**" text "**")) +(defn code-block [text] (str "```\n" text "\n```")) + +;; Base notification function +(defn- send-webhook [url data] + (try + @(http/post url + {:body (generate-string data) + :headers {"Content-Type" "application/json"}}) + (catch Exception e + (timbre/error "Discord webhook error:" (.getMessage e))))) + +(defn- notify [notifier embeds] + (let [payload {:username (username notifier) + :embeds embeds}] + (send-webhook (webhook-url notifier) payload))) + +;; ===================================================================================================================== +;; Slack Analog Functions +;; ===================================================================================================================== + +(defn start-building [notifier branches removed-branches queue-index] + (let [embed {:color 4437377 ; Blue + :title (str "#" queue-index " api `" (c/prefix) "` - start") + :fields (cond-> [] + (seq branches) + (conj {:name "Branches" + :value (string/join ", " branches) + :inline true}) + (seq removed-branches) + (conj {:name "Removed branches" + :value (string/join ", " removed-branches) + :inline true}))}] + (notify notifier [embed]))) + +(defn complete-building [notifier branches removed-branches queue-index] + (let [embed {:color 3066993 ; Green + :title (str "#" queue-index " api `" (c/prefix) "` - complete") + :fields (cond-> [] + (seq branches) + (conj {:name "Branches" + :value (string/join ", " branches) + :inline true}) + (seq removed-branches) + (conj {:name "Removed branches" + :value (string/join ", " removed-branches) + :inline true}))}] + (notify notifier [embed]))) + +(defn complete-building-with-errors [notifier branches queue-index e] + (let [embed {:color 15158332 ; Red + :title (str "#" queue-index " api `" (c/prefix) "` - complete with errors") + :description (when e (code-block (utils/format-exception e))) + :fields (when (seq branches) + [{:name "Branches" + :value (string/join ", " branches) + :inline true}])}] + (notify notifier [embed]))) + +(defn start-version-building [notifier version queue-index] + (let [embed {:color 4437377 ; Blue + :description (str "#" queue-index " api `" (c/prefix) "` - " (b version) " start")}] + (notify notifier [embed]))) + +(defn complete-version-building [notifier version queue-index] + (let [embed {:color 3066993 ; Green + :description (str "#" queue-index " api `" (c/prefix) "` - " (b version) " complete")}] + (notify notifier [embed]))) + +(defn complete-version-building-error [notifier version queue-index e {:keys [index-ts-result graphics-ts-result]}] + (let [embed {:color 15158332 ; Red + :description (str "#" queue-index " api `" (c/prefix) "` - " (b version) " failed" + (when e (str "\n" (code-block (utils/format-exception e)))) + (when (not= 0 (:exit index-ts-result)) + (str "\n[index.d.ts](" (:url index-ts-result) ") errors" + (when (:count index-ts-result) + (str " - " (b (:count index-ts-result)) " tests failed")) + ":\n" + (code-block (:out index-ts-result)))) + (when (not= 0 (:exit graphics-ts-result)) + (str "\n[graphics.d.ts](" (:url graphics-ts-result) ") errors" + (when (:count graphics-ts-result) + (str " - " (b (:count graphics-ts-result)) " tests failed")) + ":\n" + (code-block (:out graphics-ts-result)))))}] + (notify notifier [embed]))) + +(defn notify-404 [notifier path] + (let [embed {:color 15158332 ; Red + :description (str (c/domain) " 404: " path)}] + (notify notifier [embed]))) + +;; ===================================================================================================================== +;; Unique Skype Functions +;; ===================================================================================================================== + +(defn- config [notifier] (-> notifier :config :discord)) + +;; Additional formatting for Skype-style messages +(defn i [text] (str "*" text "*")) +(defn u [text] (str "__" text "__")) + +(defn send-release-message [conf version message] + (when (and (:release-webhook-url conf) + (utils/released-version? version) + (= (c/prefix) "prod")) + (let [payload {:username (username conf) + :content message}] + (send-webhook (:release-webhook-url conf) payload)))) + +;; Extended version building functions with commit info +(defn start-version-building-with-commit + [notifier {:keys [author message name commit] :as version-info} queue-index] + (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b name) + " \"" message "\" @" author " (" (subs commit 0 7) ") - start") + embed {:color 4437377 + :description msg}] + (notify notifier [embed]) + (send-release-message (config notifier) name msg))) + +(defn complete-version-building-with-commit + [notifier {:keys [author message name commit] :as version-info} queue-index dts-enabled] + (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b name) + " \"" message "\" @" author " (" (subs commit 0 7) ") - complete" + (when-not dts-enabled " (d.ts generation OFF)")) + embed {:color 3066993 + :description msg}] + (notify notifier [embed]) + (send-release-message (config notifier) name msg))) + +(defn complete-version-building-error-with-commit + [notifier {:keys [author message name commit] :as version-info} queue-index e {:keys [index-ts-result graphics-ts-result]}] + (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b name) + " \"" message "\" @" author " (" (subs commit 0 7) ") - failed" + (when e (str "\n" (code-block (utils/format-exception e)))) + (when (not= 0 (:exit index-ts-result)) + (str "\n[index.d.ts](" (:url index-ts-result) ") errors" + (when (:count index-ts-result) + (str " - " (b (:count index-ts-result)) " tests failed")) + ":\n" + (code-block (:out index-ts-result)))) + (when (not= 0 (:exit graphics-ts-result)) + (str "\n[graphics.d.ts](" (:url graphics-ts-result) ") errors" + (when (:count graphics-ts-result) + (str " - " (b (:count graphics-ts-result)) " tests failed")) + ":\n" + (code-block (:out graphics-ts-result))))) + embed {:color 15158332 + :description msg}] + (notify notifier [embed]) + (send-release-message (config notifier) name msg))) +``` + +Configuration required: +```clojure +{:discord {:webhook-url "https://discord.com/api/webhooks/your-webhook-url" + :release-webhook-url "https://discord.com/api/webhooks/your-release-webhook-url" + :username "API Bot"}} diff --git a/src/reference/notification/skype.clj b/src/reference/notification/skype.clj index ec8b21e..ca8be4f 100644 --- a/src/reference/notification/skype.clj +++ b/src/reference/notification/skype.clj @@ -4,7 +4,8 @@ [cheshire.core :as json] [reference.util.utils :as utils] [clojure.string :as string] - [reference.config.core :as c])) + [reference.config.core :as c]) + (:import (org.apache.commons.lang3 StringEscapeUtils))) ;; ===================================================================================================================== @@ -65,7 +66,7 @@ ;; ===================================================================================================================== (defn start-version-building [notifier {author :author commit-message :message version :name commit :commit} queue-index] (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b version) - " \"" commit-message "\" @" author " (" (subs commit 0 7) ") - " + " \"" (StringEscapeUtils/escapeHtml4 commit-message) "\" @" author " (" (subs commit 0 7) ") - " (-> "start" (font "#4183C4")) "\n")] (send-message (config notifier) msg) (send-release-message (config notifier) version msg))) @@ -74,7 +75,7 @@ (defn complete-version-building [notifier {author :author commit-message :message version :name commit :commit} queue-index dts-enabled] (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b version) - " \"" commit-message "\" @" author " (" (subs commit 0 7) ") - " + " \"" (StringEscapeUtils/escapeHtml4 commit-message) "\" @" author " (" (subs commit 0 7) ") - " (-> "complete" (font "#36a64f")) (when-not dts-enabled " (d.ts generation OFF)") "\n")] @@ -85,7 +86,7 @@ (defn complete-version-building-error [notifier {author :author commit-message :message version :name commit :commit} queue-index e {:keys [index-ts-result graphics-ts-result]}] (let [msg (str "[API " (c/prefix) "] #" queue-index " " (b version) - " \"" commit-message "\" @" author " (" (subs commit 0 7) ") - " + " \"" (StringEscapeUtils/escapeHtml4 commit-message) "\" @" author " (" (subs commit 0 7) ") - " (-> "failed" (font "#d00000")) "\n" (when e diff --git a/src/reference/util/utils.clj b/src/reference/util/utils.clj index 42eb312..cdb8e08 100644 --- a/src/reference/util/utils.clj +++ b/src/reference/util/utils.clj @@ -27,10 +27,11 @@ (sort-versions identity versions))) -(defn released-version? [version-key] - (or - ;; (re-matches #"^\d+\.\d+\.\d+$" version-key) - (re-matches #"^v\d+$" version-key))) +(defn released-version? + "Legacy v7/v8 branches, plus release tags 9.x.x and up (never v9+). + Older 8.x.x tags exist in the content repos and must stay hidden." + [version-key] + (boolean (re-matches #"^(?:v[78]|(?:9|[1-9]\d+)\.\d+\.\d+)$" version-key))) (defn name->url [name] diff --git a/src/reference/web/views/common.clj b/src/reference/web/views/common.clj index d290410..c1fb8af 100644 --- a/src/reference/web/views/common.clj +++ b/src/reference/web/views/common.clj @@ -4,7 +4,7 @@ (defn styles [commit] (list - [:link {:rel "stylesheet" :type "text/css" :href "https://cdn.anychart.com/fonts/2.0.0/anychart.css",}] + [:link {:rel "stylesheet" :type "text/css" :href "https://cdn.anychart.com/releases/latest/fonts/css/anychart-font.min.css",}] [:link {:rel "stylesheet" :type "text/css" :href "/lib/bootstrap/css/bootstrap.min.css"}] [:link {:rel "stylesheet" :type "text/css" :href "/lib/bootstrap-select.min.css"}] [:link {:rel "stylesheet" :type "text/css" :href "/lib/jquery-custom-content-scroller/jquery.mCustomScrollbar.min.css"}] @@ -102,4 +102,4 @@ [:span.hidden-super-small "Still have questions?" [:br] [:a {:href "http://anychart.com/support/"} - " Contact support"]]]) \ No newline at end of file + " Contact support"]]]) diff --git a/src/reference/web/views/main/main_page.clj b/src/reference/web/views/main/main_page.clj index a4185ac..3790685 100644 --- a/src/reference/web/views/main/main_page.clj +++ b/src/reference/web/views/main/main_page.clj @@ -67,15 +67,20 @@ [:div#footer [:div#footer-inner - [:a.soc-network {:target "_blank" - :href "https://www.facebook.com/AnyCharts"} - [:span.soc-network-icon.fb [:i.sn-mini-icon.ac.ac-facebook]]] - [:a.soc-network {:target "_blank" - :href "https://twitter.com/AnyChart"} - [:span.soc-network-icon.tw [:i.sn-mini-icon.ac.ac-twitter]]] - [:a.soc-network {:target "_blank" - :href "https://www.linkedin.com/company/386660"} - [:span.soc-network-icon.in [:i.sn-mini-icon.ac.ac-linkedin]]] + [:div.social-icons + [:a.soc-network {:target "_blank" + :href "https://www.facebook.com/AnyCharts"} + [:span.soc-network-icon.fb [:i.sn-mini-icon.ac.ac-facebook]]] + [:a.soc-network {:target "_blank" + :href "https://x.com/AnyChart"} + [:span.soc-network-icon.tw [:i.sn-mini-icon.ac.ac-twitter-x]]] + [:a.soc-network {:target "_blank" + :href "https://www.linkedin.com/company/386660"} + [:span.soc-network-icon.in [:i.sn-mini-icon.ac.ac-linkedin]]] + [:a.soc-network {:target "_blank" + :href "https://anychart.medium.com/"} + [:span.soc-network-icon.md [:i.sn-mini-icon.ac.ac-medium]]] + ] [:p (str " © " (t/year (t/now)) " AnyChart.Com All rights reserved.")]]] diff --git a/test/reference/util/utils_test.clj b/test/reference/util/utils_test.clj new file mode 100644 index 0000000..ad86825 --- /dev/null +++ b/test/reference/util/utils_test.clj @@ -0,0 +1,11 @@ +(ns reference.util.utils-test + (:require [clojure.test :refer [deftest is testing]] + [reference.util.utils :as utils])) + +(deftest released-version?-test + (testing "legacy branches and numbered release tags are versions" + (doseq [k ["v7" "v8" "9.0.0" "9.1.2" "10.0.0"]] + (is (true? (utils/released-version? k)) k))) + (testing "v9+, old 8.x.x tags, work branches and partial versions are not" + (doseq [k ["v9" "v10" "8.9.0" "master" "develop" "staging" "RC-8.13.0" "9.0" "9.0.0-rc1"]] + (is (false? (utils/released-version? k)) k))))