3434 type : boolean
3535 default : true
3636
37+ # Run workflow upon completion of `publish` workflow run:
38+ workflow_run :
39+ workflows : ["publish"]
40+ types : [completed]
41+
3742# Concurrency group to prevent multiple concurrent executions:
3843concurrency :
3944 group : productionize
@@ -94,10 +99,11 @@ jobs:
9499 # Change `@stdlib/string-format` to `@stdlib/error-tools-fmtprodmsg` in package.json if the former is a dependency, otherwise insert it as a dependency:
95100 - name : ' Update dependencies in package.json'
96101 run : |
102+ PKG_VERSION=$(npm view @stdlib/error-tools-fmtprodmsg version)
97103 if grep -q '"@stdlib/string-format"' package.json; then
98- sed -i "s/\"@stdlib\/string-format\"/\"@stdlib\/error-tools-fmtprodmsg\"/g" package.json
104+ sed -i "s/\"@stdlib\/string-format\": \"^.*\" /\"@stdlib\/error-tools-fmtprodmsg\": \"^$PKG_VERSION \"/g" package.json
99105 else
100- node -e "var pkg = require( './package.json' ); pkg.dependencies[ '@stdlib/error-tools-fmtprodmsg' ] = '^0.0.x '; require( 'fs' ).writeFileSync( 'package.json', JSON.stringify( pkg, null, 2 ) );"
106+ node -e "var pkg = require( './package.json' ); pkg.dependencies[ '@stdlib/error-tools-fmtprodmsg' ] = '^$PKG_VERSION '; require( 'fs' ).writeFileSync( 'package.json', JSON.stringify( pkg, null, 2 ) );"
101107 fi
102108
103109 # Configure git:
@@ -462,7 +468,6 @@ jobs:
462468 # Rewrite file contents:
463469 - name : ' Rewrite file contents'
464470 run : |
465-
466471 # Replace links to other packages with links to the umd branch:
467472 find ./umd -type f -name '*.md' -print0 | xargs -0 sed -Ei "/\/tree\/main/b; /^\[@stdlib[^:]+: https:\/\/github.com\/stdlib-js\// s/(.*)/\\1\/tree\/umd/";
468473
@@ -625,7 +630,6 @@ jobs:
625630 # Rewrite file contents:
626631 - name : ' Rewrite file contents'
627632 run : |
628-
629633 # Replace links to other packages with links to the esm branch:
630634 find ./esm -type f -name '*.md' -print0 | xargs -0 sed -Ei "/\/tree\/main/b; /^\[@stdlib[^:]+: https:\/\/github.com\/stdlib-js\// s/(.*)/\\1\/tree\/esm/";
631635
@@ -697,6 +701,198 @@ jobs:
697701 channel : ' #npm-ci'
698702 if : failure()
699703
704+ # Define job to create CLI branch:
705+ cli :
706+
707+ # Define display name:
708+ name : ' Create CLI branch'
709+
710+ # Define the type of virtual host machine on which to run the job:
711+ runs-on : ubuntu-latest
712+
713+ # Indicate that this job depends on the test job finishing:
714+ needs : test
715+
716+ # Define the sequence of job steps...
717+ steps :
718+ # Checkout the repository:
719+ - name : ' Checkout repository'
720+ uses : actions/checkout@v3
721+
722+ # Configure git:
723+ - name : ' Configure git'
724+ run : |
725+ git config --local user.email "noreply@stdlib.io"
726+ git config --local user.name "stdlib-bot"
727+
728+ # Check if remote `cli` branch exists:
729+ - name : ' Check if remote `cli` branch exists'
730+ id : cli-branch-exists
731+ continue-on-error : true
732+ run : |
733+ git fetch --all
734+ git ls-remote --exit-code --heads origin cli
735+ if [ $? -eq 0 ]; then
736+ echo "remote-exists=true" >> $GITHUB_OUTPUT
737+ else
738+ echo "remote-exists=false" >> $GITHUB_OUTPUT
739+ fi
740+
741+ # If `cli` exists, delete everything in branch and merge `production` into it
742+ - name : ' If `cli` exists, delete everything in branch and merge `production` into it'
743+ if : steps.cli-branch-exists.outputs.remote-exists
744+ run : |
745+ git checkout -b cli origin/cli
746+
747+ find . -type 'f' | grep -v -e ".git/" -e "package.json" -e "README.md" -e "LICENSE" -e "CONTRIBUTORS" -e "NOTICE" | xargs -r rm
748+ find . -mindepth 1 -type 'd' | grep -v -e ".git" | xargs -r rm -rf
749+
750+ git add -A
751+ git commit -m "Remove files" --allow-empty
752+
753+ git config merge.theirs.name 'simulate `-s theirs`'
754+ git config merge.theirs.driver 'cat %B > %A'
755+ GIT_CONFIG_PARAMETERS="'merge.default=theirs'" git merge origin/production --allow-unrelated-histories
756+
757+ # Copy files from `production` branch if necessary:
758+ git checkout origin/production -- .
759+ if [ -n "$(git status --porcelain)" ]; then
760+ git add -A
761+ git commit -m "Auto-generated commit"
762+ fi
763+
764+ # If `cli` does not exist, create `cli` branch:
765+ - name : ' If `cli` does not exist, create `cli` branch'
766+ if : ${{ steps.cli-branch-exists.outputs.remote-exists == false }}
767+ run : |
768+ git checkout production
769+ git checkout -b cli
770+
771+ # Copy files to cli directory:
772+ - name : ' Copy files to cli directory'
773+ run : |
774+ mkdir -p cli
775+ mkdir -p cli/docs cli/test
776+ cp README.md LICENSE CONTRIBUTORS NOTICE ./cli
777+ cp -r bin etc ./cli
778+ cp test/test.cli.js ./cli/test
779+ if [ -d "test/fixtures" ]; then
780+ cp -r test/fixtures ./cli/test
781+ fi
782+ cp docs/usage.txt ./cli/docs
783+
784+ # Install Node.js:
785+ - name : ' Install Node.js'
786+ uses : actions/setup-node@v3
787+ with :
788+ node-version : 16
789+ timeout-minutes : 5
790+
791+ # Install dependencies:
792+ - name : ' Install production and development dependencies'
793+ id : install
794+ run : |
795+ npm install || npm install || npm install
796+ timeout-minutes : 15
797+
798+ # Rewrite file contents:
799+ - name : ' Rewrite file contents'
800+ run : |
801+ # Define variable for package name:
802+ pkg="$(jq -r '.name' ./package.json)"
803+ escapedPkg=$(echo "$pkg" | sed -e 's/\//\\\//g')
804+ escapedPkg=$(echo "$escapedPkg" | sed -e 's/\@/\\\@/g')
805+
806+ # Define variable for package description:
807+ pkgDescription="$(jq -r '.description' ./package.json)"
808+ pkgDescription="$(echo "$pkgDescription" | sed -e 's/^\([A-Z]\)/\L\1/')"
809+
810+ # Remove sections:
811+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/<section class=\"installation\">[^<]+<\/section>//;"
812+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(\* \* \*\n+)?<section class=\"usage\">[\s\S]+?<\!\-\- \/.usage \-\->//"
813+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(\* \* \*\n+)?<section class=\"notes\">[\s\S]+?<\!\-\- \/.notes \-\->//"
814+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(\* \* \*\n+)?<section class=\"examples\">[\s\S]+?<\!\-\- \/.examples \-\->//"
815+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(\* \* \*\n+)?<section class=\"c\">[\s\S]+?<\!\-\- \/.c \-\->//g"
816+
817+ # Remove first horizontal rule * * *:
818+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(\* \* \*)//"
819+
820+ # Remove ## CLI heading:
821+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/## CLI//"
822+
823+ # Change heading levels:
824+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/###/##/g"
825+
826+ # Append -cli to package name unless it already ends with -cli:
827+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/(?<!\[)($escapedPkg)(?!-cli)/\1-cli/g"
828+
829+ # Insert a link to the main package:
830+ find ./cli -type f -name '*.md' -print0 | xargs -0 perl -0777 -i -pe "s/<section class=\"related\">(?:\n\n\* \* \*\n\n## See Also\n\n)?/<section class=\"related\">\n\n## See Also\n\n- <span class=\"package-name\">[\`$escapedPkg\`][$escapedPkg]<\/span><span class=\"delimiter\">: <\/span><span class=\"description\">$pkgDescription<\/span>\n/"
831+
832+ # Create package.json file for cli branch:
833+ jq --indent 2 '.name = .name + "-cli" | {"name": .name, "version": .version, "description": .description, "license": .license, "author": .author, "contributors": .contributors, "bin": .bin, "homepage": .homepage, "repository": .repository, "bugs": .bugs, "dependencies": .dependencies, "devDependencies": .devDependencies, "keywords": .keywords, "funding": .funding}' package.json > ./cli/package.json
834+
835+ # Add implementation package as dependency:
836+ version=$(npm view "$pkg" version)
837+ jq --indent 2 ".dependencies[\"$pkg\"] = \"$version\"" ./cli/package.json > ./cli/package.json.tmp
838+ mv ./cli/package.json.tmp ./cli/package.json
839+
840+ # Rewrite require of main module in bin/cli to depend on external package:
841+ perl -0777 -i -pe "s/require\( \'\.\/\.\.\/lib\' \)/require\( \'$escapedPkg\' \)/" ./cli/bin/cli
842+
843+ # For all dependencies, check if they are required by the CLI; if not, remove them:
844+ jq -r '.dependencies | keys[]' ./cli/package.json | while read -r dep; do
845+ dep=$(echo "$dep" | xargs)
846+ if ! grep -q "$dep" ./cli/test/** && ! grep -q "$dep" ./cli/bin/**; then
847+ jq --indent 2 "del(.dependencies[\"$dep\"])" ./cli/package.json > ./cli/package.json.tmp
848+ mv ./cli/package.json.tmp ./cli/package.json
849+ fi
850+ done
851+ jq -r '.devDependencies | keys[]' ./cli/package.json | while read -r dep; do
852+ if [[ "$dep" != "@stdlib"* ]]; then
853+ continue
854+ fi
855+ dep=$(echo "$dep" | xargs)
856+ if ! grep -q "$dep" ./cli/test/** && ! grep -q "$dep" ./cli/bin/**; then
857+ jq --indent 2 "del(.devDependencies[\"$dep\"])" ./cli/package.json > ./cli/package.json.tmp
858+ mv ./cli/package.json.tmp ./cli/package.json
859+ fi
860+ done
861+
862+ # Delete everything in current directory aside from cli folder:
863+ - name : ' Delete everything in current directory aside from cli folder'
864+ run : |
865+ find . -type 'f' | grep -v -e "cli" -e ".git/" | xargs -r rm
866+ find . -mindepth 1 -type 'd' | grep -v -e "cli" -e ".git" | xargs -r rm -rf
867+
868+ # Move cli directory to root:
869+ - name : ' Move cli directory to root'
870+ run : |
871+ mv ./cli/* .
872+ rmdir ./cli
873+
874+ # Commit changes:
875+ - name : ' Commit changes'
876+ run : |
877+ git add -A
878+ git commit -m "Auto-generated commit"
879+
880+ # Push changes to `cli` branch:
881+ - name : ' Push changes to `cli` branch'
882+ run : |
883+ SLUG=${{ github.repository }}
884+ echo "Pushing changes to $SLUG..."
885+ git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$SLUG.git" cli
886+
887+ # Send status to Slack channel if job fails:
888+ - name : ' Send status to Slack channel in case of failure'
889+ uses : act10ns/slack@v1
890+ with :
891+ status : ${{ job.status }}
892+ steps : ${{ toJson(steps) }}
893+ channel : ' #npm-ci'
894+ if : failure()
895+
700896 # Define job that succeeds if all bundles were successfully built:
701897 create-tag-bundles :
702898
@@ -707,7 +903,7 @@ jobs:
707903 runs-on : ubuntu-latest
708904
709905 # Indicate that this job depends on the bundle jobs finishing:
710- needs : [ deno, umd, esm ]
906+ needs : [ deno, umd, esm, cli ]
711907
712908 # Define the steps to be executed:
713909 steps :
@@ -789,3 +985,23 @@ jobs:
789985 git add README.md
790986 git commit -m "Auto-generated commit"
791987 git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$SLUG.git" esm
988+
989+ git checkout -b cli origin/cli
990+ sed -i -E "s/$ESCAPED/$ESCAPED@$VERSION/g" README.md
991+ git add README.md
992+ git commit -m "Update README.md for CLI branch $VERSION"
993+ git tag -a $VERSION-cli -m "$VERSION-cli"
994+ git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$SLUG.git" $VERSION-cli
995+
996+ sed -i -E "s/$ESCAPED@$VERSION/$ESCAPED/g" README.md
997+ git add README.md
998+ git commit -m "Auto-generated commit"
999+ git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$SLUG.git" cli
1000+
1001+ # Run publish workflow for CLI package:
1002+ - name : ' Run publish workflow for CLI package'
1003+ if : steps.check-if-bump.outputs.bump
1004+ env :
1005+ GH_TOKEN : ${{secrets.GITHUB_TOKEN}}
1006+ run : |
1007+ gh workflow run publish_cli.yml
0 commit comments