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

Log website URL upon deployment #1329

Merged
merged 12 commits into from
Aug 27, 2020
Merged

Conversation

KendrickAng
Copy link
Contributor

What is the purpose of this pull request? (put "X" next to an item, remove the rest)

• [ ] Documentation update
• [ ] Bug fix
• [ ] New feature
• [X] Enhancement to an existing feature
• [ ] Other, please explain:

What is the rationale for this request?
This change helps the user easily access the website after deploying it using the MarkBind CLI.

What changes did you make? (Give an overview)
Github supports custom domains through the use of CNAME. However, to do so a file called CNAME must be placed in the root of the remote repository where we are deploying (the file is automatically created if one sets a manual deploy url through the github repo itself). Hence when markbind deploy is run, the following additional steps are done:

  1. read the contents of the CNAME file in the origin remote with external library simple-git.
  2. If not, there must be no custom url, and we proceed to manually construct the URL, first from the provided repo from site.json, otherwise using the remote itself.

Provide some example code that this change will affect:

 static getDeploymentUrl(options) {
    const HTTPS_PART = 'https://';
    const SSH_PART = 'git@github.com:';
    const GITHUB_IO_PART = 'github.io';

    // https://<name|org name>.github.io/<repo name>/
    function constructGhPagesUrl(remoteUrl) {
      if (remoteUrl.includes(HTTPS_PART)) {
        // https://github.com/<name|org>/<repo>.git (HTTPS)
        const parts = remoteUrl.split('/');
        const repoName = parts[parts.length - 1].toLowerCase();
        const name = parts[parts.length - 2].toLowerCase();
        return `https://${name}.${GITHUB_IO_PART}/${repoName}`;
      } else if (remoteUrl.includes(SSH_PART)) {
        // git@github.com:<name|org>/<repo>.git (SSH)
        const parts = remoteUrl.split('/');
        const repoName = parts[parts.length - 1].toLowerCase();
        const name = (parts[0].split(':'))[0];
        return `https://${name}.${GITHUB_IO_PART}/${repoName}`;
      }
      throw new Error(`Unknown remote url ${remoteUrl}`);
    }

    const { remote, branch, repo } = options;
    const cnamePm = gitUtil.getRemoteBranchFile('blob', remote, branch, 'CNAME');
    const remoteUrlPm = gitUtil.getRemoteUrl(remote);
    const promises = [cnamePm, remoteUrlPm];

    return Promise.all(promises)
      .then((results) => {
        const cname = results[0];
        const remoteUrl = results[1];
        if (cname) {
          return cname;
        } else if (repo) {
          return constructGhPagesUrl(repo);
        }
        return constructGhPagesUrl(remoteUrl);
      })
      .catch((err) => {
        logger.error(err);
        return null;
      });
  }

Testing instructions:

  1. Create a dummy website using markbind init.
  2. Run markbind deploy and check the url the website is deployed at.

Proposed commit message: (wrap lines at 72 characters)
Log website URL upon deployment

Copy link
Contributor

@ang-zeyu ang-zeyu left a comment

Choose a reason for hiding this comment

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

package-lock (from running npm run setup) will need to be committed too

Some comments:

async getRemoteBranchFile(simpleGit, type, remote, branch, fileName) {
const catFileTarget = `${remote}/${branch}:${fileName}`;
return simpleGit.catFile([type, catFileTarget])
.catch((err) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

since async is used here, let's do a try ... return await ... catch instead!

@@ -27,6 +27,11 @@ jest.mock('fs');
jest.mock('walk-sync');
jest.mock('gh-pages');
jest.mock('../../src/Page');
jest.mock('simple-git', () => () => ({
Copy link
Contributor

Choose a reason for hiding this comment

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

is this mock still necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ang-zeyu otherwise, there would be tons of warnings warn: message=fatal: Not a valid object name origin/gh-pages:CNAME thrown in the test for deployment in Site.test.js.


// https://<name|org name>.github.io/<repo name>/
function constructGhPagesUrl(remoteUrl) {
if (remoteUrl.includes(HTTPS_PART)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

should we use startsWith here instead?

Likewise for SSH_PART (i'm not too sure on the format requirements here though, correct me if I'm wrong!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, that would make more sense, thank you!

const name = (parts[0].split(':'))[0];
return `https://${name}.${GITHUB_IO_PART}/${repoName}`;
}
throw new Error(`Unknown remote url ${remoteUrl}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the message here isn't used, let's just return null directly for use in the above.

depUrl => (depUrl != null ? resolve(`Deployed at ${depUrl}!`) : resolve('Deployed!'))

Could remove the catch(..) below as well

Copy link
Contributor Author

@KendrickAng KendrickAng Aug 21, 2020

Choose a reason for hiding this comment

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

@ang-zeyu I'm not sure whether we should remove the catch(..) statement; I put it there to deal with cases where gitUtil fails when calling the methods of simple-git, causing Promise.all to reject

Copy link
Contributor

Choose a reason for hiding this comment

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

there's a try ... catch in gitUtil already though

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, I've removed the throw statement; it returns null now

.then(resolve)
.then(() => {
const git = simpleGit({ baseDir: process.cwd() });
const options = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to move the previous options up to avoid duplication?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can use a more explicit variable name (maybe deployOptions?) to make it clearer what kind of options these are as well!

*/
async getRemoteBranchFile(simpleGit, type, remote, branch, fileName) {
const catFileTarget = `${remote}/${branch}:${fileName}`;
return simpleGit.catFile([type, catFileTarget])
Copy link
Contributor

Choose a reason for hiding this comment

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

Not too familiar with CNAME file and cat-file, give me some time to take a look at that!
Perhaps one of the other maintainers @acjh @marvinchin might have across it before though

Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't something I'm familiar with either, unfortunately :(

// git@github.com:<name|org>/<repo>.git (SSH)
const parts = remoteUrl.split('/');
const repoName = parts[parts.length - 1].toLowerCase();
const name = (parts[0].split(':'))[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

should the ending be [1]? would parts[0].substring(SSH_PART.length) work instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, that would work better!

Copy link
Contributor

@marvinchin marvinchin left a comment

Choose a reason for hiding this comment

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

Thanks for looking at this! Left a couple of suggestions 🙂

.then(() => {
logger.info('Deployed!');
})
.then(deployMsg => logger.info(deployMsg))
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't feel very intuitive for the Site constructor to return a message. The message feels more like the responsibility of the CLI. I think that it might be more appropriate for it to return some data about the site created (the url in this case), which we can then use to construct the deploy message here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, I'll do that!

.then(resolve)
.then(() => {
const git = simpleGit({ baseDir: process.cwd() });
const options = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can use a more explicit variable name (maybe deployOptions?) to make it clearer what kind of options these are as well!

options.branch = this.siteConfig.deploy.branch || defaultDeployConfig.branch;
return Site.getDeploymentUrl(git, options);
})
.then(depUrl => (depUrl != null ? resolve(`Deployed at ${depUrl}!`) : resolve('Deployed!')))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use !== instead of !=?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't notice I put !=, thanks!

}

const { remote, branch, repo } = options;
const cnamePm = gitUtil.getRemoteBranchFile(git, 'blob', remote, branch, 'CNAME');
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I'm missing some context here, but I'm not sure what Pm stands for. Is it for promise?

Copy link
Contributor

Choose a reason for hiding this comment

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

If it is, I'd prefer to avoid using uncommon (to me, at least! if this is a convention you are more familiar with please correct me) abbreviations to avoid confusion when future devs look at this variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was meant to be shorthand for 'Promise'; Ill rename it to cnamePromise for better readability. Thanks!

*/
async getRemoteBranchFile(simpleGit, type, remote, branch, fileName) {
const catFileTarget = `${remote}/${branch}:${fileName}`;
return simpleGit.catFile([type, catFileTarget])
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't something I'm familiar with either, unfortunately :(

Copy link
Contributor

@ang-zeyu ang-zeyu left a comment

Choose a reason for hiding this comment

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

Looks good code quality wise!

Some minor implementation issues:

Untitled
Hmm seems like there's a newline after the deployment url if it is from cname sometimes; Let's strip trailing whitespace / newlines just in case


Untitled2

Let's remove the logger.warn in gitUtil, since the user can use either option

- remote logger.warn from gitUtils
- trim whitespaces and line endings from cname
@KendrickAng
Copy link
Contributor Author

KendrickAng commented Aug 22, 2020

okay, I've made the changes as requested!

@@ -4,3052 +4,3023 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"jest": {
Copy link
Contributor

Choose a reason for hiding this comment

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

there shouldn't be any diffs in this package-lock; likely from a npm install

Copy link
Contributor

Choose a reason for hiding this comment

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

#1329 (comment) as well!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

rectified the changed package-lock.json!

Copy link
Contributor

@ang-zeyu ang-zeyu left a comment

Choose a reason for hiding this comment

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

Sorry for the wait

I should really have untagged this as good first issue given the amount of additions in #947 (oh well =X)
Thanks! And well done for a first issue : )

@ang-zeyu ang-zeyu added this to the v2.15.3 milestone Aug 27, 2020
@ang-zeyu ang-zeyu merged commit 08ef1ee into MarkBind:master Aug 27, 2020
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.

None yet

3 participants