From d2cef2b3aface1f06024550355c864254d940252 Mon Sep 17 00:00:00 2001 From: Dzianis Charnysh <11035379+charnysh-dev@users.noreply.github.com> Date: Mon, 12 Jul 2021 21:49:38 +0300 Subject: [PATCH] Feat/doc (#60) * feat: init doc * chore: remove unecessaries 1 * fix: config * chore: structure * chore: remove yarn * chore: use yarn, without s3 * fix: deploy * chore: use normal script to build & deploy * fix: without s3 * fix: theme provider * chore: move theme wrapper * chore: move themeprovider * chore: version * chore: theme ui version * fix: add provider again * fix: use case route in doc menu * chore: without provider * fix: dark color mode * fix: search, style * chore: meta * chore: fonts1 * chore: font 2 * fix: css 1 * chore: font & style * chore: term's map, plugins * chore: fonts * chore: redirects list * chore: use original font for doc * chore: link-check * chore: link-check * chore: use test url * chore: link check * chore: remove unused assets, fix:icon * chore: version & style * chore: font feeling * chore: version, components * chore: missing icons, ts errors * chore: types * chore: remove unused things 1 * chore: unused modules, scroll to top * chore: doc * chore: remove images * chore: plugins * fix: search result for doc * fix: header, code block, styles * fix: unresponsive parts * fix: header color on home * chore: use case instead of fetures * fix: scrolling and offset issue * chore: yarn lock * chore: package * fix: icons * Add .circleci/config.yml * chore: test, misc issues * chore: format 1 * chore: gatsby-plugin-twitter * chore: sass plugin & style * chore: lint-css * chore: ts-lint * fix: refect prev pr's change Co-authored-by: Ivan Shcheklein --- .circleci/config.yml | 81 + .codeclimate.json | 4 + .eslintignore | 5 +- .eslintrc | 24 - .eslintrc.json | 52 + .github/CONTRIBUTING.md | 2 + .github/ISSUE_TEMPLATE/bug_report.md | 4 + .github/ISSUE_TEMPLATE/feature_request.md | 4 + .github/PULL_REQUEST_TEMPLATE.md | 9 + .github/workflows/link-check-all.yml | 21 + .github/workflows/link-check-deploy.yml | 50 + .gitignore | 37 +- .node-version | 1 - .pre-commit-hooks.yaml | 6 + .prettierignore | 9 +- .prettierrc | 8 +- .restyled.yaml | 19 + .storybook/main.js | 37 - .storybook/preview-head.html | 1 - .storybook/preview.js | 43 - .stylelintrc | 18 + LICENSE | 213 +- README.md | 12 +- app.json | 12 +- config/link-check/config.yml | 4 + config/link-check/excluded-files.yml | 4 + config/link-check/excluded-links.yml | 0 config/postcss/media.js | 19 + config/postcss/mixins.js | 115 + config/prismjs/usage.js | 9 + content/docs/cml-with-dvc.md | 192 + content/docs/cml-with-npm.md | 40 + content/docs/index.md | 36 + content/docs/self-hosted-runners.md | 159 + content/docs/sidebar.json | 36 + content/docs/start/index.md | 45 + content/docs/start/start-github.md | 155 + content/docs/start/start-gitlab.md | 108 + content/docs/usage.md | 81 + gatsby-browser.js | 10 +- gatsby-config.js | 276 +- gatsby-node.js | 142 +- gatsby-ssr.js | 10 +- jest.config.js | 12 + package.json | 239 +- postcss.config.js | 26 + redirects-list.json | 8 + remarkPlugin.js | 35 - src/components/atoms/Collapser/index.js | 21 +- src/components/atoms/Headings.stories.js | 26 - .../atoms/HiddenRadioControl/index.js | 40 +- .../atoms/LayoutWidthContainer/index.tsx | 22 + .../LayoutWidthContainer/styles.module.css | 17 + src/components/atoms/Link/index.tsx | 120 + src/components/atoms/ShowOnly/index.tsx | 20 + .../atoms/ShowOnly/styles.module.css | 15 + src/components/atoms/SiteLogo/index.js | 8 - src/components/atoms/SmartLink/index.js | 8 +- .../atoms/ThemedGatsbyLink/index.js | 9 - .../atoms/ThemedGatsbyLink/index.tsx | 14 + src/components/layouts/MainLayout/index.tsx | 55 + .../layouts/MainLayout/styles.module.css | 3 + .../molecules/HamburgerIcon/index.tsx | 18 + .../molecules/HamburgerIcon/styles.module.css | 32 + .../molecules/HamburgerMenu/index.tsx | 227 + .../molecules/HamburgerMenu/styles.module.css | 225 + .../molecules/InstallPopup/index.js | 12 +- .../Paginator/LocationContext/index.ts | 13 + src/components/molecules/Paginator/arrow.svg | 3 + src/components/molecules/Paginator/index.tsx | 93 + .../molecules/Paginator/styles.module.css | 42 + .../molecules/SubscribeSection/index.js | 29 +- .../molecules/Video/LandingVideo/index.js | 4 +- src/components/molecules/Video/index.js | 22 +- .../organisms/Page/DefaultSEO/index.tsx | 150 + src/components/organisms/Page/base.css | 95 + src/components/organisms/Page/fonts.css | 92 + src/components/organisms/Page/index.tsx | 50 + .../organisms/Page/styles.module.css | 4 + src/components/organisms/Page/utils.ts | 39 + .../organisms/PageContent/index.tsx | 15 + .../organisms/PageContent/styles.module.css | 3 + src/components/organisms/PageWrapper/index.js | 6 + src/components/organisms/SEO/index.tsx | 112 + src/components/organisms/SiteFooter/index.js | 181 - src/components/organisms/SiteFooter/index.tsx | 197 + .../SiteHeader/SiteHeader.stories.js | 8 - src/components/organisms/SiteHeader/index.js | 232 - src/components/organisms/SiteHeader/index.tsx | 282 + .../organisms/SiteHeader/styles.module.css | 32 + .../organisms/SubscribeSection/Form/index.tsx | 64 + .../SubscribeSection/Form/styles.module.css | 53 + .../organisms/SubscribeSection/glyph-1.svg | 20 + .../organisms/SubscribeSection/glyph-2.svg | 20 + .../organisms/SubscribeSection/index.tsx | 29 + .../SubscribeSection/styles.module.css | 67 + .../SwitchableMode/Provider/index.js | 16 +- .../organisms/SwitchableMode/Switch/index.js | 34 +- .../SwitchableMode/Switchable/index.js | 42 +- .../SwitchableMode/SwitchableModes.stories.js | 55 - .../organisms/SwitchableMode/common.js | 4 +- .../organisms/SwitchableMode/styleHelpers.js | 12 +- src/components/organisms/Tabs/.stories.js | 40 - src/components/organisms/Tabs/Core/index.js | 12 +- src/components/organisms/Tabs/Tabs.stories.js | 41 - .../organisms/Tabs/core-styles/index.js | 34 +- .../organisms/Tabs/core-styles/styles.css | 2 +- src/components/organisms/Tabs/index.js | 54 +- src/components/organisms/Tooltip/index.js | 54 +- .../Documentation/Layout/SearchForm/index.tsx | 69 + .../Layout/SearchForm/styles.module.css | 53 + .../Layout/SidebarMenu/cml_bw_logo.svg | 7 + .../Layout/SidebarMenu/cml_logo.svg | 23 + .../Layout/SidebarMenu/external-link-icon.svg | 1 + .../Layout/SidebarMenu/house.svg | 1 + .../Layout/SidebarMenu/index.tsx | 241 + .../Layout/SidebarMenu/studio_gray_icon.svg | 457 + .../Layout/SidebarMenu/studio_icon.svg | 28 + .../Layout/SidebarMenu/styles.module.css | 116 + .../pages/Documentation/Layout/index.tsx | 69 + .../Documentation/Layout/styles.module.css | 127 + .../pages/Documentation/Markdown/index.tsx | 213 + .../Documentation/Markdown/styles.module.css | 432 + .../pages/Documentation/RightPanel/index.tsx | 222 + .../RightPanel/styles.module.css | 106 + .../Documentation/TutorialsLinks/index.tsx | 46 + .../TutorialsLinks/styles.module.css | 11 + src/components/pages/Documentation/index.tsx | 45 + .../pages/Documentation/styles.module.css | 35 + .../pages/Home/HeroSection/index.tsx | 144 + .../pages/Home/MLOpsSection/index.tsx | 65 + .../pages/Home/UseCasesSection/index.tsx | 632 + src/components/pages/Home/index.tsx | 20 + src/components/pages/Home/styles.module.css | 3 + src/components/pages/NotFound/index.tsx | 14 + .../pages/NotFound/styles.module.css | 30 + src/consts.js | 7 + src/gatsby-plugin-theme-ui/components.js | 149 +- src/gatsby-plugin-theme-ui/index.js | 1405 +- src/gatsby/common.js | 34 + src/gatsby/hooks/stars.ts | 35 + src/gatsby/models.js | 9 + src/gatsby/models/docs/createPages.js | 84 + .../models/docs/createSchemaCustomization.js | 23 + src/gatsby/models/docs/index.js | 13 + .../docs/onCreateMarkdownContentNode.js | 36 + src/gatsby/models/github/index.js | 43 + src/gatsby/models/image-source-paths/index.js | 12 + src/gatsby/models/markdown-content/fields.js | 17 + src/gatsby/models/markdown-content/index.js | 79 + src/gatsby/models/prune-cache/index.js | 62 + src/gatsby/utils/models/index.js | 36 + src/gatsby/utils/models/nodes.js | 19 + src/gatsby/utils/resolvers/index.js | 100 + src/html.tsx | 38 + src/media/icons/cml.svg | 5 +- src/media/icons/dvc-monochrome.svg | 1 - src/media/icons/dvc.svg | 7 +- src/media/icons/mail.svg | 1 + src/media/icons/slack.svg | 10 - src/media/icons/studio.svg | 5 +- src/media/site-icon.png | Bin 46033 -> 0 bytes src/media/site-logo.png | Bin 621451 -> 0 bytes .../solution-line-arrow.svg | 0 src/pages/404.js | 12 - src/pages/404.tsx | 16 + src/pages/index.tsx | 7 + src/queries/siteMeta.ts | 28 + src/server/index.js | 30 + src/server/middleware/redirects/index.js | 40 + src/server/middleware/serve/index.js | 3 + src/server/middleware/serve/local.js | 30 + src/server/utils.js | 1 + src/templates/base/SEO/index.js | 138 - src/templates/base/fonts.css | 32 - src/templates/base/index.js | 36 - src/templates/base/layout.js | 14 - src/templates/default/layout.js | 19 - src/templates/doc.tsx | 52 + src/typings.ts | 55 + src/utils/front/accessibility.ts | 14 + src/utils/front/api.ts | 102 + src/utils/front/breakpoints.ts | 12 + src/utils/front/customProperties.ts | 31 + src/utils/front/ga.ts | 46 + src/utils/front/i18n.ts | 23 + src/utils/front/images.ts | 28 + src/utils/front/isClient.ts | 12 + src/utils/front/keyboard.ts | 9 + src/utils/front/resources.ts | 64 + src/utils/front/scroll.ts | 70 + src/utils/handlers.js | 2 +- src/utils/shared/crawlPageData.js | 16 + src/utils/shared/expiration.js | 48 + src/utils/shared/expiration.test.js | 62 + src/utils/shared/redirects.js | 96 + src/utils/shared/redirects.test.js | 103 + src/utils/shared/sidebar.js | 236 + src/utils/shared/sidebar.test.js | 400 + src/utils/shared/tagToSlug.js | 2 + src/utils/use-rehydrated.js | 2 +- static.json | 18 +- static/android-chrome-192x192.png | Bin 0 -> 15699 bytes static/android-chrome-512x512.png | Bin 0 -> 56713 bytes static/apple-touch-icon.png | Bin 0 -> 13978 bytes static/favicon-16x16.png | Bin 0 -> 607 bytes static/favicon-32x32.png | Bin 0 -> 1383 bytes static/favicon-512x512.png | Bin 0 -> 56713 bytes static/favicon.ico | Bin 0 -> 15406 bytes static/fonts/DMMono-Regular.ttf | Bin static/fonts/DMMono-Regular.woff | Bin static/fonts/DMMono-Regular.woff2 | Bin static/fonts/DMSans-Bold.ttf | Bin static/fonts/DMSans-Bold.woff | Bin static/fonts/DMSans-Bold.woff2 | Bin static/fonts/DMSans-Regular.ttf | Bin static/fonts/DMSans-Regular.woff | Bin static/fonts/DMSans-Regular.woff2 | Bin static/fonts/brandon_bld.woff | Bin 0 -> 44120 bytes static/fonts/brandon_bld.woff2 | Bin 0 -> 29584 bytes static/fonts/brandon_bld_it.woff | Bin 0 -> 41796 bytes static/fonts/brandon_bld_it.woff2 | Bin 0 -> 28032 bytes static/fonts/brandon_blk.woff | Bin 0 -> 44128 bytes static/fonts/brandon_blk.woff2 | Bin 0 -> 29120 bytes static/fonts/brandon_blk_it.woff | Bin 0 -> 41152 bytes static/fonts/brandon_blk_it.woff2 | Bin 0 -> 27772 bytes static/fonts/brandon_light.woff | Bin 0 -> 43016 bytes static/fonts/brandon_light.woff2 | Bin 0 -> 28592 bytes static/fonts/brandon_light_it.woff | Bin 0 -> 40540 bytes static/fonts/brandon_light_it.woff2 | Bin 0 -> 27148 bytes static/fonts/brandon_med.woff | Bin 0 -> 44476 bytes static/fonts/brandon_med.woff2 | Bin 0 -> 29692 bytes static/fonts/brandon_med_it.woff | Bin 0 -> 41152 bytes static/fonts/brandon_med_it.woff2 | Bin 0 -> 27828 bytes static/fonts/brandon_reg.woff | Bin 0 -> 42116 bytes static/fonts/brandon_reg.woff2 | Bin 0 -> 28344 bytes static/fonts/brandon_reg_it.woff | Bin 0 -> 40940 bytes static/fonts/brandon_reg_it.woff2 | Bin 0 -> 27900 bytes static/fonts/brandon_thin.woff | Bin 0 -> 39824 bytes static/fonts/brandon_thin.woff2 | Bin 0 -> 26992 bytes static/fonts/brandon_thin_it.woff | Bin 0 -> 38432 bytes static/fonts/brandon_thin_it.woff2 | Bin 0 -> 26528 bytes static/img/arrow.svg | 13 + static/img/change_user_name.png | Bin 0 -> 92665 bytes static/img/ci_cd_navigation.png | Bin 0 -> 200217 bytes static/img/click.png | Bin 0 -> 5002 bytes static/img/cml-icon.svg | 55 + static/img/cml_first_report.png | Bin 0 -> 243882 bytes static/img/cml_neural_transfer.png | Bin 0 -> 1089030 bytes static/img/cml_start_gitlab_end.png | Bin 0 -> 267440 bytes static/img/create_merge_request.png | Bin 0 -> 28638 bytes static/img/default_bullet_dark.svg | 1 + static/img/discord.svg | 1 + static/img/dvc-icon.svg | 13 + static/img/dvc_cml_long_report.png | Bin 0 -> 274511 bytes static/img/external-link.svg | 6 + static/img/fork_cml_project.png | Bin 0 -> 200606 bytes .../img}/github/base-case-report.png | Bin .../img}/github/cloud-report.png | Bin .../img}/github/cml-runner-report.png | Bin .../img}/github/dvc-report.png | Bin .../img}/github/tensorboard-report.png | Bin static/img/github_icon.svg | 6 + .../img}/gitlab/base-case-report.png | Bin .../img}/gitlab/cloud-report.png | Bin .../img}/gitlab/cml-runner-report.png | Bin .../img}/gitlab/dvc-report.png | Bin .../img}/gitlab/tensorboard-report.png | Bin static/img/gitlab_cml_clone.png | Bin 0 -> 41913 bytes static/img/gitlab_fork_cml_project.png | Bin 0 -> 213713 bytes static/img/glyph-1.svg | 20 + static/img/glyph-2.svg | 20 + static/img/graph.png | Bin 0 -> 138535 bytes static/img/make_pr.png | Bin 0 -> 229432 bytes static/img/new_merge_request.png | Bin 0 -> 75846 bytes static/img/personal_access_token.png | Bin 0 -> 172179 bytes static/img/search.svg | 3 + static/img/studio-icon.svg | 28 + static/img/triangle_dark.svg | 1 + static/robots.txt | 4 + tsconfig.json | 24 + yarn.lock | 12094 ++++++++-------- 282 files changed, 16884 insertions(+), 8436 deletions(-) create mode 100644 .circleci/config.yml create mode 100644 .codeclimate.json delete mode 100644 .eslintrc create mode 100644 .eslintrc.json create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/link-check-all.yml create mode 100644 .github/workflows/link-check-deploy.yml delete mode 100644 .node-version create mode 100644 .pre-commit-hooks.yaml create mode 100644 .restyled.yaml delete mode 100644 .storybook/main.js delete mode 100644 .storybook/preview-head.html delete mode 100644 .storybook/preview.js create mode 100644 .stylelintrc create mode 100644 config/link-check/config.yml create mode 100644 config/link-check/excluded-files.yml create mode 100644 config/link-check/excluded-links.yml create mode 100644 config/postcss/media.js create mode 100644 config/postcss/mixins.js create mode 100644 config/prismjs/usage.js create mode 100644 content/docs/cml-with-dvc.md create mode 100644 content/docs/cml-with-npm.md create mode 100644 content/docs/index.md create mode 100644 content/docs/self-hosted-runners.md create mode 100644 content/docs/sidebar.json create mode 100644 content/docs/start/index.md create mode 100644 content/docs/start/start-github.md create mode 100644 content/docs/start/start-gitlab.md create mode 100644 content/docs/usage.md create mode 100644 jest.config.js create mode 100644 postcss.config.js create mode 100644 redirects-list.json delete mode 100644 remarkPlugin.js delete mode 100644 src/components/atoms/Headings.stories.js create mode 100644 src/components/atoms/LayoutWidthContainer/index.tsx create mode 100644 src/components/atoms/LayoutWidthContainer/styles.module.css create mode 100644 src/components/atoms/Link/index.tsx create mode 100644 src/components/atoms/ShowOnly/index.tsx create mode 100644 src/components/atoms/ShowOnly/styles.module.css delete mode 100644 src/components/atoms/SiteLogo/index.js delete mode 100644 src/components/atoms/ThemedGatsbyLink/index.js create mode 100644 src/components/atoms/ThemedGatsbyLink/index.tsx create mode 100644 src/components/layouts/MainLayout/index.tsx create mode 100644 src/components/layouts/MainLayout/styles.module.css create mode 100644 src/components/molecules/HamburgerIcon/index.tsx create mode 100644 src/components/molecules/HamburgerIcon/styles.module.css create mode 100644 src/components/molecules/HamburgerMenu/index.tsx create mode 100644 src/components/molecules/HamburgerMenu/styles.module.css create mode 100644 src/components/molecules/Paginator/LocationContext/index.ts create mode 100644 src/components/molecules/Paginator/arrow.svg create mode 100644 src/components/molecules/Paginator/index.tsx create mode 100644 src/components/molecules/Paginator/styles.module.css create mode 100644 src/components/organisms/Page/DefaultSEO/index.tsx create mode 100644 src/components/organisms/Page/base.css create mode 100644 src/components/organisms/Page/fonts.css create mode 100644 src/components/organisms/Page/index.tsx create mode 100644 src/components/organisms/Page/styles.module.css create mode 100644 src/components/organisms/Page/utils.ts create mode 100644 src/components/organisms/PageContent/index.tsx create mode 100644 src/components/organisms/PageContent/styles.module.css create mode 100644 src/components/organisms/PageWrapper/index.js create mode 100644 src/components/organisms/SEO/index.tsx delete mode 100644 src/components/organisms/SiteFooter/index.js create mode 100644 src/components/organisms/SiteFooter/index.tsx delete mode 100644 src/components/organisms/SiteHeader/SiteHeader.stories.js delete mode 100644 src/components/organisms/SiteHeader/index.js create mode 100644 src/components/organisms/SiteHeader/index.tsx create mode 100644 src/components/organisms/SiteHeader/styles.module.css create mode 100644 src/components/organisms/SubscribeSection/Form/index.tsx create mode 100644 src/components/organisms/SubscribeSection/Form/styles.module.css create mode 100644 src/components/organisms/SubscribeSection/glyph-1.svg create mode 100644 src/components/organisms/SubscribeSection/glyph-2.svg create mode 100644 src/components/organisms/SubscribeSection/index.tsx create mode 100644 src/components/organisms/SubscribeSection/styles.module.css delete mode 100644 src/components/organisms/SwitchableMode/SwitchableModes.stories.js delete mode 100644 src/components/organisms/Tabs/.stories.js delete mode 100644 src/components/organisms/Tabs/Tabs.stories.js create mode 100644 src/components/pages/Documentation/Layout/SearchForm/index.tsx create mode 100644 src/components/pages/Documentation/Layout/SearchForm/styles.module.css create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/cml_bw_logo.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/cml_logo.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/external-link-icon.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/house.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/index.tsx create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/studio_gray_icon.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/studio_icon.svg create mode 100644 src/components/pages/Documentation/Layout/SidebarMenu/styles.module.css create mode 100644 src/components/pages/Documentation/Layout/index.tsx create mode 100644 src/components/pages/Documentation/Layout/styles.module.css create mode 100644 src/components/pages/Documentation/Markdown/index.tsx create mode 100644 src/components/pages/Documentation/Markdown/styles.module.css create mode 100644 src/components/pages/Documentation/RightPanel/index.tsx create mode 100644 src/components/pages/Documentation/RightPanel/styles.module.css create mode 100644 src/components/pages/Documentation/TutorialsLinks/index.tsx create mode 100644 src/components/pages/Documentation/TutorialsLinks/styles.module.css create mode 100644 src/components/pages/Documentation/index.tsx create mode 100644 src/components/pages/Documentation/styles.module.css create mode 100644 src/components/pages/Home/HeroSection/index.tsx create mode 100644 src/components/pages/Home/MLOpsSection/index.tsx create mode 100644 src/components/pages/Home/UseCasesSection/index.tsx create mode 100644 src/components/pages/Home/index.tsx create mode 100644 src/components/pages/Home/styles.module.css create mode 100644 src/components/pages/NotFound/index.tsx create mode 100644 src/components/pages/NotFound/styles.module.css create mode 100644 src/consts.js create mode 100644 src/gatsby/common.js create mode 100644 src/gatsby/hooks/stars.ts create mode 100644 src/gatsby/models.js create mode 100644 src/gatsby/models/docs/createPages.js create mode 100644 src/gatsby/models/docs/createSchemaCustomization.js create mode 100644 src/gatsby/models/docs/index.js create mode 100644 src/gatsby/models/docs/onCreateMarkdownContentNode.js create mode 100644 src/gatsby/models/github/index.js create mode 100644 src/gatsby/models/image-source-paths/index.js create mode 100644 src/gatsby/models/markdown-content/fields.js create mode 100644 src/gatsby/models/markdown-content/index.js create mode 100644 src/gatsby/models/prune-cache/index.js create mode 100644 src/gatsby/utils/models/index.js create mode 100644 src/gatsby/utils/models/nodes.js create mode 100644 src/gatsby/utils/resolvers/index.js create mode 100644 src/html.tsx delete mode 100644 src/media/icons/dvc-monochrome.svg create mode 100644 src/media/icons/mail.svg delete mode 100644 src/media/icons/slack.svg delete mode 100644 src/media/site-icon.png delete mode 100644 src/media/site-logo.png rename src/{gatsby-plugin-theme-ui => media}/solution-line-arrow.svg (100%) delete mode 100644 src/pages/404.js create mode 100644 src/pages/404.tsx create mode 100644 src/pages/index.tsx create mode 100644 src/queries/siteMeta.ts create mode 100644 src/server/index.js create mode 100644 src/server/middleware/redirects/index.js create mode 100644 src/server/middleware/serve/index.js create mode 100644 src/server/middleware/serve/local.js create mode 100644 src/server/utils.js delete mode 100644 src/templates/base/SEO/index.js delete mode 100644 src/templates/base/fonts.css delete mode 100644 src/templates/base/index.js delete mode 100644 src/templates/base/layout.js delete mode 100644 src/templates/default/layout.js create mode 100644 src/templates/doc.tsx create mode 100644 src/typings.ts create mode 100644 src/utils/front/accessibility.ts create mode 100644 src/utils/front/api.ts create mode 100644 src/utils/front/breakpoints.ts create mode 100644 src/utils/front/customProperties.ts create mode 100644 src/utils/front/ga.ts create mode 100644 src/utils/front/i18n.ts create mode 100644 src/utils/front/images.ts create mode 100644 src/utils/front/isClient.ts create mode 100644 src/utils/front/keyboard.ts create mode 100644 src/utils/front/resources.ts create mode 100644 src/utils/front/scroll.ts create mode 100644 src/utils/shared/crawlPageData.js create mode 100644 src/utils/shared/expiration.js create mode 100644 src/utils/shared/expiration.test.js create mode 100644 src/utils/shared/redirects.js create mode 100644 src/utils/shared/redirects.test.js create mode 100644 src/utils/shared/sidebar.js create mode 100644 src/utils/shared/sidebar.test.js create mode 100644 src/utils/shared/tagToSlug.js create mode 100644 static/android-chrome-192x192.png create mode 100644 static/android-chrome-512x512.png create mode 100644 static/apple-touch-icon.png create mode 100644 static/favicon-16x16.png create mode 100644 static/favicon-32x32.png create mode 100644 static/favicon-512x512.png create mode 100644 static/favicon.ico mode change 100644 => 100755 static/fonts/DMMono-Regular.ttf mode change 100644 => 100755 static/fonts/DMMono-Regular.woff mode change 100644 => 100755 static/fonts/DMMono-Regular.woff2 mode change 100644 => 100755 static/fonts/DMSans-Bold.ttf mode change 100644 => 100755 static/fonts/DMSans-Bold.woff mode change 100644 => 100755 static/fonts/DMSans-Bold.woff2 mode change 100644 => 100755 static/fonts/DMSans-Regular.ttf mode change 100644 => 100755 static/fonts/DMSans-Regular.woff mode change 100644 => 100755 static/fonts/DMSans-Regular.woff2 create mode 100644 static/fonts/brandon_bld.woff create mode 100644 static/fonts/brandon_bld.woff2 create mode 100644 static/fonts/brandon_bld_it.woff create mode 100644 static/fonts/brandon_bld_it.woff2 create mode 100644 static/fonts/brandon_blk.woff create mode 100644 static/fonts/brandon_blk.woff2 create mode 100644 static/fonts/brandon_blk_it.woff create mode 100644 static/fonts/brandon_blk_it.woff2 create mode 100644 static/fonts/brandon_light.woff create mode 100644 static/fonts/brandon_light.woff2 create mode 100644 static/fonts/brandon_light_it.woff create mode 100644 static/fonts/brandon_light_it.woff2 create mode 100644 static/fonts/brandon_med.woff create mode 100644 static/fonts/brandon_med.woff2 create mode 100644 static/fonts/brandon_med_it.woff create mode 100644 static/fonts/brandon_med_it.woff2 create mode 100644 static/fonts/brandon_reg.woff create mode 100644 static/fonts/brandon_reg.woff2 create mode 100644 static/fonts/brandon_reg_it.woff create mode 100644 static/fonts/brandon_reg_it.woff2 create mode 100644 static/fonts/brandon_thin.woff create mode 100644 static/fonts/brandon_thin.woff2 create mode 100644 static/fonts/brandon_thin_it.woff create mode 100644 static/fonts/brandon_thin_it.woff2 create mode 100644 static/img/arrow.svg create mode 100644 static/img/change_user_name.png create mode 100644 static/img/ci_cd_navigation.png create mode 100644 static/img/click.png create mode 100644 static/img/cml-icon.svg create mode 100644 static/img/cml_first_report.png create mode 100644 static/img/cml_neural_transfer.png create mode 100644 static/img/cml_start_gitlab_end.png create mode 100644 static/img/create_merge_request.png create mode 100644 static/img/default_bullet_dark.svg create mode 100644 static/img/discord.svg create mode 100644 static/img/dvc-icon.svg create mode 100644 static/img/dvc_cml_long_report.png create mode 100644 static/img/external-link.svg create mode 100644 static/img/fork_cml_project.png rename {src/media => static/img}/github/base-case-report.png (100%) rename {src/media => static/img}/github/cloud-report.png (100%) rename {src/media => static/img}/github/cml-runner-report.png (100%) rename {src/media => static/img}/github/dvc-report.png (100%) rename {src/media => static/img}/github/tensorboard-report.png (100%) create mode 100644 static/img/github_icon.svg rename {src/media => static/img}/gitlab/base-case-report.png (100%) rename {src/media => static/img}/gitlab/cloud-report.png (100%) rename {src/media => static/img}/gitlab/cml-runner-report.png (100%) rename {src/media => static/img}/gitlab/dvc-report.png (100%) rename {src/media => static/img}/gitlab/tensorboard-report.png (100%) create mode 100644 static/img/gitlab_cml_clone.png create mode 100644 static/img/gitlab_fork_cml_project.png create mode 100644 static/img/glyph-1.svg create mode 100644 static/img/glyph-2.svg create mode 100644 static/img/graph.png create mode 100644 static/img/make_pr.png create mode 100644 static/img/new_merge_request.png create mode 100644 static/img/personal_access_token.png create mode 100644 static/img/search.svg create mode 100644 static/img/studio-icon.svg create mode 100644 static/img/triangle_dark.svg create mode 100644 static/robots.txt create mode 100644 tsconfig.json diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..fcb28911 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,81 @@ +# Javascript Node CircleCI 2.0 configuration file +# +# See https://circleci.com/docs/2.0/language-javascript/ for more details. +# +version: 2.1 + +defaults: &defaults + working_directory: ~/repo + docker: + # Specify the version you desire here. + - image: circleci/node:12 + + # Specify service dependencies here if necessary. + # CircleCI maintains a library of pre-built images, + # documented in https://circleci.com/docs/2.0/circleci-images/ + +commands: + install: + steps: + - checkout + + # CircleCI breaks master branch which affects format check below. See + # https://discuss.circleci.com/t/checkout-script-adds-commits-to-master-from-circle-branch/14194 + - run: + name: restore master + command: | + git checkout master + git reset --hard origin/master + git checkout - + + # Download cached dependencies. + - restore_cache: + keys: + - v2-dependencies-{{ checksum "yarn.lock" }} + # Fallback to using the latest cache if no exact match is found. + - v2-dependencies- + + - run: yarn + + # Upload dependencies cache. + - save_cache: + paths: + - node_modules + key: v2-dependencies-{{ checksum "yarn.lock" }} + +jobs: + test: + <<: *defaults + steps: + - install + - run: yarn test + - run: yarn lint-css + - run: yarn lint-ts + - run: yarn format-check + + test_full: + <<: *defaults + steps: + - install + - run: yarn test + - run: yarn lint-css + - run: yarn lint-ts + - run: yarn format-check + +workflows: + version: 2 + + commit: + jobs: + - test + + daily: + triggers: + - schedule: + cron: '0 0 * * *' + filters: + branches: + only: + - master + jobs: + - test_full diff --git a/.codeclimate.json b/.codeclimate.json new file mode 100644 index 00000000..9c310917 --- /dev/null +++ b/.codeclimate.json @@ -0,0 +1,4 @@ +{ + "version": "2", + "exclude_patterns": ["**/*.test.js", "**/node_modules/"] +} diff --git a/.eslintignore b/.eslintignore index bb31b918..f9304830 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,2 @@ -.cache -package.json -package-lock.json public -storybook-static* +.cache diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index c90f84d7..00000000 --- a/.eslintrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parser": "babel-eslint", - "rules": { - "strict": 0, - "react/prop-types": 0 - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended" - ], - "plugins": [ - "jsx-a11y" - ], - "env": { - "amd": true, - "node": true, - "browser": true - }, - "settings": { - "react": { - "version": "detect" - } - } -} diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..7404e260 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,52 @@ +{ + "extends": [ + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended", + "plugin:jsx-a11y/recommended", + "plugin:json/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + } + }, + "env": { + "browser": true, + "jest": true + }, + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "@typescript-eslint/interface-name-prefix": [ + "error", + { "prefixWithI": "always" } + ], + "no-tabs": "error", + "react/prop-types": "off", + "@typescript-eslint/no-unused-vars": "error" + }, + "overrides": [ + { + "files": [ + "src/utils/shared/*.?(js|ts)", + "src/gatsby/**/*.js", + "src/components/PageWrapper/index.js", + "scripts/**/*.js", + "config/**/*.js", + "src/server/**/*.js", + "gatsby-*.js", + "postcss.config.js" + ], + "rules": { + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/explicit-function-return-type": "off" + } + } + ] +} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..fe14e3ae --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,2 @@ +**Please see our contributing guide at +[dvc.org](https://dvc.org/doc/user-guide/contributing/docs).** diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..eff768be --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,4 @@ +--- +name: Bug or improvement report +about: Create a report to help us improve +--- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..c709e39a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,4 @@ +--- +name: Feature request +about: Suggest an idea for this project +--- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..abee670b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +> You may disregard these recommendations if you used the **Edit on GitHub** button from dvc.org to improve a doc in place. + +❗ Please read the guidelines in the [Contributing to the Documentation](https://dvc.org/doc/user-guide/contributing/docs) list if you make any substantial changes to the documentation or JS engine. + +🐛 Please make sure to mention `Fix #issue` (if applicable) in the description of the PR. This causes GitHub to close it automatically when the PR is merged. + +Please choose to [allow us](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) to edit your branch when creating the PR. + +Thank you for the contribution - we'll try to review it as soon as possible. 🙏 diff --git a/.github/workflows/link-check-all.yml b/.github/workflows/link-check-all.yml new file mode 100644 index 00000000..56ad17f9 --- /dev/null +++ b/.github/workflows/link-check-all.yml @@ -0,0 +1,21 @@ +name: Check all links in the repository +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + +jobs: + run: + name: Link Check All + runs-on: ubuntu-latest + env: + NODE_OPTIONS: '--max-http-header-size=65536' + + steps: + - uses: actions/checkout@v2 + + - name: Run Link Check + uses: 'iterative/link-check.action@v0.7' + with: + configFile: 'config/link-check/config.yml' + output: consoleLog diff --git a/.github/workflows/link-check-deploy.yml b/.github/workflows/link-check-deploy.yml new file mode 100644 index 00000000..9879d11e --- /dev/null +++ b/.github/workflows/link-check-deploy.yml @@ -0,0 +1,50 @@ +name: Check new links against deployment +# This workflow "triggers" and skips on deployment because GitHub Actions / +# Checks refuses to show the check on deployment_status +on: + - deployment + - deployment_status + +jobs: + run: + name: Initialize + runs-on: ubuntu-latest + if: github.event.deployment.ref != 'master' && github.event.deployment_status.state == 'success' + + steps: + - uses: actions/checkout@v2 + + - id: build_check + uses: LouisBrunner/checks-action@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + name: Report + status: queued + + - name: Run Link Check + id: check + uses: 'iterative/link-check.action@v0.7' + with: + diff: true + configFile: 'config/link-check/config.yml' + rootURL: '${{ github.event.deployment.payload.web_url }}' + output: checksAction + + - uses: LouisBrunner/checks-action@v1.0.0 + if: ${{ success() }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + check_id: ${{ steps.build_check.outputs.check_id }} + status: completed + conclusion: ${{ steps.check.outputs.conclusion }} + output: ${{ steps.check.outputs.output }} + + - uses: LouisBrunner/checks-action@v1.0.0 + if: ${{ failure() }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + check_id: ${{ steps.build_check.outputs.check_id }} + status: completed + conclusion: failure + output: >- + {"summary": "The Link Check script had an error!"} diff --git a/.gitignore b/.gitignore index 604c7cfc..f3e75fb8 100644 --- a/.gitignore +++ b/.gitignore @@ -17,9 +17,6 @@ lib-cov # Coverage directory used by tools like istanbul coverage -# nyc test coverage -.nyc_output - # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt @@ -29,14 +26,14 @@ bower_components # node-waf configuration .lock-wscript -# Compiled binary addons (http://nodejs.org/api/addons.html) +# Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ -# Typescript v1 declaration files +# TypeScript v1 declaration files typings/ # Optional npm cache directory @@ -51,21 +48,25 @@ typings/ # Output of 'npm pack' *.tgz -# dotenv environment variable files -.env* +# Yarn Integrity file +.yarn-integrity -# gatsby files -.cache/ -public +# dotenv environment variables file +.env -# Mac files +# Editors & logs +*.log +.idea +.vscode +.history + +# Mac finder artifacts .DS_Store -# Yarn -yarn-error.log -.pnp/ -.pnp.js -# Yarn Integrity file -.yarn-integrity +# Gatsby cache +.cache +public +tmp -storybook-static \ No newline at end of file +# Copied 404 for Heroku +404.html diff --git a/.node-version b/.node-version deleted file mode 100644 index bda253b7..00000000 --- a/.node-version +++ /dev/null @@ -1 +0,0 @@ -14.5 diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 00000000..c4b759a6 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,6 @@ +- id: dead-url + name: Dead URL Checker + entry: scripts/link-check.sh + language: script + types: [text] + description: This hook searches for problematic URLs. diff --git a/.prettierignore b/.prettierignore index bb31b918..c0d16a8f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,4 @@ -.cache -package.json -package-lock.json -public -storybook-static* +.cache/ +.github +public/ +src/components/pages/Home/UseCasesSection/index.tsx \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 33d2cfa3..365b1903 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,10 @@ { + "semi": false, "arrowParens": "avoid", - "semi": false + "singleQuote": true, + "trailingComma": "none", + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "proseWrap": "always" } diff --git a/.restyled.yaml b/.restyled.yaml new file mode 100644 index 00000000..fa753241 --- /dev/null +++ b/.restyled.yaml @@ -0,0 +1,19 @@ +restylers: + - name: prettier + arguments: + [ + '--write', + '--trailing-comma=none', + '--no-semi', + '--arrow-parens=avoid', + '--single-quote=true', + '--print-width=80', + '--tab-width=2', + '--use-tabs=false', + '--prose-wrap=always', + ] + include: + - './*.{js,md}' + - 'pages/**/*.js' + - 'content/**/*.md' + - 'src/**/*.js' diff --git a/.storybook/main.js b/.storybook/main.js deleted file mode 100644 index d2127e7c..00000000 --- a/.storybook/main.js +++ /dev/null @@ -1,37 +0,0 @@ -const path = require("path") - -module.exports = { - stories: ["../**/*.stories.js"], - addons: ["@storybook/addon-docs", "@storybook/addon-actions"], - webpackFinal: async config => { - config.resolve.modules.unshift(path.resolve("src")) - - config.module.rules.push({ - // Config for js and jsx files - test: /\.(js|jsx)$/, - use: [ - { - loader: require.resolve("babel-loader"), - options: { - presets: [ - // use @babel/preset-react for JSX and env (instead of staged presets) - require.resolve("@babel/preset-react"), - require.resolve("@babel/preset-env"), - ], - plugins: [ - // use @babel/plugin-proposal-class-properties for class arrow functions - require.resolve("@babel/plugin-proposal-class-properties"), - // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook - require.resolve("babel-plugin-remove-graphql-queries"), - // use babel-plugin-react-docgen to ensure PropTables still appear - require.resolve("babel-plugin-react-docgen"), - ], - }, - }, - ], - exclude: [/node_modules\/(?!(gatsby)\/)/], - }) - - return config - }, -} diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html deleted file mode 100644 index 8599422b..00000000 --- a/.storybook/preview-head.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.storybook/preview.js b/.storybook/preview.js deleted file mode 100644 index 65892b25..00000000 --- a/.storybook/preview.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from "react" -import { action } from "@storybook/addon-actions" -import { addDecorator } from "@storybook/react" -import { ThemeProvider } from "theme-ui" -import { Box } from "@theme-ui/components" -import theme from "../src/gatsby-plugin-theme-ui/index.js" - -addDecorator(storyFn => ( - - - - {storyFn()} - - -)) - -// Gatsby's Link overrides: -// Gatsby Link calls the `enqueue` & `hovering` methods on the global variable ___loader. -// This global object isn't set in storybook context. We override it to empty functions (no-op), -// so gatsby link doesn't throw any errors. -global.___loader = { - enqueue: () => {}, - hovering: () => {}, -} - -// __PATH_PREFIX__ is used inside gatsby-link an other various places. For storybook not to crash we need to set it as well. -global.__PATH_PREFIX__ = "" - -// Navigating through a gatsby app using gatsby-link or any other gatsby component will use the `___navigate` method. -// In storybook it doesn't make sense to do an actual navigate, instead we want to log an action. Checkout the actions addon docs https://github.com/storybookjs/storybook/tree/master/addons/actions. - -window.___navigate = pathname => { - action("NavigateTo:")(pathname) -} diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 00000000..063efbba --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,18 @@ +{ + "extends": "stylelint-config-standard", + "rules": { + "no-descending-specificity": null, + "no-duplicate-selectors": null, + "declaration-colon-newline-after": null, + "value-list-comma-newline-after": null, + "property-no-unknown": [true, { + "ignoreProperties": ["composes"] + }], + "selector-pseudo-class-no-unknown": [true, { + "ignorePseudoClasses": ["global", "local"] + }], + "at-rule-no-unknown": [true, { + "ignoreAtRules": ["mixin"] + }] + }, +} diff --git a/LICENSE b/LICENSE index 5169a5e4..8dada3ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,22 +1,201 @@ -The MIT License (MIT) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2015 gatsbyjs + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -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. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index fb598ebe..b48631e1 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ # CML website -This repo hosts the Gatsby-based website for [CML](https://github.com/iterative/cml). +This repo hosts the Gatsby-based website for +[CML](https://github.com/iterative/cml). -It's primarily a marketing website with some light docs, but the primary docs are in the GitHub README. +It's primarily a marketing website with some light docs, but the primary docs +are in the GitHub README. ## Running this site locally Start by cloning this repo: Get the full history with + ```bash git clone https://github.com/iterative/cml-website ``` Alternatively, you can save some space with a shallow clone: + ```bash git clone --depth 1 https://github.com/iterative/cml-website ``` @@ -25,4 +29,6 @@ cd cml-website yarn ``` -With the setup finished, you can now spin up the development server at `localhost:8000` with `gatsby develop` or try a full local build at `localhost:9000` with `gatsby build && gatsby serve`. +With the setup finished, you can now spin up the development server at +`localhost:8000` with `gatsby develop` or try a full local build at +`localhost:9000` with `gatsby build && gatsby serve`. diff --git a/app.json b/app.json index e98eb66a..fcdc1680 100644 --- a/app.json +++ b/app.json @@ -1,4 +1,5 @@ { + "addons": [], "buildpacks": [ { "url": "heroku/nodejs" @@ -6,5 +7,14 @@ { "url": "https://github.com/heroku/heroku-buildpack-static" } - ] + ], + "env": {}, + "formation": { + "web": { + "quantity": 1 + } + }, + "name": "cml.dev", + "scripts": {}, + "stack": "heroku-18" } diff --git a/config/link-check/config.yml b/config/link-check/config.yml new file mode 100644 index 00000000..fb921819 --- /dev/null +++ b/config/link-check/config.yml @@ -0,0 +1,4 @@ +fileIncludePatterns: '{.github,content,src}/**/*!(.test).{css,js,jsx,md,tsx,ts,json}' +fileExcludePatternFile: config/link-check/excluded-files.yml +linkExcludePatternFile: config/link-check/excluded-links.yml + diff --git a/config/link-check/excluded-files.yml b/config/link-check/excluded-files.yml new file mode 100644 index 00000000..eb065074 --- /dev/null +++ b/config/link-check/excluded-files.yml @@ -0,0 +1,4 @@ +- 'src/consts.js' +- '**/*.test.js' +- 'src/server/**/*' +- '.github/workflows/**/*' diff --git a/config/link-check/excluded-links.yml b/config/link-check/excluded-links.yml new file mode 100644 index 00000000..e69de29b diff --git a/config/postcss/media.js b/config/postcss/media.js new file mode 100644 index 00000000..1e30babc --- /dev/null +++ b/config/postcss/media.js @@ -0,0 +1,19 @@ +const screens = { + giant: 1200, + desktop: 1005, + tablet: 768, + phablet: 572, + phone: 376 +} + +module.exports = { + screens, + customMedia: { + '--xxs-scr': `(max-width: ${screens.phone}px)`, + '--xs-scr': `(max-width: ${screens.phablet}px)`, + '--sm-scr': `(max-width: ${screens.tablet}px)`, + '--md-scr': `(max-width: ${screens.desktop - 1}px)`, + '--lg-scr': `(min-width: ${screens.desktop}px)`, + '--xl-scr': `(min-width: ${screens.giant}px)` + } +} diff --git a/config/postcss/mixins.js b/config/postcss/mixins.js new file mode 100644 index 00000000..299dac94 --- /dev/null +++ b/config/postcss/mixins.js @@ -0,0 +1,115 @@ +const { customMedia } = require('./media') + +const focus = { + '&:focus': { + color: 'var(--color-orange)' + } +} + +const active = { + '&:active': { + position: 'relative', + top: '1px', + left: '1px' + } +} + +const hover = { + '&:hover': { + opacity: 0.7 + } +} + +module.exports = { + mixins: { + 'h1-desktop': { + 'font-weight': '500', + 'font-size': '40px', + 'line-height': '60px' + }, + 'h1-mobile': { + 'font-weight': '500', + 'font-size': '30px', + 'line-height': '40px' + }, + 'h2-desktop': { + 'font-weight': '500', + 'font-size': '30px', + 'line-height': '40px' + }, + 'h2-mobile': { + 'font-weight': '500', + 'font-size': '25px', + 'line-height': '35px' + }, + 'h3-desktop': { + 'font-weight': '500', + 'font-size': '24px', + 'line-height': '34px' + }, + 'h3-mobile': { + 'font-weight': '500', + 'font-size': '20px', + 'line-height': '30px' + }, + 'text-desktop': { + 'font-size': '24px', + 'line-height': '34px' + }, + 'text-mobile': { + 'font-size': '20px', + 'line-height': '30px' + }, + 'text-diminished': { + 'font-size': '20px', + 'line-height': '30px' + }, + 'text-secondary': { + 'font-size': '16px', + 'line-height': '24px' + }, + 'button-big': { + 'font-size': '20px', + 'line-height': '30px' + }, + 'button-small': { + 'font-size': '16px', + 'line-height': '25px' + }, + columns: { + display: 'flex', + 'flex-direction': 'row', + 'flex-flow': 'wrap', + 'justify-content': 'space-between', + + [`@media ${customMedia['--sm-scr']}`]: { + 'flex-direction': 'row' + }, + + [`@media ${customMedia['--xs-scr']}`]: { + 'justify-content': 'center' + } + }, + column: { + 'flex-basis': '33.3%', + + [`@media ${customMedia['--sm-scr']}`]: { + 'flex-basis': '50%' + }, + + [`@media ${customMedia['--xs-scr']}`]: { + 'flex-basis': '100%' + } + }, + link: { + 'text-decoration': 'none', + color: 'var(--color-blue)', + ...hover, + ...focus, + ...active + }, + hover, + focus, + active + } +} diff --git a/config/prismjs/usage.js b/config/prismjs/usage.js new file mode 100644 index 00000000..98c93405 --- /dev/null +++ b/config/prismjs/usage.js @@ -0,0 +1,9 @@ +/* eslint-env node */ + +const Prism = require('prismjs') + +Prism.languages.usage = { + usage: { + pattern: /(^|\n)\s*(usage|positional arguments|optional arguments)/ + } +} diff --git a/content/docs/cml-with-dvc.md b/content/docs/cml-with-dvc.md new file mode 100644 index 00000000..971e2d81 --- /dev/null +++ b/content/docs/cml-with-dvc.md @@ -0,0 +1,192 @@ +# CML with DVC + +In many ML projects, data isn't stored in a Git repository and needs to be +downloaded from external sources. [DVC](https://dvc.org) is a common way to +bring data to your CML runner. DVC also lets you visualize how metrics differ +between commits to make reports like this: + +![](/img/dvc_cml_long_report.png) + +The `.github/workflows/cml.yaml` file to create this report is: + +```yaml +name: train-test +on: [push] +jobs: + run: + runs-on: [ubuntu-latest] + container: docker://dvcorg/cml-py3:latest + steps: + - uses: actions/checkout@v2 + - name: cml_run + shell: bash + env: + repo_token: ${{ secrets.GITHUB_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + # Install requirements + pip install -r requirements.txt + + # Pull data & run-cache from S3 and reproduce pipeline + dvc pull data --run-cache + dvc repro + + # Report metrics + echo "## Metrics" >> report.md + git fetch --prune + dvc metrics diff master --show-md >> report.md + + # Publish confusion matrix diff + echo -e "## Plots\n### Class confusions" >> report.md + dvc plots diff \ + --target classes.csv \ + --template confusion \ + -x actual \ + -y predicted \ + --show-vega master > vega.json + vl2png vega.json -s 1.5 | cml-publish --md >> report.md + + # Publish regularization function diff + echo "### Effects of regularization\n" >> report.md + dvc plots diff \ + --target estimators.csv \ + -x Regularization \ + --show-vega master vega.json + vl2png vega.json -s 1.5 | cml-publish --md >> report.md + + cml-send-comment report.md +``` + +If you're using DVC with cloud storage, take note of environmental variables for +your storage format. + +
+ +### S3 and S3-compatible storage (Minio, DigitalOcean Spaces, IBM Cloud Object Storage...) + +```yaml +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }} +``` + +Note that `AWS_SESSION_TOKEN` is optional. + +
+ +
+ +### Azure + +```yaml +env: + AZURE_STORAGE_CONNECTION_STRING: + ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }} +``` + +
+ +
+ +### Aliyn + +```yaml +env: + OSS_BUCKET: ${{ secrets.OSS_BUCKET }} + OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }} + OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }} + OSS_ENDPOINT: ${{ secrets.OSS_ENDPOINT }} +``` + +
+ +
+ +### Google Cloud Storage + +(ℹ️) Normally, `GOOGLE_APPLICATION_CREDENTIALS` points to the path of the +`.json` file that contains the credentials. However, in this context, the +variable contains the content of the file. Copy the text inside the `.json` and +add it as a secret. + +```yaml +env: + GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} +``` + +
+ +
+ +### Google Drive + +(ℹ️) After configuring your +[Google Drive credentials](https://dvc.org/doc/command-reference/remote/add) you +will find a json file at +`your_project_path/.dvc/tmp/gdrive-user-credentials.json`. Copy the text inside +that `.json` and add it as a secret. + +```yaml +env: + GDRIVE_CREDENTIALS_DATA: ${{ secrets.GDRIVE_CREDENTIALS_DATA }} +``` + +
+ +## For GitHub Actions Users: Try the `setup-dvc` Action! + +The [iterative/setup-dvc](https://github.com/iterative/setup-dvc) action is a +JavaScript action that sets up [DVC](https://dvc.org/) in your workflow. + +### Usage + +This action can be run on `ubuntu-latest`, `macos-latest`, or `windows-latest`. +When running on `windows-latest`, Python 3 is a dependency that should be setup +first (and +[there's an action for that](https://github.com/actions/setup-python)). + +Basic usage: + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: iterative/setup-dvc@v1 +``` + +Windows: + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - uses: iterative/setup-dvc@v1 +``` + +A specific version can be pinned to your workflow using the `version` argument. + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: iterative/setup-dvc@v1 + with: + version: '1.0.1' +``` + +### Inputs + +The following inputs are supported. + +- `version` - (optional) The version of DVC to install. A value of `latest` will + install the latest version of DVC. Defaults to `latest`. + +### Outputs + +Setup DVC has no outputs. diff --git a/content/docs/cml-with-npm.md b/content/docs/cml-with-npm.md new file mode 100644 index 00000000..a28f0b64 --- /dev/null +++ b/content/docs/cml-with-npm.md @@ -0,0 +1,40 @@ +# Install CML with NPM + +In the above examples, CML is pre-installed in a custom Docker image, which is +pulled by a CI runner. You can also install CML as a package: + +```bash +npm i -g @dvcorg/cml +``` + +You may need to install additional dependencies to use DVC plots and Vega-Lite +CLI commands: + +```bash +sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev \ + libgif-dev librsvg2-dev libfontconfig-dev +npm install -g vega-cli vega-lite +``` + +CML and Vega-Lite package installation require `npm` command from Node package. +Below you can find how to install Node. + +### Install Node in GitHub + +In GitHub there is a special action for NPM installation: + +```bash +uses: actions/setup-node@v1 + with: + node-version: '12' +``` + +### Install Node in GitLab + +GitLab requires direct installation of the NMP package: + +```bash +curl -sL https://deb.nodesource.com/setup_12.x | bash +apt-get update +apt-get install -y nodejs +``` diff --git a/content/docs/index.md b/content/docs/index.md new file mode 100644 index 00000000..19e7f837 --- /dev/null +++ b/content/docs/index.md @@ -0,0 +1,36 @@ +# CML Documentation + +[Continuous Machine Learning (CML)](https://cml.dev) is an open-source library +for implementing continuous integration & delivery (CI/CD) in machine learning +projects. Use it to automate parts of your development workflow, including model +training and evaluation, comparing ML experiments across your project history, +and monitoring changing datasets. + + + + + A step-by-step introduction into basic CML features + + + + Study the detailed inner-workings of CML in its user guide. + + + + Bring data to your CML runner with DVC + + + + Use your own runners with CML + + + + +✅ Please join our [community](https://dvc.org/community) or use the +[support](https://dvc.org/support) channels if you have any questions or need +specific help. We are very responsive ⚡. + +✅ Check out our [GitHub repository](https://github.com/iterative/cml) and give +us a ⭐ if you like the project! + +✅ Contribute to DVC [on GitHub](https://github.com/iterative/cml) 🙏. diff --git a/content/docs/self-hosted-runners.md b/content/docs/self-hosted-runners.md new file mode 100644 index 00000000..ba61554a --- /dev/null +++ b/content/docs/self-hosted-runners.md @@ -0,0 +1,159 @@ +# Self-hosted Runners + +GitHub Actions and GitLab CI are run on GitHub- and GitLab- hosted runners by +default. However, there are many great reasons to use your own runners: to take +advantage of GPUs; to orchestrate your team's shared computing resources, or to +train in the cloud. + +☝️ **Tip!** Check out the official documentation from +[GitHub](https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) +and [GitLab](https://docs.gitlab.com/runner/) to get started setting up your +self-hosted runner. + +## Allocating cloud resources with CML + +When a workflow requires computational resources (such as GPUs) CML can +automatically allocate cloud instances using `cml-runner`. You can spin up +instances on your AWS or Azure account (GCP support is forthcoming!). + +For example, the following workflow deploys a `t2.micro` instance on AWS EC2 and +trains a model on the instance. After the job runs, the instance automatically +shuts down. You might notice that this workflow is quite similar to the +[basic use case](#usage) highlighted in the beginning of the docs- that's +because it is! What's new is that we've added `cml-runner`, plus a few +environmental variables for passing your cloud service credentials to the +workflow. + +```yaml +name: "Train-in-the-cloud" +on: [push] + +jobs: + deploy-runner: + runs-on: [ubuntu-latest] + steps: + - uses: iterative/setup-cml@v1 + - uses: actions/checkout@v2 + - name: "Deploy runner on EC2" + shell: bash + env: + repo_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + cml-runner \ + --cloud aws \ + --cloud-region us-west \ + --cloud-type=t2.micro \ + --labels=cml-runner + name: model-training + needs: deploy-runner + runs-on: [self-hosted,cml-runner] + container: docker://dvcorg/cml-py3:latest + steps: + - uses: actions/checkout@v2 + - name: "Train my model" + env: + repo_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: | + pip install -r requirements.txt + python train.py + + # Publish report with CML + cat metrics.txt > report.md + cml-send-comment report.md +``` + +In the above workflow, the step `deploy-runner` launches an EC2 `t2-micro` +instance in the `us-west` region. The next step, `model-training`, runs on the +newly launched instance. + +**Note that you can use any container with this workflow!** While you must have +CML and its dependencies setup to use CML functions like `cml-send-comment` from +your instance, you can create your favorite training environment in the cloud by +pulling the Docker container of your choice. + +We like the +[CML container](https://github.com/iterative/cml/blob/master/Dockerfile) +(`docker://dvcorg/cml-py3`) because it comes loaded with Python, CUDA, `git`, +`node` and other essentials for full-stack data science. But we don't mind if +you do it your way :) + +## Options + +The function `cml-runner` accepts the following arguments: + +| Name | Default | Description | +| --------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--version` | N/A | Show version number and exit (ignoring all other options) | +| `--labels ` | `cml` | One or more user-defined labels for this runner (delimited with commas) | +| `--idle-timeout ` | `300` | Time in seconds for the runner to be waiting for jobs before shutting down. Setting it to `0` disables automatic shutdown | +| `--name ` | `cml-{identifier}` where `{identifier}` is a random string | Name displayed in the repository once registered | +| `--single` | N/A | Exit after running a single job | +| `--reuse` | N/A | Don't launch a new runner if an existing one has the same name or overlapping labels | +| `--driver ` | Inferred from environment variables | Platform where the repository is hosted. Accepts `github` or `gitlab` | +| `--repo ` | Inferred from environment variables | Git repository URL e.g. https://github.com/iterative/cml | +| `--token ` | Inferred from environment variables | Personal access token with enough permissions to register a self-hosted runner on the repository | +| `--cloud ` | N/A | Cloud provider to deploy the runner. Accepts `aws` or `azure`. If not set, the runner will be deployed locally and `--cloud-` options will be ignored | +| `--cloud-region ` | `us-west` | Region where the instance is deployed. Accepts `us-east`, `us-west`, `eu-west`, `eu-north` or native regions | +| `--cloud-type ` | N/A | Instance type. Accepts `m`, `l`, `xl` or native types like `t2.micro` | +| `--cloud-gpu ` | `nogpu` | GPU type. Accepts `nogpu`, `k80` or `tesla`. | +| `--cloud-hdd-size ` | N/A | Storage size in GB | +| `--cloud-ssh-private ` | Automatically generated throwaway key | Custom private RSA SSH key | +| `--cloud-spot` | N/A | Request a spot instance. If not set, `--cloud-spot-price` won't have any effect | +| `--cloud-spot-price ` | Current spot bidding price | Maximum spot instance bidding price in USD | +| `--cloud-startup-script ` | N/A | Run the provided Base64-encoded Linux shell script during the instance initialization | +| `-h` | N/A | Show this help menu and exit | + +## Environmental variables + +You will need to +[create a personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) +with repository read/write access and workflow privileges. In the example +workflow, this token is stored as `PERSONAL_ACCESS_TOKEN`. + +Note that you will also need to provide access credentials for your cloud +compute resources as secrets. In the above example, `AWS_ACCESS_KEY_ID` and +`AWS_SECRET_ACCESS_KEY` are required to deploy EC2 instances. + +Click below to see credentials needed for supported cloud service providers. + +
+ +### AWS + +```yaml +env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }} +``` + +Note that `AWS_SESSION_TOKEN` is optional. + +
+ +
+ +### Azure + +```yaml +env: + AZURE_STORAGE_CONNECTION_STRING: + ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }} +``` + +
+ +### Using on-premise machines as self-hosted runners + +You can also use the new `cml-runner` function to set up a local self-hosted +runner. On your local machine or on-premise GPU cluster, you'll install CML as a +package and then run: + +```yaml +cml-runner \ --repo $your_project_repository_url \ +--token=$personal_access_token \ --labels tf \ --idle-timeout 180 +``` + +Now your machine will be listening for workflows from your project repository. diff --git a/content/docs/sidebar.json b/content/docs/sidebar.json new file mode 100644 index 00000000..88a0cc2c --- /dev/null +++ b/content/docs/sidebar.json @@ -0,0 +1,36 @@ +[ + { + "slug": "", + "label": "Home", + "source": "index.md", + "icon": "house" + }, + { + "label": "Get Started", + "slug": "start", + "source": "start/index.md", + "children": [ + { + "label": "GitHub", + "slug": "start-github" + }, + { + "label": "GitLab", + "slug": "start-gitlab" + } + ] + }, + "usage", + { + "label": "CML with DVC", + "slug": "cml-with-dvc" + }, + { + "label": "Self-hosted Runners", + "slug": "self-hosted-runners" + }, + { + "label": "Install as a Package", + "slug": "cml-with-npm" + } +] diff --git a/content/docs/start/index.md b/content/docs/start/index.md new file mode 100644 index 00000000..086a873d --- /dev/null +++ b/content/docs/start/index.md @@ -0,0 +1,45 @@ +# CML is Continuous Machine Learning + +[Continuous Machine Learning (CML)](https://cml.dev) is an open-source library +for implementing continuous integration & delivery (CI/CD) in machine learning +projects. Use it to automate parts of your development workflow, including model +training and evaluation, comparing ML experiments across your project history, +and monitoring changing datasets. + +Project website: https://cml.dev + +![](/img/cml_neural_transfer.png) _On every pull request, CML helps you +automatically train and evaluate models, then generates a visual report with +results and metrics. Above, an example report for a +[neural style transfer model](https://rb.gy/ub5idx)._ + +We built CML with these principles in mind: + +- **[GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) for data + science.** Use GitLab or GitHub to manage ML experiments, track who trained ML + models or modified data and when. Codify data and models with + [DVC](/doc/cml/cml-with-dvc) instead of pushing to a Git repo. +- **Auto reports for ML experiments.** Auto-generate reports with metrics and + plots in each Git Pull Request. Rigorous engineering practices help your team + make informed, data-driven decisions. +- **No additional services.** Build your own ML platform using just GitHub or + GitLab and your favorite cloud services: AWS, Azure, GCP. No databases, + services or complex setup needed. + +_Need help? Just want to chat about continuous integration for ML? +[Visit our Discord channel!](https://discord.gg/bzA6uY7)_ + +🌟 Check out our +[YouTube video series](https://www.youtube.com/playlist?list=PL7WG7YrwYcnDBDuCkFbcyjnZQrdskFsBz) +for hands-on MLOps tutorials using CML! 🌟 + +https://youtu.be/9BgIDqAzfuA + +## Case studies + +Here are some example projects using CML. + +- [Basic CML project](https://github.com/iterative/cml_base_case) +- [CML with DVC to pull data](https://github.com/iterative/cml_dvc_case) +- [CML with Tensorboard](https://github.com/iterative/cml_tensorboard_case) +- [CML with EC2 GPU](https://github.com/iterative/cml_cloud_case) diff --git a/content/docs/start/start-github.md b/content/docs/start/start-github.md new file mode 100644 index 00000000..53db50d7 --- /dev/null +++ b/content/docs/start/start-github.md @@ -0,0 +1,155 @@ +# Get Started with CML on GitHub + +Here, we'll walk through a tutorial to start using CML. For simplicity, we'll +show the demo in GitHub Actions, but these instructions are valid for all +supported CI systems (with exceptions as noted!). + +1. Fork our + [example project repository](https://github.com/iterative/example_cml). + + ⚠️ If you are using GitLab, + [you'll need to create a Personal Access Token](https://github.com/iterative/cml/wiki/CML-with-GitLab#variables) + for this example to work. + + ![](/img/fork_cml_project.png) + + The following steps can all be done in the GitHub browser interface. However, + to follow along the commands, we recommend cloning your fork to your local + workstation: + + ```bash + git clone https://github.com//example_cml + ``` + +2. To create a CML workflow, copy the following into a new file, + `.github/workflows/cml.yaml`: + + ```yaml + name: train-my-model + on: [push] + jobs: + run: + runs-on: [ubuntu-latest] + container: docker://dvcorg/cml-py3:latest + steps: + - uses: actions/checkout@v2 + - name: cml_run + env: + repo_token: ${{ secrets.GITHUB_TOKEN }} + run: | + pip install -r requirements.txt + python train.py + + cat metrics.txt >> report.md + cml-publish confusion_matrix.png --md >> report.md + cml-send-comment report.md + ``` + +3. In your text editor of choice, edit line 16 of `train.py` to `depth = 5`. + +4. Commit and push the changes: + + ```bash + git checkout -b experiment + git add . && git commit -m "modify forest depth" + git push origin experiment + ``` + +5. In GitHub, open up a Pull Request to compare the `experiment` branch to + `master`. + + ![](/img/make_pr.png) + + Shortly, you should see a comment from `github-actions` appear in the Pull + Request with your CML report. This is a result of the function + `cml-send-comment` in your workflow. + + ![](/img/cml_first_report.png) + +This is the gist of the CML workflow: when you push changes to your GitHub +repository, the workflow in your `.github/workflows/cml.yaml` file gets run and +a report generated. + +CML functions let you display relevant results from the workflow, like model +performance metrics and vizualizations, in GitHub checks and comments. What kind +of workflow you want to run, and want to put in your CML report, is up to you. + +## The CML GitHub Action + +In the above example, we got the CML functions thanks to our Docker container. +But there's another way for GitHub Actions users to get CML: the `setup-cml` +Action! + +The [iterative/setup-cml](https://github.com/iterative/setup-cml) action is a +JavaScript workflow that provides [CML](https://cml.dev/) functions in your +GitHub Actions workflow. The action allows users to install CML without using +the CML Docker container. + +This action gives you: + +- Functions like `cml-publish` and `cml-send-comment` for publishing data + visualization and metrics from your CI workflow as comments in a pull request. +- `cml-runner`, a function that enables workflows to provision cloud and + on-premise computing resources for training models +- The freedom 🦅 to mix and match CML with your favorite data science tools and + environments + +Note that CML does not include DVC and its dependencies- for that, you want the +[Setup DVC Action](https://github.com/iterative/setup-dvc). + +### Usage + +This action has been tested on `ubuntu-latest` and `macos-latest`. + +Basic usage: + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: iterative/cml-action@v1 +``` + +A specific version can be pinned to your workflow. + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: iterative/setup-cml@v1 + with: + version: '1.0.1' +``` + +### Inputs + +The following inputs are supported. + +- `version` - (optional) The version of CML to install. A value of `latest` will + install the latest version of CML functions. Defaults to `latest`. + +## Outputs + +Setup CML has no outputs. + +### A complete workflow + +Assume that we have a machine learning script, `train.py`, that outputs an image +`plot.png`. A potential workflow will look like this: + +```yaml +steps: + - uses: actions/checkout@v2 + + - uses: iterative/setup-cml@v1 + with: + version: latest + + - run: | + # train will generate plot.png + python train.py + + echo 'My first CML report' > report.md + cml-publish plot.png --md > report.md + cml-send-comment report.md +``` diff --git a/content/docs/start/start-gitlab.md b/content/docs/start/start-gitlab.md new file mode 100644 index 00000000..9385a75b --- /dev/null +++ b/content/docs/start/start-gitlab.md @@ -0,0 +1,108 @@ +# Using CML on GitLab + +Here, we'll walk through a tutorial to start using CML on GitLab. + +1. Fork our + [example project repository](https://gitlab.com/iterative.ai/example_cml). + Click on Fork and select the namespace where you would like to keep the + project. + + ![](/img/gitlab_fork_cml_project.png) + +2. ⚠️ In GitLab, to use CML, you must create a variable called a `repo_token` + whose value is a Personal Access Token. To do this: + + a. Click on your Avatar in the upper right side and click on "Edit Profile." + + b. Along the left side of the screen go to Access Tokens. + + c. In the "Name" field, type `repo_token` and check boxes to select `api`, + `read_repository` and `write_repository`. + + d. Click on the "Create personal access token" button and copy the generated + access token. + + ![](/img/personal_access_token.png) + + e. Head back to your fork by clicking the Projects tab next to the GitLab + logo and select it. + + f. On the left hand side Navigate to **Settings** ➡ **CI/CD** ➡ **Varibles**. + + ![](/img/ci_cd_navigation.png) + + f. Scroll to Variables and expand the field. Click "Add Variable". In the Key + field, type `repo_token`. In the Value field, paste your Personal Access + Token. Check the "Mask variable" box, uncheck "Protect variable", and then + save the variable by clicking "Add variable" at the bottom of the dialog box. + +> 💡 The following steps can all be done in the GitLab website. However, to +> follow along the steps, we recommend cloning your fork to your local +> workstation. + +3. Go back to your forked `example_cml` project. Copy the Clone with HTTPS as + shown in the image below, and then in your terminal, type the following + command, replacing `` with your own from GitLab. + + ![](/img/gitlab_cml_clone.png) + + ```bash + git clone https://gitlab.com//example_cml.git + ``` + +4. Change directory to `example_cml`. + + ```bash + cd example_cml + ``` + +5. To create a CML workflow, use your editor of choice to copy the following + into a new file `.gitlab-ci.yml` and save. + + ```yaml + stages: + - cml_run + + cml: + stage: cml_run + image: dvcorg/cml-py3:latest + script: + - pip3 install -r requirements.txt + - python train.py + + - cat metrics.txt >> report.md + - cml-publish confusion_matrix.png --md >> report.md + - cml-send-comment report.md + ``` + +6. In your text editor, open `train.py` and edit line 16 to `depth = 5`. + +7. Commit and push the changes using: + + ```bash + git checkout -b experiment + git add . && git commit -m "modify forest depth" + git push origin experiment + ``` + +8. Go back to GitLab in a Browser window and create a merge request. + + ![](/img/create_merge_request.png) + +9. If you arrive at a New Merge Request screen that says it's merging into + anything _other_ than your local repository, click on `Change branches` seen + here. + + ![](/img/new_merge_request.png) + +10. ⚠️ Change target branch to your local branch with your username. + + ![](/img/change_user_name.png) + +11. Click on the "Compare branches and continue" button. Enter any additional + comments you would like to put in the description and click the "Submit + merge request" button. Shortly, you should see a comment from GitLab CI + appear in the Pull Request with your CML report. This is a result of the + function cml-send-comment in your workflow. + + ![](/img/cml_start_gitlab_end.png) diff --git a/content/docs/usage.md b/content/docs/usage.md new file mode 100644 index 00000000..8795b39c --- /dev/null +++ b/content/docs/usage.md @@ -0,0 +1,81 @@ +# Using CML + +You'll need a GitHub or GitLab account to begin. Users may wish to familiarize +themselves with [Github Actions](https://help.github.com/en/actions) or +[GitLab CI/CD](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/). +Here, will discuss the GitHub use case. + +⚠️ **GitLab users:** Please see our +[docs about configuring CML with GitLab](https://github.com/iterative/cml/wiki/CML-with-GitLab). + +🪣 **Bitbucket Cloud users** We support you, too- +[see our docs here](https://github.com/iterative/cml/wiki/CML-with-Bitbucket-Cloud).🪣 +_Bitbucket Server support is in the works._ + +The key file in any CML project is `.github/workflows/cml.yaml`. + +```yaml +name: your-workflow-name +on: [push] +jobs: + run: + runs-on: [ubuntu-latest] + container: docker://dvcorg/cml-py3:latest + steps: + - uses: actions/checkout@v2 + - name: cml_run + env: + repo_token: ${{ secrets.GITHUB_TOKEN }} + run: | + + # Your ML workflow goes here + pip install -r requirements.txt + python train.py + + # Write your CML report + cat results.txt >> report.md + cml-send-comment report.md +``` + +### CML Functions + +CML provides a number of helper functions to help package outputs from ML +workflows, such as numeric data and data vizualizations about model performance, +into a CML report. The library comes pre-installed on our +[custom Docker images](https://github.com/iterative/cml/blob/master/Dockerfile). +In the above example, note the field `container: docker://dvcorg/cml-py3:latest` +specifies the CML Docker image with Python 3 will be pulled by the GitHub +Actions runner. + +Below is a list of CML functions for writing markdown reports and delivering +those reports to your CI system (GitHub Actions or GitLab CI). + +| Function | Description | Inputs | +| ----------------------- | -------------------------------------------------------------- | --------------------------------------------------------- | +| `cml-send-comment` | Return CML report as a comment in your GitHub/GitLab workflow. | ` --head-sha ` | +| `cml-send-github-check` | Return CML report as a check in GitHub | ` --head-sha ` | +| `cml-publish` | Publish an image for writing to CML report. | ` --title --md` | +| `cml-tensorboard-dev` | Return a link to a Tensorboard.dev page | `--logdir --title --md` | + +### Customizing your CML report + +CML reports are written in +[GitHub Flavored Markdown](https://github.github.com/gfm/). That means they can +contain images, tables, formatted text, HTML blocks, code snippets and more - +really, what you put in a CML report is up to you. Some examples: + +📝 **Text**. Write to your report using whatever method you prefer. For example, +copy the contents of a text file containing the results of ML model training: + +```bash +cat results.txt >> report.md +``` + +🖼️ **Images** Display images using the markdown or HTML. Note that if an image +is an output of your ML workflow (i.e., it is produced by your workflow), you +will need to use the `cml-publish` function to include it a CML report. For +example, if `graph.png` is the output of my workflow `python train.py`, run: + +```bash +cml-publish graph.png --md >> report.md +``` diff --git a/gatsby-browser.js b/gatsby-browser.js index b1e5c316..16fbf506 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,7 +1,5 @@ -/** - * Implement Gatsby's Browser APIs in this file. - * - * See: https://www.gatsbyjs.org/docs/browser-apis/ - */ +/* eslint-env node */ -// You can delete this file if you're not using it +const PageWrapper = require('./src/components/organisms/PageWrapper').default + +exports.wrapPageElement = PageWrapper diff --git a/gatsby-config.js b/gatsby-config.js index ccf03743..3133db08 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,94 +1,194 @@ -const path = require(`path`) -require(`dotenv`).config() +/* eslint-env node */ + +require('dotenv').config() +const path = require('path') + +require('./config/prismjs/usage') + +const redirectsMiddleware = require('./src/server/middleware/redirects') + +const title = 'CML - Continuous Machine Learning: Bring DevOps to Data Science' +const description = + 'CML is continuous integration for machine learning. Bring DevOps practices to your projects for automatic, reproducible, and fast machine learning.' + +const plugins = [ + { + resolve: `gatsby-plugin-typescript`, + options: { + isTSX: true, + allExtensions: true + } + }, + { + resolve: `gatsby-plugin-alias-imports`, + options: { + alias: { + '@media': 'src/media' + } + } + }, + 'gatsby-plugin-postcss', + 'gatsby-plugin-react-helmet', + 'gatsby-plugin-sitemap', + `gatsby-plugin-theme-ui`, + { + resolve: 'gatsby-source-filesystem', + options: { + name: 'content', + path: path.join(__dirname, 'content') + } + }, + { + resolve: 'gatsby-transformer-remark', + options: { + plugins: [ + 'gatsby-remark-embedder', + { + resolve: 'gatsby-remark-prismjs', + options: { + noInlineHighlight: true, + languageExtensions: [ + { + language: 'text', + definition: {} + } + ] + } + }, + { + resolve: 'gatsby-remark-smartypants', + options: { + quotes: false + } + }, + `gatsby-plugin-robots-txt`, + { + resolve: 'gatsby-remark-embed-gist', + options: { + includeDefaultCss: true + } + }, + 'gatsby-remark-relative-images', + 'gatsby-remark-copy-linked-files', + 'gatsby-remark-external-links', + { + resolve: 'gatsby-remark-autolink-headers', + options: { + enableCustomId: true, + isIconAfterHeader: true + } + }, + { + resolve: 'gatsby-remark-images', + options: { + withWebp: true + } + }, + 'gatsby-remark-responsive-iframe' + ] + } + }, + { + resolve: 'gatsby-plugin-svgr', + options: { + ref: true, + svgoConfig: { + plugins: [{ removeViewBox: false }] + } + } + }, + 'gatsby-plugin-sharp', + 'gatsby-plugin-catch-links', + { + resolve: 'gatsby-plugin-manifest', + options: { + /* eslint-disable @typescript-eslint/camelcase */ + background_color: '#663399', + display: 'minimal-ui', + icon: 'static/favicon-512x512.png', + name: 'CML', + short_name: 'CML', + start_url: '/', + theme_color: '#663399' + /* eslint-enable @typescript-eslint/camelcase */ + } + }, + { + resolve: 'gatsby-plugin-sentry', + options: { + dsn: process.env.SENTRY_DSN, + environment: process.env.NODE_ENV, + release: process.env.SOURCE_VERSION, + enabled: process.env.NODE_ENV === 'production', + ignoreErrors: [ + /* When we deploy new version we delete assets which were generated for + the previous deployed version, but users can have opened old version in + their browsers. If they hover some link on the page Gatsby.js will try + fetch old chunks and will get ChunkLoadError, but then will load static + page from the new deployed version and all will be ok. So we can just + ignore these type of errors */ + 'ChunkLoadError' + ], + /* There are some common urls which recomment to ignore. It's even + mentioned in the official documentation: https://docs.sentry.io/platforms/javascript/#decluttering-sentry + In our case we just ignore all errors from the browser's extensions, + because we can't influence on then somehow. */ + blacklistUrls: [/extensions\//i, /^chrome:\/\//i] + } + } +] + +if (process.env.GITHUB_TOKEN) { + plugins.push({ + resolve: `gatsby-source-github-api`, + options: { + // token: required by the GitHub API + token: process.env.GITHUB_TOKEN, + + // GraphQLquery: defaults to a search query + graphQLQuery: ` + { + repository(owner: "iterative", name: "cml") { + stargazers { + totalCount + } + } + } + `, + variables: {} + } + }) +} + +if (process.env.CONTEXT === 'production') { + plugins.push({ + resolve: 'gatsby-plugin-google-analytics', + options: { + respectDNT: true, + trackingId: process.env.GA_ID + } + }) +} + +if (process.env.ANALYZE) { + plugins.push({ + resolve: 'gatsby-plugin-webpack-bundle-analyzer', + options: { + analyzerPort: 4000, + production: process.env.NODE_ENV === 'production' + } + }) +} module.exports = { + plugins, siteMetadata: { - title: `CML - Continuous Machine Learning: Bring DevOps to Data Science`, - description: `CML is continuous integration for machine learning. Bring DevOps practices to your projects for automatic, reproducible, and fast machine learning.`, + description, author: `Iterative`, - siteUrl: process.env.URL || "https://cml.dev", + siteUrl: process.env.URL || 'https://cml.dev', + title }, - plugins: [ - `gatsby-plugin-preact`, - `gatsby-plugin-eslint`, - `gatsby-plugin-react-helmet`, - `gatsby-transformer-sharp`, - `gatsby-plugin-sharp`, - { - resolve: `gatsby-plugin-google-analytics`, - options: { - trackingId: `UA-120072346-5`, - }, - }, - { - resolve: `gatsby-source-filesystem`, - options: { - path: path.resolve(`./content`), - name: `content`, - }, - }, - { - resolve: `gatsby-source-filesystem`, - options: { - path: path.resolve(`./src/media`), - name: `images`, - }, - }, - { - resolve: `gatsby-plugin-react-svg`, - }, - `gatsby-remark-images`, - { - resolve: `gatsby-plugin-mdx`, - options: { - plugins: ["gatsby-remark-images"], - gatsbyRemarkPlugins: [ - require.resolve(`./remarkPlugin.js`), - { - resolve: `gatsby-remark-images`, - options: { - maxWidth: 590, - withWebp: true, - loading: "lazy", - }, - }, - ], - }, - }, - { - resolve: `gatsby-plugin-manifest`, - options: { - name: `CML`, - short_name: `CML`, - start_url: `/`, - background_color: `#663399`, - theme_color: `#663399`, - display: `minimal-ui`, - icon: `src/media/site-icon.png`, - }, - }, - `gatsby-plugin-sass`, - `gatsby-plugin-theme-ui`, - `gatsby-plugin-robots-txt`, - { - resolve: `gatsby-plugin-purge-cloudflare-cache`, - options: { - condition: - process.env.CONTEXT === "production" && - process.env.CLOUDFLARE_TOKEN && - process.env.CLOUDFLARE_ZONE, - token: process.env.CLOUDFLARE_TOKEN, - zoneId: process.env.CLOUDFLARE_ZONE, - }, - }, - `gatsby-plugin-sitemap`, - { - resolve: "@sentry/gatsby", - options: { - dsn: process.env.SENTRY_DSN, - denyUrls: [/extensions\//i, /^chrome:\/\//i], - release: process.env.SOURCE_VERSION, - }, - }, - ], + developMiddleware: app => { + app.use(redirectsMiddleware) + } } diff --git a/gatsby-node.js b/gatsby-node.js index e6d790aa..a0b456f5 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,117 +1,41 @@ -const path = require("path") -const fs = require("fs") +require('dotenv').config() -exports.createSchemaCustomization = async api => { - const { - schema: { buildObjectType }, - actions: { createTypes }, - } = api +const { setPageContext } = require('./src/gatsby/common') - createTypes([ - buildObjectType({ - name: "Page", - interfaces: ["Node"], - fields: { - slug: "String!", - pagePath: "String!", - template: "String", - file: { - type: "File!", - extensions: { - link: { by: "id" }, - }, - }, - }, - }), - ]) -} - -exports.onCreateNode = async api => { - const { - node, - getNode, - createNodeId, - createContentDigest, - actions: { createNode, createParentChildLink }, - } = api - - const indexName = "index" - - if (node.internal.type === "Mdx") { - const fileNode = getNode(node.parent) - const { relativeDirectory, name: filename } = fileNode - switch (fileNode.relativeDirectory) { - default: { - const { - frontmatter: { template }, - } = node - const slug = filename === indexName ? "" : filename - const fields = { - slug, - template, - pagePath: path.posix.join("/", relativeDirectory, slug), - } +const models = require('./src/gatsby/models.js') +const callOnModels = require('./src/gatsby/utils/models') - const pageNode = { - ...fields, - id: createNodeId(`${node.id} >>> Page`), - parent: node.id, - file: fileNode.id, - children: [], - internal: { - type: "Page", - contentDigest: createContentDigest(fields), - }, - } +exports.createSchemaCustomization = api => + callOnModels(models, 'createSchemaCustomization', api) +exports.sourceNodes = api => callOnModels(models, 'sourceNodes', api) +exports.onCreateNode = api => callOnModels(models, 'onCreateNode', api) +exports.createPages = api => callOnModels(models, 'createPages', api) +exports.createResolvers = api => callOnModels(models, 'createResolvers', api) - await createNode(pageNode) - await createParentChildLink({ parent: node, child: pageNode }) - return - } - } - } +exports.onCreatePage = ({ page, actions }) => { + setPageContext(page, actions) } -exports.createPages = async ({ graphql, actions: { createPage } }) => { - const { data, errors } = await graphql(` - query TemplatedPageQuery { - allPage { - nodes { - pagePath - template - parent { - id - } - } - } - } - `) - - if (errors) throw new Error(errors) - - const { - allPage: { nodes }, - } = data - - return Promise.all( - nodes.map(({ pagePath, template = "default", parent: { id } }) => - createPage({ - path: pagePath, - component: require.resolve( - path.resolve("src/templates", template || "default") - ), - context: { - id, - }, - }) +// Ignore warnings about CSS inclusion order, because we use CSS modules. +// https://spectrum.chat/gatsby-js/general/having-issue-related-to-chunk-commons-mini-css-extract-plugin~0ee9c456-a37e-472a-a1a0-cc36f8ae6033?m=MTU3MjYyNDQ5OTAyNQ== +exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => { + if (stage === 'build-javascript') { + const config = getConfig() + + // Add polyfills + config.entry.app = [ + 'promise-polyfill/src/polyfill', + 'isomorphic-fetch', + 'raf-polyfill', + config.entry.app + ] + + const miniCssExtractPlugin = config.plugins.find( + plugin => plugin.constructor.name === 'MiniCssExtractPlugin' ) - ) -} - -exports.onCreateWebpackConfig = ({ stage, actions }) => { - actions.setWebpackConfig({ - resolve: { - modules: [path.resolve(__dirname, "src"), "node_modules"], - }, - }) + if (miniCssExtractPlugin) { + miniCssExtractPlugin.options.ignoreOrder = true + } + actions.replaceWebpackConfig(config) + } } diff --git a/gatsby-ssr.js b/gatsby-ssr.js index b17b8fc1..16fbf506 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -1,7 +1,5 @@ -/** - * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. - * - * See: https://www.gatsbyjs.org/docs/ssr-apis/ - */ +/* eslint-env node */ -// You can delete this file if you're not using it +const PageWrapper = require('./src/components/organisms/PageWrapper').default + +exports.wrapPageElement = PageWrapper diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..d344eca3 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,12 @@ +/* eslint-env node */ + +// For a detailed explanation regarding each configuration property, visit: +// https://jestjs.io/docs/en/configuration.html + +module.exports = { + testEnvironment: 'node', + transform: { + '^.+\\.js?$': 'babel-jest' + }, + testPathIgnorePatterns: ['/node_modules/', '/.cache', '/public/'] +} diff --git a/package.json b/package.json index 49b763af..7f4ac0d8 100644 --- a/package.json +++ b/package.json @@ -1,95 +1,180 @@ { "name": "cml-website", - "private": true, - "description": "A simple starter to get up and developing quickly with Gatsby", - "version": "0.1.0", - "author": "Kyle Mathews ", - "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.10.1", - "@babel/preset-env": "^7.10.2", - "@babel/preset-react": "^7.10.1", - "@mdx-js/mdx": "^1.6.5", - "@mdx-js/react": "^1.6.5", - "@sentry/gatsby": "^6.3.5", - "@storybook/addon-actions": "^5.3.19", - "@storybook/addon-docs": "^5.3.19", - "@storybook/addon-links": "^5.3.19", - "@storybook/react": "^5.3.19", - "@theme-ui/color": "^0.3.1", - "@theme-ui/presets": "^0.3.0", - "babel-loader": "^8.1.0", - "babel-plugin-react-docgen": "^4.1.0", - "babel-plugin-remove-graphql-queries": "^2.9.11", - "gatsby": "^2.23.17", - "gatsby-cli": "2.12.54", - "gatsby-image": "^2.4.12", - "gatsby-plugin-eslint": "^2.0.8", - "gatsby-plugin-google-analytics": "^2.3.10", - "gatsby-plugin-manifest": "^2.4.17", - "gatsby-plugin-mdx": "^1.2.22", - "gatsby-plugin-offline": "^3.2.16", - "gatsby-plugin-preact": "^4.0.8", - "gatsby-plugin-purge-cloudflare-cache": "^0.0.3", - "gatsby-plugin-react-helmet": "^3.3.9", - "gatsby-plugin-react-svg": "^3.0.0", - "gatsby-plugin-robots-txt": "^1.5.1", - "gatsby-plugin-sass": "^2.3.10", - "gatsby-plugin-sharp": "^2.6.17", - "gatsby-plugin-sitemap": "^2.4.10", - "gatsby-plugin-theme-ui": "^0.3.0", - "gatsby-remark-images": "^3.3.17", - "gatsby-source-filesystem": "^2.3.17", - "gatsby-transformer-sharp": "^2.5.10", - "husky": ">=4", - "node-sass": "^4.14.1", - "preact": "^10.4.5", - "preact-render-to-string": "^5.1.9", - "prop-types": "^15.7.2", - "react": "^16.12.0", - "react-dom": "^16.12.0", - "react-helmet": "^6.1.0", - "theme-ui": "^0.3.1", - "unist-util-visit": "^2.0.2" - }, - "devDependencies": { - "babel-eslint": "^10.1.0", - "eslint": "^7.3.1", - "eslint-config-airbnb": "^18.2.0", - "eslint-loader": "^4.0.2", - "eslint-plugin-import": "^2.22.0", - "eslint-plugin-jsx-a11y": "^6.3.1", - "eslint-plugin-react": "^7.20.3", - "lint-staged": ">=10", - "prettier": "^2.0.5" - }, - "keywords": [ - "gatsby" - ], - "license": "MIT", + "version": "1.0.0", + "description": "cml.dev – website source code", + "main": "index.js", "scripts": { - "build": "gatsby build", "develop": "gatsby develop", - "format": "prettier --write \"**/*.{js,jsx,json}\"", - "start": "npm run develop", - "serve": "gatsby serve", - "clean": "gatsby clean", - "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1", - "storybook": "NODE_ENV=production start-storybook -s ./public -p 6006 --ci", - "build-storybook": "NODE_ENV=production build-storybook" + "dev": "gatsby develop", + "author": "LIMIT_BLOG_PAGES=1 SKIP_DOCS=true gatsby develop", + "build": "gatsby build", + "start": "node ./src/server/index.js", + "test": "jest", + "format-staged": "pretty-quick --staged --no-restage --bail", + "format-check": "prettier --check '**/*.{js,jsx,md,tsx,ts,json}'", + "format-all": "prettier --write '**/*.{js,jsx,md,tsx,ts,json}'", + "format": "prettier --write", + "lint-ts": "tsc --noEmit --skipLibCheck && eslint --ext .json,.js,.ts,.tsx .", + "lint-css": "stylelint \"src/**/*.css\"", + "link-check": "repo-link-check -c config/link-check/config.yml", + "link-check-diff": "repo-link-check -c config/link-check/config.yml -d", + "link-check-dev-server": "repo-link-check -c config/link-check/config.yml -r http://localhost:3000", + "link-check-exclude": "repo-link-check -c config/link-check/config.yml --unused-patterns-only" }, "repository": { "type": "git", "url": "https://github.com/gatsbyjs/cml-website" }, + "author": "", + "license": "Apache-2.0", "bugs": { "url": "https://github.com/gatsbyjs/gatsby/issues" }, + "homepage": "https://github.com/iterative/cml-website#readme", + "engines": { + "node": "<=15.x" + }, + "dependencies": { + "@hapi/wreck": "^17.0.0", + "@octokit/graphql": "^4.3.1", + "@reach/portal": "^0.10.0", + "@reach/router": "^1.3.3", + "@reach/tooltip": "^0.10.0", + "@theme-ui/color": "^0.9.1", + "@theme-ui/components": "^0.9.1", + "@theme-ui/presets": "^0.9.1", + "classnames": "^2.2.6", + "color": "^3.1.2", + "compression": "^1.7.4", + "date-fns": "^2.11.1", + "docsearch.js": "^2.6.3", + "ease-component": "^1.0.0", + "express": "^4.17.1", + "fs-extra": "^9.0.0", + "gatsby": "^2.20.13", + "gatsby-cli": "2.12.54", + "gatsby-image": "^2.3.1", + "gatsby-link": "^2.3.2", + "gatsby-plugin-alias-imports": "^1.0.5", + "gatsby-plugin-image": "0.7.2", + "gatsby-plugin-parent-resolvers": "^1.0.1", + "gatsby-plugin-robots-txt": "^1.6.2", + "gatsby-plugin-theme-ui": "^0.9.1", + "gatsby-source-github-api": "^0.2.1", + "github-markdown-css": "^4.0.0", + "iso-url": "^0.4.7", + "isomorphic-fetch": "^2.2.1", + "lodash": "^4.17.21", + "moment": "^2.25.3", + "nanoid": "^3.0.2", + "node-cache": "^5.1.0", + "perfect-scrollbar": "^1.5.0", + "pretty-quick": "^2.0.1", + "prismjs": "^1.23.0", + "promise-polyfill": "^8.1.3", + "prop-types": "^15.7.2", + "raf-polyfill": "^1.0.0", + "react": "^16.13.1", + "react-collapse": "^5.0.1", + "react-collapsible": "^2.7.0", + "react-dom": "^16.13.1", + "react-ga": "^2.7.0", + "react-helmet": "^5.2.1", + "react-popover": "^0.5.10", + "react-slick": "^0.25.2", + "react-use": "^14.0.0", + "rehype-react": "^5.0.1", + "remark-preset-lint-recommended": "^5.0.0", + "repo-link-check": "^0.7.1", + "s3-client": "^4.4.2", + "scroll": "^3.0.1", + "serve-handler": "^6.1.2", + "slick-carousel": "^1.8.1", + "theme-ui": "^0.9.1", + "title-case": "^3.0.2", + "upath": "^1.2.0" + }, + "devDependencies": { + "@babel/core": "^7.9.0", + "@svgr/webpack": "^5.3.1", + "@types/classnames": "^2.2.10", + "@types/isomorphic-fetch": "^0.0.35", + "@types/promise-polyfill": "^6.0.3", + "@types/react": "^16.9.32", + "@types/react-collapse": "^5.0.0", + "@types/react-dom": "^16.9.6", + "@types/react-helmet": "^5.0.15", + "@types/react-popover": "^0.5.3", + "@types/react-slick": "^0.23.4", + "@types/rehype-react": "^4.0.0", + "@typescript-eslint/eslint-plugin": "^2.27.0", + "@typescript-eslint/parser": "^2.27.0", + "autoprefixer": "^9.7.6", + "babel-eslint": "^10.1.0", + "babel-jest": "^26.0.1", + "babel-plugin-transform-define": "^2.0.0", + "babel-plugin-transform-object-assign": "^6.22.0", + "eslint": "^6.8.0", + "eslint-config-prettier": "^6.10.1", + "eslint-plugin-json": "^2.1.1", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-prettier": "^3.1.2", + "eslint-plugin-react": "^7.19.0", + "gatsby-plugin-catch-links": "^2.2.1", + "gatsby-plugin-google-analytics": "^2.2.2", + "gatsby-plugin-manifest": "2.2.23", + "gatsby-plugin-postcss": "^2.2.1", + "gatsby-plugin-react-helmet": "^3.2.1", + "gatsby-plugin-sentry": "^1.0.1", + "gatsby-plugin-sharp": "2.2.32", + "gatsby-plugin-sitemap": "^2.3.1", + "gatsby-plugin-svgr": "^2.0.2", + "gatsby-plugin-typescript": "^2.3.1", + "gatsby-plugin-webpack-bundle-analyzer": "^1.0.5", + "gatsby-remark-autolink-headers": "^2.2.1", + "gatsby-remark-copy-linked-files": "^2.2.1", + "gatsby-remark-embed-gist": "^1.1.9", + "gatsby-remark-embedder": "^2.0.0", + "gatsby-remark-external-links": "^0.0.4", + "gatsby-remark-images": "^3.2.2", + "gatsby-remark-prismjs": "^3.4.1", + "gatsby-remark-relative-images": "0.2.3", + "gatsby-remark-responsive-iframe": "^2.3.1", + "gatsby-remark-smartypants": "^2.2.1", + "gatsby-source-filesystem": "^2.2.2", + "gatsby-transformer-remark": "^2.7.1", + "hast-util-select": "^4.0.0", + "husky": "^4.2.3", + "jest": "^26.0.1", + "lint-staged": "^10.1.2", + "postcss-color-mod-function": "^3.0.3", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^9.1.1", + "postcss-mixins": "^6.2.3", + "postcss-nested": "^4.2.1", + "prettier": "^2.2.1", + "remark": "^12.0.0", + "remark-html": "^11.0.1", + "remark-parse": "^8.0.2", + "stylelint": "^13.3.0", + "stylelint-config-standard": "^20.0.0", + "typescript": "^3.8.3", + "unist-util-remove-position": "^2.0.1" + }, "husky": { "hooks": { - "pre-commit": "lint-staged" + "pre-commit": "yarn format-staged && yarn lint-staged" } }, "lint-staged": { - "*.{js,jsx,json}": "prettier --write" - } + "*.{js,ts,tsx,json}": [ + "eslint" + ], + "*.css": [ + "yarn stylelint --fix" + ] + }, + "cacheDirectories": [ + "node_modules" + ] } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..bb6209e2 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,26 @@ +const nested = require('postcss-nested') +const autoprefixer = require('autoprefixer') +const customMedia = require('postcss-custom-media') +const customProperties = require('postcss-custom-properties') +const mixins = require('postcss-mixins') +const colorMod = require('postcss-color-mod-function') + +const mediaConfig = require('./config/postcss/media') +const mixinsConfig = require('./config/postcss/mixins') + +module.exports = function postcssConfig() { + return { + plugins: [ + mixins(mixinsConfig), + customMedia({ importFrom: mediaConfig }), + customProperties({ + importFrom: ['src/components/organisms/Page/base.css'] + }), + nested, + colorMod({ + importFrom: ['src/components/organisms/Page/base.css'] + }), + autoprefixer + ] + } +} diff --git a/redirects-list.json b/redirects-list.json new file mode 100644 index 00000000..b9047eff --- /dev/null +++ b/redirects-list.json @@ -0,0 +1,8 @@ +[ + "^https://(?:www\\.)?cml\\.dev(.*)? https://cml.dev$1", + "^/(?:docs|documentation)(/.*)?$ /doc$1", + "^/doc/start-github(/.*)?$ /doc/start/start-github", + "^/doc/start-gitlab(/.*)?$ /doc/start/start-gitlab", + "^/doc/install(/.*)?$ /doc/install-with-npm", + "^/(.+)/$ /$1" +] diff --git a/remarkPlugin.js b/remarkPlugin.js deleted file mode 100644 index 6d407974..00000000 --- a/remarkPlugin.js +++ /dev/null @@ -1,35 +0,0 @@ -const visit = require("unist-util-visit") - -const escapedReactNewline = "{'\\n'}" - -module.exports = ({ markdownAST, markdownNode, ...rest }, { tag = "Code" }) => { - const newTree = visit(markdownAST, "code", node => { - if (node.type === "code") { - const { lang, meta, value } = node - // Make leading spaces and trailing newlines explicit - // Wrap the rest of the line in a span for better styling targets - const preContent = - value.replace(/(^ *)(.*)$/gm, (whole, whitespace, content) => { - // Skip lines that only contain a tag that isn't self-closing - if (/^<[^<>]*[^\/]>$/.test(content)) return whole - const wrappedWhitespace = whitespace ? `{'${whitespace}'}` : "" - const wrappedContent = content ? `${content}` : "" - return ( - "
" + - wrappedWhitespace + - wrappedContent + - escapedReactNewline + - "
\n" - ) - }) + escapedReactNewline - // Wrap this new content in a component - const transformedValue = `<${tag}${ - meta ? " " + meta : "" - } lang="${lang}">\n${preContent}\n` - Object.assign(node, { - type: "jsx", - value: transformedValue, - }) - } - }) -} diff --git a/src/components/atoms/Collapser/index.js b/src/components/atoms/Collapser/index.js index 010735ce..ab9a65af 100644 --- a/src/components/atoms/Collapser/index.js +++ b/src/components/atoms/Collapser/index.js @@ -1,25 +1,24 @@ -import React from "react" -import { Flex } from "@theme-ui/components" +import React from 'react' +import { Flex } from '@theme-ui/components' -const Collapser = ({ children, sx = {}, className, bp = 2, ...props }) => { - const flexDirection = ["column"] +const Collapser = ({ children, sx = {}, className = '', bp = 2 }) => { + const flexDirection = ['column'] for (let i = 1; i < bp; i++) { - flexDirection.push(null) + flexDirection.push('') } - flexDirection.push("row") + flexDirection.push('row') return ( *": { - flex: "1", + flexWrap: 'nowrap', + '>*': { + flex: '1' }, - ...sx, + ...sx }} - {...props} > {children} diff --git a/src/components/atoms/Headings.stories.js b/src/components/atoms/Headings.stories.js deleted file mode 100644 index fd5e245b..00000000 --- a/src/components/atoms/Headings.stories.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react" -import { Heading, Box } from "@theme-ui/components" - -export default { - title: "Heading", - parameters: { - component: Heading, - componentSubtitle: "The theme-ui component for Headings", - }, -} - -export const usage = () => ( - - Default (h2) - h1 - h2 - h3 - h4 - h5 - h6 - -) diff --git a/src/components/atoms/HiddenRadioControl/index.js b/src/components/atoms/HiddenRadioControl/index.js index 4ad2d4d3..9b6c6b58 100644 --- a/src/components/atoms/HiddenRadioControl/index.js +++ b/src/components/atoms/HiddenRadioControl/index.js @@ -1,27 +1,29 @@ -import React from "react" -import { Box } from "@theme-ui/components" +import React from 'react' +import { Box } from '@theme-ui/components' const HiddenRadioControl = ({ defaultChecked, checked, - inputName = "tab", + inputName = 'tab', id, ...props -}) => ( -