-
Notifications
You must be signed in to change notification settings - Fork 66
[chores] Add process for first-time package publishing #2055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bcb6367
3a0e179
af0ad1d
ef19812
0f96c7e
59955fe
1b58d6f
b5b1f58
0d10074
4880c9c
d91da28
f77411e
67e4e19
918c36f
d02698b
ea53ee5
aefdd28
cb9e936
251d8d4
9c59805
4b54a3a
b3158ff
c2adc0d
1dfd4e4
ada3efa
7ad9a71
1256623
573c719
48d387f
af78369
55cc372
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,15 +3,34 @@ name: Publish package on NPM | |
| on: | ||
| push: | ||
| tags: | ||
| - v* # Any version tag | ||
| - 'v[0-9]+.[0-9]+.[0-9]+' | ||
|
|
||
| permissions: | ||
| id-token: write # To publish on NPM with provenance and to federate tokens | ||
| id-token: write # For OIDC publishing with provenance and to federate tokens | ||
| contents: write # Required for the draft release | ||
|
|
||
| jobs: | ||
| pre-release-checks: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| pull-requests: write | ||
| steps: | ||
| - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | ||
| - name: Install node | ||
| uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 | ||
| with: | ||
| node-version: 22.19.0 | ||
| - name: Install project dependencies | ||
| run: yarn install --immutable --mode=skip-build | ||
| - name: Check NPM packages | ||
| run: yarn check-npm-packages | ||
| env: | ||
| # Used to post comments on the PR | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| create-draft-release: | ||
| runs-on: ubuntu-latest | ||
| needs: pre-release-checks | ||
| outputs: | ||
| release-id: ${{ steps.draft-release.outputs.result }} | ||
| steps: | ||
|
|
@@ -258,11 +277,11 @@ jobs: | |
| - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | ||
| - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 | ||
| with: | ||
| node-version: 24.11.1 # Version supporting OIDC | ||
| registry-url: "https://registry.npmjs.org" | ||
| node-version: '24' # Needed for OIDC publishing | ||
| registry-url: 'https://registry.npmjs.org' | ||
|
Comment on lines
+280
to
+281
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just cosmetic changes to follow https://docs.npmjs.com/trusted-publishers#automatic-provenance-generation more closely. |
||
| - run: yarn install --immutable | ||
| - run: yarn build | ||
| - run: yarn publish:all | ||
| - run: yarn publish:all --provenance | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reintroduced
|
||
|
|
||
| bump-ci-integrations: | ||
| name: Bump datadog-ci in integration | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # This script checks if all local packages are published to NPM. | ||
| # It can also first-time publish missing packages when run with --fix. | ||
| # | ||
| # Usage: | ||
| # ./bin/check-npm-packages.sh # Check mode (default) - exits 1 if packages are missing | ||
| # ./bin/check-npm-packages.sh --fix # Fix mode - publishes missing packages | ||
| # ./bin/check-npm-packages.sh --fix --dry-run # Fix mode with dry-run - simulates publishing | ||
|
|
||
| MODE="check" | ||
| DRY_RUN=false | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case $1 in | ||
| --fix) | ||
| MODE="fix" | ||
| shift | ||
| ;; | ||
| --dry-run) | ||
| DRY_RUN=true | ||
| shift | ||
| ;; | ||
| -*) | ||
| echo "Unknown option: $1" | ||
| echo "Usage: $0 [--fix] [--dry-run]" | ||
| exit 1 | ||
| ;; | ||
| *) | ||
| echo "Unknown argument: $1" | ||
| echo "Usage: $0 [--fix] [--dry-run]" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| if [ "$DRY_RUN" = true ] && [ "$MODE" != "fix" ]; then | ||
| echo "Error: --dry-run can only be used with --fix" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Colors | ||
| BOLD='\033[1m' | ||
| GREEN='\033[0;32m' | ||
| BLUE='\033[0;34m' | ||
| RED='\033[0;31m' | ||
| NC='\033[0m' | ||
|
|
||
| echo -e "${BOLD}Checking for unpublished packages...${NC}" | ||
| echo | ||
|
|
||
| # Get local and remote packages | ||
| local_packages=$(yarn workspaces list --json --no-private | jq -r '.name' | sort) | ||
| remote_packages=$(npm search 'maintainer:datadog keywords:datadog-ci' --json | jq -r '.[].name' | sort) | ||
|
|
||
| # Find packages that exist locally but not on NPM | ||
| missing_packages=() | ||
| while IFS= read -r pkg; do | ||
| if [ -n "$pkg" ] && ! echo "$remote_packages" | grep -q "^${pkg}$"; then | ||
| missing_packages+=("$pkg") | ||
| fi | ||
| done <<< "$local_packages" | ||
|
|
||
| # Exit early if everything is good | ||
| if [ ${#missing_packages[@]} -eq 0 ]; then | ||
| echo -e "${GREEN}All local packages exist on NPM ✅${NC}" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Otherwise, report missing packages | ||
| echo -e "${RED}The following packages are not published to NPM yet:${NC}" | ||
| for pkg in "${missing_packages[@]}"; do | ||
| echo " - $pkg" | ||
| done | ||
|
|
||
| # In CI environment, post a comment on the PR | ||
| if [ -n "${GITHUB_TOKEN:-}" ] && [ -n "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_SHA:-}" ]; then | ||
| # Get the PR number and author associated with this commit | ||
| PR_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ | ||
| "https://api.github.com/repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/pulls") | ||
|
|
||
| PR_NUMBER=$(echo "$PR_RESPONSE" | jq -r '.[0].number // empty') | ||
| PR_AUTHOR=$(echo "$PR_RESPONSE" | jq -r '.[0].user.login // empty') | ||
|
|
||
| DIFF_OUTPUT=$(diff -u --label "Published packages (Actual)" --label "Local packages (Expected)" \ | ||
| <(echo "$remote_packages") <(echo "$local_packages")) || true | ||
|
|
||
| COMMENT_BODY="### Some packages were not first-time published to NPM yet ❌ | ||
|
|
||
| \`\`\`diff | ||
| $DIFF_OUTPUT | ||
| \`\`\` | ||
|
|
||
| Hi @$PR_AUTHOR, please **ask an admin** to follow the instructions at https://datadoghq.atlassian.net/wiki/x/QYDRaQE" | ||
|
|
||
| if [ -n "$PR_NUMBER" ]; then | ||
| # Post comment on the PR | ||
| curl -s -X POST \ | ||
| -H "Authorization: token $GITHUB_TOKEN" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| "https://api.github.com/repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \ | ||
| -d "$(jq -n --arg body "$COMMENT_BODY" '{body: $body}')" > /dev/null | ||
|
|
||
| echo -e "${BLUE}Posted comment on PR #$PR_NUMBER (author: @$PR_AUTHOR)${NC}" | ||
| else | ||
| # Fallback when PR is not found | ||
| echo -e "${RED}No PR found for commit $GITHUB_SHA${NC}" | ||
| echo -e "${BLUE}This would be the comment body:${NC}" | ||
| echo "$COMMENT_BODY" | ||
| fi | ||
| fi | ||
|
|
||
| # Do not continue if we are in check mode | ||
| if [ "$MODE" = "check" ]; then | ||
| echo | ||
| echo -e "${BOLD}Run with --fix to publish these packages${NC}" | ||
| echo -e "See instructions at ${BLUE}https://datadoghq.atlassian.net/wiki/x/QYDRaQE${NC}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Fix mode - publish missing packages | ||
| echo | ||
| echo -e "${BOLD}Publishing missing packages to NPM...${NC}" | ||
| echo | ||
| echo -e "${BOLD}Please read the instructions${NC} at ${BLUE}https://datadoghq.atlassian.net/wiki/x/QYDRaQE${NC} before proceeding." | ||
| echo | ||
|
|
||
| if [ "$DRY_RUN" = true ]; then | ||
| echo -e "${BOLD}[DRY-RUN]${NC} None of the packages will actually be published." | ||
| echo | ||
| fi | ||
|
|
||
| read -rsp "Enter your NPM auth token: " INIT_NPM_AUTH_TOKEN | ||
| echo | ||
| if [ -z "$INIT_NPM_AUTH_TOKEN" ]; then | ||
| echo "Error: NPM auth token cannot be empty" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Export this for subsequent yarn commands in the script | ||
| export INIT_NPM_AUTH_TOKEN | ||
|
|
||
| # Do not hardcode the token in .yarnrc.yml, it will be read from the environment variable | ||
| yarn config set npmAuthToken '${INIT_NPM_AUTH_TOKEN}' | ||
| echo | ||
|
|
||
| for pkg in "${missing_packages[@]}"; do | ||
| echo -e "${BLUE}Publishing ${BOLD}$pkg${NC}${BLUE}...${NC}" | ||
|
|
||
| # Get the package directory | ||
| pkg_dir=$(yarn workspaces list --json | jq -r "select(.name == \"$pkg\") | .location") | ||
| pkg_json="$pkg_dir/package.json" | ||
|
|
||
| # Save original version | ||
| original_version=$(jq -r .version "$pkg_json") | ||
|
|
||
| # Set version to 0.0.1 for first-time publish | ||
| jq '.version = "0.0.1"' "$pkg_json" | sponge "$pkg_json" | ||
|
|
||
| if [ "$DRY_RUN" = true ]; then | ||
| echo " [DRY-RUN] Would publish $pkg@0.0.1" | ||
| yarn workspace "$pkg" npm publish --dry-run 2>&1 | sed 's/^/ /' | ||
| else | ||
| yarn workspace "$pkg" npm publish 2>&1 | sed 's/^/ /' | ||
| echo -e " ${GREEN}Successfully published $pkg@0.0.1${NC}" | ||
| fi | ||
|
|
||
| # Restore original version | ||
| jq --arg version "$original_version" '.version = $version' "$pkg_json" | sponge "$pkg_json" | ||
| echo | ||
| done | ||
|
|
||
| echo -e "${BOLD}Cleaning up...${NC}" | ||
| yarn config unset npmAuthToken | ||
|
|
||
| echo | ||
| if [ "$DRY_RUN" = true ]; then | ||
| echo -e "${GREEN}[DRY-RUN] Would have published ${#missing_packages[@]} package(s)${NC}" | ||
| else | ||
| echo -e "${GREEN}Successfully published ${#missing_packages[@]} package(s)${NC}" | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| SCOPE="" | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case $1 in | ||
| -*) | ||
| echo "Unknown option: $1" | ||
| echo "Usage: $0 <scope>" | ||
| exit 1 | ||
| ;; | ||
| *) | ||
| SCOPE="$1" | ||
| shift | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| if [ -z "$SCOPE" ]; then | ||
| echo "Usage: $0 <scope>" | ||
| exit 1 | ||
| fi | ||
| PLUGIN_PKG="@datadog/datadog-ci-plugin-$SCOPE" | ||
| PLUGIN_DIR="packages/plugin-$SCOPE" | ||
|
|
||
| if [ -d "$PLUGIN_DIR" ]; then | ||
| echo "Plugin directory $PLUGIN_DIR already exists!" | ||
| echo "This script should only be run once per scope, before migrate.sh" | ||
| exit 1 | ||
| fi | ||
|
|
||
| BOLD='\033[1m' | ||
| GREEN='\033[0;32m' | ||
| BLUE='\033[0;34m' | ||
| NC='\033[0m' # No Color | ||
|
|
||
| echo -e "This script will initialize an empty package for ${BLUE}${BOLD}$PLUGIN_PKG${NC}" | ||
| echo | ||
|
|
||
| echo -e "${BOLD}1. Creating plugin directory structure${NC}" | ||
| mkdir -p "$PLUGIN_DIR" | ||
| env cp LICENSE "$PLUGIN_DIR" | ||
| echo "Empty package" > "$PLUGIN_DIR/README.md" | ||
| cat > "$PLUGIN_DIR/package.json" <<EOF | ||
| { | ||
| "name": "$PLUGIN_PKG", | ||
| "version": "$(jq -r .version packages/base/package.json)", | ||
| "description": "Datadog CI plugin for \`$SCOPE\` commands", | ||
| "license": "Apache-2.0", | ||
| "keywords": [ | ||
| "datadog", | ||
| "datadog-ci", | ||
| "plugin" | ||
| ], | ||
| "homepage": "https://github.com/DataDog/datadog-ci/tree/master/$PLUGIN_DIR", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/DataDog/datadog-ci.git", | ||
| "directory": "$PLUGIN_DIR" | ||
| }, | ||
| "exports": { | ||
| "./package.json": "./package.json", | ||
| "./commands/*": { | ||
| "development": "./src/commands/*.ts", | ||
| "default": "./dist/commands/*.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist/**/*", | ||
| "README", | ||
| "LICENSE" | ||
| ], | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "scripts": { | ||
| "build": "yarn package:clean; yarn package:build", | ||
| "lint": "yarn package:lint", | ||
| "prepack": "yarn package:clean-dist" | ||
| }, | ||
| "peerDependencies": { | ||
| "@datadog/datadog-ci-base": "workspace:*" | ||
| } | ||
| } | ||
| EOF | ||
|
|
||
| echo -e "${BOLD}2. Running yarn install${NC}" | ||
| yarn install 2>&1 | sed 's/^/ /' | ||
|
|
||
| echo | ||
| echo -e "${GREEN}Package created successfully${NC}" | ||
|
|
||
| echo | ||
| echo -e "${BLUE}If needed, you can now run: ${BOLD}bin/migrate.sh $SCOPE${NC}" |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example comment: #2061 (comment)