Skip to content

Commit

Permalink
Merge branch 'main' into remove-localization-file-limits
Browse files Browse the repository at this point in the history
  • Loading branch information
cameronbarker committed Jan 16, 2025
2 parents 1f9dde4 + 4126f48 commit f80ea94
Show file tree
Hide file tree
Showing 95 changed files with 1,170 additions and 898 deletions.
5 changes: 5 additions & 0 deletions .changeset/healthy-tips-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/theme': minor
---

Give theme info a facelift using standard UI components
6 changes: 6 additions & 0 deletions .changeset/lemon-pants-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/cli-kit': patch
'@shopify/theme': patch
---

Fix `shopify theme dev` to no longer fail when development themes expire in internationalized stores
5 changes: 5 additions & 0 deletions .changeset/light-windows-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': minor
---

Give `app info` a facelift and correct a few display bugs
5 changes: 5 additions & 0 deletions .changeset/red-brooms-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/cli-kit': minor
---

Add tabular data display component to UI kit
5 changes: 5 additions & 0 deletions .changeset/short-tigers-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/theme': patch
---

Update documentation for `theme push --only`
5 changes: 5 additions & 0 deletions .changeset/small-guests-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Better error message for certain types of invalid app TOML files
5 changes: 5 additions & 0 deletions .changeset/tough-guests-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Validate the @shopify/shopify_function NPM package version is compatible with the Javy version
7 changes: 7 additions & 0 deletions .changeset/young-windows-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@shopify/cli-kit': patch
'@shopify/theme': patch
'@shopify/app': patch
---

Utilize Admin API to determine if a storefront is password protected
7 changes: 6 additions & 1 deletion .github/workflows/shopify-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ env:
PNPM_VERSION: '8.15.7'
BUNDLE_WITHOUT: 'test:development'
SHOPIFY_FLAG_CLIENT_ID: ${{ secrets.SHOPIFY_FLAG_CLIENT_ID }}
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
GH_TOKEN: ${{ secrets.SHOPIFY_GH_READ_CONTENT_TOKEN }}

jobs:
Expand Down Expand Up @@ -87,6 +86,8 @@ jobs:
run: pnpm nx run-many --all --skip-nx-cache --target=test --exclude=features --output-style=stream
- name: Acceptance tests
if: ${{ matrix.node == '18.20.3' }}
env:
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
run: pnpm nx run features:test
- name: Send Slack notification on failure
uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844 # pin@v1.23.0
Expand Down Expand Up @@ -305,6 +306,8 @@ jobs:
with:
node-version: ${{ matrix.node }}
- name: Acceptance tests
env:
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
run: pnpm test:features --output-style=stream

pr-test-coverage:
Expand Down Expand Up @@ -355,6 +358,8 @@ jobs:
- name: Unit tests
run: pnpm test:unit --output-style=stream
- name: Acceptance tests
env:
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
run: pnpm test:features --output-style=stream
- name: Setup tmate session
if: ${{ failure() && inputs.debug-enabled }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export interface themepush {
'-n, --nodelete'?: ''

/**
* Download only the specified files (Multiple flags allowed).
* Push only the specified files (Multiple flags allowed).
* @environment SHOPIFY_FLAG_ONLY
*/
'-o, --only <value>'?: string
Expand Down
4 changes: 2 additions & 2 deletions docs-shopify.dev/generated/generated_docs_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -6186,7 +6186,7 @@
"syntaxKind": "PropertySignature",
"name": "-o, --only <value>",
"value": "string",
"description": "Download only the specified files (Multiple flags allowed).",
"description": "Push only the specified files (Multiple flags allowed).",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_ONLY"
},
Expand Down Expand Up @@ -6236,7 +6236,7 @@
"environmentValue": "SHOPIFY_FLAG_IGNORE"
}
],
"value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment <value>'?: string\n\n /**\n * Skip downloading the specified files (Multiple flags allowed).\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore <value>'?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Download only the specified files (Multiple flags allowed).\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only <value>'?: string\n\n /**\n * Password generated from the Theme Access app.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password <value>'?: string\n\n /**\n * The path to your theme directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store <value>'?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme <value>'?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}"
"value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment <value>'?: string\n\n /**\n * Skip downloading the specified files (Multiple flags allowed).\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore <value>'?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Push only the specified files (Multiple flags allowed).\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only <value>'?: string\n\n /**\n * Password generated from the Theme Access app.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password <value>'?: string\n\n /**\n * The path to your theme directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store <value>'?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme <value>'?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"type-check": "nx run-many --target=type-check --all --skip-nx-cache",
"type-check:affected": "nx affected --target=type-check",
"build": "nx run-many --target=build --all --skip-nx-cache",
"bundle": "nx run-many --target=bundle --all --skip-nx-cache",
"bundle-for-release": "nx run-many --target=bundle --all --skip-nx-cache",
"build:affected": "nx affected --target=build",
"refresh-templates": "nx run-many --target=refresh-templates --all --skip-nx-cache",
"refresh-manifests": "nx run-many --target=refresh-manifests --all --skip-nx-cache && bin/prettify-manifests.js && pnpm refresh-readme",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ export const ListOrganizations = {
{
kind: 'Field',
name: {kind: 'Name', value: 'organizations'},
arguments: [
{
kind: 'Argument',
name: {kind: 'Name', value: 'hasAccessToDestination'},
value: {kind: 'EnumValue', value: 'DEVELOPER_DASHBOARD'},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
query ListOrganizations {
currentUserAccount {
uuid
organizations {
organizations(hasAccessToDestination: DEVELOPER_DASHBOARD) {
nodes {
id
name
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/cli/commands/app/env/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ export default class EnvPull extends AppCommand {
public async run(): Promise<AppCommandOutput> {
const {flags} = await this.parse(EnvPull)

const {app, remoteApp} = await linkedAppContext({
const {app, remoteApp, organization} = await linkedAppContext({
directory: flags.path,
clientId: flags['client-id'],
forceRelink: flags.reset,
userProvidedConfigName: flags.config,
})
const envFile = joinPath(app.directory, flags['env-file'] ?? getDotEnvFileName(app.configuration.path))
outputInfo(await pullEnv({app, remoteApp, envFile}))
outputInfo(await pullEnv({app, remoteApp, organization, envFile}))
return {app}
}
}
4 changes: 2 additions & 2 deletions packages/app/src/cli/commands/app/env/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ export default class EnvShow extends AppCommand {

public async run(): Promise<AppCommandOutput> {
const {flags} = await this.parse(EnvShow)
const {app, remoteApp} = await linkedAppContext({
const {app, remoteApp, organization} = await linkedAppContext({
directory: flags.path,
clientId: flags['client-id'],
forceRelink: flags.reset,
userProvidedConfigName: flags.config,
})
outputInfo(await showEnv(app, remoteApp))
outputInfo(await showEnv(app, remoteApp, organization))
return {app}
}
}
22 changes: 13 additions & 9 deletions packages/app/src/cli/commands/app/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {linkedAppContext} from '../../services/app-context.js'
import {Flags} from '@oclif/core'
import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli'
import {outputInfo} from '@shopify/cli-kit/node/output'
import {renderInfo} from '@shopify/cli-kit/node/ui'

export default class AppInfo extends AppCommand {
static summary = 'Print basic information about your app and extensions.'
Expand Down Expand Up @@ -33,21 +34,24 @@ export default class AppInfo extends AppCommand {
public async run(): Promise<AppCommandOutput> {
const {flags} = await this.parse(AppInfo)

const {app, remoteApp, developerPlatformClient} = await linkedAppContext({
const {app, remoteApp, organization, developerPlatformClient} = await linkedAppContext({
directory: flags.path,
clientId: flags['client-id'],
forceRelink: flags.reset,
userProvidedConfigName: flags.config,
unsafeReportMode: true,
})
outputInfo(
await info(app, remoteApp, {
format: (flags.json ? 'json' : 'text') as Format,
webEnv: flags['web-env'],
configName: flags.config,
developerPlatformClient,
}),
)
const results = await info(app, remoteApp, organization, {
format: (flags.json ? 'json' : 'text') as Format,
webEnv: flags['web-env'],
configName: flags.config,
developerPlatformClient,
})
if (typeof results === 'string' || 'value' in results) {
outputInfo(results)
} else {
renderInfo({customSections: results})
}
if (app.errors) process.exit(2)

return {app}
Expand Down
8 changes: 7 additions & 1 deletion packages/app/src/cli/models/app/app.test-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,7 @@ export function testDeveloperPlatformClient(stubs: Partial<DeveloperPlatformClie
requiresOrganization: false,
supportsAtomicDeployments: false,
supportsDevSessions: stubs.supportsDevSessions ?? false,
organizationSource: OrganizationSource.BusinessPlatform,
session: () => Promise.resolve(testPartnersUserSession),
refreshToken: () => Promise.resolve(testPartnersUserSession.token),
accountInfo: () => Promise.resolve(testPartnersUserSession.accountInfo),
Expand Down Expand Up @@ -1378,7 +1379,12 @@ export function testDeveloperPlatformClient(stubs: Partial<DeveloperPlatformClie
retVal[
key as keyof Omit<
DeveloperPlatformClient,
'requiresOrganization' | 'supportsAtomicDeployments' | 'clientName' | 'webUiName' | 'supportsDevSessions'
| 'requiresOrganization'
| 'supportsAtomicDeployments'
| 'clientName'
| 'webUiName'
| 'supportsDevSessions'
| 'organizationSource'
>
] = vi.fn().mockImplementation(value)
}
Expand Down
29 changes: 29 additions & 0 deletions packages/app/src/cli/models/app/app.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AppSchema,
CurrentAppConfiguration,
LegacyAppConfiguration,
getAppScopes,
Expand Down Expand Up @@ -30,6 +31,7 @@ const CORRECT_CURRENT_APP_SCHEMA: CurrentAppConfiguration = {
path: '',
name: 'app 1',
client_id: '12345',
extension_directories: ['extensions/*'],
webhooks: {
api_version: '2023-04',
privacy_compliance: {
Expand Down Expand Up @@ -91,6 +93,33 @@ describe('app schema validation', () => {

expect(isCurrentAppSchema(config)).toBe(false)
})

test('extension_directories should be transformed to double asterisks', () => {
const config = {
...CORRECT_CURRENT_APP_SCHEMA,
extension_directories: ['extensions/*'],
}
const parsed = AppSchema.parse(config)
expect(parsed.extension_directories).toEqual(['extensions/**'])
})

test('extension_directories is not transformed if it ends with double asterisks', () => {
const config = {
...CORRECT_CURRENT_APP_SCHEMA,
extension_directories: ['extensions/**'],
}
const parsed = AppSchema.parse(config)
expect(parsed.extension_directories).toEqual(['extensions/**'])
})

test('extension_directories is not transformed if it doesnt end with a wildcard', () => {
const config = {
...CORRECT_CURRENT_APP_SCHEMA,
extension_directories: ['extensions'],
}
const parsed = AppSchema.parse(config)
expect(parsed.extension_directories).toEqual(['extensions'])
})
})
})

Expand Down
24 changes: 19 additions & 5 deletions packages/app/src/cli/models/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ import {getArrayRejectingUndefined} from '@shopify/cli-kit/common/array'

// Schemas for loading app configuration

const ExtensionDirectoriesSchema = zod
.array(zod.string())
.optional()
.transform(removeTrailingPathSeparator)
.transform(fixSingleWildcards)

/**
* Schema for a freshly minted app template.
*/
Expand All @@ -34,7 +40,7 @@ export const LegacyAppSchema = zod
.string()
.transform((scopes) => normalizeDelimitedString(scopes) ?? '')
.default(''),
extension_directories: zod.array(zod.string()).optional().transform(removeTrailingPathSeparator),
extension_directories: ExtensionDirectoriesSchema,
web_directories: zod.array(zod.string()).optional(),
webhooks: zod
.object({
Expand All @@ -49,6 +55,14 @@ function removeTrailingPathSeparator(value: string[] | undefined) {
// eslint-disable-next-line no-useless-escape
return value?.map((dir) => dir.replace(/[\/\\]+$/, ''))
}

// If a path ends with a single asterisk, modify it to end with a double asterisk.
// This is to support the glob pattern used by chokidar and watch for changes in subfolders.
function fixSingleWildcards(value: string[] | undefined) {
// eslint-disable-next-line no-useless-escape
return value?.map((dir) => dir.replace(/([^\*])\*$/, '$1**'))
}

/**
* Schema for a normal, linked app. Properties from modules are not validated.
*/
Expand All @@ -62,7 +76,7 @@ export const AppSchema = zod.object({
include_config_on_deploy: zod.boolean().optional(),
})
.optional(),
extension_directories: zod.array(zod.string()).optional().transform(removeTrailingPathSeparator),
extension_directories: ExtensionDirectoriesSchema,
web_directories: zod.array(zod.string()).optional(),
})

Expand Down Expand Up @@ -259,7 +273,7 @@ export interface AppInterface<
*/
creationDefaultOptions(): AppCreationDefaultOptions
manifest: () => Promise<JsonMapType>
removeExtension: (extensionHandle: string) => void
removeExtension: (extensionUid: string) => void
}

type AppConstructor<
Expand Down Expand Up @@ -427,8 +441,8 @@ export class App<
}
}

removeExtension(extensionHandle: string) {
this.realExtensions = this.realExtensions.filter((ext) => ext.handle !== extensionHandle)
removeExtension(extensionUid: string) {
this.realExtensions = this.realExtensions.filter((ext) => ext.uid !== extensionUid)
}

get includeConfigOnDeploy() {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/cli/models/app/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export async function loadConfigurationFileContent(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
// TOML errors have line, pos and col properties
if (err.line && err.pos && err.col) {
if (err.line !== undefined && err.pos !== undefined && err.col !== undefined) {
return abortOrReport(
outputContent`Fix the following error in ${outputToken.path(filepath)}:\n${err.message}`,
{},
Expand Down
9 changes: 5 additions & 4 deletions packages/app/src/cli/models/extensions/extension-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {DeveloperPlatformClient} from '../../utilities/developer-platform-client
import {AppConfigurationWithoutPath, CurrentAppConfiguration} from '../app/app.js'
import {ok} from '@shopify/cli-kit/node/result'
import {constantize, slugify} from '@shopify/cli-kit/common/string'
import {hashString, nonRandomUUID, randomUUID} from '@shopify/cli-kit/node/crypto'
import {hashString, nonRandomUUID} from '@shopify/cli-kit/node/crypto'
import {partnersFqdn} from '@shopify/cli-kit/node/context/fqdn'
import {joinPath, basename} from '@shopify/cli-kit/node/path'
import {fileExists, touchFile, moveFile, writeFile, glob} from '@shopify/cli-kit/node/fs'
Expand Down Expand Up @@ -150,11 +150,12 @@ export class ExtensionInstance<TConfiguration extends BaseConfigType = BaseConfi
this.directory = options.directory
this.specification = options.specification
this.handle = this.buildHandle()
this.devUUID = `dev-${nonRandomUUID(this.handle)}`
const uuidFromHandle = nonRandomUUID(this.handle)
this.devUUID = `dev-${uuidFromHandle}`
this.localIdentifier = this.handle
this.idEnvironmentVariableName = `SHOPIFY_${constantize(this.localIdentifier)}_ID`
this.outputPath = this.directory
this.uid = this.configuration.uid ?? randomUUID()
this.uid = this.configuration.uid ?? uuidFromHandle

if (this.features.includes('esbuild') || this.type === 'tax_calculation') {
this.outputPath = joinPath(this.directory, 'dist', this.outputFileName)
Expand Down Expand Up @@ -369,7 +370,7 @@ export class ExtensionInstance<TConfiguration extends BaseConfigType = BaseConfi
}

getOutputFolderId(extensionId?: string) {
return extensionId ?? this.configuration.uid ?? this.handle
return extensionId ?? this.uid ?? this.handle
}

getOutputPathForDirectory(directory: string, extensionId?: string) {
Expand Down
Loading

0 comments on commit f80ea94

Please sign in to comment.