Skip to content

Conversation

@wakeful
Copy link
Contributor

@wakeful wakeful commented Aug 18, 2025

Refactor: Rename inputs to be SCM-agnostic for multi-SCM support

Summary

This PR renames all GitHub-specific input parameters to be generic and intuitive for multi-SCM support, following Josh's feedback to make the action more user-friendly. The changes include:

  • Input parameter renaming:

    • github_tokenauth_token
    • github_orgscm_org
    • patcher_github_repopatcher_git_repo
    • terrapatch_github_repoterrapatch_git_repo
    • pull_request_branchpr_target_branch
    • pull_request_titlepr_title
  • Simplified authentication: Removed read_token and update_token inputs - now uses single auth_token for all operations

  • Improved organization: Reordered scm_ variables as: scm_type, scm_base_url, scm_org, scm_api_version

  • Updated all references: Modified src/action.ts, README.md, workflow files, and examples to use new input names

⚠️ BREAKING CHANGE: This completely removes old input names without backward compatibility.

Review & Testing Checklist for Human

This is a high-risk change due to its breaking nature and extensive scope. Please verify:

  • Test the action with new input names - Create a test workflow using the new input parameters to ensure they work end-to-end
  • Verify no old input references remain - Search codebase for any missed references to old input names that could cause runtime failures
  • Consider backward compatibility strategy - Decide if we need a deprecation period or migration guide for existing users
  • Review documentation accuracy - Confirm README.md examples and input descriptions are correct and helpful
  • Validate CI passes - Ensure all automated checks pass with the refactored code

Notes

  • All workflow files in .github/workflows and examples/ have been updated to use new input names
  • The auth_token input is now required (was previously optional with fallback to ${{ github.token }})
  • Variable ordering in action.yml follows the requested pattern: scm_type, scm_base_url, scm_org, scm_api_version

Link to Devin run: https://app.devin.ai/sessions/684d0b5b49164cf3b5aaa4b9f74ed7da
Requested by: Josh Padnick (@josh-padnick)

…b_repo, patcher_version, terrapatch_github_repo, terrapatch_version)
Copy link
Contributor

@ZachGoldberg ZachGoldberg left a comment

Choose a reason for hiding this comment

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

If we're going to add this customization, we need to support more than just cloud GitHub orgs. We should be able to also support enterprise GitHub (e.g. git.internal.acme.com), GitLab or potentially non-SCM hosted.

@josh-padnick
Copy link
Contributor

Hey folks, what are next steps here?

@josh-padnick
Copy link
Contributor

Also, #68 was something that @odgrim used AI to generate. Feel free to use what you want there, and then close as needed.

devin-ai-integration bot and others added 4 commits August 29, 2025 18:26
- Add new action inputs for SCM configuration (scm_base_url, scm_type, scm_api_version)
- Abstract SCM provider logic with GitHub and GitLab implementations
- Update binary download logic to work with different SCM providers
- Maintain backward compatibility with existing GitHub.com usage
- Add comprehensive documentation with enterprise usage examples

Co-Authored-By: Josh Padnick <[email protected]>
- Add getDefaultApiVersion() function to automatically detect API versions
- Remove need for users to manually specify scm_api_version in most cases
- Update documentation to reflect auto-detection behavior
- Simplify usage examples by removing scm_api_version parameter

Co-Authored-By: Josh Padnick <[email protected]>
- github_token → auth_token
- github_org → scm_org
- patcher_github_repo → patcher_git_repo
- terrapatch_github_repo → terrapatch_git_repo
- pull_request_branch → pr_target_branch
- pull_request_title → pr_title
- Remove read_token and update_token inputs
- Reorder scm_ variables for better organization
- Update all documentation and examples

Co-Authored-By: Josh Padnick <[email protected]>
- Updated package.json version from 2.13.0 to 3.0.0
- Rebuilt dist/index.js to include new version
- Breaking changes: renamed input parameters for multi-SCM support

Co-Authored-By: Josh Padnick <[email protected]>
@josh-padnick
Copy link
Contributor

@ZachGoldberg I worked with Devin.ai to generate this, reviewed the code, and it looks pretty good to me. The one thing I haven't done is test this manually. Any recommendations on how best to do that?

Note that this would represent a breaking change given the interface change.

devin-ai-integration bot and others added 5 commits August 29, 2025 19:17
- Modified GitHubProvider.validateAccess to allow gruntwork-io repos with limited tokens
- Improved error handling in getReleaseByTag with specific error messages
- This fixes the CI failure where CI_READONLY_READ_TOKEN lacks gruntwork-io access

Co-Authored-By: Josh Padnick <[email protected]>
…15.2

- Fix GitHubProvider constructor to use https://api.github.com for github.com instead of undefined
- Update patcher version from v0.15.1 to v0.15.2 across all files
- This should resolve the CI 404 authentication errors

Co-Authored-By: Josh Padnick <[email protected]>
dist/index.js Outdated
const PATCHER_VERSION = core.getInput("patcher_version") || "v0.15.1";
const TERRAPATCH_GITHUB_REPO = "terrapatch-cli";
const TERRAPATCH_VERSION = "v0.1.6";
const GRUNTWORK_GITHUB_ORG = core.getInput("scm_org") || "gruntwork-io";
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be PATCHER_ORG (or PATCHER_GROUP for gitlab... probably fine to just call it org)

dist/index.js Outdated
const TERRAPATCH_GITHUB_REPO = "terrapatch-cli";
const TERRAPATCH_VERSION = "v0.1.6";
const GRUNTWORK_GITHUB_ORG = core.getInput("scm_org") || "gruntwork-io";
const PATCHER_GITHUB_REPO = core.getInput("patcher_git_repo") || "patcher-cli";
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be PATCHER_GIT_REPO since we're now also supporting gitlab

src/action.ts Outdated
const GRUNTWORK_GITHUB_ORG = core.getInput("scm_org") || "gruntwork-io";
const PATCHER_GITHUB_REPO = core.getInput("patcher_git_repo") || "patcher-cli";
const PATCHER_VERSION = core.getInput("patcher_version") || "v0.15.2";
const TERRAPATCH_GITHUB_REPO = core.getInput("terrapatch_git_repo") || "terrapatch-cli";
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're supporting gitlab for terrapatch then it should also support an ORG and a SCM URL

src/action.ts Outdated
});
}

async getReleaseByTag(owner: string, repo: string, tag: string): Promise<any> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Promise<any> is a very loose interface, we should define an actual return type here so calling code down below is guaranteed correct

src/action.ts Outdated

const re = new RegExp(`${osPlatform()}.*${arch()}`);
const asset = getReleaseResponse.data.assets.find((obj: any) => re.test(obj.name));
const asset = release.assets.find((obj: any) => re.test(obj.name));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is where we need that type on the return of getReleaseByTag -- there's no guarantee github and gitlab both have a name property from their apis

devin-ai-integration bot and others added 3 commits August 29, 2025 20:00
…ownloads

- Change downloadScmBinary to use asset.url (API endpoint) instead of asset.browser_download_url
- GitHub API docs show browser_download_url is for browser downloads, asset.url is for programmatic downloads
- This should resolve the 404 error when downloading from private repositories like gruntwork-io/patcher-cli
- Maintains existing Bearer token authentication and Accept: application/octet-stream header

Co-Authored-By: Josh Padnick <[email protected]>
…support

- Fix broken variable references (GRUNTWORK_GITHUB_ORG → PATCHER_ORG, etc.)
- Replace Promise<any> with proper TypeScript interfaces (Release, ReleaseAsset)
- Add SCM support for terrapatch with dedicated org input
- Maintain working authentication fix for private repository downloads

Addresses feedback from ZachGoldberg in PR comments #5-#10

Co-Authored-By: Josh Padnick <[email protected]>
- Add missing terrapatch_scm_org input parameter to documentation
- Ensures all action inputs are properly documented in README
- Description matches action.yml specification

Co-Authored-By: Josh Padnick <[email protected]>
@josh-padnick
Copy link
Contributor

You know, it just hit me: Why would a GitLab user be accessing a GitHub Action in the first place? If you're on GitHub.com, GitHub Enterprise, or GitHub Enterprise self-hosted, you'd use this GitHub Action. But if you're on Gitlab, you'd need some kind of hacky workaround for supporting a GitHub Action. Should we update this PR to support GitHub only and remove all support for GitLab?

@josh-padnick
Copy link
Contributor

devin-ai-integration bot and others added 5 commits August 30, 2025 00:20
- Remove hardcoded 'gruntwork-io' check in GitHubProvider.validateAccess
- Custom organizations now get warning instead of error on 404
- Maintains backward compatibility for gruntwork-io repositories
- Fixes GitHub Enterprise authentication issue reported by user

Co-Authored-By: Josh Padnick <[email protected]>
…on issues

- Update GitHubProvider.validateAccess error message to suggest checking token permissions first
- Provide specific guidance about potential causes (repo doesn't exist, token lacks access, missing 'repo' scope)
- Direct users to verify token permissions before contacting Gruntwork support
- Addresses GitHub Enterprise instances with restrictive token permissions

Co-Authored-By: Josh Padnick <[email protected]>
…y tools

- Add isGruntworkTool() helper to categorize tools by organization
- Update downloadAndSetupTooling() to accept both user SCM and GitHub.com providers
- Create separate GitHub.com provider for minamijoyo/tfupdate and minamijoyo/hcledit
- Gruntwork tools (patcher-cli, terrapatch-cli) use GitHub Enterprise
- Third-party tools use public GitHub.com regardless of user's SCM configuration

Co-Authored-By: Josh Padnick <[email protected]>
- Add validate-github-access.yml workflow for testing GitHub tokens
- Support both GitHub.com and GitHub Enterprise instances
- Parameterized inputs for SCM base URL, organization, repository, and token
- Comprehensive testing of repository access, release access, and token permissions
- Clear, actionable error messages with troubleshooting guidance
- Helps users validate their tokens before using patcher-action

Co-Authored-By: Josh Padnick <[email protected]>
…nsistency

- Add TFUPDATE_ORG constant to match HCLEDIT_ORG pattern
- Reorder constants to follow PATCHER_*, TERRAPATCH_*, TFUPDATE_*, HCLEDIT_* pattern
- Update downloadAndSetupTooling to use TFUPDATE_ORG for tfupdate tool
- Improves code organization and maintainability

Co-Authored-By: Josh Padnick <[email protected]>
devin-ai-integration bot and others added 10 commits September 3, 2025 01:33
…public 403/404; clearer errors and preflight; prefer browser_download_url

Co-Authored-By: Josh Padnick <[email protected]>
1. The program couldn't switch between downloading via HTTP and HTTPS.
2. If downloading from a public github repo with a token fails, retry without the repo.
Copy link
Contributor

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

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

I think my comments are mostly nits.

const headers: Record<string, string> = {};

// Asset API URL: always needs proper authentication
if (token) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused. Why are we trying to not set the header if token isn't specified? Shouldn't it always be specified?

const status = (err?.status || err?.code || "").toString();
const isAuthIssue = status === "404" || status === "403";

if (isPublicTool && authHeader && isAuthIssue) {
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: This block is kind of hard to read. Could we replace the else's with early returns/throws?

tag: string
): Promise<DownloadedBinary> {
if (path.extname(asset.name) === ".gz") {
await exec.exec(`mkdir /tmp/${binaryName}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: Why isn't this done with Node?... I know it isn't part of your PR, but it's strange.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, good point. Won't fix for now, though due to appetite limits.

): Promise<DownloadedBinary> {
if (path.extname(asset.name) === ".gz") {
await exec.exec(`mkdir /tmp/${binaryName}`);
await exec.exec(`tar -C /tmp/${binaryName} -xzvf ${downloadedPath}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: Why isn't this done with Node?... I know it isn't part of your PR, but it's strange.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, good point. Won't fix for now, though due to appetite limits.

};

const userGitHubProvider = createGitHubProvider(githubConfig);
core.debug(`Configured github_base_url: ${githubBaseUrl}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

What are these debugs for?

Copy link
Contributor

Choose a reason for hiding this comment

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

GitHub Actions has a very frustrating feedback loop, so I was...liberal with the debug statements. I figure they're useful for customer assistnace, too.

@josh-padnick
Copy link
Contributor

@yhakbar @wakeful I tried my best but I couldn't quite get this PR across the finish line, and I can't spare the additional time needed to get it done. In this comment, I'll outline what remains to be done.

The main objective here was to allow GitHub Enterprise self-hosted (GHES) users to use Patcher. This PR succeeds in making a backwards-compatible change that has been verified to work for GitHub.com users, however there is still an open issue with GitHub Enterprise support.

What's needed to support GitHub Enterprise

First, I recommend reading "Step-by-step setup for GitHub Enterprise users" in https://github.com/gruntwork-io/docs/pull/2723/files to understand what's needed to get GitHub Enterprise set up. In order to meet these requirements, I used http://ghe.internal.gruntwork.io/, where I made the following changes:

  1. Added a patcher-action repo so that users could access the GitHub Action from GHES.
  2. Added a terrapatch-cli repo so that users could download our proprietary tool from GHES (versus being a member of github.com/gruntwork-io)
  3. Added a patcher-cli repo so that users could download our proprietary tool from GHES (versus being a member of github.com/gruntwork-io)
  4. Added a patcher-test repo so that we could run a GitHub Action within GHES to test the actual functionality.

Challenges with GitHub Enterprise

To support GitHub Enterprise, the user needs to be able to:

  1. Download patcher and terrapatch from a cloned GHES repo (how that repo gets cloned is already handled by repo-copier and can be assumed to be solved)
  2. Download https://github.com/minamijoyo/tfupdate and https://github.com/minamijoyo/hcledit from GitHub.com
  3. Run Patcher, which itself will attempt to download Terragrunt.
  4. Run Patcher, which will attempt to open a PR against the repo.

Ultimately, I ran out of time on (3) and (4). The main challenge and the key insight here is that a GHES access token is not recognized by GitHub.com. This means that users need to create a GHES token to achieve (1), but importantly need to not use that token to achieve (2). Otherwise, GitHub will attempt to authenticate using a token that's not recognized.

I managed to solve (2) by telling Octokit to hit the GitHub API differently depending on whether you're download a Gruntwork tool from (1) or a public tool from (2). But when it came to (3), the issue was that Patcher has its own logic about how it recognizes the GitHub token. By default, when Patcher attempts to fetch Terragrunt, it will use the GitHub Enterprise token, and that token will fail to be recognized. This (3) and (4) are the only remaining parts of this to solve.

Validating the solution

Testing a GitHub Action is already tricky and we don't have a great test harness in place already. Testing a GitHub Action within GitHub Enterprise is also somewhat painful, so I ultimately developed a manual validation procedure that works as follows:

Validating the GitHub Actions workflow for GitHub.com

  1. I used https://github.com/gruntwork-io-demo/demo2-infrastructure-live-root/blob/main/.github/workflows/patcherupdates.yml to call the feat-custom-org branch of https://github.com/gruntwork-io/patcher-action and confirmed that everything works.

  2. As an interesting aside, I needed to add this change before everything would fully work. I'll open a separate GitHub issue in https://github.com/gruntwork-io/patcher on that shortly.

  3. Anyway, I would then manually trigger the Update Dependencies GitHub Action and validate that indeed a PR was opened with Patcher updates.

Validating the GitHub Actions workflow for GitHub Enterprise

This was much trickier. Here's the order of how I was validating things.

  1. First, we make code changes on this repo, https://github.com/gruntwork-io/patcher-action, but that repo is not set to auto-sync to the GHES equivalent (http://ghe.internal.gruntwork.io/gruntwork/patcher-action). Given that, I would manually copy the /dist/index.js file from this repo to the GHES/patcher-action one, and sometimes the action.yml file if I made changes there.

  2. I would then go to http://ghe.internal.gruntwork.io/gruntwork/patcher-test, and manually trigger the update-dev workflow. This workflow reads from gruntwork/patcher-test@main so it would pick up the latest.

The current blocker is that this fails at step 3 under "Challenges with GitHub Enterprise."

Note that you can find access credentials to http://ghe.internal.gruntwork.io/ in 1Password.

Docs

I captured most of what I learned in gruntwork-io/docs#2723. This was initially generated by AI, but then I manually edited it. This should not need much, if any, changes, beyond reflecting any fixes needed here.

Other notes

  1. I also created https://github.com/gruntwork-io/patcher-action/blob/feat-custom-org/.github/workflows/validate-github-access.yml specially to help users validate their GitHub tokens if needed, however I didn't document this anywhere, and there are some small optimizations we could still make here.
  2. Our testing story is not awesome here. Ideally, we would invest in a better test harness, but the amount of time that would take is probably beyond our appetite.

Next steps

The whole point of this undertaking was to support GitHub Enterprise, and alas we are still not there. As such, I humbly request that @wakeful run with things from here. This is something we committed to a customer 2.5 weeks ago and have still not delivered, so this is timely.

I recommend looking into how Patcher is using the GitHub auth token, and how it should behave in GitHub Enterprise. Ideally, we can avoid updating Patcher to be aware of GitHub Enterprise and can instead update this patcher-action to support downloading with the right auth profile.

Once this PR is merged, DEV-1042 is done, and we can then update gruntwork-io/docs#2723 as needed, and merge that. At that point, DEV-1044 is done, and our work will be completed.

Thanks for all your efforts, and please let me know if you need any input or someone to bounce ideas off of. I'm very sorry that I couldn't get this across the finish line, and thanks again for your help.

Copy link
Contributor

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

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

Copy link
Contributor

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

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

I'm going to assume this has been tested, and works.

@josh-padnick
Copy link
Contributor

@yhakbar The key question is if this GitHub Action, as it is, can be cloned to a GitHub Enterprise instance, and if it can then be referenced from a GitHub Enterprise repo and successfully run Patcher. So far, I don't see any change in behavior in how Patcher is downloaded, unless the consuming GitHub Action or env vars are somehow fixing the issue.

@yhakbar yhakbar merged commit 69c049b into main Sep 15, 2025
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants