diff --git a/.github/workflows/experiment.yml b/.github/workflows/experiment.yml new file mode 100644 index 00000000..d302f4ea --- /dev/null +++ b/.github/workflows/experiment.yml @@ -0,0 +1,226 @@ +name: publish-package-to-npm +on: + workflow_call: + inputs: + code-analyzer-core: + description: Should the code-analyzer-core package be released? + type: boolean + required: false + default: false + code-analyzer-engine-api: + description: Should the code-analyzer-engine-api package be released? + type: boolean + required: false + default: false + code-analyzer-eslint-engine: + description: Should the code-analyzer-eslint-engine package be released? + type: boolean + required: false + default: false + code-analyzer-flowtest-engine: + description: Should the code-analyzer-flowtest-engine package be released? + type: boolean + required: false + default: false + code-analyzer-pmd-engine: + description: Should the code-analyzer-pmd-engine package be released? + type: boolean + required: false + default: false + code-analyzer-regex-engine: + description: Should the code-analyzer-regex-engine package be released? + type: boolean + required: false + default: false + code-analyzer-retirejs-engine: + description: Should the code-analyzer-retirejs-engine package be released? + type: boolean + required: false + default: false + dryrun: + description: Add --dry-run to npm publish step? (Uncheck to actually publish) + type: boolean + required: false + default: true + +defaults: + run: + shell: bash + +jobs: + validate-packages-as-releasable: + runs-on: macos-latest + outputs: + packages-to-release: ${{ steps.main.outputs.packages_to_release }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + - name: Verify to-be-released packages are SNAPSHOT-versioned + id: main + run: | + PACKAGES_TO_CHECK_ARR=() + # ENGINE API GETS CHECKED FIRST, BECAUSE IT MUST PUBLISH FIRST + if [ "${{ inputs.code-analyzer-engine-api }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-engine-api') + fi + if [ "${{ inputs.code-analyzer-core }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-core') + fi + if [ "${{ inputs.code-analyzer-eslint-engine }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-eslint-engine') + fi + if [ "${{ inputs.code-analyzer-flowtest-engine }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-flowtest-engine') + fi + if [ "${{ inputs.code-analyzer-pmd-engine }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-pmd-engine') + fi + if [ "${{ inputs.code-analyzer-regex-engine }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-regex-engine') + fi + if [ "${{ inputs.code-analyzer-retirejs-engine }}" == "true" ]; then + PACKAGES_TO_CHECK_ARR+=('code-analyzer-retirejs-engine') + fi + PACKAGES_TO_CHECK_STR=$(IFS=' '; echo "${PACKAGES_TO_CHECK_ARR[*]}") + node ./.github/workflows/publish-package-to-npm/validate-packages-as-releasable.js "$PACKAGES_TO_CHECK_STR" + echo "packages_to_release=$PACKAGES_TO_CHECK_STR" >> "$GITHUB_OUTPUT" + prepare-release-branch: + runs-on: macos-latest + env: + GH_TOKEN: ${{ github.token }} + permissions: + contents: write + needs: validate-packages-as-releasable + outputs: + branch-name: ${{ steps.create-release-branch.outputs.branch_name }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + - name: Create release branch + id: create-release-branch + run: | + NOW_TIMESTAMP=$(date +%s) + git checkout -b release/$NOW_TIMESTAMP + # Immediately push the branch with no changes, so GraphQL can push to it later. + git push --set-upstream origin release/$NOW_TIMESTAMP + # Output the branch name so that it can be used later. + echo "branch_name=release/$NOW_TIMESTAMP" >> "$GITHUB_OUTPUT" + - name: Strip '-SNAPSHOT' from to-be-released package versions + run: | + PACKAGE_NAMES_STRING="${{ needs.validate-packages-as-releasable.outputs.packages-to-release }}" + node ./.github/workflows/publish-package-to-npm/update-versions-in-released-packages.js "$PACKAGE_NAMES_STRING" + - name: Update inter-package dependencies + run: | + PACKAGES_TO_RELEASE_STRING="${{ needs.validate-packages-as-releasable.outputs.packages-to-release }}" + cd packages + ALL_PACKAGES=`ls` + cd .. + node ./.github/workflows/publish-package-to-npm/update-dependencies-on-released-packages.js "$PACKAGES_TO_RELEASE_STRING" "$ALL_PACKAGES" + - name: Build + run: | + npm install + npm run build + # No need to test; that comes later. + - name: Commit changes to release branch + run: | + # GraphQL needs to know what branch to push to. + BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) + # GraphQL needs a message for the commit. + MESSAGE="Preparing Core Ecosystem for release" + # GraphQL needs the latest versions of all the package.json files, as Base64 encoded strings. + CORE_PACKAGE_JSON="$(cat packages/code-analyzer-core/package.json | base64)" + API_PACKAGE_JSON="$(cat packages/code-analyzer-engine-api/package.json | base64)" + ESLINT_PACKAGE_JSON="$(cat packages/code-analyzer-eslint-engine/package.json | base64)" + FLOWTEST_PACKAGE_JSON="$(cat packages/code-analyzer-flowtest-engine/package.json | base64)" + PMD_PACKAGE_JSON="$(cat packages/code-analyzer-pmd-engine/package.json | base64)" + REGEX_PACKAGE_JSON="$(cat packages/code-analyzer-regex-engine/package.json | base64)" + RETIREJS_PACKAGE_JSON="$(cat packages/code-analyzer-retirejs-engine/package.json | base64)" + TEMPLATE_PACKAGE_JSON="$(cat packages/T-E-M-P-L-A-T-E/package.json | base64)" + # GraphQL also needs the top-level package-lock.json + PACKAGE_LOCK_JSON="$(cat package-lock.json | base64)" + + gh api graphql -F message="$MESSAGE" -F oldOid=`git rev-parse HEAD` -F branch="$BRANCH_NAME" \ + -F corePackage="$CORE_PACKAGE_JSON" \ + -F apiPackage="$API_PACKAGE_JSON" \ + -F eslintPackage="$ESLINT_PACKAGE_JSON" \ + -F flowtestPackage="$FLOWTEST_PACKAGE_JSON" \ + -F pmdPackage="$PMD_PACKAGE_JSON" \ + -F regexPackage="$REGEX_PACKAGE_JSON" \ + -F retirejsPackage="$RETIREJS_PACKAGE_JSON" \ + -F templatePackage="$TEMPLATE_PACKAGE_JSON" \ + -F packageLock="$PACKAGE_LOCK_JSON" \ + -f query=' + mutation ($message: String!, $oldOid: GitObjectID!, $branch: String!, + $corePackage: Base64String!, $apiPackage: Base64String!, $eslintPackage: Base64String!, + $flowtestPackage: Base64String!, $pmdPackage: Base64String!, $regexPackage: Base64String!, + $retirejsPackage: Base64String!, $templatePackage: Base64String!, $packageLock: Base64String!) { + createCommitOnBranch(input: { + branch: { + repositoryNameWithOwner: "forcedotcom/code-analyzer-core", + branchName: $branch + }, + message: { + headline: $message + }, + fileChanges: { + additions: [ + { + path: "packages/code-analyzer-core/package.json", + contents: $corePackage + }, { + path: "packages/code-analyzer-engine-api/package.json", + contents: $apiPackage + }, { + path: "packages/code-analyzer-eslint-engine/package.json", + contents: $eslintPackage + }, { + path: "packages/code-analyzer-flowtest-engine/package.json", + contents: $flowtestPackage + }, { + path: "packages/code-analyzer-pmd-engine/package.json", + contents: $pmdPackage + }, { + path: "packages/code-analyzer-regex-engine/package.json", + contents: $regexPackage + }, { + path: "packages/code-analyzer-retirejs-engine/package.json", + contents: $retirejsPackage + }, { + path: "packages/T-E-M-P-L-A-T-E/package.json", + contents: $templatePackage + }, { + path: "package-lock.json", + contents: $packageLock + } + ] + }, + expectedHeadOid: $oldOid + }) { + commit { + id + } + } + }' + create-postrelease-pull-request: + runs-on: macos-latest + needs: [prepare-release-branch] + if: ${{ inputs.dryrun == false }} # A Dry Run doesn't release, so no PR should be made + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.prepare-release-branch.outputs.branch-name }} + - run: | + echo -e "This branch and PR were automatically created as part of a Package Publish.\n\ + The branch increments the .version property of published packages from X.Y.Z-SNAPSHOT to X.Y.Z, and updates any\ + inter-package dependencies appropriately.\n\ + The narrow scope of these changes makes a merge conflict unlikely, but if one does occur, you should consult\ + with the author of the conflicting change and decide what to do next. Ultimately it may make sense to not merge\ + this pull request at all. Use your judgment." > body.txt + gh pr create -B dev -H ${{ needs.prepare-release-branch.outputs.branch-name }} --title "POSTRELEASE @W-XXXXXXXX@ Merging after ecosystem release" -F body.txt diff --git a/.github/workflows/verify-pr.yml b/.github/workflows/verify-pr.yml index 3568e10e..b9ff3549 100644 --- a/.github/workflows/verify-pr.yml +++ b/.github/workflows/verify-pr.yml @@ -79,4 +79,8 @@ jobs: with: python-version: 3.12 - run: npm install - - run: npm run all \ No newline at end of file + - run: npm run all + run_experiment: + uses: ./.github/workflows/experiment.yml + with: + code-analyzer-core: true \ No newline at end of file