Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion .github.jsonnet
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
local util = import '.github/jsonnet/index.jsonnet';

util.workflowJavascriptPackage(branch='main')
util.workflowJavascriptPackage(
repositories=['github', 'gynzy'],
packageManager='pnpm',
branch='main',
isPublicFork=true,
testJob=null,
)
2 changes: 1 addition & 1 deletion .github/jsonnet/GIT_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
aa305cb073663f1cc427017459aa90fa37127e4a
f71d0345e1cb3df2f7da5795e11a11c5a45bb534
6 changes: 4 additions & 2 deletions .github/jsonnet/base.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,10 @@ local misc = import 'misc.jsonnet';
* @param {string} [id=null] - Unique identifier for this step (used to reference outputs)
* @param {string} [ifClause=null] - Conditional expression to determine if step should run
* @param {boolean} [continueOnError=null] - Whether to continue job if this step fails
* @param {number} [timeoutMinutes=null] - Maximum minutes to run this step before failing
* @returns {steps} - Array containing a single step object
*/
action(name, uses, env=null, with=null, id=null, ifClause=null, continueOnError=null)::
action(name, uses, env=null, with=null, id=null, ifClause=null, continueOnError=null, timeoutMinutes=null)::
[
{
name: name,
Expand All @@ -179,6 +180,7 @@ local misc = import 'misc.jsonnet';
+ (if with != null && with != {} then { with: with } else {})
+ (if id != null then { id: id } else {})
+ (if ifClause != null then { 'if': ifClause } else {})
+ (if continueOnError == null then {} else { 'continue-on-error': continueOnError }),
+ (if continueOnError == null then {} else { 'continue-on-error': continueOnError })
+ (if timeoutMinutes == null then {} else { 'timeout-minutes': timeoutMinutes })
],
}
32 changes: 25 additions & 7 deletions .github/jsonnet/complete-workflows.jsonnet
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local base = import 'base.jsonnet';
local misc = import 'misc.jsonnet';
local pnpm = import 'pnpm.jsonnet';
local yarn = import 'yarn.jsonnet';

{
Expand All @@ -16,27 +17,44 @@ local yarn = import 'yarn.jsonnet';
* @param {boolean} [checkVersionBump=true] - Whether to assert if the version was bumped (recommended)
* @param {jobs} [testJob=null] - A job to be run during PR to assert tests. Can be an array of jobs
* @param {string} [branch='main'] - The branch to run the publish-prod job on
* @param {string} [packageManager='yarn'] - Package manager to use ('yarn' or 'pnpm')
* @param {string} [image=null] - Docker image override for publish jobs; null uses the PM-specific default
* @param {array} [buildSteps=null] - Build steps override; null uses the PM-specific default. Pass `[]` to skip build.
* @returns {workflows} - Complete set of GitHub Actions workflows for JavaScript package lifecycle
*/
workflowJavascriptPackage(repositories=['gynzy'], isPublicFork=true, checkVersionBump=true, testJob=null, branch='main')::
workflowJavascriptPackage(
repositories=['gynzy'],
isPublicFork=true,
checkVersionBump=true,
testJob=null,
branch='main',
packageManager='yarn',
image='mirror.gcr.io/node:24',
buildSteps=null,
)::
local runsOn = (if isPublicFork then 'ubuntu-latest' else null);
local defaultBuildSteps = if packageManager == 'pnpm' then [base.step('build', 'pnpm run build')]
else [base.step('build', 'yarn build')];
local effectiveBuildSteps = if buildSteps != null then buildSteps else defaultBuildSteps;
local pubJob = if packageManager == 'pnpm'
then pnpm.pnpmPublishJob(repositories=repositories, runsOn=runsOn, image=image, buildSteps=effectiveBuildSteps)
else yarn.yarnPublishJob(repositories=repositories, runsOn=runsOn, image=image, buildSteps=effectiveBuildSteps);
local prevJob = if packageManager == 'pnpm'
then pnpm.pnpmPublishPreviewJob(repositories=repositories, runsOn=runsOn, checkVersionBump=checkVersionBump, image=image, buildSteps=effectiveBuildSteps)
else yarn.yarnPublishPreviewJob(repositories=repositories, runsOn=runsOn, checkVersionBump=checkVersionBump, image=image, buildSteps=effectiveBuildSteps);

base.pipeline(
'misc',
[misc.verifyJsonnet(fetch_upstream=false, runsOn=runsOn)],
) +
base.pipeline(
'publish-prod',
[
yarn.yarnPublishJob(repositories=repositories, runsOn=runsOn),
],
[pubJob],
event={ push: { branches: [branch] } },
) +
base.pipeline(
'pr',
[
yarn.yarnPublishPreviewJob(repositories=repositories, runsOn=runsOn, checkVersionBump=checkVersionBump),
] +
[prevJob] +
(if testJob != null then
[testJob]
else [])
Expand Down
5 changes: 4 additions & 1 deletion .github/jsonnet/misc.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ local images = import 'images.jsonnet';
* @param {string} [ref=null] - Specific git ref/branch/tag to checkout
* @param {boolean} [preferSshClone=true] - Whether to attempt SSH clone first
* @param {boolean} [includeSubmodules=true] - Whether to checkout git submodules
* @param {number} [cloneTimeout=10] - Timeout for git clone operation (in minutes)
* @returns {steps} - GitHub Actions steps for repository checkout
*/
checkout(ifClause=null, fullClone=false, ref=null, preferSshClone=true, includeSubmodules=true)::
checkout(ifClause=null, fullClone=false, ref=null, preferSshClone=true, includeSubmodules=true, cloneTimeout=10)::
local with =
(if fullClone then { 'fetch-depth': 0 } else {}) +
(if ref != null then { ref: ref } else {}) +
Expand Down Expand Up @@ -76,12 +77,14 @@ local images = import 'images.jsonnet';
actions.checkout_action,
with=with + (if preferSshClone then { 'ssh-key': '${{ secrets.VIRKO_GITHUB_SSH_KEY }}' } else {}),
ifClause='${{ ' + (if ifClause == null then '' else '( ' + localIfClause + ' ) && ') + " ( steps.check-binaries.outputs.sshBinaryExists == 'true' && steps.check-binaries.outputs.gitBinaryExists == 'true' ) }}",
timeoutMinutes=cloneTimeout,
) +
base.action(
'Check out repository code via https',
actions.checkout_action,
with=with,
ifClause='${{ ' + (if ifClause == null then '' else '( ' + localIfClause + ' ) && ') + " ( steps.check-binaries.outputs.sshBinaryExists == 'false' || steps.check-binaries.outputs.gitBinaryExists == 'false' ) }}",
timeoutMinutes=cloneTimeout,
) +
base.step('git safe directory', "command -v git && git config --global --add safe.directory '*' || true")
else
Expand Down
160 changes: 155 additions & 5 deletions .github/jsonnet/pnpm.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ local yarn = import 'yarn.jsonnet';
*
* @param {array} [args=[]] - Additional command line arguments for pnpm install
* @param {object} [with={}] - Additional configuration options
* @param {string} [version='10'] - PNPM version to use
* @param {boolean} [prod=false] - Whether to install only production dependencies
* @param {string} [storeDir=null] - Directory for pnpm store
* @param {string} [ifClause=null] - Conditional expression to determine if step should run
* @param {string} [workingDirectory=null] - Directory to run pnpm in
* @returns {steps} - Array containing a single step object
*/
install(args=[], with={}, version='10', prod=false, storeDir=null, ifClause=null, workingDirectory=null)::
install(args=[], with={}, prod=false, storeDir=null, ifClause=null, workingDirectory=null)::
base.action(
'Install pnpm tool',
'pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320', // v5
with=
{ version: version } +
with,
with=with + if workingDirectory != null then {
package_json_file: workingDirectory + '/package.json'
} else {},
ifClause=ifClause,
) +
self.installPackages(
Expand Down Expand Up @@ -194,4 +193,155 @@ local yarn = import 'yarn.jsonnet';
],
event='pull_request',
),

/**
* Creates a step to publish a package with pnpm, handling version/tag for PR, tag and branch builds.
*
* @param {boolean} [isPr=true] - Whether this is a PR build (affects versioning)
* @param {string} [ifClause=null] - Conditional expression to determine if step should run
* @returns {steps} - Array containing a single step object
*/
pnpmPublish(isPr=true, ifClause=null)::
base.step(
'publish',
|||
bash -c 'set -xeo pipefail;

cp package.json package.json.bak;

VERSION=$(node -p "require(\"./package.json\").version");
if [[ ! -z "${PR_NUMBER}" ]]; then
echo "Setting tag/version for pr build.";
TAG=pr-$PR_NUMBER;
PUBLISHVERSION="$VERSION-pr$PR_NUMBER.$GITHUB_RUN_NUMBER";
elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
if [[ "${GITHUB_REF_NAME}" != "${VERSION}" ]]; then
echo "Tag version does not match package version. They should match. Exiting";
exit 1;
fi
echo "Setting tag/version for release/tag build.";
PUBLISHVERSION=$VERSION;
TAG="latest";
elif [[ "${GITHUB_REF_TYPE}" == "branch" && ( "${GITHUB_REF_NAME}" == "main" || "${GITHUB_REF_NAME}" == "master" ) ]] || [[ "${GITHUB_EVENT_NAME}" == "deployment" ]]; then
echo "Setting tag/version for release/tag build.";
PUBLISHVERSION=$VERSION;
TAG="latest";
else
exit 1
fi

npm version --no-git-tag-version --allow-same-version "$PUBLISHVERSION";
pnpm publish --no-git-checks --tag "$TAG";

mv package.json.bak package.json;
';
|||,
env={} + (if isPr then { PR_NUMBER: '${{ github.event.number }}' } else {}),
ifClause=ifClause,
),

/**
* Creates steps to publish a package to multiple repositories with pnpm.
*
* @param {boolean} isPr - Whether this is a PR build (affects versioning)
* @param {array} repositories - List of repository types ('gynzy' or 'github')
* @param {string} [ifClause=null] - Conditional expression to determine if steps should run
* @returns {steps} - Array of step objects for publishing to all repositories
*/
pnpmPublishToRepositories(isPr, repositories, ifClause=null)::
(std.flatMap(function(repository)
if repository == 'gynzy' then [yarn.setGynzyNpmToken(ifClause=ifClause), self.pnpmPublish(isPr=isPr, ifClause=ifClause)]
else if repository == 'github' then [yarn.setGithubNpmToken(ifClause=ifClause), self.pnpmPublish(isPr=isPr, ifClause=ifClause)]
else error 'Unknown repository type given.',
repositories)),

/**
* Creates a GitHub Actions job for publishing preview pnpm packages from PRs.
*
* @param {string} [image='node:24'] - Docker image to use for the job
* @param {boolean} [useCredentials=false] - Whether to use Docker registry credentials
* @param {string} [gitCloneRef='${{ github.event.pull_request.head.sha }}'] - Git reference to checkout
* @param {array} [buildSteps=null] - Build steps; null defaults to `[pnpm run build]`. Pass `[]` to skip build.
* @param {boolean} [checkVersionBump=true] - Whether to check if package version was bumped
* @param {array} [repositories=['gynzy']] - List of repositories to publish to
* @param {boolean|string} [onChangedFiles=false] - Whether to only run on changed files (or glob pattern)
* @param {string} [changedFilesHeadRef=null] - Head reference for changed files comparison
* @param {string} [changedFilesBaseRef=null] - Base reference for changed files comparison
* @param {string} [runsOn=null] - Runner type to use
* @returns {jobs} - GitHub Actions job definition
*/
pnpmPublishPreviewJob(
image='mirror.gcr.io/node:24',
useCredentials=false,
gitCloneRef='${{ github.event.pull_request.head.sha }}',
buildSteps=null,
checkVersionBump=true,
repositories=['gynzy'],
onChangedFiles=false,
changedFilesHeadRef=null,
changedFilesBaseRef=null,
runsOn=null,
)::
local effectiveBuildSteps = if buildSteps == null then [base.step('build', 'pnpm run build')] else buildSteps;
local ifClause = (if onChangedFiles != false then "steps.changes.outputs.package == 'true'" else null);
base.ghJob(
'pnpm-publish-preview',
runsOn=runsOn,
image=image,
useCredentials=useCredentials,
steps=
[self.checkoutAndPnpm(ref=gitCloneRef, fullClone=false, source=repositories[0], pnpmInstallArgs=['--frozen-lockfile'])] +
(if onChangedFiles != false then misc.testForChangedFiles({ package: onChangedFiles }, headRef=changedFilesHeadRef, baseRef=changedFilesBaseRef) else []) +
(if checkVersionBump then [
base.action('check-version-bump', uses='del-systems/check-if-version-bumped@d5d13ffd75dc8aa9c2e1dca10d9bb27be10307b2', with={ // check-if-version-bumped@d5d13 == v2
token: '${{ github.token }}',
}, ifClause=ifClause),
] else []) +
(if onChangedFiles != false then std.map(function(step) std.map(function(s) s { 'if': ifClause }, step), effectiveBuildSteps) else effectiveBuildSteps) +
self.pnpmPublishToRepositories(isPr=true, repositories=repositories, ifClause=ifClause),
permissions={ packages: 'write', contents: 'read', 'pull-requests': 'read' },
),

/**
* Creates a GitHub Actions job for publishing pnpm packages from main branch or releases.
*
* @param {string} [image='node:24'] - Docker image to use for the job
* @param {boolean} [useCredentials=false] - Whether to use Docker registry credentials
* @param {string} [gitCloneRef='${{ github.sha }}'] - Git reference to checkout
* @param {array} [buildSteps=null] - Build steps; null defaults to `[pnpm run build]`. Pass `[]` to skip build.
* @param {array} [repositories=['gynzy']] - List of repositories to publish to
* @param {boolean|string} [onChangedFiles=false] - Whether to only run on changed files (or glob pattern)
* @param {string} [changedFilesHeadRef=null] - Head reference for changed files comparison
* @param {string} [changedFilesBaseRef=null] - Base reference for changed files comparison
* @param {string} [ifClause=null] - Conditional expression to determine if job should run
* @param {string} [runsOn=null] - Runner type to use
* @returns {jobs} - GitHub Actions job definition
*/
pnpmPublishJob(
image='mirror.gcr.io/node:24',
useCredentials=false,
gitCloneRef='${{ github.sha }}',
buildSteps=null,
repositories=['gynzy'],
onChangedFiles=false,
changedFilesHeadRef=null,
changedFilesBaseRef=null,
ifClause=null,
runsOn=null,
)::
local effectiveBuildSteps = if buildSteps == null then [base.step('build', 'pnpm run build')] else buildSteps;
local stepIfClause = (if onChangedFiles != false then "steps.changes.outputs.package == 'true'" else null);
base.ghJob(
'pnpm-publish',
image=image,
runsOn=runsOn,
useCredentials=useCredentials,
steps=
[self.checkoutAndPnpm(ref=gitCloneRef, fullClone=false, source=repositories[0], pnpmInstallArgs=['--frozen-lockfile'])] +
(if onChangedFiles != false then misc.testForChangedFiles({ package: onChangedFiles }, headRef=changedFilesHeadRef, baseRef=changedFilesBaseRef) else []) +
(if onChangedFiles != false then std.map(function(step) std.map(function(s) s { 'if': stepIfClause }, step), effectiveBuildSteps) else effectiveBuildSteps) +
self.pnpmPublishToRepositories(isPr=false, repositories=repositories, ifClause=stepIfClause),
permissions={ packages: 'write', contents: 'read', 'pull-requests': 'read' },
ifClause=ifClause,
),
}
2 changes: 2 additions & 0 deletions .github/workflows/misc.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading