Skip to content

Conversation

@xakraz
Copy link
Contributor

@xakraz xakraz commented Sep 24, 2025

Address #168

@GrantBirki
Copy link
Member

👋 @xakraz hey! I see you are still actively working on this PR. I just merged a pretty large PR that migrates the project from CommonJS to ES modules and it looks like it has caused a lot of merge conflicts on your PR and just wanted to say I am sorry as that is no fun.

@xakraz
Copy link
Contributor Author

xakraz commented Oct 8, 2025

👋 @xakraz hey! I see you are still actively working on this PR. I just merged a pretty large PR that migrates the project from CommonJS to ES modules and it looks like it has caused a lot of merge conflicts on your PR and just wanted to say I am sorry as that is no fun.

Arf, I was almost there 😅
I have 1 last check to do that I was not able to make yesterday.

Nevermind, I will try to update my PR 🤷‍♂️
Thanks for the heads up 🙏

…ent auto unlock feature on pull request closure

- Update the `action.yml` file to include a new `unlock_on_close_mode` input
- Add a new file `unlock-on-close.js` with a function to release locks when a pull request is closed
- Update the `unlock-on-merge.js` file to include a reference to `lock metadata` and other related functions
- Introduce a new function `unlockOnClose` in the `main.js` file to run auto-unlock logic in the `unlock on close` mode
…ut parameter

- Change description of `deployment_task` in `action.yml`
- Modify parsing of task parameter in `src/functions/environment-targets.js`
- Update handling of `deployment_task` in `src/functions/inputs.js`
- Introduce task validation logic in `src/main.js`
@xakraz xakraz force-pushed the feat/deployment-task branch from ff85cc2 to 7c076ab Compare November 8, 2025 18:08
- Fixed ESM import conflicts in src/main.js (added .js extensions)
- Updated all test files to use Vitest (vi) instead of Jest
- Added missing imports in test files
- Mocked actionStatus in environment-targets.test.js
- Regenerated dist files with correct source maps
- All tests passing with 100% coverage
@xakraz xakraz force-pushed the feat/deployment-task branch from 7c076ab to 129fa69 Compare November 8, 2025 18:09
@xakraz xakraz marked this pull request as ready for review November 8, 2025 18:09
@xakraz xakraz requested a review from GrantBirki as a code owner November 8, 2025 18:09
Copilot AI review requested due to automatic review settings November 8, 2025 18:09
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for task-based concurrent deployments to the same environment and introduces an "unlock on close" mode. The key changes enable multiple deployment workflows to run simultaneously against the same environment by using task identifiers (e.g., --task frontend, --task backend), while maintaining separate locks per task. Additionally, it provides a new unlock-on-close mode to automatically release locks when PRs are closed (not merged).

Key Changes:

  • Task parameter support for concurrent deployments with --task flag in PR comments
  • Lock mechanism enhancement to include task identifiers in branch names
  • New unlock-on-close mode for automatic lock cleanup on PR closure

Reviewed Changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/main.js Adds unlock-on-close mode, task validation logic, and passes task parameter through deployment flow
src/functions/lock.js Updates lock branch naming to include task suffix and enhances ownership checks with branch comparison
src/functions/unlock.js Adds task parameter parsing from comments and includes task in lock branch names
src/functions/unlock-on-merge.js Updates to handle multiple lock branches per environment when deployment_task is 'all'
src/functions/unlock-on-close.js New file implementing unlock functionality for closed (non-merged) PRs
src/functions/environment-targets.js Adds task parsing from --task flag in deployment commands
src/functions/deployment.js Updates deployment queries to filter by task parameter
src/functions/valid-deployment-order.js Passes task parameter through to deployment checks
src/functions/post-deploy.js Updates lock function calls with null task parameter
src/functions/inputs.js Adds deployment_task input handling with 'all' or comma-separated list support
action.yml Adds deployment_task and unlock_on_close_mode inputs, plus deployment_task output
tests/*.test.js Comprehensive test coverage for all new task-related functionality

@xakraz
Copy link
Contributor Author

xakraz commented Nov 8, 2025

Hi @GrantBirki 👋🏻

One month later, I finally got time to update my PR 😅

@xakraz
Copy link
Contributor Author

xakraz commented Nov 21, 2025

Hi @GrantBirki ,

Is there something else I should do in order to merge this PR?

@GrantBirki
Copy link
Member

👋 Hey @xakraz, sorry for the delay! I was on holiday pretty much all of November and just got back today. I will try and take a look at this sometime later this week. Thanks!

@xakraz
Copy link
Contributor Author

xakraz commented Nov 24, 2025

Thanks for the reply!

@GrantBirki GrantBirki requested a review from Copilot November 26, 2025 18:29
Copilot finished reviewing on behalf of GrantBirki November 26, 2025 18:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 20 changed files in this pull request and generated no new comments.

@GrantBirki GrantBirki added the enhancement New feature or request label Nov 26, 2025
Copy link
Member

@GrantBirki GrantBirki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xakraz I reviewed these changes and they look phenomenal! This is a massively high quality contribution and is the reason open source makes me so happy. I'm going to merge these changes and do some extensive testing against them to ensure everything is working as expected outside of unit tests.

Once I complete testing, I'll do some maintenance updates and cut a release for you. Thanks! 🙇 ❤️

@GrantBirki GrantBirki merged commit 284ad3e into github:main Nov 26, 2025
4 checks passed
@GrantBirki
Copy link
Member

@xakraz I ran into a few critical issues when testing out these changes so out of an abundance of caution I rolled the changes back out.

I would suggest opening a fresh PR again with these same changes and address a few of the issues and we can try to merge these changes in again.

Here are some details around the issues I ran into when testing.

The first issue was a pretty easy fix, I needed to add the .js extensions in the new unlock-on-close.js file like this:

import {unlock} from './unlock.js'
import {LOCK_METADATA} from './lock-metadata.js'
import {checkLockFile} from './check-lock-file.js'
import {checkBranch} from './lock.js'
import {constructValidBranchName} from './valid-branch-name.js'
import {COLORS} from './colors.js'

I needed to do this otherwise the Action would fail on startup with an error like this:

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/home/runner/work/_actions/github/branch-deploy/fixes/dist/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at eval (eval at 4740 (file:///home/runner/work/_actions/github/branch-deploy/fixes/node_modules/@vercel/ncc/dist/ncc/@@notfound.js:1:1), <anonymous>:1:1)
    at Object.4740 (file:///home/runner/work/_actions/github/branch-deploy/fixes/node_modules/@vercel/ncc/dist/ncc/@@notfound.js:1:1)
    at __nccwpck_require__ (file:///home/runner/work/_actions/github/branch-deploy/fixes/webpack/bootstrap:21:1)
    at file:///home/runner/work/_actions/github/branch-deploy/fixes/dist/index.js:45524:23
    at ModuleJob.run (node:internal/modules/esm/module_job:377:25)
    at onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:691:26)
    at asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Once I got the Action to load correctly, I tried testing out a whole bunch of .deploy, .lock, .wcid and other commands to test out your changes. Everything seemed to work okay from a backwards compatibility perspective but as soon as I added the deployment_task: frontend,backend param it started failing again.

Here are the logs from a failed run: https://github.com/GrantBirki/actions-sandbox/actions/runs/19715041840/job/56485103776

Since Actions logs eventually expire, here they are copy/pasted for future reference:

Main Step:

##[debug]no parameters detected in command
##[debug]using default environment for branch deployment
##[debug]environmentObj: {"environment":"production","environmentUrl":null,"environmentObj":{"target":"production","stable_branch_used":false,"noop":false,"params":null,"parsed_params":null,"sha":null,"task":null}}
🌍 environment: production
##[debug]base_ref: main
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
🟢 the pull request is approved
##[debug]raw admins value: false
##[debug]GrantBirki is not an admin
##[debug]outdated_mode: strict
##[debug]checking isOutdated with strict mode
##[debug]The PR branch is not behind the base branch - OK
##[debug]The PR branch is not behind the base branch - OK
##[debug]precheck values for debugging:
##[debug]reviewDecision: APPROVED
##[debug]mergeStateStatus: CLEAN
##[debug]commitStatus: SUCCESS
##[debug]userIsAdmin: false
##[debug]update_branch: warn
##[debug]skipCi: false
##[debug]skipReviews: false
##[debug]allowForks: true
##[debug]forkBypass: false
##[debug]environment: production
##[debug]outdated: false
##[debug]approvedReviewsCount: 1
✅ PR is approved and all CI checks passed
##[debug]precheckResults.sha: f06d1233e4f89f09e700b036618ab5507dd524f3
##[debug]branch rulesets: [{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":true,"do_not_enforce_on_create":false,"required_status_checks":[{"context":"test1","integration_id":15368}]},"ruleset_source_type":"Repository","ruleset_source":"GrantBirki/actions-sandbox","ruleset_id":2956129},{"type":"deletion","ruleset_source_type":"Repository","ruleset_source":"GrantBirki/actions-sandbox","ruleset_id":2956129},{"type":"pull_request","parameters":{"required_approving_review_count":1,"dismiss_stale_reviews_on_push":true,"required_reviewers":[],"require_code_owner_review":true,"require_last_push_approval":false,"required_review_thread_resolution":false,"automatic_copilot_code_review_enabled":false,"allowed_merge_methods":["merge","squash","rebase"]},"ruleset_source_type":"Repository","ruleset_source":"GrantBirki/actions-sandbox","ruleset_id":2956129},{"type":"required_deployments","parameters":{"required_deployment_environments":["production"]},"ruleset_source_type":"Rep
🔐 branch ruleset checks passed
##[debug]comment_created_at: 2025-11-26T19:20:52Z
##[debug]commit_created_at: 2025-11-26T19:20:49Z
##[debug]verified_at: 2025-11-26T19:20:50Z
##[debug]isVerified: true
##[debug]2025-11-26T19:20:52Z is not older than 2025-11-26T19:20:49Z
🔑 commit signature is valid
##[debug]2025-11-26T19:20:52Z is not older than 2025-11-26T19:20:50Z
🍯 sticky_locks: true
🍯 sticky_locks_for_noop: false
##[debug]🔒 stickyLocks: true
##[debug]💬 leaveComment: false
##[debug]lock() called with ref: birkibirki-non-fork-test
##[debug]lock() called with sticky: true
##[debug]lock() called with environment: production
##[debug]lock() called with detailsOnly: null
##[debug]lock() called with postDeployStep: false
##[debug]lock() called with leaveComment: false
##[debug]lock() called with task: null
##[debug]lock() called with issue_number: 130
##[debug]constructing valid branch name: production
##[debug]constructed valid branch name: production
##[debug]detected lock env: production
##[debug]detected lock global: false
##[debug]constructed lock branch name: production-branch-deploy-lock
##[debug]constructing valid branch name: global-branch-deploy-lock
##[debug]constructed valid branch name: global-branch-deploy-lock
##[debug]checking if lock file exists on branch: global-branch-deploy-lock
##[debug]checkLockFile() error.status: 404
##[debug]🔍 lock file does not exist on branch: global-branch-deploy-lock
##[debug]checking if branch production-branch-deploy-lock exists...
##[debug]branch 'production-branch-deploy-lock' exists
##[debug]constructing valid branch name: production-branch-deploy-lock
##[debug]constructed valid branch name: production-branch-deploy-lock
##[debug]checking if lock file exists on branch: production-branch-deploy-lock
##[debug]checking the owner of the lock...
##[debug]Lock ownership check - sameUser: true, sameBranch: false
##[debug]Current actor: GrantBirki, Lock owner: GrantBirki
##[debug]Current PR: 130, Lock PR: 130
##[debug]Current branch: undefined, Lock branch: birkibirki-non-fork-test
Warning: ⚠️ Same user but different branch - denying lock access
##[debug]no reason detected
##[debug]constructing valid branch name: production
##[debug]constructed valid branch name: production
##[debug]comment body is within length limit
Error: ### ⚠️ Cannot claim deployment lock

Sorry __GrantBirki__, the `production` environment deployment lock is currently claimed by __GrantBirki__

#### Lock Details 🔒


- __Environment__: `production`
- __Branch__: `birkibirki-non-fork-test`
- __PR Number__: `#130`
- __Task__: `N/A`
- __Created At__: `2025-11-26T19:21:02.739Z`
- __Created By__: `GrantBirki`
- __Sticky__: `true`
- __Global__: `false`
- __Comment Link__: [click here](https://github.com/GrantBirki/actions-sandbox/pull/130#issuecomment-3582873490)
- __Lock Link__: [click here](https://github.com/GrantBirki/actions-sandbox/blob/production-branch-deploy-lock/lock.json)

The current lock has been active for `0d:0h:1m:14s`

> If you need to release the lock, please comment `.unlock production`
##[debug]the lock was not claimed as it is owned by GrantBirki
##[debug]Node Action run completed with exit code 1
##[debug]Save intra-action state isPost = true
##[debug]Save intra-action state actionsToken = ***
##[debug]Save intra-action state comment_id = 3582873490
##[debug]Save intra-action state reaction_id = 316392500
##[debug]Save intra-action state params = 
##[debug]Save intra-action state parsed_params = 
##[debug]Save intra-action state environment = production
##[debug]Save intra-action state fork = false
##[debug]Save intra-action state review_decision = APPROVED
##[debug]Save intra-action state approved_reviews_count = 1
##[debug]Save intra-action state ref = birkibirki-non-fork-test
##[debug]Save intra-action state sha = f06d1233e4f89f09e700b036618ab5507dd524f3
##[debug]Save intra-action state commit_verified = true
##[debug]Save intra-action state bypass = true
##[debug]Set output comment_body = .deploy
##[debug]Set output issue_number = 130
##[debug]Set output type = deploy
##[debug]Set output triggered = true
##[debug]Set output comment_id = 3582873490
##[debug]Set output initial_reaction_id = 316392500
##[debug]Set output actor_handle = GrantBirki
##[debug]Set output params = 
##[debug]Set output parsed_params = 
##[debug]Set output environment = production
##[debug]Set output actor = GrantBirki
##[debug]Set output base_ref = main
##[debug]Set output default_branch_tree_sha = 1dbc3147b4146f922d6cb67d84730df3e5a74306
##[debug]Set output fork = false
##[debug]Set output commit_status = SUCCESS
##[debug]Set output review_decision = APPROVED
##[debug]Set output is_outdated = false
##[debug]Set output merge_state_status = CLEAN
##[debug]Set output approved_reviews_count = 1
##[debug]Set output ref = birkibirki-non-fork-test
##[debug]Set output sha = f06d1233e4f89f09e700b036618ab5507dd524f3
##[debug]Set output commit_verified = true
##[debug]Finishing: Run github/branch-deploy@fixes

Post Run Step:

##[debug]Evaluating condition for step: 'Post Run github/branch-deploy@fixes'
##[debug]Evaluating: always()
##[debug]Evaluating always:
##[debug]=> true
##[debug]Result: true
##[debug]Starting: Post Run github/branch-deploy@fixes
##[debug]Loading inputs
##[debug]Evaluating: github.token
##[debug]Evaluating Index:
##[debug]..Evaluating github:
##[debug]..=> Object
##[debug]..Evaluating String:
##[debug]..=> 'token'
##[debug]=> '***'
##[debug]Result: '***'
##[debug]Evaluating: job.status
##[debug]Evaluating Index:
##[debug]..Evaluating job:
##[debug]..=> Object
##[debug]..Evaluating String:
##[debug]..=> 'status'
##[debug]=> 'failure'
##[debug]Result: 'failure'
##[debug]Loading env
Post job cleanup.
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
##[debug]in stringToArray(), an empty String was found so an empty Array was returned
Warning: ⛔ bypass set, exiting
##[debug]Node Action run completed with exit code 0
##[debug]Finishing: Post Run github/branch-deploy@fixes

Specifically this section is of note:

##[debug]checking if branch production-branch-deploy-lock exists...
##[debug]branch 'production-branch-deploy-lock' exists
##[debug]constructing valid branch name: production-branch-deploy-lock
##[debug]constructed valid branch name: production-branch-deploy-lock
##[debug]checking if lock file exists on branch: production-branch-deploy-lock
##[debug]checking the owner of the lock...
##[debug]Lock ownership check - sameUser: true, sameBranch: false
##[debug]Current actor: GrantBirki, Lock owner: GrantBirki
##[debug]Current PR: 130, Lock PR: 130
##[debug]Current branch: undefined, Lock branch: birkibirki-non-fork-test
Warning: ⚠️ Same user but different branch - denying lock access
##[debug]no reason detected
##[debug]constructing valid branch name: production
##[debug]constructed valid branch name: production
##[debug]comment body is within length limit
Error: ### ⚠️ Cannot claim deployment lock

Sorry __GrantBirki__, the `production` environment deployment lock is currently claimed by __GrantBirki__

The expected behavior should be that if a user claims a lock for a given environment, they should be able to deploy to that environment everywhere regardless of which branch is involved. Perhaps there is a bug since Current branch: undefined is showing up in the logs as well.

It does make sense the approach that you took with making task based locks differ so if a user has the lock for frontend in the production environment then another user is still free to deploy backend in the production environment using a different lock. So I like that and it will free up the deployment pipeline for teams working in monorepos a lot (very nice).


Take-away items to get this merged back in:

  1. Open a fresh PR with these same changes as a starting point
  2. First ensure .js extensions are added in imports so the Action correctly loads
  3. Look at the commit I made on this PR to fix the Action schema CI check and apply the same fixes
  4. I would suggest renaming the deployment_task input option to deployment_tasks to be uniform with other input options (note it is just an "s" at the end there)
  5. Create a repo similar to this one that I have https://github.com/GrantBirki/actions-sandbox. It is basically just a sandbox repo to test out branch deployments and ensure that your changes are working in a real-world scenario outside of just the unit tests this repo provides. You can then point a variant of the branch deploy Action to your own repo/fork like so xakraz/branch-deploy@your-feature and easily test that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants