Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1054f7f
Replace instances of require() with import
agibson-godaddy Feb 28, 2025
f1be39f
Move config to separate file that we can export
agibson-godaddy Mar 12, 2025
67e1f65
Initialize config from inside sake file
agibson-godaddy Mar 12, 2025
ea38b7a
Refactor replacement pipes
agibson-godaddy Mar 12, 2025
b9ad28d
Export scripts
agibson-godaddy Mar 12, 2025
d05267b
Refactor validation task
agibson-godaddy Mar 12, 2025
95ae9ed
Refactor bump task
agibson-godaddy Mar 12, 2025
d6cb231
Rework wc tasks
agibson-godaddy Mar 13, 2025
a6a6826
Only import the fs function we use
agibson-godaddy Mar 13, 2025
742c38a
Rework config task
agibson-godaddy Mar 13, 2025
b20d287
Rework linting
agibson-godaddy Mar 13, 2025
c87cc19
Rework imagemin
agibson-godaddy Mar 13, 2025
a8d9bd3
Adjust gulpif import
agibson-godaddy Mar 14, 2025
8f118fe
Rework shell tasks
agibson-godaddy Mar 14, 2025
47a4296
Rework watch
agibson-godaddy Mar 14, 2025
6e429df
Rework styles
agibson-godaddy Mar 14, 2025
975f55e
Rework makepot
agibson-godaddy Mar 14, 2025
0a99b85
Rework decaffeinate
agibson-godaddy Mar 14, 2025
08d14e1
Rework clean tasks
agibson-godaddy Mar 14, 2025
2182c87
Rework compile task
agibson-godaddy Mar 14, 2025
f1ff8e8
Rework scripts
agibson-godaddy Mar 14, 2025
0f20169
Rework github tasks
agibson-godaddy Mar 14, 2025
d235325
Rework zip
agibson-godaddy Mar 14, 2025
75f1ebb
Rework prompt
agibson-godaddy Mar 14, 2025
40a5a55
Rework bundle
agibson-godaddy Mar 14, 2025
06141a6
Use task suffix in constants
agibson-godaddy Mar 14, 2025
beafea5
Use task suffix
agibson-godaddy Mar 14, 2025
5c517b0
Use task suffix
agibson-godaddy Mar 14, 2025
e1c28d6
Use task suffix
agibson-godaddy Mar 14, 2025
a68bfe0
Use task suffix
agibson-godaddy Mar 14, 2025
0370715
Start reworking deploy
agibson-godaddy Mar 14, 2025
59a5cca
Rework deploy tasks
agibson-godaddy Mar 17, 2025
d0bae0f
Update prerelease tasks
agibson-godaddy Mar 17, 2025
c0a821b
Update upfw tasks
agibson-godaddy Mar 17, 2025
1291ccd
Update naming
agibson-godaddy Mar 17, 2025
0212867
Update naming
agibson-godaddy Mar 17, 2025
c79a6e0
Fix import
agibson-godaddy Mar 17, 2025
c1ccfcf
Update deprecated sass import
agibson-godaddy Mar 17, 2025
2b08904
Remove console log
agibson-godaddy Mar 19, 2025
df04967
Rework how series is created
agibson-godaddy Mar 19, 2025
d72c2ba
Add force option
agibson-godaddy Mar 25, 2025
2e979e0
Add support for non-interactive mode
agibson-godaddy Mar 25, 2025
079bb20
Create hasGitRelease helper
agibson-godaddy Mar 25, 2025
ef6a28c
Set up more options for dry runs, etc.
agibson-godaddy Mar 26, 2025
d059ca4
Reorganize logic
agibson-godaddy Mar 26, 2025
89cf78e
Skip validation if no code changes
agibson-godaddy Mar 26, 2025
081d5ae
Adjust variable validation
agibson-godaddy Mar 26, 2025
f5c7a3b
Add one to test validatione rrors
agibson-godaddy Mar 26, 2025
a6cf75f
Set exit code on errors
agibson-godaddy Mar 26, 2025
b704b76
Propagate child process exit code up to main process
agibson-godaddy Mar 27, 2025
f66ddbd
Remove test variable
agibson-godaddy Mar 27, 2025
3d4b670
Rework upload URL param
agibson-godaddy Mar 27, 2025
9b194f2
Account for pre-release path being undefined
agibson-godaddy Mar 27, 2025
b1a42e5
Add support for skipping linting
agibson-godaddy Mar 27, 2025
72757ab
Create a new separate deploy task
agibson-godaddy Mar 27, 2025
e335b09
Create a series to fetch and bump
agibson-godaddy Mar 27, 2025
a03ef46
Allow s pecifying what the new plugin version is
agibson-godaddy Mar 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions bin/sake.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/usr/bin/env node
const { spawn } = require('child_process')
const path = require('path')
import { spawn } from 'node:child_process'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import resolve from 'resolve-bin'
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
* `sake` is simply a nice wrapper around `gulp`, designed to simplify using gulp
Expand All @@ -17,11 +21,16 @@ const path = require('path')
// The concat portion passes in any optional CLI args as well as the gulpfile from sake and
// current workind directory.
const args = [
require('resolve-bin').sync('gulp')
resolve.sync('gulp')
].concat(process.argv.splice(2).concat([
'--gulpfile', path.join(__dirname, '../gulpfile.js'),
'--cwd', process.cwd()
]))

// fire up gulp
spawn('node', args, { cwd: process.cwd(), stdio: 'inherit' })
const child = spawn('node', args, { cwd: process.cwd(), stdio: 'inherit' })

// we need the exit code of the child process to propagate up to the main process
child.on('exit', function(code) {
process.exitCode = code
})
161 changes: 43 additions & 118 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
'use strict'

const gulp = require('gulp')
const path = require('path')
const fs = require('fs')
const minimist = require('minimist')
const log = require('fancy-log')
const _ = require('lodash')
const ForwardReference = require('undertaker-forward-reference')
import gulp from 'gulp'
import path from 'node:path'
import fs from 'node:fs'
import log from 'fancy-log'
import ForwardReference from 'undertaker-forward-reference'
import dotenv from 'dotenv'
import gulpPlugins from 'gulp-load-plugins'
import notifier from 'node-notifier'
import stripAnsi from 'strip-ansi'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// local .env file, overriding any global env variables
let parentEnvPath = path.join('..', '.env')
let envPath = fs.existsSync('.env') ? '.env' : (fs.existsSync(parentEnvPath) ? parentEnvPath : null)

if (envPath) {
let result = require('dotenv').config({ path: envPath })
let result = dotenv.config({ path: envPath })

log.warn(`Loading ENV variables from ${path.join(process.cwd(), envPath)}`)

Expand All @@ -25,7 +28,7 @@ if (envPath) {
// development .env file, overriding any global env variables, or repo/plugin specific variables
let devEnv = path.join(__dirname, '.env')
if (fs.existsSync(devEnv)) {
let result = require('dotenv').config({path: devEnv})
let result = dotenv.config({path: devEnv})

log.warn('LOADING DEVELOPMENT ENV VARIABLES FROM ' + devEnv)

Expand All @@ -37,116 +40,12 @@ if (fs.existsSync(devEnv)) {
// enable forward-referencing tasks, see https://github.com/gulpjs/gulp/issues/1028
gulp.registry(ForwardReference())

// define default config
let defaults = {
// sets up the plugin folder structure
paths: {
// Path to plugin source files - this is where the main plugin entry file is located. Set this to a dot (.) if the
// main plugin file and sake.config.js are in teh same directory. The path is relative to the current working directory.
// Mostly, this is the only path a plugin/repo needs to explicitly set
src: '.',
// where plugin assets are located, relative to `src`
assets: 'assets',
// where plugin CSS/SCSS assets are located, relative to `src`
css: 'assets/css',
// where plugin JS/COFFEE assets are located, relative to `src`
js: 'assets/js',
// where plugin image assets are located, relative to `src`
images: 'assets/img',
// where plugin font assets are located, relative to `src`
fonts: 'assets/fonts',
// the directory where plugin files are copied during the build task, relative to current working directory
build: 'build',
// path to the directory where production (WC and WP.org SVN) repos are cloned, may be an absolute path or relative to current working directory
tmp: '/tmp/sake',
// array of paths that should be excluded from the build
exclude: []
},

// Task-specific settings, set the key to task name and provide any settings as needed. Since sake uses Gulp behind the scenes
// and Gulp prefers code over configuration, there isn't a lot to do here. As you can see, some of these values can be defined
// as environment variables, as this makes more sense - ie whether you want to use browsersync or not is specific tp your local
// dev environment and workflow, not to a particular repo.
tasks: {
makepot: {
reportBugsTo: 'https://woocommerce.com/my-account/marketplace-ticket-form/',
domainPath: 'i18n/languages'
},
watch: {
useBrowserSync: process.env.USE_BROWSERSYNC || false
},
browserSync: {
url: process.env.BROWSERSYNC_URL || 'plugins-skyverge.test'
}
},

// which framework version this plugin uses - valid values: 'v5', 'v4', or pass boolean `false` to indicate a non-frameworked plugin
framework: 'v5',
// which deploy type does this plugin use - either 'wc' or 'wp', defaults to 'wc', specify `null` or `false` for no automated deploy
deploy: 'wc',
// the e-commerce platform this plugin is for, 'wc' or 'edd'
platform: 'wc'
}

// load local configuration
// TODO: allow passing in config file path or config as string (for multi-plugin repos?)
let localConfig = {}

// support supplying a single / parent config file in multi-plugin repos
let parentConfigPath = path.join(process.cwd(), '../sake.config.js')
let found = false

if (fs.existsSync(parentConfigPath)) {
log.warn('Found config file in parent folder')
localConfig = require(parentConfigPath)
found = true
}

// load local, plugin-specific config file
let configFilePath = path.join(process.cwd(), 'sake.config.js')

if (fs.existsSync(configFilePath)) {
localConfig = _.merge(localConfig, require(configFilePath))
found = true
}

if (!found) {
log.warn('Could not find local config file, using default config values.')
}

let config = _.merge(defaults, localConfig)

// parse CLI options
let options = minimist(process.argv.slice(2), {
boolean: ['minify'],
default: {
minify: true,
debug: false
}
})

const sake = require('./lib/sake')(config, options)

sake.initConfig()

let plugins = require('gulp-load-plugins')()

// Attach browsersync as a plugin - not really a plugin, but it helps to
// pass around the browsersync instance between tasks. Unfortunately, we
// always have to load and create an instance of it, because gulp-if does not
// support lazy evaluation yet: https://github.com/robrich/gulp-if/issues/75
plugins.browserSync = require('browser-sync').create()

// load gulp plugins and tasks
require('fs').readdirSync(path.join(__dirname, 'tasks')).forEach((file) => {
require(path.join(__dirname, 'tasks', file))(gulp, plugins, sake)
// @link https://github.com/jackfranklin/gulp-load-plugins/issues/141#issuecomment-2373391177
let plugins = gulpPlugins({
config: path.resolve(__dirname, 'package.json')
})

gulp.task('default', gulp.series('compile'))

// show notification on task errors
const notifier = require('node-notifier')
const stripAnsi = require('strip-ansi')
let loggedErrors = []

gulp.on('error', (event) => {
Expand All @@ -161,3 +60,29 @@ gulp.on('error', (event) => {
loggedErrors.push(event.error)
}
})

/************** Task Exports */

export * from './tasks/build.js'
export * from './tasks/bump.js'
export * from './tasks/bundle.js'
export * from './tasks/clean.js'
export * from './tasks/compile.js'
export * from './tasks/config.js'
export * from './tasks/copy.js'
export * from './tasks/decaffeinate.js'
export * from './tasks/deploy.js'
export * from './tasks/github.js'
export * from './tasks/imagemin.js'
export * from './tasks/lint.js'
export * from './tasks/makepot.js'
export * from './tasks/prerelease.js'
export * from './tasks/prompt.js'
export * from './tasks/scripts.js'
export * from './tasks/shell.js'
export * from './tasks/styles.js'
export * from './tasks/upfw.js'
export * from './tasks/validate.js'
export * from './tasks/watch.js'
export * from './tasks/wc.js'
export * from './tasks/zip.js'
65 changes: 65 additions & 0 deletions helpers/arguments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import minimist from 'minimist'

/**
* Determines if the command is being run in "non-interactive mode". If true, we should never present with prompts.
* @returns {boolean}
*/
export function isNonInteractive()
{
return process.argv.includes('--non-interactive');
}

/**
* Whether we already have a GitHub release for this deployment. If we don't, we'll be creating one.
* @returns {boolean}
*/
export function hasGitRelease()
{
return !! gitReleaseUploadUrl;
}

export const gitReleaseUploadUrl = () => {
const argv = minimist(process.argv.slice(2))

return argv['release-upload-url'] || null;
}

/**
* Gets the name of the GitHub "release tag" to deploy.
* @returns {string|null}
*/
export const gitReleaseTag = () => {
const argv = minimist(process.argv.slice(2))

return argv['release-tag'] || null;
}

/**
* Whether this is a dry run deployment. If true, the deploy will not actually happen.
* @returns {boolean}
*/
export function isDryRunDeploy()
{
return process.argv.includes('--dry-run');
}

/**
* If specified, then no changes will be made/committed to the code base during a deployment. This should be used if
* you're specifying an _exact_ release to deploy, rather than having Sake create the release for you. The expectation
* here is that prior to deployment the code has already had all the versions/min-reqs bumped.
* @returns {boolean}
*/
export function withoutCodeChanges()
{
return process.argv.includes('--without-code-changes');
}

export const skipLinting = () => {
return process.argv.includes('--skip-linting');
}

export const newPluginVersion = () => {
const argv = minimist(process.argv.slice(2))

return argv['new-version'] || null;
}
91 changes: 91 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import path from 'node:path'
import { existsSync } from 'node:fs'
import log from 'fancy-log'
import _ from 'lodash'
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url);

const buildSakeConfig = () => {
// define default config
let defaults = {
// sets up the plugin folder structure
paths: {
// Path to plugin source files - this is where the main plugin entry file is located. Set this to a dot (.) if the
// main plugin file and sake.config.js are in teh same directory. The path is relative to the current working directory.
// Mostly, this is the only path a plugin/repo needs to explicitly set
src: '.',
// where plugin assets are located, relative to `src`
assets: 'assets',
// where plugin CSS/SCSS assets are located, relative to `src`
css: 'assets/css',
// where plugin JS/COFFEE assets are located, relative to `src`
js: 'assets/js',
// where plugin image assets are located, relative to `src`
images: 'assets/img',
// where plugin font assets are located, relative to `src`
fonts: 'assets/fonts',
// the directory where plugin files are copied during the build task, relative to current working directory
build: 'build',
// path to the directory where production (WC and WP.org SVN) repos are cloned, may be an absolute path or relative to current working directory
tmp: '/tmp/sake',
// array of paths that should be excluded from the build
exclude: []
},

// Task-specific settings, set the key to task name and provide any settings as needed. Since sake uses Gulp behind the scenes
// and Gulp prefers code over configuration, there isn't a lot to do here. As you can see, some of these values can be defined
// as environment variables, as this makes more sense - ie whether you want to use browsersync or not is specific tp your local
// dev environment and workflow, not to a particular repo.
tasks: {
makepot: {
reportBugsTo: 'https://woocommerce.com/my-account/marketplace-ticket-form/',
domainPath: 'i18n/languages'
},
watch: {
useBrowserSync: process.env.USE_BROWSERSYNC || false
},
browserSync: {
url: process.env.BROWSERSYNC_URL || 'plugins-skyverge.test'
}
},

// which framework version this plugin uses - valid values: 'v5', 'v4', or pass boolean `false` to indicate a non-frameworked plugin
framework: 'v5',
// which deploy type does this plugin use - either 'wc' or 'wp', defaults to 'wc', specify `null` or `false` for no automated deploy
deploy: 'wc',
// the e-commerce platform this plugin is for, 'wc' or 'edd'
platform: 'wc'
}

// load local configuration
// TODO: allow passing in config file path or config as string (for multi-plugin repos?)
let localConfig = {}

// support supplying a single / parent config file in multi-plugin repos
let parentConfigPath = path.join(process.cwd(), '../sake.config.js')
let found = false

if (existsSync(parentConfigPath)) {
log.warn('Found config file in parent folder')
localConfig = require(parentConfigPath)
found = true
}

// load local, plugin-specific config file
let configFilePath = path.join(process.cwd(), 'sake.config.js')

if (existsSync(configFilePath)) {
localConfig = _.merge(localConfig, require(configFilePath))
found = true
}

if (!found) {
log.warn('Could not find local config file, using default config values.')
}

return _.merge(defaults, localConfig)
}

const sakeConfig = buildSakeConfig();

export default sakeConfig;
Loading