From 709624a2d7a7c8fa7c8e8d7256d4c18696a5c7ab Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Sat, 7 Oct 2023 19:21:08 +0200 Subject: [PATCH] fix: outdated version warning --- .dependency-cruiser.js | 15 +++++ .github/workflows/build-extension.yml | 7 +- package.json | 8 +-- scripts/generate-manifest.js | 11 ++-- src/app/components/app-version.tsx | 65 +++++++++++++++++++ src/app/components/header.tsx | 41 ++---------- .../common/outdated-pr/outdated-pr.query.ts | 32 ++++++--- src/shared/environment.ts | 2 +- webpack/webpack.config.base.js | 8 ++- yarn.lock | 18 ++--- 10 files changed, 140 insertions(+), 67 deletions(-) create mode 100644 src/app/components/app-version.tsx diff --git a/.dependency-cruiser.js b/.dependency-cruiser.js index ed3e2367473..345cfdee961 100644 --- a/.dependency-cruiser.js +++ b/.dependency-cruiser.js @@ -19,6 +19,21 @@ module.exports = { path: '^(domain|constants|sys|_linklist|_stream_wrap)$', }, }, + // Overriding from recommended set + { + name: 'not-to-unresolvable', + comment: + "This module depends on a module that cannot be found ('resolved to disk'). " + + "If it's an npm module: add it to your package.json. In all other cases you " + + 'likely already know what to do.', + severity: 'error', + from: {}, + to: { + // Depcruiser fails on some legitimate type imports, so allowing them there + dependencyTypesNot: ['type-only'], + couldNotResolve: true, + }, + }, { name: 'no-orphans', severity: 'error', diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml index 5772b58e423..70e46b7afc8 100644 --- a/.github/workflows/build-extension.yml +++ b/.github/workflows/build-extension.yml @@ -8,6 +8,7 @@ env: SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY_STAGING }} TRANSAK_API_KEY: ${{ secrets.TRANSAK_API_KEY }} PR_NUMBER: ${{ github.event.number }} + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} WALLET_ENVIRONMENT: feature jobs: @@ -38,6 +39,8 @@ jobs: - pre-run steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - uses: actions/cache@v3 id: cache-node-modules @@ -47,6 +50,8 @@ jobs: - uses: ./.github/actions/provision + - run: echo ${{ github.event.pull_request.head.sha }} + - name: Build project run: yarn build @@ -70,7 +75,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.ref }} + ref: ${{ github.event.pull_request.head.sha }} - uses: actions/cache@v3 id: cache-node-modules diff --git a/package.json b/package.json index f3811a627b1..956cbd08cf5 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "version": "6.9.2", "author": "Hiro Systems PBC", "scripts": { - "dev": "cross-env WALLET_ENVIRONMENT=development concurrently --raw \"node webpack/dev-server.js\" \"redux-devtools --hostname=localhost --port=8000\"", + "dev": "concurrently --raw \"node webpack/dev-server.js\" \"redux-devtools --hostname=localhost --port=8000\"", "dev:test-app": "webpack serve --config test-app/webpack/webpack.config.dev.js", - "build": "cross-env WALLET_ENVIRONMENT=production webpack --config webpack/webpack.config.prod.js", - "build:analyze": "cross-env ANALYZE=true WALLET_ENVIRONMENT=production webpack --config webpack/webpack.config.prod.js", + "build": "webpack --config webpack/webpack.config.prod.js", + "build:analyze": "cross-env ANALYZE=true webpack --config webpack/webpack.config.prod.js", "build:dev": "cross-env WALLET_ENVIRONMENT=development webpack --config webpack/webpack.config.dev.js", "build:ext:test": "cross-env WALLET_ENVIRONMENT=testing webpack --config webpack/webpack.config.prod.js", "build:ext:test:watch": "cross-env WALLET_ENVIRONMENT=testing webpack --config webpack/webpack.config.prod.js --watch", @@ -290,7 +290,7 @@ "cross-env": "7.0.3", "crypto-browserify": "3.12.0", "deepmerge": "4.3.1", - "dependency-cruiser": "14.1.0", + "dependency-cruiser": "14.1.1", "dotenv-webpack": "8.0.1", "esbuild": "0.19.4", "esbuild-loader": "4.0.2", diff --git a/scripts/generate-manifest.js b/scripts/generate-manifest.js index ca75b46fe8d..80bca9acdb0 100644 --- a/scripts/generate-manifest.js +++ b/scripts/generate-manifest.js @@ -3,9 +3,11 @@ */ const deepMerge = require('deepmerge'); -const IS_DEV = process.env.WALLET_ENVIRONMENT === 'development'; +// Manifest can only be prod or dev +const WALLET_ENVIRONMENT = + process.env.WALLET_ENVIRONMENT === 'production' ? 'production' : 'development'; -const WALLET_ENVIRONMENT = process.env.WALLET_ENVIRONMENT ?? 'development'; +const IS_DEV = WALLET_ENVIRONMENT === 'development'; const PREVIEW_RELEASE = process.env.PREVIEW_RELEASE; @@ -20,9 +22,6 @@ function generateImageAssetUrlsWithSuffix(suffix = '') { } const environmentIcons = { - testing: { - icons: generateImageAssetUrlsWithSuffix(PREVIEW_RELEASE ? '-preview' : ''), - }, development: { icons: generateImageAssetUrlsWithSuffix('-dev'), }, @@ -32,14 +31,12 @@ const environmentIcons = { }; const contentSecurityPolicyEnvironment = { - testing: `default-src 'none'; connect-src *; style-src 'unsafe-inline'; img-src 'self' data: https:; script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-src 'none'; frame-ancestors 'none';`, development: "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; frame-src 'none'; frame-ancestors 'none';", production: `default-src 'none'; connect-src *; style-src 'unsafe-inline'; img-src 'self' data: https:; script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-src 'none'; frame-ancestors 'none';`, }; const defaultIconEnvironment = { - testing: 'assets/connect-logo/Stacks128w.png', development: 'assets/connect-logo/Stacks128w-dev.png', production: 'assets/connect-logo/Stacks128w.png', }; diff --git a/src/app/components/app-version.tsx b/src/app/components/app-version.tsx new file mode 100644 index 00000000000..c3f72e9cfe1 --- /dev/null +++ b/src/app/components/app-version.tsx @@ -0,0 +1,65 @@ +import { useMemo } from 'react'; +import { forwardRef } from 'react'; + +import { HTMLStyledProps, styled } from 'leather-styles/jsx'; + +import { BRANCH_NAME, COMMIT_SHA } from '@shared/environment'; + +import { openInNewTab } from '@app/common/utils/open-in-new-tab'; +import { useIsLatestPullRequestBuild } from '@app/query/common/outdated-pr/outdated-pr.query'; + +import { Tooltip } from './tooltip'; + +interface AppVersionLabelProps extends HTMLStyledProps<'span'> { + isLatestVersion: boolean; +} +const AppVersionLabel = forwardRef( + ({ children, isLatestVersion, ...props }: AppVersionLabelProps, ref) => ( + + {children} + + ) +); + +export function AppVersion() { + const { pullRequestLink, isLatestBuild } = useIsLatestPullRequestBuild(); + + const version = useMemo(() => { + // eslint-disable-next-line no-console + console.log('process.env.WALLET_ENVIRONMENT', process.env.WALLET_ENVIRONMENT); + switch (process.env.WALLET_ENVIRONMENT) { + case 'development': + return `dev@${BRANCH_NAME}`; + case 'feature': + return `${BRANCH_NAME}#${COMMIT_SHA?.slice(0, 8)}`; + default: + return `v${VERSION}`; + } + }, []); + + if (!isLatestBuild && process.env.WALLET_ENVIRONMENT === 'feature') { + return ( + + openInNewTab(pullRequestLink ?? '')} + > + {version} + + + ); + } + + return {version}; +} diff --git a/src/app/components/header.tsx b/src/app/components/header.tsx index 80a4c86f91d..ad547dcaeef 100644 --- a/src/app/components/header.tsx +++ b/src/app/components/header.tsx @@ -1,21 +1,20 @@ -import { memo, useMemo } from 'react'; +import { useMemo } from 'react'; import { FiArrowLeft } from 'react-icons/fi'; import { useLocation, useNavigate } from 'react-router-dom'; -import { Box, Flex, FlexProps, IconButton, Stack, Text, useMediaQuery } from '@stacks/ui'; +import { Box, Flex, FlexProps, IconButton, Stack, useMediaQuery } from '@stacks/ui'; import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors'; import { SettingsSelectors } from '@tests/selectors/settings.selectors'; import { token } from 'leather-styles/tokens'; -import { BRANCH_NAME, COMMIT_SHA } from '@shared/environment'; import { RouteUrls } from '@shared/route-urls'; import { useDrawers } from '@app/common/hooks/use-drawers'; import { LeatherLogo } from '@app/components/leather-logo'; import { NetworkModeBadge } from '@app/components/network-mode-badge'; import { Title } from '@app/components/typography'; -import { useIsOutdatedPrQuery } from '@app/query/common/outdated-pr/outdated-pr.query'; +import { AppVersion } from './app-version'; import { LeatherButton } from './button/button'; import { HamburgerIcon } from './icons/hamburger-icon'; @@ -25,15 +24,12 @@ interface HeaderProps extends FlexProps { onClose?(): void; title?: string; } -export const Header: React.FC = memo(props => { +export function Header(props: HeaderProps) { const { actionButton, hideActions, onClose, title, ...rest } = props; const { isShowingSettings, setIsShowingSettings } = useDrawers(); const { pathname } = useLocation(); const navigate = useNavigate(); - const { data } = useIsOutdatedPrQuery(); - console.log({ data }); - const [desktopViewport] = useMediaQuery(`(min-width: ${token('sizes.desktopViewportMinWidth')})`); const leatherLogoIsClickable = useMemo(() => { @@ -45,20 +41,6 @@ export const Header: React.FC = memo(props => { ); }, [pathname]); - const version = useMemo(() => { - switch (process.env.WALLET_ENVIRONMENT) { - case 'feature': - return `${BRANCH_NAME}#${COMMIT_SHA?.slice(0, 8)}`; - case 'development': - return 'dev'; - case 'production': - case 'preview': - return `v${VERSION}`; - default: - return null; - } - }, []); - return ( = memo(props => { isClickable={leatherLogoIsClickable} onClick={leatherLogoIsClickable ? () => navigate(RouteUrls.Home) : undefined} /> - - {version} - + ) : ( @@ -133,4 +104,4 @@ export const Header: React.FC = memo(props => { ); -}); +} diff --git a/src/app/query/common/outdated-pr/outdated-pr.query.ts b/src/app/query/common/outdated-pr/outdated-pr.query.ts index 6228ae3e968..712da35b39b 100644 --- a/src/app/query/common/outdated-pr/outdated-pr.query.ts +++ b/src/app/query/common/outdated-pr/outdated-pr.query.ts @@ -1,4 +1,4 @@ -import { Endpoints } from '@octokit/types'; +import type { Endpoints } from '@octokit/types'; import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; @@ -6,21 +6,35 @@ import { GITHUB_ORG, GITHUB_REPO } from '@shared/constants'; import { COMMIT_SHA, PR_NUMBER } from '@shared/environment'; import { isDefined } from '@shared/utils'; -type PrInfoResp = Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']; +type PrDetailsResp = Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data']; -async function getPullRequestDetails(pr: string): Promise { - return axios.get(`https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/pulls/${pr}`); +async function getPullRequestDetails(pr: string): Promise { + const resp = await axios.get( + `https://api.github.com/repos/${GITHUB_ORG}/${GITHUB_REPO}/pulls/${pr}` + ); + + return resp.data; } -export function useIsOutdatedPrQuery() { +function usePullRequestDetailsQuery() { return useQuery({ enabled: isDefined(PR_NUMBER) && isDefined(COMMIT_SHA), - queryKey: ['outdated-pr-', PR_NUMBER], + queryKey: ['pull-request-details', PR_NUMBER], async queryFn() { return getPullRequestDetails(PR_NUMBER ?? ''); }, - select(resp) { - return resp.data.head.sha.startsWith(COMMIT_SHA ?? ''); - }, }); } + +export function useIsLatestPullRequestBuild() { + const { data: pullRequest } = usePullRequestDetailsQuery(); + if (!pullRequest) return { isLatestBuild: true }; + // eslint-disable-next-line no-console + console.log('debug info', { fromGithubApi: pullRequest.head.sha, fromEnv: COMMIT_SHA }); + return { + // If the latest commit SHA on the PR is not the same one used for this build, + // we can assume it's outdated + isLatestBuild: pullRequest.head.sha.startsWith(COMMIT_SHA ?? ''), + pullRequestLink: pullRequest.html_url, + }; +} diff --git a/src/shared/environment.ts b/src/shared/environment.ts index bd84d9a2924..793f37a3075 100644 --- a/src/shared/environment.ts +++ b/src/shared/environment.ts @@ -2,7 +2,7 @@ export const BRANCH = process.env.GITHUB_REF; export const BRANCH_NAME = process.env.GITHUB_HEAD_REF ?? process.env.BRANCH_NAME; export const PR_NUMBER = process.env.PR_NUMBER; export const COINBASE_APP_ID = process.env.COINBASE_APP_ID ?? ''; -export const COMMIT_SHA = process.env.COMMIT_SHA ?? process.env.GITHUB_SHA; +export const COMMIT_SHA = process.env.GITHUB_SHA ?? process.env.COMMIT_SHA; export const IS_DEV_ENV = process.env.WALLET_ENVIRONMENT === 'development'; export const IS_TEST_ENV = process.env.WALLET_ENVIRONMENT === 'testing'; export const MOONPAY_API_KEY = process.env.MOONPAY_API_KEY ?? ''; diff --git a/webpack/webpack.config.base.js b/webpack/webpack.config.base.js index d76d6a834be..35871201bc0 100755 --- a/webpack/webpack.config.base.js +++ b/webpack/webpack.config.base.js @@ -30,7 +30,13 @@ function executeGitCommand(command) { } const BRANCH_NAME = executeGitCommand('git rev-parse --abbrev-ref HEAD'); -const COMMIT_SHA = executeGitCommand('git rev-parse HEAD'); +const COMMIT_SHA = process.env.COMMIT_SHA ?? executeGitCommand('git rev-parse HEAD'); + +console.log({ + BRANCH_NAME, + envSha: process.env.COMMIT_SHA, + locallyExe: executeGitCommand('git rev-parse HEAD'), +}); // For non main branch builds, add a random number const getVersionWithRandomSuffix = ref => { diff --git a/yarn.lock b/yarn.lock index 307fa94615f..576f89cb383 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10767,10 +10767,10 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -dependency-cruiser@14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/dependency-cruiser/-/dependency-cruiser-14.1.0.tgz#7312f17e905f6183e3e47298ed2019b20534b217" - integrity sha512-JF7F0SFG4K5vXmUMvgYHKQnMuU2JzO18/+r/hTuaGEr3KTlMYkR16WNc+WDqS0y5fjq8khDy/WKO4bR5xhw2sQ== +dependency-cruiser@14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/dependency-cruiser/-/dependency-cruiser-14.1.1.tgz#8d466ebe69af7c85af3670ba947c7b196d23260d" + integrity sha512-npNLWv11pMH9BW4GBLuA5p6KYOXA9UjVDKQ4DzorEhAac5BS1J23K5I2WpEfkJMpwl9PKMsF4T/GDLSq3pogTw== dependencies: acorn "8.10.0" acorn-jsx "5.3.2" @@ -10796,7 +10796,7 @@ dependency-cruiser@14.1.0: semver-try-require "6.2.3" teamcity-service-messages "0.1.14" tsconfig-paths-webpack-plugin "4.1.0" - watskeburt "1.0.1" + watskeburt "2.0.0" wrap-ansi "8.1.0" dequal@^2.0.0: @@ -20207,10 +20207,10 @@ watchpack@2.4.0, watchpack@^2.4.0: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -watskeburt@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/watskeburt/-/watskeburt-1.0.1.tgz#157e87319cedac222c2524e138136fad70ba253e" - integrity sha512-MOvC8vf3hAVo1HPF/pkba7065mt6A/P9unLlFvYhZ7Yyuht16tmfCYi/LqHABG4hIRMZCbvY8eDWHPy81eSADA== +watskeburt@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/watskeburt/-/watskeburt-2.0.0.tgz#9599978fdf3c994354390bac7ca368726b6771ac" + integrity sha512-RJ961Bcw9sfHr1NqZwvcFBYWo6bN9xE1CeBy6LigLqpzzrdnvsMT5HFg2JhOe4ioDOrCndjNa3tsErIVZtCc3g== wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3"