Update Automation #97
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Automation | |
| on: | |
| # schedule: | |
| # - cron: '0 0 * * *' | |
| workflow_dispatch: | |
| jobs: | |
| update-automation: | |
| name: Run Automation Tasks | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| outputs: | |
| staging-branch: ${{ env.STAGING_BRANCH }} | |
| existing-code-oss-tag: ${{ env.EXISTING_CODE_OSS_TAG }} | |
| latest-code-oss-tag: ${{ env.LATEST_CODE_OSS_TAG }} | |
| steps: | |
| - name: Setup environment | |
| run: | | |
| echo "Installing required dependencies" | |
| sudo apt-get update | |
| sudo apt-get install -y quilt libxml2-utils jq | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Get latest semver branch | |
| run: | | |
| git fetch origin | |
| LATEST_SEMVER=$(git branch -r | grep -E 'origin/[0-9]+\.[0-9]+$' | sed 's/.*origin\///' | sort -V | tail -1) | |
| # For testing purposes | |
| if [ -z "$LATEST_SEMVER" ]; then | |
| LATEST_SEMVER="build-test" | |
| echo "No semver branches found, using main" | |
| fi | |
| echo "LATEST_SEMVER=$LATEST_SEMVER" >> $GITHUB_ENV | |
| echo "Using branch: $LATEST_SEMVER" | |
| git checkout "$LATEST_SEMVER" | |
| git submodule update --init --recursive | |
| - name: Check if update needed | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| cd third-party-src | |
| git fetch --tags | |
| EXISTING_CODE_OSS_TAG=$(git describe --tags --exact-match HEAD 2>/dev/null | head -1) | |
| if [ -z "$EXISTING_CODE_OSS_TAG" ]; then | |
| echo "Error: Submodule is not on a tagged commit" | |
| exit 1 | |
| fi | |
| cd .. | |
| LATEST_CODE_OSS_TAG=$(gh api repos/microsoft/vscode/releases/latest --template '{{.tag_name}}') | |
| echo "EXISTING_CODE_OSS_TAG=$EXISTING_CODE_OSS_TAG" >> $GITHUB_ENV | |
| echo "LATEST_CODE_OSS_TAG=$LATEST_CODE_OSS_TAG" >> $GITHUB_ENV | |
| echo "Existing tag: $EXISTING_CODE_OSS_TAG" | |
| echo "Latest tag: $LATEST_CODE_OSS_TAG" | |
| if [ "$EXISTING_CODE_OSS_TAG" = "$LATEST_CODE_OSS_TAG" ]; then | |
| echo "Submodule is up to date with latest VS Code release" | |
| exit 0 | |
| else | |
| echo "Update needed: $EXISTING_CODE_OSS_TAG -> $LATEST_CODE_OSS_TAG" | |
| # Create or checkout staging branch | |
| STAGING_BRANCH="staging-code-editor-$LATEST_CODE_OSS_TAG" | |
| if git show-ref --verify --quiet refs/remotes/origin/"$STAGING_BRANCH"; then | |
| echo "Staging branch $STAGING_BRANCH already exists, checking it out" | |
| git checkout -b "$STAGING_BRANCH" origin/"$STAGING_BRANCH" | |
| else | |
| echo "Creating new staging branch: $STAGING_BRANCH" | |
| git checkout -b "$STAGING_BRANCH" | |
| fi | |
| # Update submodule to latest VS Code release | |
| echo "Updating submodule to $LATEST_CODE_OSS_TAG" | |
| cd third-party-src | |
| git fetch --tags | |
| git checkout "$EXISTING_CODE_OSS_TAG" | |
| cd .. | |
| git add third-party-src | |
| if git diff --staged --quiet; then | |
| echo "No changes to commit, submodule already up to date" | |
| git push origin "$STAGING_BRANCH" | |
| else | |
| git commit -m "Update VS Code submodule to $LATEST_CODE_OSS_TAG" | |
| git push origin "$STAGING_BRANCH" | |
| fi | |
| echo "STAGING_BRANCH=$STAGING_BRANCH" >> $GITHUB_ENV | |
| echo "Created staging branch: $STAGING_BRANCH with VS Code $LATEST_CODE_OSS_TAG" | |
| fi | |
| - name: Rebase patches for all targets | |
| run: | | |
| # echo "Rebasing patches for all build targets" | |
| # # Test each target sequentially with rebasing | |
| # FAILED_TARGETS=() | |
| # for target in code-editor-server code-editor-sagemaker-server code-editor-web-embedded code-editor-web-embedded-with-terminal; do | |
| # echo "" | |
| # echo "=== REBASING TARGET: $target ===" | |
| # if ./scripts/prepare-src.sh --command rebase_patches "$target"; then | |
| # echo "Successfully rebased $target" | |
| # else | |
| # echo "Failed to rebase $target" | |
| # FAILED_TARGETS+=("$target") | |
| # fi | |
| # # Clean up for next target | |
| # rm -rf code-editor-src | |
| # echo "=== END TARGET: $target ===" | |
| # done | |
| # # Report results | |
| # if [ ${#FAILED_TARGETS[@]} -gt 0 ]; then | |
| # echo "Failed targets: ${FAILED_TARGETS[*]}" | |
| # exit 1 | |
| # else | |
| # echo "All targets rebased successfully" | |
| # fi | |
| # # Commit rebased patches if any changes | |
| # git add patches/ | |
| # if ! git diff --staged --quiet; then | |
| # git commit -m "Rebase patches for all targets" | |
| # git push origin "$STAGING_BRANCH" | |
| # fi | |
| build-and-update-package-locks: | |
| name: Build and Update Package Lock Overrides | |
| runs-on: ubuntu-latest | |
| needs: update-automation | |
| if: needs.update-automation.outputs.staging-branch != '' | |
| permissions: | |
| contents: write | |
| strategy: | |
| matrix: | |
| target: [code-editor-server, code-editor-sagemaker-server, code-editor-web-embedded, code-editor-web-embedded-with-terminal] | |
| steps: | |
| - name: Setup environment | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y quilt libxml2-utils jq libx11-dev libxkbfile-dev | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.update-automation.outputs.staging-branch }} | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Build target | |
| run: | | |
| ./scripts/prepare-src.sh "${{ matrix.target }}" | |
| cd code-editor-src | |
| npm install | |
| cd .. | |
| # ./scripts/build-artifacts.sh ${{ matrix.target }} | |
| echo "Built target: ${{ matrix.target }}" | |
| - name: Update package-lock for target | |
| run: | | |
| OVERRIDE_PATH=$(jq -r '."package-lock-overrides".path' "configuration/${{ matrix.target }}.json") | |
| rm -rf "$OVERRIDE_PATH" | |
| mkdir -p "$OVERRIDE_PATH" | |
| find code-editor-src -name "package-lock.json" -type f | while read -r file; do | |
| rel_path="${file#code-editor-src/}" | |
| third_party_file="third-party-src/$rel_path" | |
| if [ ! -f "$third_party_file" ] || ! cmp -s "$file" "$third_party_file"; then | |
| dest_dir="$OVERRIDE_PATH/$(dirname "$rel_path")" | |
| mkdir -p "$dest_dir" | |
| cp "$file" "$dest_dir/" | |
| echo "Copied updated $rel_path to $OVERRIDE_PATH" | |
| fi | |
| done | |
| - name: Upload prepared source as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ github.run_id }}-prepared-source-${{ matrix.target }} | |
| path: code-editor-src/ | |
| retention-days: 1 | |
| - name: Commit package-lock overrides | |
| run: | | |
| git add package-lock-overrides/ | |
| if ! git diff --staged --quiet; then | |
| git commit -m "Update package-lock.json overrides for ${{ matrix.target }}" | |
| # Retry push with rebase until successful | |
| for i in {1..5}; do | |
| if git pull --rebase origin "${{ needs.update-automation.outputs.staging-branch }}" && git push origin "${{ needs.update-automation.outputs.staging-branch }}"; then | |
| break | |
| fi | |
| sleep $((i * 2)) | |
| done | |
| fi | |
| generate-oss-attribution: | |
| name: Generate OSS Attribution | |
| runs-on: ubuntu-latest | |
| needs: [update-automation, build-and-update-package-locks] | |
| if: needs.update-automation.outputs.staging-branch != '' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Setup environment | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y jq | |
| npm i -g license-checker | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.update-automation.outputs.staging-branch }} | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Download prepared sources from artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: ${{ github.run_id }}-prepared-source-* | |
| merge-multiple: false | |
| - name: Organize downloaded sources | |
| run: | | |
| for target in code-editor-server code-editor-sagemaker-server code-editor-web-embedded code-editor-web-embedded-with-terminal; do | |
| if [[ -d "${{ github.run_id }}-prepared-source-$target" ]]; then | |
| mv "${{ github.run_id }}-prepared-source-$target" "code-editor-src-$target" | |
| echo "Organized prepared source for $target" | |
| else | |
| echo "Missing prepared source artifact for target: $target" | |
| exit 1 | |
| fi | |
| done | |
| - name: Generate unified OSS attribution | |
| run: | | |
| ./scripts/generate-oss-attribution.sh --command generate_unified_oss_attribution | |
| - name: Commit OSS attribution | |
| run: | | |
| # Copy LICENSE-THIRD-PARTY to root directory | |
| cp overrides/LICENSE-THIRD-PARTY LICENSE-THIRD-PARTY | |
| git add overrides/ LICENSE-THIRD-PARTY | |
| if ! git diff --staged --quiet; then | |
| git commit -m "Update unified OSS attribution" | |
| git push origin "${{ needs.update-automation.outputs.staging-branch }}" | |
| fi | |
| - name: Clean up prepared source directories | |
| run: | | |
| rm -rf code-editor-src-* | |
| echo "Cleaned up local prepared source directories" | |
| create-pr: | |
| name: Create Pull Request | |
| runs-on: ubuntu-latest | |
| needs: [update-automation, build-and-update-package-locks, generate-oss-attribution] | |
| if: needs.update-automation.outputs.staging-branch != '' | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.update-automation.outputs.staging-branch }} | |
| fetch-depth: 0 | |
| - name: Determine target branch and create PR | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Check if PR already exists for this staging branch | |
| EXISTING_PR=$(gh pr list --head "${{ needs.update-automation.outputs.staging-branch }}" --json number --jq '.[0].number' || echo "") | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "PR already exists for branch ${{ needs.update-automation.outputs.staging-branch }}: #$EXISTING_PR" | |
| exit 0 | |
| fi | |
| EXISTING_CODE_OSS_TAG="${{ needs.update-automation.outputs.initial-tag }}" | |
| LATEST_CODE_OSS_TAG="${{ needs.update-automation.outputs.current-tag }}" | |
| # Parse version numbers | |
| EXISTING_CODE_OSS_MAJOR=$(echo "$EXISTING_CODE_OSS_TAG" | cut -d. -f1) | |
| EXISTING_CODE_OSS_MINOR=$(echo "$EXISTING_CODE_OSS_TAG" | cut -d. -f2) | |
| LATEST_CODE_OSS_MAJOR=$(echo "$LATEST_CODE_OSS_TAG" | cut -d. -f1) | |
| LATEST_CODE_OSS_MINOR=$(echo "$LATEST_CODE_OSS_TAG" | cut -d. -f2) | |
| git fetch origin | |
| LATEST_SEMVER=$(git branch -r | grep -E 'origin/[0-9]+\.[0-9]+$' | sed 's/.*origin\///' | sort -V | tail -1) | |
| if [ -n "$LATEST_SEMVER" ]; then | |
| LATEST_MAJOR=$(echo "$LATEST_SEMVER" | cut -d. -f1) | |
| LATEST_MINOR=$(echo "$LATEST_SEMVER" | cut -d. -f2) | |
| else | |
| LATEST_MAJOR=0 | |
| LATEST_MINOR=0 | |
| fi | |
| # Determine if this is a patch or minor/major update | |
| if [ "$LATEST_CODE_OSS_MAJOR" = "$EXISTING_CODE_OSS_MAJOR" ] && [ "$LATEST_CODE_OSS_MINOR" = "$EXISTING_CODE_OSS_MINOR" ]; then | |
| # Patch update - use existing branch | |
| TARGET_BRANCH="$LATEST_SEMVER" | |
| echo "Patch update detected: targeting existing branch $TARGET_BRANCH" | |
| else | |
| # Minor/major update - create new branch | |
| LATEST_MAJOR=$(echo "$LATEST_SEMVER" | cut -d. -f1) | |
| LATEST_MINOR=$(echo "$LATEST_SEMVER" | cut -d. -f2) | |
| NEW_MINOR=$((LATEST_MINOR + 1)) | |
| TARGET_BRANCH="$LATEST_MAJOR.$NEW_MINOR" | |
| echo "Minor/major update detected: targeting new branch $TARGET_BRANCH" | |
| # Create new version branch if it doesn't exist | |
| if ! git show-ref --verify --quiet refs/remotes/origin/"$TARGET_BRANCH"; then | |
| echo "Creating new version branch: $TARGET_BRANCH" | |
| git checkout -b "$TARGET_BRANCH" "origin/$LATEST_SEMVER" | |
| git push origin "$TARGET_BRANCH" | |
| fi | |
| fi | |
| # Get release body and generate links | |
| RELEASE_BODY=$(gh api repos/microsoft/vscode/releases/tags/$LATEST_CODE_OSS_TAG --template '{{.body}}') | |
| VERSION_NUMBER=$(echo "$LATEST_CODE_OSS_TAG" | cut -d. -f1,2 | sed 's/\./\_/g') | |
| VSCODE_RELEASE_NOTES="https://code.visualstudio.com/updates/v$VERSION_NUMBER" | |
| # Create PR | |
| PR_TITLE="Update VS Code to $LATEST_CODE_OSS_TAG" | |
| PR_BODY="## Automated update of VS Code submodule to version $LATEST_CODE_OSS_TAG | |
| Changes: | |
| - Updated third-party-src submodule to $LATEST_CODE_OSS_TAG | |
| - Rebased patches for all targets | |
| - Updated package-lock.json overrides | |
| - Updated OSS attribution | |
| ## Release Notes | |
| [VS Code Release Notes]($VSCODE_RELEASE_NOTES) | |
| ### Code-OSS Release Details | |
| $RELEASE_BODY | |
| ## Review Notes | |
| Please review the release notes above for: | |
| - Breaking changes | |
| - Changes in default behavior | |
| - Newly introduced features that may need to be disabled/modified | |
| - Remote extension host changes | |
| ## Next Steps | |
| After this PR is merged, a release can be created by following the guide in [RELEASE.md](RELEASE.md)." | |
| gh pr create \ | |
| --title "$PR_TITLE" \ | |
| --body "$PR_BODY" \ | |
| --base "$TARGET_BRANCH" \ | |
| --head "${{ needs.update-automation.outputs.staging-branch }}" | |
| echo "Created PR from ${{ needs.update-automation.outputs.staging-branch }} to $TARGET_BRANCH" | |
| handle-failures: | |
| name: Handle Failures | |
| runs-on: ubuntu-latest | |
| needs: [update-automation, build-and-update-package-locks, generate-oss-attribution, create-pr] | |
| if: failure() | |
| steps: | |
| - name: Report rebase failures | |
| run: | | |
| # TODO: Implement metric reporting to CW. | |
| exit 1 |