Skip to content
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

Test current code base as an integration test for PRs and pushes #505

Merged
merged 18 commits into from
Dec 14, 2020
Merged

Test current code base as an integration test for PRs and pushes #505

merged 18 commits into from
Dec 14, 2020

Conversation

Pike
Copy link
Contributor

@Pike Pike commented Nov 18, 2020

Description

Add a build step to create lib and node_modules artifact
Add an integration test to run on PRs

Testing Instructions

Happens as part of this PR.

Additional Notes

I bet the integration test will fail for insufficient permissions. We'll see.

@Pike Pike requested a review from JamesIves as a code owner November 18, 2020 14:45
@codecov-io
Copy link

codecov-io commented Nov 18, 2020

Codecov Report

❗ No coverage uploaded for pull request base (dev-v4@7a94841). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             dev-v4      #505   +/-   ##
==========================================
  Coverage          ?   100.00%           
==========================================
  Files             ?         6           
  Lines             ?       179           
  Branches          ?        50           
==========================================
  Hits              ?       179           
  Misses            ?         0           
  Partials          ?         0           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7a94841...62dc44b. Read the comment docs.

@Pike
Copy link
Contributor Author

Pike commented Nov 18, 2020

So, this failed in a good way.

Things I like about this PR: It indicates that just installing the prod dependencies should do the trick for the action (3.7.1 ships dev dependencies, too). It runs an integration test.

I'm tempted to stack dry-run on top to allow for the integration test to actually pass :-) . @JamesIves ?

@JamesIves
Copy link
Owner

JamesIves commented Nov 19, 2020

I think adding the dry run stuff to this PR will be the only way this will work unfortunately, but I'm a big fan of this. It should really help! I'm thinking we should expand this to run the entire integration test suite and not just a single one.

The release branch gets updated manually by me whenever I merge something into it (I just switch and run yarn install). I've been wanting to automate that process as the action could in theory deploy the dependencies its self in a similar manor to this whenever content is merged into that branch.

Thanks for this, it's really appreciated!

runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
Copy link
Owner

Choose a reason for hiding this comment

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

We should run v2 here with persist-credentials: false as it's the latest version; https://github.com/JamesIves/github-pages-deploy-action/blob/dev/.github/workflows/integration.yml#L42-L45

with:
FOLDER: integration
BASE_BRANCH: ${{ github.sha }}
BRANCH: gh-pages-pr
Copy link
Owner

@JamesIves JamesIves Nov 19, 2020

Choose a reason for hiding this comment

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

We should consider adding a cleanup step after this in the off chance that it does actually generate these branches (ie if someone with adequate permissions made a PR). This is a potential window for abuse so it's probably best we prevent things from lingering: https://github.com/JamesIves/github-pages-deploy-action/blob/dev/.github/workflows/integration.yml#L31-L35

@Pike Pike mentioned this pull request Nov 30, 2020
@JamesIves JamesIves added the version 4 Issues related to version 4 of this action. label Nov 30, 2020
@JamesIves JamesIves changed the base branch from dev to dev-v4 December 1, 2020 14:26
@Pike
Copy link
Contributor Author

Pike commented Dec 7, 2020

I've spun dry-run into its own PR #526 , with some unit tests.

With that, I wonder if I should move the steps into the integration.yml workflow completely?

@JamesIves
Copy link
Owner

Lemme gather my thoughts on this, I'll take a closer look later today!

@JamesIves JamesIves added the testing 🧪 This change is being tested. label Dec 8, 2020
@JamesIves JamesIves added this to the 4.0.0 milestone Dec 8, 2020
@JamesIves
Copy link
Owner

Quick question before I merge: Should this include the dry-run flag? I think keeping this in build/PR makes sense as the intention of this is to smoke test PR's instead of running the scheduled tests.

@Pike
Copy link
Contributor Author

Pike commented Dec 9, 2020

I think this should, yes, otherwise the tests won't pass.

Also, I still need to address your review comments, let me get to that real quick (I'm actually hacking on this right now 😄 )

@Pike
Copy link
Contributor Author

Pike commented Dec 9, 2020

Soooo, --dry-run isn't as dry run as I thought it was, it does fail for failed permissions. I filed #536 on that, should I tackle this as part of this PR? Sounds like doing it here is the best to avoid more chickens and eggs?

@JamesIves
Copy link
Owner

Yeah tackling it as part of this PR makes the most sense to me!

@Pike
Copy link
Contributor Author

Pike commented Dec 9, 2020

Nice, I'm finding actual bugs now. Also bugs I introduced.

@Pike
Copy link
Contributor Author

Pike commented Dec 9, 2020

For reference, generateBranch runs in workspace, but needs to run in temporaryDeploymentDirectory, now that we don't mess with workspace anymore. More refactorings coming up, sorry for that.

@Pike Pike marked this pull request as draft December 10, 2020 16:20
@Pike
Copy link
Contributor Author

Pike commented Dec 10, 2020

I'm putting this into draft state for now, I need to do a couple of iterations here, probably.

I'll update the PR here soon, but I'm also changing a lot, so feel free to comment and complain liberally.

The high-level idea is that the mix of worktree and generateBranch and singleCommit turned out to be hard to untangle for me. So I'm switching over to a generateWorktree, and then a rather different logic for singleCommit. Basically, I'm starting off with an orphan branch right away, and then use hg diff to figure out if to actually commit or not.

@JamesIves
Copy link
Owner

Sounds good to me, I'll keep an eye out. I've got a lot of spare time coming up this weekend so I'm hoping to knock out a lot of these remaining tasks for v4.

For pull requests, the github.sha is the sha of the merge to the
target branch, not the head of the PR. Special case that.
I also made the branches more generic, as there are now more of them.
Also add tests for dryRun and singleCommit and generateBranch
code flows.
…ngleCommit

This is a continuation of the no-checkout work, and sadly suggested pretty
intensive changes.
@Pike Pike marked this pull request as ready for review December 10, 2020 20:59
@Pike
Copy link
Contributor Author

Pike commented Dec 10, 2020

I think this is in a shape where I'd appreciate feedback. Candid-european is perfectly fine.

A few thoughts I have:

I think the dry-run integration testing turned out rather well. I wish it was more strict, which might be be OK to do with checking the action output. Right now it's an environment, in particular with multiple deploy steps, that's interesting. Is there a reason to not make it an step output? I also entertained the idea to expose the count of commits done as step output, which could be checked for things like singleCommit or not.

I introduced an abstraction of a git command. It's not placed anywhere logical, but just close to where it's used. I like being able to set options one by one, and then have the class generate the command string. I do think I only did this half-way, though. execute could probably take that abstraction|string as argument, and toString() itself. I'm not sure if this pays off in other parts of the code. In generateWorktree, there's a mix between --orphan and -B that might be more confusing to write as a string composition..

I also like the actual testing of createWorktree with actual git content. With that being properly (IMHO) tested by itself, it'd be nice to mock it in git.test.ts, but I haven't found a way to do that.

Also, I'm a bit lost on how to test the error handling in createWorktree.

@JamesIves
Copy link
Owner

JamesIves commented Dec 11, 2020

I will take a look first thing tomorrow when I wake up.

Copy link
Owner

@JamesIves JamesIves left a comment

Choose a reason for hiding this comment

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

This looks really good, and I really appreciate you taking the time on this. I have a few comments/questions.

Regarding testing the error handling there's a way you can make the execute function throw if it's given a specific string, I believe it's done here: https://github.com/JamesIves/github-pages-deploy-action/blob/dev/__tests__/git.test.ts#L56-L58

As we can't necessarily test git failures just ensuring that we have coverage on the catch would be significant, that way we know it will bubble up to the calling function and provide the user with an adequate error message.

Comment on lines 18 to 42
beforeAll(async () => {
const silent = true
tempdir = fs.mkdtempSync(path.join(os.tmpdir(), 'gh-deploy-'))
const origin = path.join(tempdir, 'origin')
await execute('git init origin', tempdir, silent)
await execute('git config user.email "you@example.com"', origin, silent)
await execute('git config user.name "Jane Doe"', origin, silent)
await execute('git checkout -b main', origin, silent)
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\n')
await execute('git add .', origin, silent)
await execute('git commit -mc0', origin, silent)
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\nonce more\n')
await execute('git add .', origin, silent)
await execute('git commit -mc1', origin, silent)
await execute('git checkout --orphan gh-pages', origin, silent)
await execute('git reset --hard', origin, silent)
await fs.promises.writeFile(path.join(origin, 'gh1'), 'pages content\n')
await execute('git add .', origin, silent)
await execute('git commit -mgh0', origin, silent)
await fs.promises.writeFile(
path.join(origin, 'gh1'),
'pages content\ngoes on\n'
)
await execute('git add .', origin, silent)
await execute('git commit -mgh1', origin, silent)
Copy link
Owner

Choose a reason for hiding this comment

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

Can you explain to me so I understand what's happening here. Is this setting up the requirements in the env for generateWorkTree to run? It feels weird to manually run a sequence of git commands like this but I understand the need if it's just required setup.

If that is the case we should probably comment this file to indicate such.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I'm adding a bunch of comments to the test file now.

fs.writeFileSync(path.join(origin, 'f1'), 'hello world\n')
await execute('git add .', origin, silent)
await execute('git commit -mc0', origin, silent)
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\nonce more\n')
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\nonce more\n')
fs.writeFileSync(path.join(origin, 'f1'), 'hello world\once more\n')

This is a very unfortunate typo 😛

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See, this happens when you're not a native speaker. Not really a typo, I'll just use \nand planets instead.

Copy link
Owner

Choose a reason for hiding this comment

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

haha yeah totally understand

src/git.ts Outdated
constructor(branch: string) {
this.branch = branch
}
toString(): string {
Copy link
Owner

Choose a reason for hiding this comment

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

Not sure I love naming this toString, but I get the idea of what's happening here. 😬

src/git.ts Outdated
// Special case is singleCommit with existing history, when
// we're really interested if the diff against the upstream branch
// changed.
const checkCmd =
Copy link
Owner

Choose a reason for hiding this comment

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

This might be better named checkGitStatus or something more descriptive.

)
await execute(`git fetch`, action.workspace, action.silent)

info(`Created the ${action.branch} branch… 🔧`)
Copy link
Owner

Choose a reason for hiding this comment

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

We should keep the logging in place when a branch is created

src/git.ts Outdated
@@ -33,34 +33,79 @@ export async function init(action: ActionInterface): Promise<void | Error> {
}
}

/* Generates the branch if it doesn't exist on the remote. */
export async function generateBranch(action: ActionInterface): Promise<void> {
export class GitCheckout {
Copy link
Owner

Choose a reason for hiding this comment

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

I think it would be a good idea to throw this class and its methods into a worktree.ts file as an associated worktree.test.ts file already exists. That way each test file tests its adjacent functions/classes.

with:
FOLDER: integration
BRANCH: ${{ matrix.branch }}
SINGLE_COMMIT: ${{ matrix.commit == 'singleCommit' }}
Copy link
Owner

Choose a reason for hiding this comment

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

Clever!

@Pike
Copy link
Contributor Author

Pike commented Dec 11, 2020

I'm going to just add an explicit test file for error handing. The problem (AFAICT) is that you can only mock modules per test file. So I'm having one test file that doesn't mock execute.ts, and one test file that does.

@Pike
Copy link
Contributor Author

Pike commented Dec 11, 2020

Thanks for the review, I think I've got them all.

I'm not all that fond of c3cddcb, but I also don't have a better idea. W/out that, coverage complains about the conditional check for changes files. I made that a separate commit so it's easier to mess with.

@Pike
Copy link
Contributor Author

Pike commented Dec 11, 2020

Another idea I just had was to mock

jest.mock('../src/worktree', () => ({
  // eslint-disable-next-line @typescript-eslint/naming-convention
  __esModule: true,
  generateWorktree: jest.fn()
}))

in git.test.ts. That's an opportunity now that generateWorktree is in its own module.That would decouple the tests further, in particular if the commands in generateWorktree changed. Not sure it does much more than that. Well, it cuts down the different call counts to execute from 8, 10, 11, 12 to 4, 7, 8

@JamesIves
Copy link
Owner

JamesIves commented Dec 13, 2020

Thanks for the review, I think I've got them all.

I'm not all that fond of c3cddcb, but I also don't have a better idea. W/out that, coverage complains about the conditional check for changes files. I made that a separate commit so it's easier to mess with.

There is already a isTest variable, would that be appropriate instead of adding another?

For the most part this is looking great! I'll merge this Sunday afternoon and get a pre-release up for this so we can start some more in-depth testing.

@Pike
Copy link
Contributor Author

Pike commented Dec 13, 2020

There is already a isTest variable, would that be appropriate instead of adding another?

I've been wondering about that a bit. Right now, isTest is basically hasChangedFilesForTest?

I'm not too fond of using the same value for both test flags, but we could use an enum like

enum TestFlag {
  NONE = 0,
  HAS_CHANGED_FILES = 1 << 1,
  HAS_REMOTE_BRANCH = 1 << 2,
}

Than we only need one variable, but can combine different scenarios in one test. It's also explicit when setting up the test?

@JamesIves
Copy link
Owner

I like the use of the enum!

@Pike
Copy link
Contributor Author

Pike commented Dec 14, 2020

I have mixed feelings on whether a required or an optional isTest flag is worse. TS complains about action.isTest & TestFlag.HAS_CHANGED_FILES if it's optional, which makes the code harder to read if we'd work around that. And requiring it makes the tests more verbose.

The .eslintrc.json change is something I found on the net when trying to fix the new exception, and it seems to work w/out exceptions and details now.

@JamesIves
Copy link
Owner

JamesIves commented Dec 14, 2020

I see what you mean, it is somewhat confusing to have the two. I think for now let's merge this, and in a follow-up figure out if we can deprecate the use case of isTest as it's a bit of a cheeky workaround to begin with anyway. I will take care of that as I wrote it and I think it's just used for getting test coverage, but a better handling of mocking would be more appropriate.

@JamesIves JamesIves merged commit 4e40ddd into JamesIves:dev-v4 Dec 14, 2020
@JamesIves
Copy link
Owner

@Pike Pike deleted the test-pr branch December 14, 2020 17:58
@Pike Pike mentioned this pull request Dec 14, 2020
JamesIves added a commit that referenced this pull request Feb 6, 2021
* Stop checking out workspace (#515)

* Stop checking out base branch before deployment, drop option.

* Don't check out default branch, as we don't check out base branch, drop option.

* Don't stash/unstash as we don't update the workdir, drop preserve option.

* Don't init the workspace

* Only fetch the remote branch if it exists, only with depth 1.

* Rely on previous checkouts to have handled lfs files correctly, drop option.

* Update README, action.yml, integration tests

* Set up eslint for test files. (#517)

* Add DRY_RUN option, passing --dry-run to git push. (#526)

See #499 for the proposal.

* Simplifies Token Setup (#530)

* Token simplification

* Access Token / Github Token -> Token

* Oops

* Typos

* Update README.md

* Update README.md

* Update action.yml

Co-authored-by: Axel Hecht <axel@pike.org>

* Update README.md

Co-authored-by: Axel Hecht <axel@pike.org>

* Update README.md

Co-authored-by: Axel Hecht <axel@pike.org>

* Adjust codeql action to latest recommendations (#540)

Also, add the dev and release branches, and drop master.

* Add workflow to update build and node_modules on release branches (#541)

* Stores username/email in secrets

* Removing stale bot integration

* Test current code base as an integration test for PRs and pushes (#505)

* Add a build step to create lib and node_modules artifact

* Run integration test with built dist and current SHA as base

For pull requests, the github.sha is the sha of the merge to the
target branch, not the head of the PR. Special case that.

* Use v2 checkout, and DRY_RUN for the integration test.

I also made the branches more generic, as there are now more of them.

* Fix #536, don't push at all on dryRun

Also add tests for dryRun and singleCommit and generateBranch
code flows.

* Try to fix dryRun on new remote branches, refactor fetch

* Try to fix dryRun, only fetch if origin branch exists

* Refactor worktree setup to include branch generation and setup for singleCommit

This is a continuation of the no-checkout work, and sadly suggested pretty
intensive changes.

* Set up git config to fix tests, also make debugging easier

* Add matrix for existing and non-existing branch

* Add matrix for singleCommit and not

* Drop GITHUB_TOKEN, add DRY_RUN to action.yml

* When deploying existing branch, add a modifcation and deploy again

* Force branch checkout to work in redeployment scenarios

* Make singleCommit easier to see in job descriptions

* Review comments

* Add a test-only property to action to test code paths with remote branch.

* Introduce TestFlag enum to signal different test scenarios to unit tests

* Fix util.test.ts

* Update worktree.ts

* Fix a few nits in tests and automation. Don't try to wordcount ls-rem… (#546)

* Fix a few nits in tests and automation. Don't try to wordcount ls-remote.

Nits in tests are around undoing changes made to the environment,
and to not modify the checkout.

* Describe suite with empty SHA

* Lowercase Inputs (#547)

* Lowercases inputs

* Adjusts workflow tests and deployment_status

* Use multi-line string for clean-exclude patterns. (#553)

As this change is subtle, I'm taking the opportunity to change
the underscore for the hyphen, which makes it less likely that
users of this action will just pass in an old json array.

* Hyphenate inputs and outputs, add step output, fix #558 (#559)

* Hyphenate inputs and outputs, add step output, fix #558

I've also tried to make the clean docs a bit clearer, and consistent
about clean being on my default. Still not totally happy with the intro
of the docs there, though.

* Add testing of step outputs to build integration tests

* Security Docs

* Integration tests

* Revert "Integration tests"

This reverts commit 639ff53.

* Native SSH Key Support (#569)

* SSH Key Support 🔑

* Update ssh.ts

* Update src/ssh.ts

Co-authored-by: Axel Hecht <axel@pike.org>

* README fixes/etc

* Unit Tests & README

* ssh key

* Update README.md

* Update ssh.test.ts

* Update ssh.test.ts

* Update ssh.test.ts

* Update ssh.test.ts

* Update ssh.test.ts

* Update ssh.test.ts

* Update integration.yml

Co-authored-by: Axel Hecht <axel@pike.org>

* Deployment Issues (#583)

* Update git.ts

* Tests

* Update git.ts

* Formatting

* Update src/git.ts

Co-authored-by: Axel Hecht <axel@pike.org>

* TestFlag

* Logging

* Update git.ts

Co-authored-by: Axel Hecht <axel@pike.org>

* Codespace Support (#584)

* Add files via upload

* Update README.md

* Add files via upload

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* SSH Issues (#588)

* Unsets Persisted Credentials (#587)

* Persist

* Config Setup/Tests

* Assets

* Update git.ts

* Spacing

* Update integration.yml

* Update README.md

Co-authored-by: Axel Hecht <axel@pike.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
testing 🧪 This change is being tested. version 4 Issues related to version 4 of this action.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants