ci.yml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. name: CICD
  2. env:
  3. CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
  4. MSRV_FEATURES: ""
  5. on:
  6. workflow_dispatch:
  7. pull_request:
  8. push:
  9. branches:
  10. - master
  11. tags:
  12. - '*'
  13. jobs:
  14. crate_metadata:
  15. name: Extract crate metadata
  16. runs-on: ubuntu-latest
  17. steps:
  18. - uses: actions/checkout@v4
  19. - name: Extract crate information
  20. id: crate_metadata
  21. run: |
  22. cargo metadata --no-deps --format-version 1 | jq -r '"name=" + .packages[0].name' | tee -a $GITHUB_OUTPUT
  23. cargo metadata --no-deps --format-version 1 | jq -r '"version=" + .packages[0].version' | tee -a $GITHUB_OUTPUT
  24. cargo metadata --no-deps --format-version 1 | jq -r '"maintainer=" + .packages[0].authors[0]' | tee -a $GITHUB_OUTPUT
  25. cargo metadata --no-deps --format-version 1 | jq -r '"homepage=" + .packages[0].homepage' | tee -a $GITHUB_OUTPUT
  26. cargo metadata --no-deps --format-version 1 | jq -r '"msrv=" + .packages[0].rust_version' | tee -a $GITHUB_OUTPUT
  27. outputs:
  28. name: ${{ steps.crate_metadata.outputs.name }}
  29. version: ${{ steps.crate_metadata.outputs.version }}
  30. maintainer: ${{ steps.crate_metadata.outputs.maintainer }}
  31. homepage: ${{ steps.crate_metadata.outputs.homepage }}
  32. msrv: ${{ steps.crate_metadata.outputs.msrv }}
  33. ensure_cargo_fmt:
  34. name: Ensure 'cargo fmt' has been run
  35. runs-on: ubuntu-20.04
  36. steps:
  37. - uses: dtolnay/rust-toolchain@stable
  38. with:
  39. components: rustfmt
  40. - uses: actions/checkout@v4
  41. - run: cargo fmt -- --check
  42. documentation_checks:
  43. name: Documentation checks
  44. runs-on: ubuntu-20.04
  45. steps:
  46. - uses: dtolnay/rust-toolchain@stable
  47. - uses: actions/checkout@v3
  48. - uses: actions/setup-python@v5
  49. - name: Install mdbook
  50. run: |
  51. cargo install mdbook
  52. cargo install mdbook-linkcheck
  53. - name: Build documentation
  54. run: |
  55. cd book
  56. python build.py
  57. if [ -n "$(git status --porcelain)" ]; then
  58. echo "Documentation not up to date."
  59. echo "Make sure to run 'build.py' in the book/ folder"
  60. exit 1
  61. fi
  62. wasm:
  63. name: WASM version
  64. runs-on: ubuntu-20.04
  65. steps:
  66. - uses: dtolnay/rust-toolchain@stable
  67. - uses: actions/checkout@v3
  68. - name: Install wasm-pack
  69. run: |
  70. curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
  71. - name: Build WASM version
  72. run: |
  73. cd numbat-wasm
  74. bash build.sh
  75. - name: Test WASM version
  76. run: |
  77. cd numbat-wasm
  78. bash test.sh
  79. min_version:
  80. name: Minimum supported rust version
  81. runs-on: ubuntu-20.04
  82. needs: crate_metadata
  83. steps:
  84. - name: Checkout source code
  85. uses: actions/checkout@v4
  86. - name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
  87. uses: dtolnay/rust-toolchain@master
  88. with:
  89. toolchain: ${{ needs.crate_metadata.outputs.msrv }}
  90. components: clippy
  91. - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
  92. run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
  93. - name: Run tests
  94. run: cargo test --locked ${{ env.MSRV_FEATURES }}
  95. build:
  96. name: ${{ matrix.job.target }} (${{ matrix.job.os }})
  97. runs-on: ${{ matrix.job.os }}
  98. needs: crate_metadata
  99. strategy:
  100. fail-fast: false
  101. matrix:
  102. job:
  103. - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
  104. - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
  105. - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
  106. - { target: i686-pc-windows-msvc , os: windows-2019 }
  107. - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
  108. - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
  109. - { target: x86_64-apple-darwin , os: macos-12 }
  110. #- { target: x86_64-pc-windows-gnu , os: windows-2019 }
  111. - { target: x86_64-pc-windows-msvc , os: windows-2019 }
  112. - { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
  113. - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
  114. env:
  115. BUILD_CMD: cargo
  116. steps:
  117. - name: Checkout source code
  118. uses: actions/checkout@v4
  119. - name: Install prerequisites
  120. shell: bash
  121. run: |
  122. case ${{ matrix.job.target }} in
  123. arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
  124. aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
  125. esac
  126. - name: Install Rust toolchain
  127. uses: dtolnay/rust-toolchain@stable
  128. with:
  129. targets: ${{ matrix.job.target }}
  130. - name: Install cross
  131. if: matrix.job.use-cross
  132. uses: taiki-e/install-action@v2
  133. with:
  134. tool: cross
  135. - name: Overwrite build command env variable
  136. if: matrix.job.use-cross
  137. shell: bash
  138. run: echo "BUILD_CMD=cross" >> $GITHUB_ENV
  139. - name: Show version information (Rust, cargo, GCC)
  140. shell: bash
  141. run: |
  142. gcc --version || true
  143. rustup -V
  144. rustup toolchain list
  145. rustup default
  146. cargo -V
  147. rustc -V
  148. - name: Build
  149. shell: bash
  150. run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}
  151. - name: Set binary name & path
  152. id: bin
  153. shell: bash
  154. run: |
  155. # Figure out suffix of binary
  156. EXE_suffix=""
  157. case ${{ matrix.job.target }} in
  158. *-pc-windows-*) EXE_suffix=".exe" ;;
  159. esac;
  160. # Setup paths
  161. BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}"
  162. BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}"
  163. # Let subsequent steps know where to find the binary
  164. echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
  165. echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT
  166. - name: Set testing options
  167. id: test-options
  168. shell: bash
  169. run: |
  170. # test only library unit tests and binary for arm-type targets
  171. unset CARGO_TEST_OPTIONS
  172. unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
  173. echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
  174. - name: Run tests
  175. shell: bash
  176. run: $BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
  177. - name: Create tarball
  178. id: package
  179. shell: bash
  180. run: |
  181. PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
  182. PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }}
  183. PKG_NAME=${PKG_BASENAME}${PKG_suffix}
  184. echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
  185. PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
  186. ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
  187. mkdir -p "${ARCHIVE_DIR}"
  188. # Binary
  189. cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
  190. # README and LICENSE files
  191. cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "$ARCHIVE_DIR"
  192. # Desktop file and icons
  193. mkdir "$ARCHIVE_DIR/assets"
  194. cp "assets/numbat.desktop" assets/numbat-*x*.png "assets/numbat.svg" "$ARCHIVE_DIR/assets"
  195. # Numbat prelude
  196. cp -r numbat/modules "$ARCHIVE_DIR"
  197. # base compressed package
  198. pushd "${PKG_STAGING}/" >/dev/null
  199. case ${{ matrix.job.target }} in
  200. *-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;;
  201. *) tar czf "${PKG_NAME}" "${PKG_BASENAME}"/* ;;
  202. esac;
  203. popd >/dev/null
  204. # Let subsequent steps know where to find the compressed package
  205. echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
  206. - name: Create Debian package
  207. id: debian-package
  208. shell: bash
  209. if: startsWith(matrix.job.os, 'ubuntu')
  210. run: |
  211. COPYRIGHT_YEARS="2022 - "$(date "+%Y")
  212. DPKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/debian-package"
  213. DPKG_DIR="${DPKG_STAGING}/dpkg"
  214. mkdir -p "${DPKG_DIR}"
  215. DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}
  216. DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }}-musl
  217. case ${{ matrix.job.target }} in *-musl*) DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-musl ; DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }} ;; esac;
  218. DPKG_VERSION=${{ needs.crate_metadata.outputs.version }}
  219. unset DPKG_ARCH
  220. case ${{ matrix.job.target }} in
  221. aarch64-*-linux-*) DPKG_ARCH=arm64 ;;
  222. arm-*-linux-*hf) DPKG_ARCH=armhf ;;
  223. i686-*-linux-*) DPKG_ARCH=i686 ;;
  224. x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
  225. *) DPKG_ARCH=notset ;;
  226. esac;
  227. DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
  228. echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
  229. # Binary
  230. install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}"
  231. # README and LICENSE
  232. install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
  233. install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-MIT"
  234. install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-APACHE"
  235. # Desktop file and icons
  236. install -Dm644 "assets/numbat.desktop" "${DPKG_DIR}/usr/share/applications/numbat.desktop"
  237. install -Dm644 "assets/numbat.svg" "${DPKG_DIR}/usr/share/icons/hicolor/scalable/apps/numbat.svg"
  238. for s in 16 22 24 32 48 64 128 256 512; do
  239. install -Dm644 "assets/numbat-${s}x${s}.png" "${DPKG_DIR}/usr/share/icons/hicolor/${s}x${s}/apps/numbat.png"
  240. done
  241. # Numbat prelude
  242. mkdir -p "${DPKG_DIR}/usr/share/${DPKG_BASENAME}"
  243. cp -r numbat/modules "${DPKG_DIR}/usr/share/${DPKG_BASENAME}"
  244. cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
  245. Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
  246. Upstream-Name: ${{ needs.crate_metadata.outputs.name }}
  247. Source: ${{ needs.crate_metadata.outputs.homepage }}
  248. Files: *
  249. Copyright: ${{ needs.crate_metadata.outputs.maintainer }}
  250. Copyright: $COPYRIGHT_YEARS ${{ needs.crate_metadata.outputs.maintainer }}
  251. License: Apache-2.0 or MIT
  252. License: Apache-2.0
  253. On Debian systems, the complete text of the Apache-2.0 can be found in the
  254. file /usr/share/common-licenses/Apache-2.0.
  255. License: MIT
  256. Permission is hereby granted, free of charge, to any
  257. person obtaining a copy of this software and associated
  258. documentation files (the "Software"), to deal in the
  259. Software without restriction, including without
  260. limitation the rights to use, copy, modify, merge,
  261. publish, distribute, sublicense, and/or sell copies of
  262. the Software, and to permit persons to whom the Software
  263. is furnished to do so, subject to the following
  264. conditions:
  265. .
  266. The above copyright notice and this permission notice
  267. shall be included in all copies or substantial portions
  268. of the Software.
  269. .
  270. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  271. ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  272. TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  273. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  274. SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  275. CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  276. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  277. IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  278. DEALINGS IN THE SOFTWARE.
  279. EOF
  280. chmod 644 "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright"
  281. # control file
  282. mkdir -p "${DPKG_DIR}/DEBIAN"
  283. cat > "${DPKG_DIR}/DEBIAN/control" <<EOF
  284. Package: ${DPKG_BASENAME}
  285. Version: ${DPKG_VERSION}
  286. Section: utils
  287. Priority: optional
  288. Maintainer: ${{ needs.crate_metadata.outputs.maintainer }}
  289. Homepage: ${{ needs.crate_metadata.outputs.homepage }}
  290. Architecture: ${DPKG_ARCH}
  291. Provides: ${{ needs.crate_metadata.outputs.name }}
  292. Conflicts: ${DPKG_CONFLICTS}
  293. Description: Statically typed programming language for scientific computations with first class support for physical dimensions and units
  294. EOF
  295. DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
  296. echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT
  297. # build dpkg
  298. fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"
  299. - name: "Artifact upload: tarball"
  300. uses: actions/upload-artifact@master
  301. with:
  302. name: ${{ steps.package.outputs.PKG_NAME }}
  303. path: ${{ steps.package.outputs.PKG_PATH }}
  304. - name: "Artifact upload: Debian package"
  305. uses: actions/upload-artifact@master
  306. if: steps.debian-package.outputs.DPKG_NAME
  307. with:
  308. name: ${{ steps.debian-package.outputs.DPKG_NAME }}
  309. path: ${{ steps.debian-package.outputs.DPKG_PATH }}
  310. - name: Check for release
  311. id: is-release
  312. shell: bash
  313. run: |
  314. unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
  315. echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
  316. - name: Publish archives and packages
  317. uses: softprops/action-gh-release@v1
  318. if: steps.is-release.outputs.IS_RELEASE
  319. with:
  320. files: |
  321. ${{ steps.package.outputs.PKG_PATH }}
  322. ${{ steps.debian-package.outputs.DPKG_PATH }}
  323. env:
  324. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}